diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 000000000..f29d257cc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,11 @@ +# editorconfig.org + +root = true + +[*] +charset = utf-8 +end_of_line = lf +indent_size = 2 +indent_style = space +insert_final_newline = true +trim_trailing_whitespace = true diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 000000000..6313b56c5 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml new file mode 100644 index 000000000..dd2241b0b --- /dev/null +++ b/.github/FUNDING.yml @@ -0,0 +1 @@ +open_collective: layui diff --git a/.github/ISSUE_TEMPLATE/bug-feature.yml b/.github/ISSUE_TEMPLATE/bug-feature.yml new file mode 100644 index 000000000..b8d90c2f0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-feature.yml @@ -0,0 +1,69 @@ +name: 😄 创建议题 +description: 此处只受理 Bug 报告、功能请求。若是其他业务相关的问题建议在 Discussions 寻求社区帮助。 +title: '[组件名称] 描述问题的标题' +body: + - type: markdown + attributes: + value: | + > 💡 请务必遵循标题格式。例如:[table] 表格能否支持自定义请求 + - type: checkboxes + attributes: + label: 议题条件 + description: 在你开始之前,请花几分钟时间确保你已如实完成以下工作,以便让我们更高效地沟通。 + options: + - label: 我确认已查看官方使用文档:https://layui.dev ,但没有找到相关解决方案。 + required: true + - label: 我确认已在 [Issues](https://github.com/layui/layui/issues?q=is%3Aissue ) 中搜索过类似的问题,但没有找到相关解决方案。 + required: true + - label: 我已仔细阅读: 🍀[ Layui Issue 贡献指南](https://github.com/layui/layui/blob/main/CONTRIBUTING.md) + required: true + - type: dropdown + id: type + attributes: + label: 议题类型 + options: + - 疑是 BUG + - 功能请求 + validations: + required: true + - type: input + attributes: + label: 使用版本 + description: 请提供您当前使用的 Layui 版本号。若不清楚,可打开 `layui.js` 查看头部注释。 + placeholder: 如:v2.8.18 + validations: + required: true + - type: textarea + attributes: + label: 问题描述 + description: 请提供详细的问题描述和操作步骤等信息,以便我们也能够更轻松地将问题复现。 + validations: + required: true + - type: textarea + attributes: + label: 业务代码 + description: 即你在调用组件时编写的代码片段。直接将你的代码粘贴到文本框即可,此处无需书写 `Markdown` + render: auto + validations: + required: true + - type: textarea + attributes: + label: 截图补充 + description: 如上述仍然无法准确地表述问题,可提供必要的截图(可直接粘贴上传) + - type: input + attributes: + label: 浏览器 + placeholder: 如:Chrome x.x.x.x(正式版本)(64 位) + validations: + required: true + - type: input + attributes: + label: 演示地址 + description: 若能提供 Stackblitz, CodePen 或自主搭建的页面演示地址,将更有助于解决问题 + placeholder: URL + - type: checkboxes + attributes: + label: 友好承诺 + options: + - label: 我承诺将本着相互尊重、理解和友善的态度进行交流,共同维护 Layui 良好的社区氛围。 + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..3869a88a2 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: 📄 官方文档 + url: https://layui.dev/ + about: 在创建 Issue 之前,请仔细查阅 Layui 开发文档,以便对其有更深入的了解,和更好地分析问题。 + - name: 🔎 Gitee Issues + url: https://gitee.com/layui/layui/issues + about: 从 Gitee 平台的 6000+ Issues 中搜索相似议题,找到可供参考的解决方案。适用于 2.x 版本。 diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 000000000..00b5d6701 --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,261 @@ +# Layui 协作者指南 + +欢迎加入 Layui 的协作。Layui 是一个采用原生态开发模式的开源 Web UI 组件库,它为更便捷地构建通用级业务界面而生。在您开始 Coding 之前,请先仔细阅读并熟悉这个项目的既有代码、文件和该协作者指南。 + +## 开发规范 + +> **核心理念**:让 Layui 严格遵循基准规范,保证项目的可读性、可扩展性。 + +### 技术栈 + +- **开发语言**: JavaScript(ES6+)、CSS3 、HTML5 +- **构建工具**: Rollup + Babel + PostCSS +- **其他工具**: Prettier + ESLint + Jest 等 +- **模块规范**:ES Modules + +### 核心模块 + +- 通过 `src/core/lay.js` 为组件提供通用的基础支撑。 +- 通过 `src/core/component.js` 创建组件。 +- 通过 `src/core/i18n.js` 为组件提供多语言的国际化支持。 + +### 目录结构 + +```text +layui/ +├── dist/ # 构建产物 +├── docs/ # 文档目录 +├── src/ # 源代码开发目录 +│ ├── components/ # 组件模块 +│ │ ├── button/ +│ │ └── ... +│ ├── core/ # 核心模块 +│ ├── index.js # ESM 打包入口 +│ └── index.umd.js # UMD 打包入口 +├── scripts/ # 构建脚本 +├── tests/ # 测试目录 +│ ├── unit/ # 单元测试 +│ ├── visual/ # 可视化测试示例 +└── package.json +``` + +### 代码规范 + +#### Code formatting + +采用 Prettier 作为代码格式化工具,使用单引号 `{ "singleQuote": true }` 规则,其余采用默认配置。 + +#### Code linting + +采用 ESLint 作为代码静态分析工具,禁止随意使用 `console.log`,仅允许:`console.warn` 和 `console.error`。 + +#### 命名空间 + +用于 DOM 层面的命名空间,采用 `lay` 为前缀,如: + +- CSS 类名 + +```css +.lay-btn { +} +``` + +- HTML 特定属性名 + +```html +
+``` + +- Web Components 标签名 + +```html + +``` + +用于项目产物名称、UMD 全局变量,采用 `layui`,如: + +```html + + + +``` + +#### 命名规则 + +| 类型 | 命名规则 | 示例 | +| --------------- | ------------------------------------------ | --------------------------- | +| CSS 类名 | `lay-` + `kebab-case` (小写字母加连字符) | `.lay-tabs-header` | +| JavaScript 类名 | PascalCase (大驼峰) | `Button, TreeTable` | +| 组件名、文件名 | camelCase (小驼峰)或全小写 | `button, treeTable` | +| 回调函数 | camelCase + 生命周期 | `beforeRender, afterRender` | +| 事件处理器属性 | `on` + 事件名 | `onClick` | + +#### 样式主题 + +Layui 3 内置蓝绿双主题(可切换), 使用 CSS 自定义属性管理颜色。 + +```css +:root { + /* 蓝绿双主题色 */ + --lay-color-primary-green: #16b777; + --lay-color-primary-blue: #1e9fff; + /* 默认主题色 */ + --lay-color-primary: var(--lay-color-primary-green); +} +``` + +--- + +## 代码注释与可维护性规范 + +> **核心理念**:你不是一个人在开发。注释服务于团队协作,帮助新成员快速理解代码意图与边界。 + +### 适用范围 + +- `src/` 下所有源代码 +- `tests/` 下所有测试用例 + +### 配置项注释(强制) + +每个 `config` 选项必须在定义处写**行尾注释**,包含: + +- 用途 +- 可选值范围或默认行为 +- 若存在优先级关系,须注明优先级 +- 若涉及兼容行为,须注明兼容语义 + +示例: + +```js +config: { + trigger: 'click', // 标签切换的触发事件(click | hover) + headerMode: 'auto' // 标签头部显示模式:auto | scroll | normal +} +``` + +### 方法注释(强制) + +- **所有公开方法**必须写完整 JSDoc。 +- **复杂私有方法**必须写 JSDoc,解释职责与关键流程。 + +JSDoc 必须包含: + +- 方法职责(做什么) +- 参数含义(含默认行为) +- 返回值类型与含义 +- 关键副作用(如事件触发、缓存写入、DOM 变更) + +示例: + +```js +/** + * 设置分隔条位置并触发对应事件。 + * @param {string|number} id - 实例 ID + * @param {number|string} value - 目标位置(像素或百分比) + * @returns {number|false|undefined} + */ +``` + +### 事件与回调注释(强制) + +- 必须说明事件的触发时机。 +- 若事件支持阻断机制(`return false`),必须在注释中明确说明。 + +### 示例代码注释(强制) + +适用于 `docs/` 与 `tests/visual/` 中的示例: + +- **实例创建代码块**必须添加**实例级注释**,并与页面中的 `h2` 标题一一对应。 +- 对关键行为(如限制条件、事件监听、API 触发)补充简短说明。 +- 注释应简洁明确,避免冗余,且与页面文案保持一致。 + +示例: + +```js +// 动态操作 +tabs.render({ ... }); + +// 方法渲染 +tabs.render({ ... }); +``` + +### 维护要求 + +- 新增配置项 → 必须同步新增配置注释。 +- 新增/修改公开方法 → 必须同步更新 JSDoc。 +- 新增/修改示例 → 必须检查实例级注释是否与标题对应。 + +--- + +## 测试用例编写规范 + +任何功能新增、破坏性变更,都必须在 `tests/` 中同步更新相关用例。 + +--- + +## 文档编写规范 + +Layui 文档采用 `Markdown + HTML + laytpl` 混合编写,其中 laytpl 为视图引擎(后面考虑更换为 ejs),支持导入文档子模板,格式示例:`{{- d.include("/{组件名}/detail/demo.md") }}` + +### 创建文档 + +当新增组件时,必须在 `docs/` 中根据 `docs/.template/` 给定的模板为组件新增对应的完整文档,保存在 `docs/{组件名}/` 目录。文档模板介绍: + +- `index.md`: 组件文档主文件,包含示例、API、属性等完整内容。当整体内容过大时,可将内容篇幅较大的碎片作为子模板放置在 `detail/` 目录,并导入对应的子模板即可。 +- `detail/`: 该目录用于存放文档子模板。 + - `detail/demo.md`: 组件示例主模板。当整体内容过大时,可将示例内容拆分成多个子模板,保存在 `examples/` 目录,并导入对应的示例子模板即可。 + - `detail/options.md`: 组件 `render()` 方法接受的配置选项。采用表格的方式展示。 +- `examples/`: 该目录用于存放组件示例子模板。 + +### 更新文档 + +- 任何功能新增、破坏性变更,都必须更新文档说明及相关示例。 +- 新增功能必须添加 `` 标签标注,如 `3.2.0+` 即代表该功能从 `3.2.0` 版本开始新增。 + +--- + +## 构建产物策略(强制) + +- 日常开发与任务交付阶段,**禁止执行生成 `dist/` 的构建命令**。 +- 验证优先使用:静态检查、单元测试、局部验证、可视化页面验证。 +- `dist/` 仅在 **版本发布(release)阶段**统一生成。 +- 若确需本地构建产物,必须由用户**明确提出后再执行**。 + +--- + +## PR 提交规范 + +### 触发条件 + +当用户表达「准备提交 PR / 打算提 PR / 帮我写 PR 内容 / 帮我写提交信息」等意图时,必须启用本规范。 + +### 输出格式(强制) + +#### PR 标题 + +标题必须符合 [语义化提交规范(Conventional Commits)](https://www.conventionalcommits.org/zh-hans/v1.0.0/),简洁准确反映变更本质,例如: + +- `feat(table): 新增 Virtualized List 支持` +- `fix(table): 修复 Virtualized List 边缘问题` + +#### PR 描述 + +- 基于 `.github/pull_request_template.md` 的结构输出完整 PR 文本: + - **变化性质**:至少勾选一项,按实际改动选择;不确定时优先选择最贴近的一项。 + - **变化内容**:使用清晰条目描述关键改动,优先覆盖: + - 解决了什么问题、变更了哪些功能或行为、对用户或维护者的直接收益 + - 若存在关联 issue,请使用 `closes` / `fixes` / `resolves` 等关键词(如 `closes #123`)。 + - **满足条件**:根据当前上下文如实勾选;无法确认时保守不勾选,并注明「待补充项」。 + +### 质量要求 + +- 禁止输出与模板结构不一致的 PR 文本。 +- 禁止生成与实际改动无关的标题或提交说明。 + +--- + +> **协作者承诺**:请将本指南作为日常开发的「检查清单」,共同守护项目质量与协作效率。 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 000000000..859839ac1 --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,21 @@ +### 😃 本次 PR 的变化性质 + +> 请至少勾选一项 + +- [ ] 功能新增 +- [x] 问题修复 +- [ ] 功能优化 +- [ ] 分支合并 +- [ ] 其他改动:请在此处填写 + +### 🌱 本次 PR 的变化内容 + +- 在此处列出本次 PR 的每一项改动内容 + +### ✅ 本次 PR 的满足条件 + +> 请在申请合并之前,将符合条件的每一项进行勾选 + +- [ ] 已提供在线演示地址(如:[codepen](https://codepen.io/), [stackblitz](https://stackblitz.com/))或无需演示 +- [ ] 已对每一项的改动均测试通过 +- [ ] 已提供具体的变化内容说明 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 000000000..c1564862f --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,38 @@ +name: CI + +on: + pull_request: + push: + branches: + - main + - '*.x-stable' + +jobs: + lint: + name: Lint code + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm + + - name: Install dependencies + run: npm ci + + - name: Check formatting with Prettier + run: | + npx prettier --write --log-level=warn . + git --no-pager diff --exit-code + + - name: Lint code with ESLint + run: npx eslint . + + # 串行运行测试 + - name: Run tests with Jest + run: npx jest --ci --runInBand diff --git a/.github/workflows/issue-closed.yml b/.github/workflows/issue-closed.yml new file mode 100644 index 000000000..b38dd6f1c --- /dev/null +++ b/.github/workflows/issue-closed.yml @@ -0,0 +1,35 @@ +name: Issue Closed + +on: + issues: + types: [closed] + +jobs: + issue-closed: + runs-on: ubuntu-latest + steps: + # 追加标签 + - name: Add labels + id: label-check + uses: actions/github-script@v8 + with: + github-token: ${{secrets.GITHUB_TOKEN}} + script: | + const config = { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }; + const issue = await github.rest.issues.get(config); + + // 是否带有 `bug`, `wontfix` 标签 + const hasBugLabel = issue.data.labels.some(label => label.name === 'bug'); + const hasWontfixLabel = issue.data.labels.some(label => label.name === 'wontfix'); + + // 对带有 `bug` 标签的 issue 追加 `resolved` 标签,表示 bug 已解决。 + if (hasBugLabel && !hasWontfixLabel) { + github.rest.issues.addLabels({ + ...config, + labels: ['resolved'] + }); + } diff --git a/.github/workflows/issue-labeled.yml b/.github/workflows/issue-labeled.yml new file mode 100644 index 000000000..f202fbaf8 --- /dev/null +++ b/.github/workflows/issue-labeled.yml @@ -0,0 +1,91 @@ +name: Issue Labeled + +on: + issues: + types: [labeled] + +permissions: + contents: read + +jobs: + issue-labeled: + permissions: + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: content template + id: template + run: | + contribute="详见:🍀 [Layui Issue 贡献指南](https://github.com/layui/layui/blob/main/CONTRIBUTING.md)" + echo "CONTRIBUTING=$contribute" >> $GITHUB_OUTPUT + + - name: handle labeled issue + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const labelName = context.payload.label?.name; + const issue = context.payload.issue; + const config = { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }; + + const templates = { + 'help wanted': { + close: false, + body: `@${issue.user.login} 你好 👋。 + 我们赞成为该议题寻求社区帮助,欢迎创建 [Pull Request](https://github.com/layui/layui/pulls) 来协助实现,若变更内容涉及到 API 新增和改动,除了提交核心代码外,还需包含:文档、测试用例等相关文件,以便我们更好地进行 Review。期待您的贡献! + > ${{ steps.template.outputs.CONTRIBUTING }}`, + }, + 'invalid': { + close: true, + body: `@${issue.user.login} 你好,为了提升沟通效率,我们对 Issue 制定了严格的要求,你的 Issue 因不符合规定而被自动关闭。 + 建议你在下次创建 Issue 时,遵循相应规范和社区行为准则。谢谢。 + > ${{ steps.template.outputs.CONTRIBUTING }}`, + }, + 'need reproduce': { + close: false, + body: `@${issue.user.login} 你好,请提供一个最小化的重现,以便我们为你协助排查问题。良好的重现应当包括但不仅限于: + - 产生问题的详细步骤 + - 与问题相关的完整代码 + - 在线 Demo (推荐通过 [stackblitz](https://stackblitz.com/) 或 [codepen](https://codepen.io/) 创建) + > ${{ steps.template.outputs.CONTRIBUTING }} + > 延伸:👉 [为什么要提供最小化重现?](https://antfu.me/posts/why-reproductions-are-required-zh)`, + }, + 'discussion': { + close: true, + body: `@${issue.user.login} 你好,Issue 只接受「Bug 报告」和「功能请求」,而你的议题涉及到如何使用、功能疑惑或其他业务相关的问题,这并不适合作为 Issue 讨论。建议你通过以下方式寻求解决方案: + - 仔细查阅 Layui 官方文档:https://layui.dev + - 通过其他技术社区搜索相关资料、或充分利用当前主流的人工智能大模型 + - [Discussions](https://github.com/layui/layui/discussions) + > ${{ steps.template.outputs.CONTRIBUTING }}`, + }, + 'unrelated': { + close: true, + body: `@${issue.user.login} 你提出的问题与 Layui 可能不存在相关联。建议通过以下方式寻求解决方案: + - 通过其他技术社区搜索相关资料、或充分利用当前主流的人工智能大模型 + - [Discussions](https://github.com/layui/layui/discussions) + > ${{ steps.template.outputs.CONTRIBUTING }}`, + }, + }; + + const action = templates[labelName]; + if (!action) { + core.info(`Skip unsupported label: ${labelName}`); + return; + } + + await github.rest.issues.createComment({ + ...config, + body: action.body, + }); + + if (action.close) { + await github.rest.issues.update({ + ...config, + state: 'closed', + }); + } diff --git a/.github/workflows/issue-opened.yml b/.github/workflows/issue-opened.yml new file mode 100644 index 000000000..405576162 --- /dev/null +++ b/.github/workflows/issue-opened.yml @@ -0,0 +1,69 @@ +name: Issue Opened + +on: + issues: + types: [opened, edited] + +permissions: + contents: read + +jobs: + issue-opened: + permissions: + issues: write + pull-requests: write + runs-on: ubuntu-latest + steps: + - name: content template + id: template + run: | + contribute="详见:🍀 [Layui Issue 贡献指南](https://github.com/layui/layui/blob/main/CONTRIBUTING.md)" + echo "CONTRIBUTING=$contribute" >> $GITHUB_ENV + + - name: check invalid + uses: actions/github-script@v8 + with: + github-token: ${{ secrets.GITHUB_TOKEN }} + script: | + const config = { + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.issue.number, + }; + + const payload = context.payload; + const isCreatedByBot = payload.sender.type === 'Bot'; + const issue = payload.issue; + const isValid = issue.body?.includes('layui-issue-template'); + + // 跳过 closed 状态的 issues + if (issue.state === 'closed') { + return console.log('Issue is closed.'); + } + + // 若修改的不是内容,则不必校验 + if (payload.action === 'edited') { + if (payload.changes && !payload.changes.body.from) { + return console.log('Edited fields exclude "body".'); + } + } + + // 不符合规则或由机器人创建 + if (isCreatedByBot || !isValid) { + if (!isCreatedByBot) { + github.rest.issues.createComment({ + ...config, + body: `@${payload.sender.login} 你好,为了提升沟通效率,我们对 Issue 制定了严格的要求,你的 Issue 因不符合规定而被自动关闭。 + 建议你在下次创建 Issue 时,遵循相应规范和社区行为准则。谢谢。\n > ${process.env.CONTRIBUTING}` + }); + } + // 给 issue 添加指定标签和关闭 + github.rest.issues.addLabels({ + ...config, + labels: ['invalid'] + }); + github.rest.issues.update({ + ...config, + state: 'closed' + }); + } diff --git a/.github/workflows/pr-preview.yml b/.github/workflows/pr-preview.yml new file mode 100644 index 000000000..26b00428a --- /dev/null +++ b/.github/workflows/pr-preview.yml @@ -0,0 +1,23 @@ +name: Publish Pull Request Preview +on: [pull_request] + +jobs: + build: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup node + uses: actions/setup-node@v6 + with: + node-version: 24 + + - name: Install dependencies + run: npm install + + - name: Build + run: npm run build + + - run: npx pkg-pr-new publish --template './tests/visual/template/pr-preview' diff --git a/.github/workflows/release-npm.yml b/.github/workflows/release-npm.yml new file mode 100644 index 000000000..46ca28d4f --- /dev/null +++ b/.github/workflows/release-npm.yml @@ -0,0 +1,19 @@ +name: Publish to NPM + +on: + push: + tags: + - 'v*' + +jobs: + publish-npm: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + - uses: actions/setup-node@v6 + with: + node-version: 24 + registry-url: https://registry.npmjs.org + - run: npm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml new file mode 100644 index 000000000..ef06197ca --- /dev/null +++ b/.github/workflows/release.yml @@ -0,0 +1,89 @@ +name: Create Release + +on: + push: + tags: + - 'v*' + +jobs: + build: + name: Create Release + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v6 + + - name: Setup Node.js + uses: actions/setup-node@v6 + with: + node-version: 24 + cache: npm + + - name: Install dependencies + run: npm ci + env: + NODE_ENV: development + + - name: Get the version + id: get_version + run: echo "VERSION=${GITHUB_REF#refs/tags/}" >> $GITHUB_ENV + + # 获取当前版本贡献者 + - name: Fetch Contributors + id: contributors + run: | + USERNAME_LIST="" + + # 获取完整的提交历史 + git fetch --prune --unshallow + + # 按日期排序标签,获取上一个标签 + PREVIOUS_TAG=$(git for-each-ref --sort=-creatordate --format '%(refname:short)' refs/tags | sed -n 2p) + + # 获取当前标签 + CURRENT_TAG=${GITHUB_REF#refs/tags/} + + echo "Previous Tag: $PREVIOUS_TAG" + echo "Current Tag: $CURRENT_TAG" + + for COMMIT_SHA in $(git log ${PREVIOUS_TAG}...$CURRENT_TAG --pretty=format:"%H") + do + USER=$(curl -s -H "Authorization: Bearer ${{ secrets.GITHUB_TOKEN }}" \ + https://api.github.com/repos/${GITHUB_REPOSITORY}/commits/$COMMIT_SHA \ + | jq -r '.author.login') + if [ "$USER" != "null" ] && [ ! -z "$USER" ]; then + USERNAME_LIST="$USERNAME_LIST @$USER" + fi + done + USERNAME_LIST=$(echo $USERNAME_LIST | tr ' ' '\n' | sort -u | tr '\n' ' ') + echo "usernames=$USERNAME_LIST" >> $GITHUB_OUTPUT + + - name: Determine Prerelease + id: prerelease + run: | + if [[ ${{ github.ref }} =~ - ]]; then + echo "Setting prerelease to true" + echo "prerelease=true" >> $GITHUB_OUTPUT + else + echo "Setting prerelease to false" + echo "prerelease=false" >> $GITHUB_OUTPUT + fi + + - name: Create Zip File + id: asset + run: | + npm run release + DIR_NAME="release/assets/layui-${{ env.VERSION }}" + echo "filename=$DIR_NAME" >> $GITHUB_OUTPUT + + - name: GH Release + id: create_release + uses: softprops/action-gh-release@v2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + body: | + - **更新日志**: https://layui.dev/docs/3/versions.html#${{ env.VERSION }} + - **本次贡献**: ${{ steps.contributors.outputs.usernames }} 🎉 + prerelease: ${{ steps.prerelease.outputs.prerelease }} + files: ${{ steps.asset.outputs.filename }}.zip diff --git a/.gitignore b/.gitignore index b5ddbc0c5..3be4829a6 100644 --- a/.gitignore +++ b/.gitignore @@ -1,27 +1,45 @@ -*.iml -.idea/ -.ipr -.iws *~ ~* + +*.bak +*.bat *.diff +*.err +*.log *.patch -*.bak -.DS_Store -Thumbs.db -.svn/ +*.swo *.swp +*.zip + +.DS_Store +.env .nojekyll .project -.settings/ -node_modules/ +.settings +Thumbs.db + +.idea/ +.svn/ _site/ -run.bat -dir.txt -/**/layim/ -/**/layim.js -/**/layim-mobile.js -/**/layim.html -/**/layim.m.html -release/ +.vscode/ +node_modules/ + +# AI IDE configuration +.claude/ +.codex/ +.cursor/ +.windsurf/ +.trae/ +.qoder/ +.lingma/ +.ai/ +.agents/ + +# ESLint cache +.eslintcache + +# Development build artifacts +/tests/visual/assets/dist/ +# Published folders +/release/ diff --git a/.husky/install.mjs b/.husky/install.mjs new file mode 100644 index 000000000..29401b5fb --- /dev/null +++ b/.husky/install.mjs @@ -0,0 +1,6 @@ +// 在生产环境和 CI 中跳过 Husky 安装 +if (process.env.NODE_ENV === 'production' || process.env.CI === 'true') { + process.exit(0); +} +const husky = (await import('husky')).default; +console.log(husky()); diff --git a/.husky/pre-commit b/.husky/pre-commit new file mode 100644 index 000000000..f0db25bff --- /dev/null +++ b/.husky/pre-commit @@ -0,0 +1 @@ +lint-staged --concurrent false diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..8e28f2551 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,10 @@ +*.min.js +*.bundle.js +*.map + +dist +node_modules +package-lock.json + +/docs/ +/release/ diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 000000000..544138be4 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,3 @@ +{ + "singleQuote": true +} diff --git a/CHANGELOG.md b/CHANGELOG.md index db64521b5..cff31c296 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,147 +1,8 @@ +# Change Log -# v1.0.9_rls 2017-03-01 +- [更新日志](https://layui.dev/docs/versions.html) -* checkbox复选框原始风格支持不显示文字(之前会默认显示:勾选) -* 进度条超出100%情况下的自动处理 -* 修复Tab选项卡在出现下拉按钮时,点击最后的几个选项卡未能正常切换的bug -* 修复select组件搜索选择时会先显示之前的值再替换新的值的不良体验 -* 修复默认进度条0%时,文本出现太过于左侧的问题 - - -# v1.0.9 2017-02-28 - -* 新增“折叠面板”页面元素及相关事件监听 -* select组件增加搜索匹配功能,通过参数 lay-search 开启 -* checkbox组件增加原始风格样式,通过设置 lay-skin="primary" 开启(跟系统自带的类似样貌) -* 升级 layer弹层组件到 3.0.2 (相关更新日志见layer主页) - -* 表单元素增加属性 lay-ignore ,设置后,将不会对该标签进行美化渲染,即保留系统风格 -* 开关增加两种状态的自定义文本,通过参数 lay-text="ON|OFF" 开启 - -* 修复Tab选项卡嵌套的Tab没有对应的内容结构时,切换到了父级内容的bug -* 修复Tab选项卡容器中使用下拉框时,被溢出隐藏的问题 -* 修复Tab选项卡溢满情况下,点击展开按钮,再在外部添加一个选项卡出现异常的bug -* Tab选项卡部分UI细节优化 -* Tab选项卡的tabAdd增加id参数,用于在删除和切换时,以id作为匹配媒介 -* Tab选项卡的tabDelete/tabChange第二个参数有改动,不再是index(索引),而是对应的lay-id的值 - - ---- - - -# v1.0.8 2017-02-21 - -* 新增“进度条”页面元素及相关操作方法 -* 表单模块lay-verify属性增加对同一字段的多条验证规则的支持 -* 新增按钮组样式 -* 新增赤、橙、绿、青、蓝、黑、灰7中背景样式(见文档:页面元素→CSS公共类) -* 新增7个字体图标 - -* 完善loading图标在旋转时出现偏移的不友好问题 -* 完善表单元素设置为盒子风格时,复选框/单选框等区块的别扭问题。需对特定区块设置pane属性。 -* 对盒子风格的表单字段开启验证高亮提示,以及hover/focus效果 -* 调整用于后台布局的layout框架比例,对之前版本会有所影响,请注意修改 - -* 修复Form模块的部分样式在高DPI缩放时的样式问题 -* 修复layer组件动画keyframes与其它css库可能引发的冲突 -* 修复当使用layui.all.js时,部分功能报错的bug - - ---- - - -# v1.0.6/1.0.7 2016-11-30 - -* 修复发布1.0.6时,因构建工具的重写引发的一些列样式问题 -* 修复导航点击二级菜单时,未取消其它菜单的bug -* 修复上传按钮与表单组2px偏差 - -* 当引入layui.all.js时,如果仍然使用了layui.use,则不加载相应模块(因为layui.all.js已包含)。 -* 剔除 layui.all(callback) 方法,如果要用到全部模块,直接用 layui.all.js 的方式即可 -* 整个框架文件减少了 150kb - - ---- - - -# v1.0.5 2016-11-29 - -* 增加多种table样式(表格相关的功能和数据操作会在 2.0大版本时推出) - -* Flow模块的信息流改为从第一页开始,done在初始时就会执行一次(更新时请特别注意,在你用到flow的地方进行微调,详见最新文档。为之前这个愚蠢的机制表示抱歉!) -* Flow模块的信息流剔除参数:isShowEnd -* Flow模块的信息流新增参数:end,用于显示末页内容(默认为:没有更多了) -* 导航菜单新增点击事件监听:element.on('nav(filter)', callback); -* 导航二级菜单增加当前选中样式,并对导航增加点击选中事件 -* 导航一级菜单的树形选中块调短,及多处细节调整 - -* 修复表单select选择下拉时对浏览器滚动条造成的不良体验 -* 修复如果对Tab选项卡设置了lay-allowClose属性,新增选项卡时未出现关闭图标的bug -* 修复layer组件如果end回调中再执行close出现死循环的问题 - - ---- - - -# v1.0.4 2016-11-18 - -* Tab选项卡新增用于添加Tab选项的接口:element.tabAdd(filter, options); -* Tab选项卡新增用于外部删除Tab选项的接口:element.tabDelete(filter, index); -* Tab选项卡新增用于动态切换的接口:element.tabChange(filter, index); -* 表单组select、checkbox、radio等新增 disabled 属性的禁用支持 - -* 修复水平导航二级菜单在ie8下无法使用的bug -* 修复layPage分页在ie8的样式兼容问题 -* 修复Form表单组radio框使用name="a[b]"、name="a.b"这种格式出现报错的bug -* 修复在使用了element.init()后,Tab选项卡的相关事件出现多次执行的bug -* 修复在使用了element.init()后,面包屑重复插入了分隔符的bug - -* checkbox框样式调整,勾选图标放在左侧 -* 导航菜单在ie10以下浏览器开启了hover效果 - - ---- - - -# v1.0.3 2016-11-10 - -* 集成 layer 3.0 -* 重点增加导航菜单的二级菜单支持(水平导航和树形导航都支持) -* 表单select增加optgroup的分组支持 -* 富文本编辑器新增获取选中内容的方法:layedit.getSelection(index) - -* 修复layer模块无法使用layer.config的extend来加载拓展皮肤的bug -* 修复Tab选项卡与select的小冲突 -* 修复Tab选项卡简洁模式与内容区域的导航的样式小冲突 -* 修复Tab选项卡与内容区域的子Tab选项卡存在冲突的bug -* 修除表单组label标签、layDate与第三方框架(如Bootstrap)的样式冲突 -* 修复flow流加载模块的的信息流,在设置isLazyimg:true时下拉报错的bug - -* 表单select内容若超出最大宽度,则自适应宽度 -* layui.js合并到layui.all.js中,也就是说,如果你不采用layui模块化规范,只需引入layui.all.js即可。 - - ---- - - -# v1.0.2 2016-10-18 - -* 修复layui.data('table', null); 无法删除本地表的bug -* 修改自定义事件监听机制 - -* 新增“引用”的区块多套显示风格 -* 新增“字段集”多套显示风格 -* 新增“纯圆角”公共CSS类 -* 新增 hr标签 全局初始化CSS类 - -* 富文本编辑器增加用于同步编辑器内容到textarea的sync方法(一般用于异步提交) -* 修复富文本编辑器点击编辑区域无法关闭表情的bug -* 修复富文本编辑器未正确把内容同步到textarea的较严重bug -* 修复富文本编辑器中的一个css语法错误 -* 修复表单input框ie8下某些小兼容问题 - -* 将复选框风格瘦身(因为群众普遍认为之前的“复选框”实在太胖了) -* 将表单下边距由20px调整为15px -* 完善表单响应式 -* 处理layPage分页可能被第三方框架(如Bootstrap)引发的样式冲突 +## 发行日志 +- [Github](https://github.com/layui/layui/releases) +- [Gitee](https://gitee.com/layui/layui/releases) diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md new file mode 100644 index 000000000..838a421a2 --- /dev/null +++ b/CODE_OF_CONDUCT.md @@ -0,0 +1,131 @@ +# Contributor Code of Conduct + +## Our Pledge + +We as members, contributors, and leaders pledge to make participation in our +community a harassment-free experience for everyone, regardless of age, body +size, visible or invisible disability, ethnicity, sex characteristics, gender +identity and expression, level of experience, education, socio-economic status, +nationality, personal appearance, race, caste, color, religion, or sexual +identity and orientation. + +We pledge to act and interact in ways that contribute to an open, welcoming, +diverse, inclusive, and healthy community. + +## Our Standards + +Examples of behavior that contributes to a positive environment for our +community include: + +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the overall + community + +Examples of unacceptable behavior include: + +- The use of sexualized language or imagery, and sexual attention or advances of + any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email address, + without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Enforcement Responsibilities + +Community leaders are responsible for clarifying and enforcing our standards of +acceptable behavior and will take appropriate and fair corrective action in +response to any behavior that they deem inappropriate, threatening, offensive, +or harmful. + +Community leaders have the right and responsibility to remove, edit, or reject +comments, commits, code, wiki edits, issues, and other contributions that are +not aligned to this Code of Conduct, and will communicate reasons for moderation +decisions when appropriate. + +## Scope + +This Code of Conduct applies within all community spaces, and also applies when +an individual is officially representing the community in public spaces. +Examples of representing our community include using an official e-mail address, +posting via an official social media account, or acting as an appointed +representative at an online or offline event. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported to the community leaders responsible. +All complaints will be reviewed and investigated promptly and fairly. + +All community leaders are obligated to respect the privacy and security of the +reporter of any incident. + +## Enforcement Guidelines + +Community leaders will follow these Community Impact Guidelines in determining +the consequences for any action they deem in violation of this Code of Conduct: + +### 1. Correction + +**Community Impact**: Use of inappropriate language or other behavior deemed +unprofessional or unwelcome in the community. + +**Consequence**: A private, written warning from community leaders, providing +clarity around the nature of the violation and an explanation of why the +behavior was inappropriate. A public apology may be requested. + +### 2. Warning + +**Community Impact**: A violation through a single incident or series of +actions. + +**Consequence**: A warning with consequences for continued behavior. No +interaction with the people involved, including unsolicited interaction with +those enforcing the Code of Conduct, for a specified period of time. This +includes avoiding interactions in community spaces as well as external channels +like social media. Violating these terms may lead to a temporary or permanent +ban. + +### 3. Temporary Ban + +**Community Impact**: A serious violation of community standards, including +sustained inappropriate behavior. + +**Consequence**: A temporary ban from any sort of interaction or public +communication with the community for a specified period of time. No public or +private interaction with the people involved, including unsolicited interaction +with those enforcing the Code of Conduct, is allowed during this period. +Violating these terms may lead to a permanent ban. + +### 4. Permanent Ban + +**Community Impact**: Demonstrating a pattern of violation of community +standards, including sustained inappropriate behavior, harassment of an +individual, or aggression toward or disparagement of classes of individuals. + +**Consequence**: A permanent ban from any sort of public interaction within the +community. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], +version 2.1, available at +[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. + +Community Impact Guidelines were inspired by +[Mozilla's code of conduct enforcement ladder][Mozilla CoC]. + +For answers to common questions about this code of conduct, see the FAQ at +[https://www.contributor-covenant.org/faq][FAQ]. Translations are available at +[https://www.contributor-covenant.org/translations][translations]. + +[homepage]: https://www.contributor-covenant.org +[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html +[Mozilla CoC]: https://github.com/mozilla/diversity +[FAQ]: https://www.contributor-covenant.org/faq +[translations]: https://www.contributor-covenant.org/translations diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 000000000..a42f3263e --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,110 @@ +# 🍀 Layui 贡献指南 + +为了提升沟通效率,请花几分钟时间仔细阅读本文档。遵循这些指南有助于表达您尊重管理和开发这个开源项目的贡献者。作为回报,他们也会以同样的尊重来处理或评估您的 Issue 和 Pull Request。 + +## Issue + +### 创建 Issue 之前 + +Layui 的 issue 只受理 「Bug 报告」和「功能请求」。如果是关于如何使用、功能疑惑或其他业务相关的问题建议在 Discussions 寻找社区帮助。若 issue 不符合规定或违背社区行为准则,它将会被立即关闭。 + +**在正式创建 Issue 之前,您应当确保已完成以下前置工作**: + +- 仔细查看 Layui 官方文档和每个版本的更新日志:https://layui.dev +- 在 Issues 中搜索相似问题,找到解决方案,但应避免在旧的 Issue 中留言。 +- 通过其他技术社区搜索相关资料、或充分利用当前主流的人工智能大模型 + +**为什么要有严格的 issue 规定**: + +维护开源项目是一项艰辛的工作,它崇高而又略显卑微。加上 Layui 的使用门槛相对较低,随着受众的广为推崇,我们每天疲于应对各种技术反馈,包括:bug 报告,功能需求和 Pull Requests。 + +作为一个免费使用的开源项目,Layui 的维护人手是有限的。这意味着想要让项目可持续发展,我们必须: + +1. 给予更具体的工作、更高的优先级(如 bug 修复和新功能的开发); +2. 提高 issue 处理的效率。 + +针对 (1),我们决定将 GitHub issue 严格地限制在有具体目标和内容的工作。问题和讨论应当发送到更适合它们的场合。比如关于「如何使用」,建议发到 Layui 讨论区,或者把它细化成更具体的 Bug 和 Feature Request。这两者的区别是,「如何使用」是一个未经思考和调研的问句,而 Bug 和 Feature Request 需要提问者进一步明确这是一个缺陷或者未支持的特性。 + +针对 (2),我们发现影响 issue 处理效率最大两点因素是:a) 用户开 issue 之前并没有做好前置工作,这导致大量重复且初级的 issue 不断出现;b) 用户开 issue 时没有提供足够有效的信息,这导致我们需要花费大量的时间去跟用户来回沟通,只为了获得一些基本信息好让我们对 issue 进行真正的分析。因此,为了减少不必要的资源消耗,严格要求 Issue 规定是迫切和必要的。尤其对于 Layui 核心维护者,应当让他们的主要精力投入到项目更重要的工作中去。 + +**最重要的是,请明白一件事:开源项目的用户和维护者之间并不是甲方和乙方的关系,issue 也不是客服。在开 issue 的时候,请抱着「一起合作来解决这个问题」的心态,避免期待社区单方面地为你服务。** + +> 以上借鉴了 Ant Design 社区的成熟经验,并做了适用于 Layui 社区的相关修改。 + +### 正式创建 issue + +当您已对上述事项充分阅读并理解,在正式创建过程中,您应当遵循 Issue 提供表单规范仔细填写,尽可能将您所遇到的 Bug 或 Feature Request 描述详细。 + +### 创建 issue 之后 + +- 在 issue 交流过程中,若议题已经得到解决,请主动关闭 issue。 +- 大家本着相互尊重、理解和友善的态度,共同维护 Layui 来之不易的良好的社区氛围,谢谢 💖。 + +### 其他参考资料 + +1. [**贡献者行为准则**](CODE_OF_CONDUCT.md) +2. [**提问的智慧**](https://github.com/tvvocold/How-To-Ask-Questions-The-Smart-Way) @tvvocold +3. [**为什么需要最小重现**](https://antfu.me/posts/why-reproductions-are-required-zh) @antfu + +## Pull Request + +Layui 采用灵活的分支管理策略,我们鼓励您选择对应的分支发送 Pull Request。 + +为了使得 Reivew 和 Merge 的工作流程更加流畅,请仔细阅读以下全部说明: + +### 分支说明 + +- `main` 作为主干分支,代表的是项目当前最新版本,接受 feature 和 hotfix 。 +- `*.x-stable` 作为历史稳定版本分支,如 `2.x-stable` 即代表 2.x 系列稳定版本,只接受 hotfix,不接受 feature 。 +- `dev/*` 作为未来大版本开发分支,如 `dev/3.0` 即代表 3.0 的开发版本,接受 feature 和 hotfix,但不保证稳定性。 + +其余日常分支均以 `/` 规则命名,根据 `` 决定内容修改类型。 + +### 操作步骤 + +Layui 使用 Node.js 工具链进行构建与测试,在您参与项目开发之前,请先确保已安装 Node.js 运行环境,推荐版本:`>=20.17.0` + +#### 1. 安装依赖 + +将 Layui 项目 clone 到本地后,请务必使用 `npm ci` 安装依赖,确保所有贡献者与 CI 环境基本一致。 + +```bash +npm ci +``` + +> 注:若是 Layui 2.x 版本,需使用 `npm install` + +#### 2. 开发阶段 + +依赖安装完毕后,即可启动开发模式 + +```bash +npm run dev +``` + +开发过程中,我们推荐您在编辑器安装 Prettier 插件,以保持代码风格一致。 + +完成开发后,请对代码进行静态分析和测试。 + +```bash +# lint +npm run lint + +# test +npm test +``` + +上述流程通过,即可提交代码。在 pre-commit 阶段,git hooks 会再次自动检查代码是否符合规范,并自动 lint fix 和格式化代码,对于无法自动 fix 的代码,请按照提示进行手动修改。 + +#### 3. 提交代码 + +Layui 遵循 [约定式提交](https://www.conventionalcommits.org/zh-hans/v1.0.0/) 规范,您的提交信息(git commit `message` 和 PR `title`)都应遵循这一规范。 + +- 创建 PR 时,请在 description 项严格遵循预设的「内容模板」规范填写,以提供必要的信息,如:变更说明、预览地址等。 +- 提交 PR 后,确保已通过 Github CI 检查,若失败,可查看具体原因进行调整。 + +确保以上所有步骤都符合要求后,即可等待项目成员对您的代码进行 Review 及合并评估。 + +### 其他参考资料 + +- [Conventional Commits](https://www.conventionalcommits.org/zh-hans/v1.0.0/) diff --git a/DISCLAIMER.md b/DISCLAIMER.md new file mode 100644 index 000000000..76a54113f --- /dev/null +++ b/DISCLAIMER.md @@ -0,0 +1,14 @@ +# Layui 免责声明 + +> 任何用户在使用由 Layui 技术团队及贡献者(以下统称为「本团队」)研发的系列开源界面组件库(以下简称「Layui」)前,请您仔细阅读并透彻理解本声明。您可以选择不使用 Layui ,若您一旦使用 Layui ,您的使用行为即被视为对本声明全部内容的认可和接受。 + +1. Layui 是一套免费的开源 Web UI 纯静态组件库,主要用于更高效地开发网页界面。Layui 不具备「互联网接入、网络数据存储、通讯传输以及窃取用户隐私」中的任何一项与用户数据等信息相关的动态功能,Layui 仅是 UI 组件或素材类的本地资源。 +2. Layui 仅为纯静态的 Web 前端代码,不包含任何后台或服务端程序代码;其尊重并保护所有用户的个人隐私权,不窃取任何用户计算机中的信息。更不具备用户数据存储等网络传输功能。 +3. 您承诺秉着合法、合理的原则使用 Layui ,不利用 Layui 进行任何违法、侵害他人合法利益等恶意的行为,亦不将 Layui 运用于任何违反我国法律法规的 Web 平台。 +4. 任何单位或个人因下载使用 Layui 而产生的任何意外、疏忽、合约毁坏、诽谤、版权或知识产权侵犯及其造成的损失 (包括但不限于直接、间接、附带或衍生的损失等),本团队不承担任何法律责任。 +5. 用户明确并同意本声明条款列举的全部内容,对使用 Layui 可能存在的风险和相关后果将完全由用户自行承担,本团队不承担任何法律责任。 +6. 任何单位或个人在阅读本免责声明后,应在《MIT 开源许可证》所允许的范围内进行合法的发布、传播和使用 Layui 等行为,若违反本免责声明条款或违反法律法规所造成的法律责任(包括但不限于民事赔偿和刑事责任),由违约者自行承担。 +7. 本团队对 Layui 拥有知识产权(包括但不限于商标权、专利权、著作权、商业秘密等),上述产品均受到相关法律法规的保护。 +8. 任何单位或个人不得在未经本团队书面授权的情况下对 Layui 本身申请相关的知识产权。 +9. 如果本声明的任何部分被认为无效或不可执行,则该部分将被解释为反映本团队的初衷,其余部分仍具有完全效力。不可执行的部分声明,并不构成我们放弃执行该声明的权利。 +10. 本团队有权随时对本声明条款及附件内容进行单方面的变更,并以消息推送、网页公告等方式予以公布,公布后立即自动生效,无需另行单独通知;若您在本声明内容公告变更后继续使用的,表示您已充分阅读、理解并接受修改后的声明内容。 diff --git a/LICENSE b/LICENSE index be179b1a0..869eb55c8 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ -MIT License +The MIT License (MIT) -Copyright (c) 2016 layui +Copyright (c) 2016-present Layui contributors Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal @@ -9,8 +9,8 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. \ No newline at end of file +SOFTWARE. diff --git a/README.en-US.md b/README.en-US.md new file mode 100644 index 000000000..4911e9001 --- /dev/null +++ b/README.en-US.md @@ -0,0 +1,52 @@ +
+ + + Layui + + +
+ +# Layui + +[中文](./README.md) · English + +Classic Web UI Component Library + +

+ + CI Status + + + NPM Version + + + License + +

+ +> Layui is an open-source and free web UI component library developed using pure HTML, CSS, and JavaScript. It is designed to facilitate the efficient creation of modern web interfaces. Over the years, it has been widely adopted for its distinctive design style. Layui significantly lowers the barrier for non-front-end developers to build complex web pages, enabling them to implement required page elements and interactions directly within the browser environment without relying on build tools. + +## Documentation + +- [**Layui 3**](https://github.com/layui/layui/issues/2889) (under development) +- [**Layui 2**](https://layui.dev/docs/2/) + +## Contributors + +[Project contributors](https://github.com/layui/layui/graphs/contributors) + +## Break with the old and establish the new 🌱 + +On October 14, 2016, Layui released its first version `1.0.0`, after which it was widely adopted across web platforms. + +On October 13, 2021, Layui announced the decommissioning of its original official website (details) and migrated its documentation site to Gitee Pages. Concurrently, community management and daily maintenance activities were fully transitioned to both Gitee and Github platforms, encouraging users to embrace other superior mainstream frameworks. This move inadvertently led some to believe that Layui had ceased updates. In reality, since then, Layui has remained active on Github and Gitee, never halting updates, progressing from version `2.6.8` at the time to its current latest release. + +On April 24, 2023, Layui released version `2.8.0` officially and launched a [new documentation site](https://layui.dev). This marked a sincere comeback and a continuation of its commitment to open-source ideals. We still uphold the perspective expressed in the announcement two years ago, advocating that developers embrace mainstream technologies and nurture an unwavering passion for cutting-edge advancements. **What Layui does is to fill those narrow gaps outside the mainstream**. Although not a mainstream frontend framework, Layui has long transcended being a personal creation of its author, becoming a collective work of all who persist in using it. It continues to underpin numerous projects and represents the efforts of many individuals. As open-source creators, we should walk alongside these dedicated Layui developers. + +On October 24, 2025, Layui released version `2.13.0` as the final major version of the 2.x series. This marked a tribute to the bittersweet decade past and officially ushered in a new chapter. + +In the future, Layui will steadfastly accompany all those who hold it dear, jointly substantiating the feasibility of the Layui development model. + +## License + +Layui is released under the [MIT](https://opensource.org/licenses/MIT) license. Other relevant agreements may also refer to the [Disclaimer](https://gitee.com/layui/layui/blob/main/DISCLAIMER.md). diff --git a/README.md b/README.md index daec3cb89..7d8d5a5ff 100644 --- a/README.md +++ b/README.md @@ -1,112 +1,52 @@ -

- - layui +

+ + + Layui + + +
+ +# Layui + +中文 · [English](./README.en-US.md) + +原生态 Web UI 组件库 + +

+ + CI Status + + + NPM Version + + + License

-

- 经典模块化前端UI框架 -

---- - -Layui 是一款采用自身模块规范编写的国产前端UI框架,遵循原生HTML/CSS/JS的书写与组织形式,门槛极低,拿来即用。其外在极简,却又不失饱满的内在,体积轻盈,组件丰盈,从核心代码到API的每一处细节都经过精心雕琢,非常适合界面的快速开发。layui还很年轻,首个版本发布于2016年金秋,她区别于那些基于MVVM底层的UI框架,却并非逆道而行,而是信奉返璞归真之道,准确地说,她更多是为服务端程序员量身定做,你无需涉足各种前端工具的复杂配置,只需面对浏览器本身,让一切你所需要的元素与交互、从这里信手拈来。 - -## 返璞归真 - -Layui 定义为“经典模块化”,并非是自吹她自身有多优秀,而是有意避开当下JS社区的主流方案,试图以最简单的方式去诠释高效!她的所谓经典,是在于对返璞归真的执念,她以当前浏览器普通认可的方式去组织模块!我们认为,这恰是符合当下国内绝大多数程序员从旧时代过度到未来新标准的最佳指引。所以 Layui 本身也并不是完全遵循于AMD时代,准确地说,她试图建立自己的模式,所以你会看到: - -``` - //layui模块的定义 - layui.define([mods], function(exports){ - - //…… - - exports('mod', api); - }); - - //layui模块的使用 - layui.use(['mod1', 'mod2'], function(args){ - var mod = layui.mod1; - - //…… - - }); - -``` -没错,她具备AMD的影子,又并非受限于commonjs的那些条条框框,Layui认为这种轻量的组织方式,比WebPack更符合绝大多数场景。所以她坚持采用经典模块化,也正是能让人避开工具的复杂配置,回归简单,安静高效地撸一会原生态的HTML、CSS、JavaScript。 - -但是 Layui 又并非是Requirejs那样的模块加载器,而是一款UI解决方案,她与Bootstrap最大的不同恰恰在于她糅合了自身对经典模块化的理解。 - - -## 快速上手 - -获得layui后,将其完整地部署到你的项目目录(或静态资源服务器),你只需要引入下述两个文件: - -``` -./layui/css/layui.css -./layui/layui.js -``` - -不用去管其它任何文件。因为他们(比如各模块)都是在最终使用的时候才会自动加载。这是一个基本的入门页面: - -``` - - - - - - 开始使用Layui - - - - - - - - - - - -``` - -如果你想快速使用Layui的组件,你还是跟平时一样script标签引入你的js文件,然后在你的js文件中使用layui的组件。但我们更推荐你遵循Layui的模块规范,建立一个自己的模块作为入口: - -``` - -``` - -上述的 index 即为你 /res/js/modules/ 目录下的 index.js,它的内容应该如下: - -``` -/** - 项目JS主入口 - 以依赖Layui的layer和form模块为例 -**/ -layui.define(['layer', 'form'], function(exports){ - var layer = layui.layer - ,form = layui.form(); - - layer.msg('Hello World'); - - exports('index', {}); -}); -``` - -好了,不管你采用什么样的方式,从现在开始,尽情地使用Layui吧!但愿这是你的一段轻松而美妙的旅程。 - - -## 相关 -[官网](http://www.layui.com/)、[更新日志](https://github.com/sentsin/layui/blob/master/CHANGELOG.md)、[社区交流](http://fly.layui.com) \ No newline at end of file +> Layui 是一套开源免费的 Web UI 组件库,采用纯原生态的 HTML CSS JavaScript 开发模式,它为更便捷地构建现代 Web 界面而生。多年来,凭借别具一格的内外风格而被广泛应用。它给非前端开发者极大地降低了构建复杂网页界面的门槛,开发者只需面向浏览器,即可让页面所需呈现的元素与交互,变得信手拈来。 + +## 使用文档 + +- [**Layui 3**](https://github.com/layui/layui/issues/2889) (正在开发中) +- [**Layui 2**](https://layui.dev/docs/2/) + +## 项目参与 + +[项目参与者](https://github.com/layui/layui/graphs/contributors) + +## 破旧立新 🌱 + +2016年10月14日,Layui 发布了 `1.0.0` 首版,此后多年被广泛应用于众多 Web 平台。 + +2021年10月13日,Layui 发布了原官网下线的公告(导读),并将文档站点切换到了 Gitee Pages,社区及日常维护亦全面转移到了 Gitee 和 Github 平台,以此呼吁大家拥抱其他更好的主流框架,导致大家误以为 Layui 停更了。事实上,自那以后,Layui 仍然在 Github 和 Gitee 保持活跃,并不存在所谓的停止更新,从当时的 `2.6.8` 一直连续迭代到如今的最新版本。 + +2023年4月24日,Layui 发布了 `2.8.0` 正式版,并上线了[新的文档站点](https://layui.dev),这是一次朴实的回归,更是情怀的延续。 但我们仍然坚持两年前那则公告中的观点, _即仍然推荐大家去拥抱主流,始终保持对前沿技术的无限热爱,是开发者们都应具备的思维属性_。 **而 Layui 所做的,是为填补主流之外的那些略显狭小的空隙**。Layui 虽不是前端主流,但也早已不是作者个人的 Layui,而是所有仍在坚持使用它的人的 Layui,它仍然支撑着许多项目,也代表着许多人的工作。作为开源创作者,应该要为这些坚持者而守望。 + +2025年10月24日,Layui 发布了 `2.13.0` 重要阶段版本,以致敬过去个中滋味的 10 年,并正式开启一个新的节点。 + +未来,Layui 会持续陪伴着所有为之热爱的人们,共同去论证 Layui 开发模式的可行性。 + +## 开源许可 + +Layui 采用 [MIT](https://opensource.org/licenses/MIT) 许可发布。其他相关协议亦可参考《[免责声明](https://gitee.com/layui/layui/blob/main/DISCLAIMER.md)》。 diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 000000000..dccd9a64d --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,20 @@ +# 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 | +| -------- | ------------------ | +| 3.x | :white_check_mark: | +| 2.10+ | :white_check_mark: | +| < 2.10.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. diff --git a/biome.json b/biome.json new file mode 100644 index 000000000..8b4d6905c --- /dev/null +++ b/biome.json @@ -0,0 +1,41 @@ +{ + "$schema": "./node_modules/@biomejs/biome/configuration_schema.json", + "vcs": { + "enabled": true, + "clientKind": "git", + "useIgnoreFile": true + }, + "files": { + "includes": [ + "src/**", + "scripts/**", + "tests/**", + "*.{js,mjs,cjs}", + "!!**/dist" + ] + }, + "formatter": { + "enabled": true, + "indentStyle": "space", + "indentWidth": 2 + }, + "linter": { + "enabled": false, + "rules": { + "recommended": true + } + }, + "javascript": { + "formatter": { + "quoteStyle": "single" + } + }, + "assist": { + "enabled": true, + "actions": { + "source": { + "organizeImports": "off" + } + } + } +} diff --git a/bower.json b/bower.json deleted file mode 100644 index e06f37b03..000000000 --- a/bower.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "name": "layui", - "main": "src/layui.js", - "version": "1.0.9_rls", - "homepage": "https://github.com/sentsin/layui", - "authors": [ - "sentsin " - ], - "description": "模块化前端UI框架", - "moduleType": [ - "amd", - "globals" - ], - "keywords": [ - "layui", - "ui" - ], - "license": "MIT" -} diff --git a/build/css/layui.css b/build/css/layui.css deleted file mode 100644 index e86730331..000000000 --- a/build/css/layui.css +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - .layui-laypage a,a{text-decoration:none}.layui-btn,.layui-inline,img{vertical-align:middle}.layui-btn,.layui-unselect{-webkit-user-select:none;-ms-user-select:none;-moz-user-select:none}.layui-btn,.layui-tree li i,.layui-unselect{-moz-user-select:none}blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}a:active,a:hover{outline:0}img{display:inline-block;border:none}li{list-style:none}table{border-collapse:collapse;border-spacing:0}h1,h2,h3{font-size:14px;font-weight:400}h4,h5,h6{font-size:100%;font-weight:400}button,input,optgroup,option,select,textarea{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;outline:0}pre{white-space:pre-wrap;white-space:-moz-pre-wrap;white-space:-pre-wrap;white-space:-o-pre-wrap;word-wrap:break-word}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-button:vertical{display:none}::-webkit-scrollbar-corner,::-webkit-scrollbar-track{background-color:#e2e2e2}::-webkit-scrollbar-thumb{border-radius:0;background-color:rgba(0,0,0,.3)}::-webkit-scrollbar-thumb:vertical:hover{background-color:rgba(0,0,0,.35)}::-webkit-scrollbar-thumb:vertical:active{background-color:rgba(0,0,0,.38)}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=1.0.9);src:url(../font/iconfont.eot?v=1.0.9#iefix) format('embedded-opentype'),url(../font/iconfont.svg?v=1.0.9#iconfont) format('svg'),url(../font/iconfont.woff?v=1.0.9) format('woff'),url(../font/iconfont.ttf?v=1.0.9) format('truetype')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}body{line-height:24px;font:14px Helvetica Neue,Helvetica,PingFang SC,\5FAE\8F6F\96C5\9ED1,Tahoma,Arial,sans-serif}hr{height:1px;margin:10px 0;border:0;background-color:#e2e2e2;clear:both}a{color:#333}a:hover{color:#777}a cite{font-style:normal;*cursor:pointer}.layui-box,.layui-box *{-webkit-box-sizing:content-box!important;-moz-box-sizing:content-box!important;box-sizing:content-box!important}.layui-border-box,.layui-border-box *{-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-clear{clear:both;*zoom:1}.layui-clear:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1}.layui-edge{position:absolute;width:0;height:0;border-style:dashed;border-color:transparent;overflow:hidden}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-disabled,.layui-disabled:hover{color:#d2d2d2!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-main{position:relative;width:1140px;margin:0 auto}.layui-header{position:relative;z-index:1000;height:60px}.layui-header a:hover{transition:all .5s;-webkit-transition:all .5s}.layui-side{position:fixed;top:0;bottom:0;z-index:999;width:200px;overflow-x:hidden}.layui-side-scroll{width:220px;height:100%;overflow-x:hidden}.layui-body{position:absolute;left:200px;right:0;top:0;bottom:0;z-index:998;width:auto;overflow:hidden;overflow-y:auto;-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box}.layui-layout-admin .layui-header{background-color:#23262E}.layui-layout-admin .layui-side{top:60px;width:200px;overflow-x:hidden}.layui-layout-admin .layui-body{top:60px;bottom:44px}.layui-layout-admin .layui-main{width:auto;margin:0 15px}.layui-layout-admin .layui-footer{position:fixed;left:200px;right:0;bottom:0;height:44px;background-color:#eee}.layui-btn,.layui-input,.layui-select,.layui-textarea,.layui-upload-button{outline:0;-webkit-transition:border-color .3s cubic-bezier(.65,.05,.35,.5);transition:border-color .3s cubic-bezier(.65,.05,.35,.5);-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-elem-quote{margin-bottom:10px;padding:15px;line-height:22px;border-left:5px solid #009688;border-radius:0 2px 2px 0;background-color:#f2f2f2}.layui-quote-nm{border-color:#e2e2e2;border-style:solid;border-width:1px 1px 1px 5px;background:0 0}.layui-elem-field{margin-bottom:10px;padding:0;border:1px solid #e2e2e2}.layui-elem-field legend{margin-left:20px;padding:0 10px;font-size:20px;font-weight:300}.layui-field-title{margin:10px 0 20px;border:none;border-top:1px solid #e2e2e2}.layui-field-box{padding:10px 15px}.layui-field-title .layui-field-box{padding:10px 0}.layui-progress{position:relative;height:6px;border-radius:20px;background-color:#e2e2e2}.layui-progress-bar{position:absolute;width:0;max-width:100%;height:6px;border-radius:20px;text-align:right;background-color:#5FB878;transition:all .3s;-webkit-transition:all .3s}.layui-progress-big,.layui-progress-big .layui-progress-bar{height:18px;line-height:18px}.layui-progress-text{position:relative;top:-18px;line-height:18px;font-size:12px;color:#666}.layui-progress-big .layui-progress-text{position:static;padding:0 10px;color:#fff}.layui-collapse{border:1px solid #e2e2e2;border-radius:2px}.layui-colla-item{border-top:1px solid #e2e2e2}.layui-colla-item:first-child{border-top:none}.layui-colla-title{position:relative;height:42px;line-height:42px;padding:0 15px 0 35px;color:#333;background-color:#f2f2f2;cursor:pointer}.layui-colla-content{display:none;padding:10px 15px;line-height:22px;border-top:1px solid #e2e2e2;color:#666}.layui-colla-icon{position:absolute;left:15px;top:0;font-size:14px}.layui-bg-red{background-color:#FF5722}.layui-bg-orange{background-color:#F7B824}.layui-bg-green{background-color:#009688}.layui-bg-cyan{background-color:#2F4056}.layui-bg-blue{background-color:#1E9FFF}.layui-bg-black{background-color:#393D49}.layui-bg-gray{background-color:#eee}.layui-word-aux{font-size:12px;color:#999;padding:0 5px}.layui-btn{display:inline-block;height:38px;line-height:38px;padding:0 18px;background-color:#009688;color:#fff;white-space:nowrap;text-align:center;font-size:14px;border:none;border-radius:2px;cursor:pointer;opacity:.9;filter:alpha(opacity=90)}.layui-btn:hover{opacity:.8;filter:alpha(opacity=80);color:#fff}.layui-btn:active{opacity:1;filter:alpha(opacity=100)}.layui-btn+.layui-btn{margin-left:10px}.layui-btn-radius{border-radius:100px}.layui-btn .layui-icon{font-size:18px;vertical-align:bottom}.layui-btn-primary{border:1px solid #C9C9C9;background-color:#fff;color:#555}.layui-btn-primary:hover{border-color:#009688;color:#333}.layui-btn-normal{background-color:#1E9FFF}.layui-btn-warm{background-color:#F7B824}.layui-btn-danger{background-color:#FF5722}.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{border:1px solid #e6e6e6;background-color:#FBFBFB;color:#C9C9C9;cursor:not-allowed;opacity:1}.layui-btn-big{height:44px;line-height:44px;padding:0 25px;font-size:16px}.layui-btn-small{height:30px;line-height:30px;padding:0 10px;font-size:12px}.layui-btn-small i{font-size:16px!important}.layui-btn-mini{height:22px;line-height:22px;padding:0 5px;font-size:12px}.layui-btn-mini i{font-size:14px!important}.layui-btn-group{display:inline-block;vertical-align:middle;font-size:0}.layui-btn-group .layui-btn{margin-left:0!important;margin-right:0!important;border-left:1px solid rgba(255,255,255,.5);border-radius:0}.layui-btn-group .layui-btn-primary{border-left:none}.layui-btn-group .layui-btn-primary:hover{border-color:#C9C9C9;color:#009688}.layui-btn-group .layui-btn:first-child{border-left:none;border-radius:2px 0 0 2px}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid #c9c9c9}.layui-btn-group .layui-btn:last-child{border-radius:0 2px 2px 0}.layui-btn-group .layui-btn+.layui-btn{margin-left:0}.layui-btn-group+.layui-btn-group{margin-left:10px}.layui-input,.layui-select,.layui-textarea{height:38px;line-height:38px;line-height:36px\9;border:1px solid #e6e6e6;background-color:#fff;border-radius:2px}.layui-form-label,.layui-form-mid,.layui-textarea{line-height:20px;position:relative}.layui-input,.layui-textarea{display:block;width:100%;padding-left:10px}.layui-input:hover,.layui-textarea:hover{border-color:#D2D2D2!important}.layui-input:focus,.layui-textarea:focus{border-color:#C9C9C9!important}.layui-textarea{min-height:100px;height:auto;padding:6px 10px;resize:vertical}.layui-select{padding:0 10px}.layui-form input[type=checkbox],.layui-form input[type=radio],.layui-form select{display:none}.layui-form-item{margin-bottom:15px;clear:both;*zoom:1}.layui-form-item:after{content:'\20';clear:both;*zoom:1;display:block;height:0}.layui-form-label{float:left;display:block;padding:9px 15px;width:80px;font-weight:400;text-align:right}.layui-form-item .layui-inline{margin-bottom:5px;margin-right:10px}.layui-input-block,.layui-input-inline{position:relative}.layui-input-block{margin-left:110px;min-height:36px}.layui-input-inline{display:inline-block;vertical-align:middle}.layui-form-item .layui-input-inline{float:left;width:190px;margin-right:10px}.layui-form-text .layui-input-inline{width:auto}.layui-form-mid{float:left;display:block;padding:8px 0;margin-right:10px}.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border:1px solid #FF5722!important}.layui-form-select{position:relative}.layui-form-select .layui-input{padding-right:30px;cursor:pointer}.layui-form-select .layui-edge{position:absolute;right:10px;top:50%;margin-top:-3px;cursor:pointer;border-width:6px;border-top-color:#c2c2c2;border-top-style:solid;transition:all .3s;-webkit-transition:all .3s}.layui-form-select dl{display:none;position:absolute;left:0;top:42px;padding:5px 0;z-index:999;min-width:100%;border:1px solid #d2d2d2;max-height:300px;overflow-y:auto;background-color:#fff;border-radius:2px;box-shadow:0 2px 4px rgba(0,0,0,.12);box-sizing:border-box}.layui-form-select dl dd,.layui-form-select dl dt{padding:0 10px;line-height:36px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.layui-form-select dl dt{font-size:12px;color:#999}.layui-form-select dl dd{cursor:pointer}.layui-form-select dl dd:hover{background-color:#f2f2f2}.layui-form-select .layui-select-group dd{padding-left:20px}.layui-form-select dl dd.layui-this{background-color:#5FB878;color:#fff}.layui-form-checkbox,.layui-form-select dl dd.layui-disabled{background-color:#fff}.layui-form-selected dl{display:block}.layui-form-checkbox,.layui-form-checkbox *,.layui-form-radio,.layui-form-radio *,.layui-form-switch{display:inline-block;vertical-align:middle}.layui-form-selected .layui-edge{margin-top:-9px;-webkit-transform:rotate(180deg);transform:rotate(180deg);margin-top:-3px\9}:root .layui-form-selected .layui-edge{margin-top:-9px\0/IE9}.layui-select-none{margin:5px 0;text-align:center;color:#999}.layui-select-disabled .layui-disabled{border-color:#eee!important}.layui-select-disabled .layui-edge{border-top-color:#d2d2d2}.layui-form-checkbox{position:relative;height:30px;line-height:28px;margin-right:10px;padding-right:30px;border:1px solid #d2d2d2;cursor:pointer;font-size:0;border-radius:2px;-webkit-transition:.1s linear;transition:.1s linear;box-sizing:border-box!important}.layui-form-checkbox:hover{border:1px solid #c2c2c2}.layui-form-checkbox span{padding:0 10px;height:100%;font-size:14px;background-color:#d2d2d2;color:#fff;overflow:hidden;white-space:nowrap;text-overflow:ellipsis}.layui-form-checkbox:hover span{background-color:#c2c2c2}.layui-form-checkbox i{position:absolute;right:0;width:30px;color:#fff;font-size:20px;text-align:center}.layui-form-checkbox:hover i{color:#c2c2c2}.layui-form-checked,.layui-form-checked:hover{border-color:#5FB878}.layui-form-checked span,.layui-form-checked:hover span{background-color:#5FB878}.layui-form-checked i,.layui-form-checked:hover i{color:#5FB878}.layui-form-item .layui-form-checkbox{margin-top:4px}.layui-form-checkbox[lay-skin=primary]{height:auto!important;line-height:normal!important;border:none!important;margin-right:0;padding-right:0;background:0 0}.layui-form-checkbox[lay-skin=primary] span{float:right;padding-right:15px;line-height:18px;background:0 0;color:#666}.layui-form-checkbox[lay-skin=primary] i{position:relative;top:0;width:16px;line-height:16px;border:1px solid #d2d2d2;font-size:12px;border-radius:2px;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-checkbox[lay-skin=primary]:hover i{border-color:#5FB878;color:#fff}.layui-form-checked[lay-skin=primary] i{border-color:#5FB878;background-color:#5FB878;color:#fff}.layui-checkbox-disbaled[lay-skin=primary] span{background:0 0!important}.layui-checkbox-disbaled[lay-skin=primary]:hover i{border-color:#d2d2d2}.layui-form-item .layui-form-checkbox[lay-skin=primary]{margin-top:10px}.layui-form-switch{position:relative;height:22px;line-height:22px;width:42px;padding:0 5px;margin-top:8px;border:1px solid #d2d2d2;border-radius:20px;cursor:pointer;background-color:#fff;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch i{position:absolute;left:5px;top:3px;width:16px;height:16px;border-radius:20px;background-color:#d2d2d2;-webkit-transition:.1s linear;transition:.1s linear}.layui-form-switch em{position:absolute;right:5px;top:0;width:25px;padding:0!important;text-align:center!important;color:#999!important;font-style:normal!important;font-size:12px}.layui-form-onswitch{border-color:#5FB878;background-color:#5FB878}.layui-form-onswitch i{left:32px;background-color:#fff}.layui-form-onswitch em{left:5px;right:auto;color:#fff!important}.layui-checkbox-disbaled{border-color:#e2e2e2!important}.layui-checkbox-disbaled span{background-color:#e2e2e2!important}.layui-checkbox-disbaled:hover i{color:#fff!important}.layui-form-radio{line-height:28px;margin:6px 10px 0 0;padding-right:10px;cursor:pointer;font-size:0}.layui-form-radio i{margin-right:8px;font-size:22px;color:#c2c2c2}.layui-form-radio span{font-size:14px}.layui-form-radio i:hover,.layui-form-radioed i{color:#5FB878}.layui-radio-disbaled i{color:#e2e2e2!important}.layui-form-pane .layui-form-label{width:110px;padding:8px 15px;height:38px;line-height:20px;border:1px solid #e6e6e6;border-radius:2px 0 0 2px;text-align:center;background-color:#FBFBFB;overflow:hidden;white-space:nowrap;text-overflow:ellipsis;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-form-pane .layui-input-inline{margin-left:-1px}.layui-form-pane .layui-input-block{margin-left:110px;left:-1px}.layui-form-pane .layui-input{border-radius:0 2px 2px 0}.layui-form-pane .layui-form-text .layui-form-label{float:none;width:100%;border-right:1px solid #e6e6e6;border-radius:2px;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important;text-align:left}.layui-laypage button,.layui-laypage input,.layui-nav{-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important}.layui-form-pane .layui-form-text .layui-input-inline{display:block;margin:0;top:-1px;clear:both}.layui-form-pane .layui-form-text .layui-input-block{margin:0;left:0;top:-1px}.layui-form-pane .layui-form-text .layui-textarea{min-height:100px;border-radius:0 0 2px 2px}.layui-form-pane .layui-form-checkbox{margin:4px 0 4px 10px}.layui-form-pane .layui-form-radio,.layui-form-pane .layui-form-switch{margin-top:6px;margin-left:10px}.layui-form-pane .layui-form-item[pane]{position:relative;border:1px solid #e6e6e6}.layui-form-pane .layui-form-item[pane] .layui-form-label{position:absolute;left:0;top:0;height:100%;border-width:0 1px 0 0}.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left:110px}.layui-layedit{border:1px solid #d2d2d2;border-radius:2px}.layui-layedit-tool{padding:3px 5px;border-bottom:1px solid #e2e2e2;font-size:0}.layedit-tool-fixed{position:fixed;top:0;border-top:1px solid #e2e2e2}.layui-layedit-tool .layedit-tool-mid,.layui-layedit-tool .layui-icon{display:inline-block;vertical-align:middle;text-align:center;font-size:14px}.layui-layedit-tool .layui-icon{position:relative;width:32px;height:30px;line-height:30px;margin:3px 5px;color:#777;cursor:pointer;border-radius:2px}.layui-layedit-tool .layui-icon:hover{color:#393D49}.layui-layedit-tool .layui-icon:active{color:#000}.layui-layedit-tool .layedit-tool-active{background-color:#e2e2e2;color:#000}.layui-layedit-tool .layui-disabled,.layui-layedit-tool .layui-disabled:hover{color:#d2d2d2;cursor:not-allowed}.layui-layedit-tool .layedit-tool-mid{width:1px;height:18px;margin:0 10px;background-color:#d2d2d2}.layedit-tool-html{width:50px!important;font-size:30px!important}.layedit-tool-b,.layedit-tool-code,.layedit-tool-help{font-size:16px!important}.layedit-tool-d,.layedit-tool-face,.layedit-tool-image,.layedit-tool-unlink{font-size:18px!important}.layedit-tool-image input{position:absolute;font-size:0;left:0;top:0;width:100%;height:100%;opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-layedit-iframe iframe{display:block;width:100%}#LAY_layedit_code{overflow:hidden}.layui-table{width:100%;margin:10px 0;background-color:#fff}.layui-table tr{transition:all .3s;-webkit-transition:all .3s}.layui-table thead tr{background-color:#f2f2f2}.layui-table th{text-align:left}.layui-table td,.layui-table th{padding:9px 15px;min-height:20px;line-height:20px;border:1px solid #e2e2e2;font-size:14px}.layui-table tr:hover,.layui-table[lay-even] tr:nth-child(even){background-color:#f8f8f8}.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border:1px solid #e2e2e2}.layui-table[lay-skin=line] td,.layui-table[lay-skin=line] th{border:none;border-bottom:1px solid #e2e2e2}.layui-table[lay-skin=row] td,.layui-table[lay-skin=row] th{border:none;border-right:1px solid #e2e2e2}.layui-table[lay-skin=nob] td,.layui-table[lay-skin=nob] th{border:none}.layui-upload-button{position:relative;display:inline-block;vertical-align:middle;min-width:60px;height:38px;line-height:38px;border:1px solid #DFDFDF;border-radius:2px;overflow:hidden;background-color:#fff;color:#666}.layui-upload-button:hover{border:1px solid #aaa;color:#333}.layui-upload-button:active{border:1px solid #4CAF50;color:#000}.layui-upload-button input,.layui-upload-file{opacity:.01;filter:Alpha(opacity=1);cursor:pointer}.layui-upload-button input{position:absolute;left:0;top:0;z-index:10;font-size:100px;width:100%;height:100%}.layui-upload-icon{display:block;margin:0 15px;text-align:center}.layui-upload-icon i{margin-right:5px;vertical-align:top;font-size:20px;color:#5FB878}.layui-upload-iframe{position:absolute;width:0;height:0;border:0;visibility:hidden}.layui-upload-enter{border:1px solid #009E94;background-color:#009E94;color:#fff;-webkit-transform:scale(1.1);transform:scale(1.1)}.layui-upload-enter .layui-upload-icon,.layui-upload-enter .layui-upload-icon i{color:#fff}.layui-flow-more{margin:10px 0;text-align:center;color:#999;font-size:14px}.layui-flow-more a{height:32px;line-height:32px}.layui-flow-more a *{display:inline-block;vertical-align:top}.layui-flow-more a cite{padding:0 20px;border-radius:3px;background-color:#eee;color:#333;font-style:normal}.layui-flow-more a cite:hover{opacity:.8}.layui-flow-more a i{font-size:30px;color:#737383}.layui-laypage{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;margin:10px 0;font-size:0}.layui-laypage>:first-child,.layui-laypage>:first-child em{border-radius:2px 0 0 2px}.layui-laypage>:last-child,.layui-laypage>:last-child em{border-radius:0 2px 2px 0}.layui-laypage a,.layui-laypage span{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;padding:0 15px;border:1px solid #e2e2e2;height:28px;line-height:28px;margin:0 -1px 5px 0;background-color:#fff;color:#333;font-size:12px}.layui-laypage em{font-style:normal}.layui-laypage span{color:#999;font-weight:700}.layui-laypage .layui-laypage-curr{position:relative}.layui-laypage .layui-laypage-curr em{position:relative;color:#fff;font-weight:400}.layui-laypage .layui-laypage-curr .layui-laypage-em{position:absolute;left:-1px;top:-1px;padding:1px;width:100%;height:100%;background-color:#009688}.layui-laypage-em{border-radius:2px}.layui-laypage-next em,.layui-laypage-prev em{font-family:Sim sun;font-size:16px}.layui-laypage .layui-laypage-total{height:30px;line-height:30px;margin-left:1px;border:none;font-weight:400}.layui-laypage button,.layui-laypage input{height:30px;line-height:30px;border:1px solid #e2e2e2;border-radius:2px;vertical-align:top;background-color:#fff;box-sizing:border-box!important}.layui-laypage input{width:50px;margin:0 5px;text-align:center}.layui-laypage button{margin-left:5px;padding:0 15px;cursor:pointer}.layui-code{position:relative;margin:10px 0;padding:15px;line-height:20px;border:1px solid #ddd;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New;font-size:12px}.layui-tree{line-height:26px}.layui-tree li{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-tree li .layui-tree-spread,.layui-tree li a{display:inline-block;vertical-align:top;height:26px;*display:inline;*zoom:1;cursor:pointer}.layui-tree li a{font-size:0}.layui-tree li a i{font-size:16px}.layui-tree li a cite{padding:0 6px;font-size:14px;font-style:normal}.layui-tree li i{padding-left:6px;color:#333}.layui-tree li .layui-tree-check{font-size:13px}.layui-tree li .layui-tree-check:hover{color:#009E94}.layui-tree li ul{display:none;margin-left:20px}.layui-tree li .layui-tree-enter{line-height:24px;border:1px dotted #000}.layui-tree-drag{display:none;position:absolute;left:-666px;top:-666px;background-color:#f2f2f2;padding:5px 10px;border:1px dotted #000;white-space:nowrap}.layui-tree-drag i{padding-right:5px}.layui-nav{position:relative;padding:0 20px;background-color:#393D49;color:#c2c2c2;border-radius:2px;font-size:0;box-sizing:border-box!important}.layui-nav *{font-size:14px}.layui-nav .layui-nav-item{position:relative;display:inline-block;*display:inline;*zoom:1;vertical-align:middle;line-height:60px}.layui-nav .layui-nav-item a{display:block;padding:0 20px;color:#c2c2c2;transition:all .3s;-webkit-transition:all .3s}.layui-nav .layui-this:after,.layui-nav-bar,.layui-nav-tree .layui-nav-itemed:after{position:absolute;left:0;top:0;width:0;height:5px;background-color:#5FB878;transition:all .2s;-webkit-transition:all .2s}.layui-nav-bar{z-index:1000}.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color:#fff}.layui-nav .layui-this:after{content:'';top:auto;bottom:0;width:100%}.layui-nav .layui-nav-more{content:'';width:0;height:0;border-style:solid dashed dashed;border-color:#c2c2c2 transparent transparent;overflow:hidden;cursor:pointer;transition:all .2s;-webkit-transition:all .2s;position:absolute;top:28px;right:3px;border-width:6px}.layui-nav .layui-nav-mored,.layui-nav-itemed .layui-nav-more{top:22px;border-style:dashed dashed solid;border-color:transparent transparent #c2c2c2}.layui-nav-child{display:none;position:absolute;left:0;top:65px;min-width:100%;line-height:36px;padding:5px 0;box-shadow:0 2px 4px rgba(0,0,0,.12);border:1px solid #d2d2d2;background-color:#fff;z-index:100;border-radius:2px;white-space:nowrap}.layui-nav .layui-nav-child a{color:#333}.layui-nav .layui-nav-child a:hover{background-color:#f2f2f2;color:#333}.layui-nav-child dd{position:relative}.layui-nav-child dd.layui-this{background-color:#5FB878;color:#fff}.layui-nav-child dd.layui-this a{color:#fff}.layui-nav-child dd.layui-this:after{display:none}.layui-nav-tree{width:200px;padding:0}.layui-nav-tree .layui-nav-item{display:block;width:100%;line-height:45px}.layui-nav-tree .layui-nav-item a{height:45px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-nav-tree .layui-nav-item a:hover{background-color:#4E5465}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color:#009688;color:#fff}.layui-nav-tree .layui-this:after{display:none}.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{background-color:#2B2E37!important;color:#fff!important}.layui-nav-tree .layui-nav-bar{width:5px;height:0;background-color:#009688}.layui-nav-tree .layui-nav-child{position:relative;z-index:0;top:0;border:none;box-shadow:none}.layui-nav-tree .layui-nav-child a{height:40px;line-height:40px;color:#c2c2c2}.layui-nav-tree .layui-nav-child,.layui-nav-tree .layui-nav-child a:hover{background:0 0;color:#fff}.layui-nav-tree .layui-nav-more{top:20px;right:10px}.layui-nav-itemed .layui-nav-more{top:14px}.layui-nav-itemed .layui-nav-child{display:block;padding:0}.layui-nav-side{position:fixed;top:0;bottom:0;left:0;overflow-x:hidden;z-index:999}.layui-breadcrumb{visibility:hidden;font-size:0}.layui-breadcrumb a{padding-right:8px;line-height:22px;font-size:14px;color:#333!important}.layui-breadcrumb a:hover{color:#01AAED!important}.layui-breadcrumb a cite,.layui-breadcrumb a span{color:#666;cursor:text;font-style:normal}.layui-breadcrumb a span{padding-left:8px;font-family:Sim sun}.layui-tab{margin:10px 0;text-align:left!important}.layui-fixbar li,.layui-tab-bar,.layui-tab-title li,.layui-util-face ul li{cursor:pointer;text-align:center}.layui-tab[overflow]>.layui-tab-title{overflow:hidden}.layui-tab-title{position:relative;left:0;height:40px;white-space:nowrap;font-size:0;border-bottom:1px solid #e2e2e2;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li{display:inline-block;*display:inline;*zoom:1;vertical-align:middle;font-size:14px;transition:all .2s;-webkit-transition:all .2s;position:relative;line-height:40px;min-width:65px;padding:0 10px}.layui-tab-title li a{display:block}.layui-tab-title .layui-this{color:#000}.layui-tab-title .layui-this:after{position:absolute;left:0;top:0;content:'';width:100%;height:41px;border:1px solid #e2e2e2;border-bottom-color:#fff;border-radius:2px 2px 0 0;-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important;pointer-events:none}.layui-tab-bar{position:absolute;right:0;top:0;z-index:10;width:30px;height:39px;line-height:39px;border:1px solid #e2e2e2;border-radius:2px;background-color:#fff}.layui-tab-bar .layui-icon{position:relative;display:inline-block;top:3px;transition:all .3s;-webkit-transition:all .3s}.layui-tab-item,.layui-util-face .layui-layer-TipsG{display:none}.layui-tab-more{padding-right:30px;height:auto;white-space:normal}.layui-tab-more li.layui-this:after{border-bottom-color:#e2e2e2;border-radius:2px}.layui-tab-more .layui-tab-bar .layui-icon{top:-2px;top:3px\9;-webkit-transform:rotate(180deg);transform:rotate(180deg)}:root .layui-tab-more .layui-tab-bar .layui-icon{top:-2px\0/IE9}.layui-tab-content{padding:10px}.layui-tab-title li .layui-tab-close{position:relative;margin-left:8px;top:1px;color:#c2c2c2;transition:all .2s;-webkit-transition:all .2s}.layui-tab-title li .layui-tab-close:hover{border-radius:2px;background-color:#FF5722;color:#fff}.layui-tab-brief>.layui-tab-title .layui-this{color:#009688}.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border:none;border-radius:0;border-bottom:3px solid #5FB878}.layui-tab-brief[overflow]>.layui-tab-title .layui-this:after{top:-1px}.layui-tab-card{border:1px solid #e2e2e2;border-radius:2px;box-shadow:0 2px 5px 0 rgba(0,0,0,.1)}.layui-tab-card>.layui-tab-title{background-color:#f2f2f2}.layui-tab-card>.layui-tab-title li{margin-right:-1px;margin-left:-1px}.layui-tab-card>.layui-tab-title .layui-this{background-color:#fff}.layui-tab-card>.layui-tab-title .layui-this:after{border-top:none;border-width:1px;border-bottom-color:#fff}.layui-tab-card>.layui-tab-title .layui-tab-bar{height:40px;line-height:40px;border-radius:0;border-top:none;border-right:none}.layui-tab-card>.layui-tab-more .layui-this{background:0 0;color:#5FB878}.layui-tab-card>.layui-tab-more .layui-this:after{border:none}.layui-fixbar{position:fixed;right:15px;bottom:15px;z-index:9999}.layui-fixbar li{width:50px;height:50px;line-height:50px;margin-bottom:1px;font-size:30px;background-color:#9F9F9F;color:#fff;border-radius:2px;opacity:.95}.layui-fixbar li:hover{opacity:.85}.layui-fixbar li:active{opacity:1}.layui-fixbar .layui-fixbar-top{display:none;font-size:40px}body .layui-util-face{border:none;background:0 0}body .layui-util-face .layui-layer-content{padding:0;background-color:#fff;color:#666;box-shadow:none}.layui-util-face ul{position:relative;width:372px;padding:10px;border:1px solid #D9D9D9;background-color:#fff;box-shadow:0 0 20px rgba(0,0,0,.2)}.layui-util-face ul li{float:left;border:1px solid #e8e8e8;height:22px;width:26px;overflow:hidden;margin:-1px 0 0 -1px;padding:4px 2px}.layui-util-face ul li:hover{position:relative;z-index:2;border:1px solid #eb7350;background:#fff9ec}.layui-anim{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-anim-loop{-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}@-webkit-keyframes layui-rotate{from{-webkit-transform:rotate(0)}to{-webkit-transform:rotate(360deg)}}@keyframes layui-rotate{from{transform:rotate(0)}to{transform:rotate(360deg)}}.layui-anim-rotate{-webkit-animation-name:layui-rotate;animation-name:layui-rotate;-webkit-animation-duration:1s;animation-duration:1s;-webkit-animation-timing-function:linear;animation-timing-function:linear}@-webkit-keyframes layui-up{from{-webkit-transform:translate3d(0,100%,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-up{from{transform:translate3d(0,100%,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-up{-webkit-animation-name:layui-up;animation-name:layui-up}@-webkit-keyframes layui-upbit{from{-webkit-transform:translate3d(0,30px,0);opacity:.3}to{-webkit-transform:translate3d(0,0,0);opacity:1}}@keyframes layui-upbit{from{transform:translate3d(0,30px,0);opacity:.3}to{transform:translate3d(0,0,0);opacity:1}}.layui-anim-upbit{-webkit-animation-name:layui-upbit;animation-name:layui-upbit}@-webkit-keyframes layui-scale{0%{opacity:.3;-webkit-transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale{0%{opacity:.3;-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-ms-transform:scale(1);transform:scale(1)}}.layui-anim-scale{-webkit-animation-name:layui-scale;animation-name:layui-scale}@-webkit-keyframes layui-scale-spring{0%{opacity:.5;-webkit-transform:scale(.5)}80%{opacity:.8;-webkit-transform:scale(1.1)}100%{opacity:1;-webkit-transform:scale(1)}}@keyframes layui-scale-spring{0%{opacity:.5;-ms-transform:scale(.5);transform:scale(.5)}80%{opacity:.8;-ms-transform:scale(1.1);transform:scale(1.1)}100%{opacity:1;-ms-transform:scale(1);transform:scale(1)}}.layui-anim-scaleSpring{-webkit-animation-name:layui-scale-spring;animation-name:layui-scale-spring}@media screen and (max-width:450px){.layui-form-item .layui-form-label{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-form-item .layui-inline{display:block;margin-right:0;margin-bottom:20px;clear:both}.layui-form-item .layui-inline:after{content:'\20';clear:both;display:block;height:0}.layui-form-item .layui-input-inline{display:block;float:none;left:-3px;width:auto;margin:0 0 10px 112px}.layui-form-item .layui-input-inline+.layui-form-mid{margin-left:110px;top:-5px;padding:0}.layui-form-item .layui-form-checkbox{margin-right:5px;margin-bottom:5px}} \ No newline at end of file diff --git a/build/css/layui.mobile.css b/build/css/layui.mobile.css deleted file mode 100644 index 2a238cda3..000000000 --- a/build/css/layui.mobile.css +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,legend,li,ol,p,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}html{font:12px 'Helvetica Neue','PingFang SC',STHeitiSC-Light,Helvetica,Arial,sans-serif;-ms-text-size-adjust:100%;-webkit-text-size-adjust:100%}a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0)}a{text-decoration:none;background:0 0}a:active,a:hover{outline:0}table{border-collapse:collapse;border-spacing:0}li{list-style:none}b,strong{font-weight:700}h1,h2,h3,h4,h5,h6{font-weight:500}address,cite,dfn,em,var{font-style:normal}dfn{font-style:italic}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}img{border:0;vertical-align:bottom}.layui-inline,input,label{vertical-align:middle}button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0;outline:0}button,select{text-transform:none}select{-webkit-appearance:none;border:none}input{line-height:normal}input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0}input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto}input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box}input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none}@font-face{font-family:layui-icon;src:url(../font/iconfont.eot?v=1.0.7);src:url(../font/iconfont.eot?v=1.0.7#iefix) format('embedded-opentype'),url(../font/iconfont.woff?v=1.0.7) format('woff'),url(../font/iconfont.ttf?v=1.0.7) format('truetype'),url(../font/iconfont.svg?v=1.0.7#iconfont) format('svg')}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-box,.layui-box *{-webkit-box-sizing:content-box!important;-moz-box-sizing:content-box!important;box-sizing:content-box!important}.layui-border-box,.layui-border-box *{-webkit-box-sizing:border-box!important;-moz-box-sizing:border-box!important;box-sizing:border-box!important}.layui-inline{position:relative;display:inline-block;*display:inline;*zoom:1}.layui-edge,.layui-upload-iframe{position:absolute;width:0;height:0}.layui-edge{border-style:dashed;border-color:transparent;overflow:hidden}.layui-elip{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-unselect{-moz-user-select:none;-webkit-user-select:none;-ms-user-select:none}.layui-disabled,.layui-disabled:active{background-color:#d2d2d2!important;color:#fff!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-upload-iframe{border:0;visibility:hidden}.layui-upload-enter{border:1px solid #009E94;background-color:#009E94;color:#fff;-webkit-transform:scale(1.1);transform:scale(1.1)}@-webkit-keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layui-m-anim-scale{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}.layui-m-anim-scale{animation-name:layui-m-anim-scale;-webkit-animation-name:layui-m-anim-scale}@-webkit-keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layui-m-anim-up{0%{opacity:0;-webkit-transform:translateY(800px);transform:translateY(800px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}.layui-m-anim-up{-webkit-animation-name:layui-m-anim-up;animation-name:layui-m-anim-up}@-webkit-keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-left{0%{-webkit-transform:translateX(100%);transform:translateX(100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-left{-webkit-animation-name:layui-m-anim-left;animation-name:layui-m-anim-left}@-webkit-keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes layui-m-anim-right{0%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}100%{-webkit-transform:translateX(0);transform:translateX(0)}}.layui-m-anim-right{-webkit-animation-name:layui-m-anim-right;animation-name:layui-m-anim-right}@-webkit-keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}@keyframes layui-m-anim-lout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(-100%);transform:translateX(-100%)}}.layui-m-anim-lout{-webkit-animation-name:layui-m-anim-lout;animation-name:layui-m-anim-lout}@-webkit-keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}@keyframes layui-m-anim-rout{0%{-webkit-transform:translateX(0);transform:translateX(0)}100%{-webkit-transform:translateX(100%);transform:translateX(100%)}}.layui-m-anim-rout{-webkit-animation-name:layui-m-anim-rout;animation-name:layui-m-anim-rout}.layui-m-layer{position:relative;z-index:19891014}.layui-m-layer *{-webkit-box-sizing:content-box;-moz-box-sizing:content-box;box-sizing:content-box}.layui-m-layermain,.layui-m-layershade{position:fixed;left:0;top:0;width:100%;height:100%}.layui-m-layershade{background-color:rgba(0,0,0,.7);pointer-events:auto}.layui-m-layermain{display:table;font-family:Helvetica,arial,sans-serif;pointer-events:none}.layui-m-layermain .layui-m-layersection{display:table-cell;vertical-align:middle;text-align:center}.layui-m-layerchild{position:relative;display:inline-block;text-align:left;background-color:#fff;font-size:14px;border-radius:5px;box-shadow:0 0 8px rgba(0,0,0,.1);pointer-events:auto;-webkit-overflow-scrolling:touch;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.2s;animation-duration:.2s}.layui-m-layer0 .layui-m-layerchild{width:90%;max-width:640px}.layui-m-layer1 .layui-m-layerchild{border:none;border-radius:0}.layui-m-layer2 .layui-m-layerchild{width:auto;max-width:260px;min-width:40px;border:none;background:0 0;box-shadow:none;color:#fff}.layui-m-layerchild h3{padding:0 10px;height:60px;line-height:60px;font-size:16px;font-weight:400;border-radius:5px 5px 0 0;text-align:center}.layui-m-layerbtn span,.layui-m-layerchild h3{text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.layui-m-layercont{padding:50px 30px;line-height:22px;text-align:center}.layui-m-layer1 .layui-m-layercont{padding:0;text-align:left}.layui-m-layer2 .layui-m-layercont{text-align:center;padding:0;line-height:0}.layui-m-layer2 .layui-m-layercont i{width:25px;height:25px;margin-left:8px;display:inline-block;background-color:#fff;border-radius:100%;-webkit-animation:layui-m-anim-loading 1.4s infinite ease-in-out;animation:layui-m-anim-loading 1.4s infinite ease-in-out;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-m-layerbtn,.layui-m-layerbtn span{position:relative;text-align:center;border-radius:0 0 5px 5px}.layui-m-layer2 .layui-m-layercont p{margin-top:20px}@-webkit-keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}@keyframes layui-m-anim-loading{0%,100%,80%{transform:scale(0);-webkit-transform:scale(0)}40%{transform:scale(1);-webkit-transform:scale(1)}}.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0;-webkit-animation-delay:-.32s;animation-delay:-.32s}.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay:-.16s;animation-delay:-.16s}.layui-m-layer2 .layui-m-layercont>div{line-height:22px;padding-top:7px;margin-bottom:20px;font-size:14px}.layui-m-layerbtn{display:box;display:-moz-box;display:-webkit-box;width:100%;height:50px;line-height:50px;font-size:0;border-top:1px solid #D0D0D0;background-color:#F2F2F2}.layui-m-layerbtn span{display:block;-moz-box-flex:1;box-flex:1;-webkit-box-flex:1;font-size:14px;cursor:pointer}.layui-m-layerbtn span[yes]{color:#40AFFE}.layui-m-layerbtn span[no]{border-right:1px solid #D0D0D0;border-radius:0 0 0 5px}.layui-m-layerbtn span:active{background-color:#F6F6F6}.layui-m-layerend{position:absolute;right:7px;top:10px;width:30px;height:30px;border:0;font-weight:400;background:0 0;cursor:pointer;-webkit-appearance:none;font-size:30px}.layui-m-layerend::after,.layui-m-layerend::before{position:absolute;left:5px;top:15px;content:'';width:18px;height:1px;background-color:#999;transform:rotate(45deg);-webkit-transform:rotate(45deg);border-radius:3px}.layui-m-layerend::after{transform:rotate(-45deg);-webkit-transform:rotate(-45deg)}body .layui-m-layer .layui-m-layer-footer{position:fixed;width:95%;max-width:100%;margin:0 auto;left:0;right:0;bottom:10px;background:0 0}.layui-m-layer-footer .layui-m-layercont{padding:20px;border-radius:5px 5px 0 0;background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn{display:block;height:auto;background:0 0;border-top:none}.layui-m-layer-footer .layui-m-layerbtn span{background-color:rgba(255,255,255,.8)}.layui-m-layer-footer .layui-m-layerbtn span[no]{color:#FD482C;border-top:1px solid #c2c2c2;border-radius:0 0 5px 5px}.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top:10px;border-radius:5px}body .layui-m-layer .layui-m-layer-msg{width:auto;max-width:90%;margin:0 auto;bottom:-150px;background-color:rgba(0,0,0,.7);color:#fff}.layui-m-layer-msg .layui-m-layercont{padding:10px 20px} \ No newline at end of file diff --git a/build/css/modules/code.css b/build/css/modules/code.css deleted file mode 100644 index 704b8f3d7..000000000 --- a/build/css/modules/code.css +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - html #layuicss-skincodecss{display:none;position:absolute;width:1989px}.layui-code-h3,.layui-code-view{position:relative;font-size:12px}.layui-code-view{display:block;margin:10px 0;padding:0;border:1px solid #ddd;border-left-width:6px;background-color:#F2F2F2;color:#333;font-family:Courier New}.layui-code-h3{padding:0 10px;height:30px;line-height:30px;border-bottom:1px solid #ddd}.layui-code-h3 a{position:absolute;right:10px;top:0;color:#999}.layui-code-view .layui-code-ol{position:relative;overflow:auto}.layui-code-view .layui-code-ol li{position:relative;margin-left:45px;line-height:20px;padding:0 5px;border-left:1px solid #ddd;list-style-type:decimal-leading-zero;*list-style-type:decimal;background-color:#fff}.layui-code-view pre{margin:0}.layui-code-notepad{border:1px solid #0C0C0C;border-left-color:#3F3F3F;background-color:#0C0C0C;color:#C2BE9E}.layui-code-notepad .layui-code-h3{border-bottom:none}.layui-code-notepad .layui-code-ol li{background-color:#3F3F3F;border-left:none} \ No newline at end of file diff --git a/build/css/modules/laydate/icon.png b/build/css/modules/laydate/icon.png deleted file mode 100644 index 5a50673e0..000000000 Binary files a/build/css/modules/laydate/icon.png and /dev/null differ diff --git a/build/css/modules/laydate/laydate.css b/build/css/modules/laydate/laydate.css deleted file mode 100644 index c0eec2f81..000000000 --- a/build/css/modules/laydate/laydate.css +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - #layuicss-laydatecss{display:none;position:absolute;width:1989px}.laydate_body .laydate_box,.laydate_body .laydate_box *{margin:0;padding:0;box-sizing:content-box}.laydate-icon,.laydate-icon-dahong,.laydate-icon-danlan,.laydate-icon-default,.laydate-icon-molv{height:22px;line-height:22px;padding-right:20px;border:1px solid #C6C6C6;background-repeat:no-repeat;background-position:right center;background-color:#fff;outline:0}.laydate-icon-default{background-image:url(../skins/default/icon.png)}.laydate-icon-danlan{border:1px solid #B1D2EC;background-image:url(../skins/danlan/icon.png)}.laydate-icon-dahong{background-image:url(../skins/dahong/icon.png)}.laydate-icon-molv{background-image:url(../skins/molv/icon.png)}.laydate_body .laydate_box{width:240px;font:12px '\5B8B\4F53';z-index:99999999;*overflow:hidden;_margin:0;_position:absolute!important}.laydate_body .laydate_box li{list-style:none}.laydate_body .laydate_box .laydate_void{cursor:text!important}.laydate_body .laydate_box cite,.laydate_body .laydate_box label{position:absolute;width:0;height:0;border-width:5px;border-style:dashed;border-color:transparent;overflow:hidden;cursor:pointer}.laydate_body .laydate_box .laydate_time,.laydate_body .laydate_box .laydate_yms{display:none}.laydate_body .laydate_box .laydate_show{display:block}.laydate_body .laydate_box input{outline:0;font-size:14px;background-color:#fff;color:#333}.laydate_body .laydate_top{position:relative;height:26px;padding:5px;*width:100%;z-index:99}.laydate_body .laydate_ym{position:relative;float:left;height:24px;cursor:pointer}.laydate_body .laydate_ym input{float:left;height:24px;line-height:24px;text-align:center;border:none;cursor:pointer}.laydate_body .laydate_ym .laydate_yms{position:absolute;left:-1px;top:24px;height:181px}.laydate_body .laydate_y{width:121px;margin-right:6px}.laydate_body .laydate_y input{width:64px;margin-right:15px}.laydate_body .laydate_y .laydate_yms{width:121px;text-align:center}.laydate_body .laydate_y .laydate_yms a{position:relative;display:block;height:20px}.laydate_body .laydate_y .laydate_yms ul{height:139px;padding:0;*overflow:hidden}.laydate_body .laydate_y .laydate_yms ul li{float:left;width:60px;height:20px;line-height:20px;text-overflow:ellipsis;overflow:hidden;white-space:nowrap}.laydate_body .laydate_m{width:99px}.laydate_body .laydate_m .laydate_yms{width:99px;padding:0}.laydate_body .laydate_m input{width:42px;margin-right:15px}.laydate_body .laydate_m .laydate_yms span{display:block;float:left;width:42px;margin:5px 0 0 5px;line-height:24px;text-align:center;_display:inline}.laydate_body .laydate_choose{display:block;float:left;position:relative;width:20px;height:24px}.laydate_body .laydate_choose cite,.laydate_body .laydate_tab cite{left:50%;top:50%}.laydate_body .laydate_chtop cite{margin:-7px 0 0 -5px;border-bottom-style:solid}.laydate_body .laydate_chdown cite,.laydate_body .laydate_ym label{top:50%;margin:-2px 0 0 -5px;border-top-style:solid}.laydate_body .laydate_chprev cite{margin:-5px 0 0 -7px}.laydate_body .laydate_chnext cite{margin:-5px 0 0 -2px}.laydate_body .laydate_ym label{right:28px}.laydate_body .laydate_table{width:230px;margin:0 5px;border-collapse:collapse;border-spacing:0}.laydate_body .laydate_table td{width:31px;text-align:center;cursor:pointer;font-size:12px}.laydate_body .laydate_table thead th{font-weight:400;font-size:12px;text-align:center}.laydate_body .laydate_bottom{position:relative;height:22px;line-height:20px;padding:5px;font-size:12px}.laydate_body .laydate_bottom #laydate_hms{position:relative;z-index:1;float:left}.laydate_body .laydate_time{position:absolute;left:5px;bottom:26px;width:129px;height:125px;*overflow:hidden}.laydate_body .laydate_time .laydate_hmsno{padding:5px 0 0 5px}.laydate_body .laydate_time .laydate_hmsno span{display:block;float:left;width:24px;height:19px;line-height:19px;text-align:center;cursor:pointer;*margin-bottom:-5px}.laydate_body .laydate_time1{width:228px;height:154px}.laydate_body .laydate_time1 .laydate_hmsno{padding:6px 0 0 8px}.laydate_body .laydate_time1 .laydate_hmsno span{width:21px;height:20px;line-height:20px}.laydate_body .laydate_msg{left:49px;bottom:67px;width:141px;height:auto;overflow:hidden}.laydate_body .laydate_msg p{padding:5px 10px}.laydate_body .laydate_bottom li{float:left;height:20px;line-height:20px;border-right:none;font-weight:900}.laydate_body .laydate_bottom .laydate_sj{width:33px;text-align:center;font-weight:400}.laydate_body .laydate_bottom input{float:left;width:21px;height:20px;line-height:20px;border:none;text-align:center;cursor:pointer;font-size:12px;font-weight:400}.laydate_body .laydate_bottom .laydte_hsmtex{height:20px;line-height:20px;text-align:center}.laydate_body .laydate_bottom .laydte_hsmtex span{position:absolute;width:20px;top:0;right:0;cursor:pointer}.laydate_body .laydate_bottom .laydte_hsmtex span:hover{font-size:14px}.laydate_body .laydate_bottom .laydate_btn{position:absolute;right:5px;top:5px}.laydate_body .laydate_bottom .laydate_btn a{float:left;height:20px;padding:0 6px;_padding:0 5px}.laydate_body .laydate_table td,.laydate_body .laydate_table thead{height:21px!important;line-height:21px!important}.laydate-icon{border:1px solid #C6C6C6;background-image:url(icon.png)}.laydate_body .laydate_bottom #laydate_hms,.laydate_body .laydate_bottom .laydate_btn a,.laydate_body .laydate_box,.laydate_body .laydate_table,.laydate_body .laydate_table td,.laydate_body .laydate_time,.laydate_body .laydate_ym,.laydate_body .laydate_ym .laydate_yms{border:1px solid #ccc}.laydate_body .laydate_bottom .laydte_hsmtex,.laydate_body .laydate_choose,.laydate_body .laydate_table thead,.laydate_body .laydate_y .laydate_yms a{background-color:#F6F6F6}.laydate_body .laydate_box,.laydate_body .laydate_time,.laydate_body .laydate_ym .laydate_yms{box-shadow:2px 2px 5px rgba(0,0,0,.1)}.laydate_body .laydate_box{border-top:none;border-bottom:none;background-color:#fff;color:#333}.laydate_body .laydate_box .laydate_void{color:#ccc!important}.laydate_body .laydate_box .laydate_void:hover{background-color:#fff!important}.laydate_body .laydate_box a,.laydate_body .laydate_box a:hover{text-decoration:none;blr:expression(this.onFocus=this.blur());cursor:pointer;color:#333}.laydate_body .laydate_box a:hover{text-decoration:none;color:#666}.laydate_body .laydate_click{background-color:#eee!important}.laydate_body .laydate_bottom #laydate_hms,.laydate_body .laydate_choose:hover,.laydate_body .laydate_table td,.laydate_body .laydate_time,.laydate_body .laydate_y .laydate_yms a:hover{background-color:#fff}.laydate_body .laydate_top{border-top:1px solid #C6C6C6}.laydate_body .laydate_ym .laydate_yms{border:1px solid #C6C6C6;background-color:#fff}.laydate_body .laydate_y .laydate_yms a{border-bottom:1px solid #C6C6C6}.laydate_body .laydate_y .laydate_yms .laydate_chdown{border-top:1px solid #C6C6C6;border-bottom:none}.laydate_body .laydate_choose{border-left:1px solid #C6C6C6}.laydate_body .laydate_chprev{border-left:none;border-right:1px solid #C6C6C6}.laydate_body .laydate_chtop cite{border-bottom-color:#666}.laydate_body .laydate_chdown cite,.laydate_body .laydate_ym label{border-top-color:#666}.laydate_body .laydate_chprev cite{border-right-style:solid;border-right-color:#666}.laydate_body .laydate_chnext cite{border-left-style:solid;border-left-color:#666}.laydate_body .laydate_table td{border:none}.laydate_body .laydate_table .laydate_nothis{color:#999}.laydate_body .laydate_table thead th{border-bottom:1px solid #ccc}.laydate_body .laydate_bottom,.laydate_body .laydate_bottom .laydte_hsmtex{border-bottom:1px solid #C6C6C6}.laydate_body .laydate_bottom .laydate_sj{border-right:1px solid #C6C6C6;background-color:#F6F6F6}.laydate_body .laydate_bottom input{background-color:#fff}.laydate_body .laydate_bottom .laydate_btn{border-right:1px solid #C6C6C6}.laydate_body .laydate_bottom .laydate_v{position:absolute;left:10px;top:6px;font-family:Courier;z-index:0;color:#999}.laydate_body .laydate_bottom .laydate_btn a{border-right:none;background-color:#F6F6F6}.laydate_body .laydate_bottom .laydate_btn a:hover{color:#000;background-color:#fff}.laydate_body .laydate_m .laydate_yms span:hover,.laydate_body .laydate_table td:hover,.laydate_body .laydate_time .laydate_hmsno span:hover,.laydate_body .laydate_y .laydate_yms ul li:hover{background-color:#F3F3F3} \ No newline at end of file diff --git a/build/css/modules/layer/default/icon-ext.png b/build/css/modules/layer/default/icon-ext.png deleted file mode 100644 index bbbb669bb..000000000 Binary files a/build/css/modules/layer/default/icon-ext.png and /dev/null differ diff --git a/build/css/modules/layer/default/icon.png b/build/css/modules/layer/default/icon.png deleted file mode 100644 index 3e17da8b1..000000000 Binary files a/build/css/modules/layer/default/icon.png and /dev/null differ diff --git a/build/css/modules/layer/default/layer.css b/build/css/modules/layer/default/layer.css deleted file mode 100644 index 9f2e52321..000000000 --- a/build/css/modules/layer/default/layer.css +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - .layui-layer-imgbar,.layui-layer-imgtit a,.layui-layer-tab .layui-layer-title span,.layui-layer-title{text-overflow:ellipsis;white-space:nowrap}*html{background-image:url(about:blank);background-attachment:fixed}html #layuicss-skinlayercss{display:none;position:absolute;width:1989px}.layui-layer,.layui-layer-shade{position:fixed;_position:absolute;pointer-events:auto}.layui-layer-shade{top:0;left:0;width:100%;height:100%;_height:expression(document.body.offsetHeight+"px")}.layui-layer{-webkit-overflow-scrolling:touch;top:150px;left:0;margin:0;padding:0;background-color:#fff;-webkit-background-clip:content;box-shadow:1px 1px 50px rgba(0,0,0,.3)}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #B2B2B2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url(loading-1.gif) center center no-repeat #eee}.layui-layer-ico{background:url(icon.png) no-repeat}.layui-layer-btn a,.layui-layer-dialog .layui-layer-ico,.layui-layer-setwin a{display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-move{display:none;position:fixed;*position:absolute;left:0;top:0;width:100%;height:100%;cursor:move;opacity:0;filter:alpha(opacity=0);background-color:#fff;z-index:2147483647}.layui-layer-resize{position:absolute;width:15px;height:15px;right:0;bottom:0;cursor:se-resize}.layui-layer{border-radius:2px;-webkit-animation-fill-mode:both;animation-fill-mode:both;-webkit-animation-duration:.3s;animation-duration:.3s}@-webkit-keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceIn{0%{opacity:0;-webkit-transform:scale(.5);-ms-transform:scale(.5);transform:scale(.5)}100%{opacity:1;-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim{-webkit-animation-name:layer-bounceIn;animation-name:layer-bounceIn}@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown}@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig}@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft}@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0) rotate(0);-ms-transform:translateX(0) rotate(0);transform:translateX(0) rotate(0)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn}@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}}.layui-layer-title{padding:0 80px 0 20px;height:42px;line-height:42px;border-bottom:1px solid #eee;font-size:14px;color:#333;overflow:hidden;background-color:#F8F8F8;border-radius:2px 2px 0 0}.layui-layer-setwin{position:absolute;right:15px;*right:0;top:15px;font-size:0;line-height:initial}.layui-layer-setwin a{position:relative;width:16px;height:16px;margin-left:10px;font-size:12px;_overflow:hidden}.layui-layer-setwin .layui-layer-min cite{position:absolute;width:14px;height:2px;left:0;top:50%;margin-top:-1px;background-color:#2E2D3C;cursor:pointer;_overflow:hidden}.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA}.layui-layer-setwin .layui-layer-max{background-position:-32px -40px}.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px}.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px}.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px}.layui-layer-setwin .layui-layer-close1{background-position:1px -40px;cursor:pointer}.layui-layer-setwin .layui-layer-close1:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{position:absolute;right:-28px;top:-28px;width:30px;height:30px;margin-left:0;background-position:-149px -31px;*right:-18px;_display:none}.layui-layer-setwin .layui-layer-close2:hover{background-position:-180px -31px}.layui-layer-btn{text-align:right;padding:0 10px 12px;pointer-events:auto;user-select:none;-webkit-user-select:none}.layui-layer-btn a{height:28px;line-height:28px;margin:6px 6px 0;padding:0 15px;border:1px solid #dedede;background-color:#f1f1f1;color:#333;border-radius:2px;font-weight:400;cursor:pointer;text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{border-color:#4898d5;background-color:#2e8ded;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-dialog{min-width:260px}.layui-layer-dialog .layui-layer-content{position:relative;padding:20px;line-height:24px;word-break:break-all;overflow:hidden;font-size:14px;overflow-x:hidden;overflow-y:auto}.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute;top:16px;left:15px;_left:-40px;width:30px;height:30px}.layui-layer-ico1{background-position:-30px 0}.layui-layer-ico2{background-position:-60px 0}.layui-layer-ico3{background-position:-90px 0}.layui-layer-ico4{background-position:-120px 0}.layui-layer-ico5{background-position:-150px 0}.layui-layer-ico6{background-position:-180px 0}.layui-layer-rim{border:6px solid #8D8D8D;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{min-width:180px;border:1px solid #D3D4D3;box-shadow:none}.layui-layer-hui{min-width:100px;background-color:#000;filter:alpha(opacity=60);background-color:rgba(0,0,0,.6);color:#fff;border:none}.layui-layer-hui .layui-layer-content{padding:12px 25px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:20px 20px 20px 55px;text-align:left}.layui-layer-page .layui-layer-content{position:relative;overflow:auto}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:0 0}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{border-radius:100%;background:0 0;box-shadow:none;border:none}.layui-layer-loading .layui-layer-content{width:60px;height:24px;background:url(loading-0.gif) no-repeat}.layui-layer-loading .layui-layer-loading1{width:37px;height:37px;background:url(loading-1.gif) no-repeat}.layui-layer-ico16,.layui-layer-loading .layui-layer-loading2{width:32px;height:32px;background:url(loading-2.gif) no-repeat}.layui-layer-tips{background:0 0;box-shadow:none;border:none}.layui-layer-tips .layui-layer-content{position:relative;line-height:22px;min-width:12px;padding:5px 10px;font-size:12px;_float:left;border-radius:2px;box-shadow:1px 1px 3px rgba(0,0,0,.2);background-color:#000;color:#fff}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{position:absolute;width:0;height:0;border-width:8px;border-color:transparent;border-style:dashed;*overflow:hidden}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{left:5px;border-right-style:solid;border-right-color:#000}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{top:1px;border-bottom-style:solid;border-bottom-color:#000}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan[type=dialog]{min-width:280px}.layui-layer-lan .layui-layer-title{background:#4476A7;color:#fff;border:none}.layui-layer-lan .layui-layer-btn{padding:5px 10px 10px;text-align:right;border-top:1px solid #E9E7E7}.layui-layer-lan .layui-layer-btn a{background:#BBB5B5;border:none}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5}.layui-layer-molv .layui-layer-title{background:#009f95;color:#fff;border:none}.layui-layer-molv .layui-layer-btn a{background:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1}.layui-layer-iconext{background:url(icon-ext.png) no-repeat}.layui-layer-prompt .layui-layer-input{display:block;width:220px;height:30px;margin:0 auto;line-height:30px;padding:0 5px;border:1px solid #ccc;box-shadow:1px 1px 5px rgba(0,0,0,.1) inset;color:#333}.layui-layer-prompt textarea.layui-layer-input{width:300px;height:100px;line-height:20px}.layui-layer-prompt .layui-layer-content{padding:20px}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{padding-left:0;border-bottom:1px solid #ccc;background-color:#eee;overflow:visible}.layui-layer-tab .layui-layer-title span{position:relative;float:left;min-width:80px;max-width:260px;padding:0 20px;text-align:center;cursor:default;overflow:hidden}.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px;border-left:1px solid #ccc;border-right:1px solid #ccc;background-color:#fff;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left:none}.layui-layer-tabmain{line-height:24px;clear:both}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block}.xubox_tabclose{position:absolute;right:10px;top:5px;cursor:pointer}.layui-layer-photos{-webkit-animation-duration:.8s;animation-duration:.8s}.layui-layer-photos .layui-layer-content{overflow:hidden;text-align:center}.layui-layer-photos .layui-layer-phimg img{position:relative;width:100%;display:inline-block;*display:inline;*zoom:1;vertical-align:top}.layui-layer-imgbar,.layui-layer-imguide{display:none}.layui-layer-imgnext,.layui-layer-imgprev{position:absolute;top:50%;width:27px;_width:44px;height:44px;margin-top:-22px;outline:0;blr:expression(this.onFocus=this.blur())}.layui-layer-imgprev{left:10px;background-position:-5px -5px;_background-position:-70px -5px}.layui-layer-imgprev:hover{background-position:-33px -5px;_background-position:-120px -5px}.layui-layer-imgnext{right:10px;_right:8px;background-position:-5px -50px;_background-position:-70px -50px}.layui-layer-imgnext:hover{background-position:-33px -50px;_background-position:-120px -50px}.layui-layer-imgbar{position:absolute;left:0;bottom:0;width:100%;height:32px;line-height:32px;background-color:rgba(0,0,0,.8);background-color:#000\9;filter:Alpha(opacity=80);color:#fff;overflow:hidden;font-size:0}.layui-layer-imgtit *{display:inline-block;*display:inline;*zoom:1;vertical-align:top;font-size:12px}.layui-layer-imgtit a{max-width:65%;overflow:hidden;color:#fff}.layui-layer-imgtit a:hover{color:#fff;text-decoration:underline}.layui-layer-imgtit em{padding-left:10px;font-style:normal}@-webkit-keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);transform:scale(1)}}@keyframes layer-bounceOut{100%{opacity:0;-webkit-transform:scale(.7);-ms-transform:scale(.7);transform:scale(.7)}30%{-webkit-transform:scale(1.05);-ms-transform:scale(1.05);transform:scale(1.05)}0%{-webkit-transform:scale(1);-ms-transform:scale(1);transform:scale(1)}}.layer-anim-close{-webkit-animation-name:layer-bounceOut;animation-name:layer-bounceOut;-webkit-animation-duration:.2s;animation-duration:.2s}@media screen and (max-width:1100px){.layui-layer-iframe{overflow-y:auto;-webkit-overflow-scrolling:touch}} \ No newline at end of file diff --git a/build/css/modules/layer/default/loading-0.gif b/build/css/modules/layer/default/loading-0.gif deleted file mode 100644 index 6f3c9539a..000000000 Binary files a/build/css/modules/layer/default/loading-0.gif and /dev/null differ diff --git a/build/css/modules/layer/default/loading-1.gif b/build/css/modules/layer/default/loading-1.gif deleted file mode 100644 index db3a483e4..000000000 Binary files a/build/css/modules/layer/default/loading-1.gif and /dev/null differ diff --git a/build/css/modules/layer/default/loading-2.gif b/build/css/modules/layer/default/loading-2.gif deleted file mode 100644 index 5bb90fd6a..000000000 Binary files a/build/css/modules/layer/default/loading-2.gif and /dev/null differ diff --git a/build/font/iconfont.eot b/build/font/iconfont.eot deleted file mode 100644 index ad72e8dba..000000000 Binary files a/build/font/iconfont.eot and /dev/null differ diff --git a/build/font/iconfont.svg b/build/font/iconfont.svg deleted file mode 100644 index 387cf4bb7..000000000 --- a/build/font/iconfont.svg +++ /dev/null @@ -1,390 +0,0 @@ - - - - -Created by FontForge 20120731 at Fri Mar 10 03:16:47 2017 - By admin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/build/font/iconfont.ttf b/build/font/iconfont.ttf deleted file mode 100644 index f79ff7725..000000000 Binary files a/build/font/iconfont.ttf and /dev/null differ diff --git a/build/font/iconfont.woff b/build/font/iconfont.woff deleted file mode 100644 index fd2428129..000000000 Binary files a/build/font/iconfont.woff and /dev/null differ diff --git a/build/images/face/0.gif b/build/images/face/0.gif deleted file mode 100644 index a63f0d523..000000000 Binary files a/build/images/face/0.gif and /dev/null differ diff --git a/build/images/face/1.gif b/build/images/face/1.gif deleted file mode 100644 index b2b78b218..000000000 Binary files a/build/images/face/1.gif and /dev/null differ diff --git a/build/images/face/10.gif b/build/images/face/10.gif deleted file mode 100644 index 556c7e326..000000000 Binary files a/build/images/face/10.gif and /dev/null differ diff --git a/build/images/face/11.gif b/build/images/face/11.gif deleted file mode 100644 index 2bfc58be8..000000000 Binary files a/build/images/face/11.gif and /dev/null differ diff --git a/build/images/face/12.gif b/build/images/face/12.gif deleted file mode 100644 index 1c321c7eb..000000000 Binary files a/build/images/face/12.gif and /dev/null differ diff --git a/build/images/face/13.gif b/build/images/face/13.gif deleted file mode 100644 index 300bbc2a0..000000000 Binary files a/build/images/face/13.gif and /dev/null differ diff --git a/build/images/face/14.gif b/build/images/face/14.gif deleted file mode 100644 index 43b6d0a43..000000000 Binary files a/build/images/face/14.gif and /dev/null differ diff --git a/build/images/face/15.gif b/build/images/face/15.gif deleted file mode 100644 index c9f25fa1d..000000000 Binary files a/build/images/face/15.gif and /dev/null differ diff --git a/build/images/face/16.gif b/build/images/face/16.gif deleted file mode 100644 index 34f28e4cd..000000000 Binary files a/build/images/face/16.gif and /dev/null differ diff --git a/build/images/face/17.gif b/build/images/face/17.gif deleted file mode 100644 index 39cd03538..000000000 Binary files a/build/images/face/17.gif and /dev/null differ diff --git a/build/images/face/18.gif b/build/images/face/18.gif deleted file mode 100644 index 7bce2997f..000000000 Binary files a/build/images/face/18.gif and /dev/null differ diff --git a/build/images/face/19.gif b/build/images/face/19.gif deleted file mode 100644 index adac542fd..000000000 Binary files a/build/images/face/19.gif and /dev/null differ diff --git a/build/images/face/2.gif b/build/images/face/2.gif deleted file mode 100644 index 7edbb58a8..000000000 Binary files a/build/images/face/2.gif and /dev/null differ diff --git a/build/images/face/20.gif b/build/images/face/20.gif deleted file mode 100644 index 50631a6e3..000000000 Binary files a/build/images/face/20.gif and /dev/null differ diff --git a/build/images/face/21.gif b/build/images/face/21.gif deleted file mode 100644 index b98421282..000000000 Binary files a/build/images/face/21.gif and /dev/null differ diff --git a/build/images/face/22.gif b/build/images/face/22.gif deleted file mode 100644 index 1f0bd8b00..000000000 Binary files a/build/images/face/22.gif and /dev/null differ diff --git a/build/images/face/23.gif b/build/images/face/23.gif deleted file mode 100644 index e05e0f97a..000000000 Binary files a/build/images/face/23.gif and /dev/null differ diff --git a/build/images/face/24.gif b/build/images/face/24.gif deleted file mode 100644 index f35928a26..000000000 Binary files a/build/images/face/24.gif and /dev/null differ diff --git a/build/images/face/25.gif b/build/images/face/25.gif deleted file mode 100644 index 0b4a88322..000000000 Binary files a/build/images/face/25.gif and /dev/null differ diff --git a/build/images/face/26.gif b/build/images/face/26.gif deleted file mode 100644 index 45c4fb556..000000000 Binary files a/build/images/face/26.gif and /dev/null differ diff --git a/build/images/face/27.gif b/build/images/face/27.gif deleted file mode 100644 index 7a4c0131d..000000000 Binary files a/build/images/face/27.gif and /dev/null differ diff --git a/build/images/face/28.gif b/build/images/face/28.gif deleted file mode 100644 index fc5a0cfaf..000000000 Binary files a/build/images/face/28.gif and /dev/null differ diff --git a/build/images/face/29.gif b/build/images/face/29.gif deleted file mode 100644 index 5dd7442b1..000000000 Binary files a/build/images/face/29.gif and /dev/null differ diff --git a/build/images/face/3.gif b/build/images/face/3.gif deleted file mode 100644 index 86df67b7a..000000000 Binary files a/build/images/face/3.gif and /dev/null differ diff --git a/build/images/face/30.gif b/build/images/face/30.gif deleted file mode 100644 index b751f98ab..000000000 Binary files a/build/images/face/30.gif and /dev/null differ diff --git a/build/images/face/31.gif b/build/images/face/31.gif deleted file mode 100644 index c9476d796..000000000 Binary files a/build/images/face/31.gif and /dev/null differ diff --git a/build/images/face/32.gif b/build/images/face/32.gif deleted file mode 100644 index 9931b0636..000000000 Binary files a/build/images/face/32.gif and /dev/null differ diff --git a/build/images/face/33.gif b/build/images/face/33.gif deleted file mode 100644 index 59111a38c..000000000 Binary files a/build/images/face/33.gif and /dev/null differ diff --git a/build/images/face/34.gif b/build/images/face/34.gif deleted file mode 100644 index a334548e8..000000000 Binary files a/build/images/face/34.gif and /dev/null differ diff --git a/build/images/face/35.gif b/build/images/face/35.gif deleted file mode 100644 index a9322643d..000000000 Binary files a/build/images/face/35.gif and /dev/null differ diff --git a/build/images/face/36.gif b/build/images/face/36.gif deleted file mode 100644 index 6de432ae9..000000000 Binary files a/build/images/face/36.gif and /dev/null differ diff --git a/build/images/face/37.gif b/build/images/face/37.gif deleted file mode 100644 index d05f2da45..000000000 Binary files a/build/images/face/37.gif and /dev/null differ diff --git a/build/images/face/38.gif b/build/images/face/38.gif deleted file mode 100644 index 8b1c88a3e..000000000 Binary files a/build/images/face/38.gif and /dev/null differ diff --git a/build/images/face/39.gif b/build/images/face/39.gif deleted file mode 100644 index 38b84a513..000000000 Binary files a/build/images/face/39.gif and /dev/null differ diff --git a/build/images/face/4.gif b/build/images/face/4.gif deleted file mode 100644 index d52200c51..000000000 Binary files a/build/images/face/4.gif and /dev/null differ diff --git a/build/images/face/40.gif b/build/images/face/40.gif deleted file mode 100644 index ae429912d..000000000 Binary files a/build/images/face/40.gif and /dev/null differ diff --git a/build/images/face/41.gif b/build/images/face/41.gif deleted file mode 100644 index b9c715c52..000000000 Binary files a/build/images/face/41.gif and /dev/null differ diff --git a/build/images/face/42.gif b/build/images/face/42.gif deleted file mode 100644 index 0eb1434b4..000000000 Binary files a/build/images/face/42.gif and /dev/null differ diff --git a/build/images/face/43.gif b/build/images/face/43.gif deleted file mode 100644 index ac0b70085..000000000 Binary files a/build/images/face/43.gif and /dev/null differ diff --git a/build/images/face/44.gif b/build/images/face/44.gif deleted file mode 100644 index ad4449769..000000000 Binary files a/build/images/face/44.gif and /dev/null differ diff --git a/build/images/face/45.gif b/build/images/face/45.gif deleted file mode 100644 index 6837fcaf2..000000000 Binary files a/build/images/face/45.gif and /dev/null differ diff --git a/build/images/face/46.gif b/build/images/face/46.gif deleted file mode 100644 index d62916d40..000000000 Binary files a/build/images/face/46.gif and /dev/null differ diff --git a/build/images/face/47.gif b/build/images/face/47.gif deleted file mode 100644 index 58a083611..000000000 Binary files a/build/images/face/47.gif and /dev/null differ diff --git a/build/images/face/48.gif b/build/images/face/48.gif deleted file mode 100644 index 7ffd1613b..000000000 Binary files a/build/images/face/48.gif and /dev/null differ diff --git a/build/images/face/49.gif b/build/images/face/49.gif deleted file mode 100644 index 959b99296..000000000 Binary files a/build/images/face/49.gif and /dev/null differ diff --git a/build/images/face/5.gif b/build/images/face/5.gif deleted file mode 100644 index 4e8b09f15..000000000 Binary files a/build/images/face/5.gif and /dev/null differ diff --git a/build/images/face/50.gif b/build/images/face/50.gif deleted file mode 100644 index 6e22e7ff1..000000000 Binary files a/build/images/face/50.gif and /dev/null differ diff --git a/build/images/face/51.gif b/build/images/face/51.gif deleted file mode 100644 index ad3f4d3a8..000000000 Binary files a/build/images/face/51.gif and /dev/null differ diff --git a/build/images/face/52.gif b/build/images/face/52.gif deleted file mode 100644 index 39f8a2284..000000000 Binary files a/build/images/face/52.gif and /dev/null differ diff --git a/build/images/face/53.gif b/build/images/face/53.gif deleted file mode 100644 index a181ee778..000000000 Binary files a/build/images/face/53.gif and /dev/null differ diff --git a/build/images/face/54.gif b/build/images/face/54.gif deleted file mode 100644 index e289d929b..000000000 Binary files a/build/images/face/54.gif and /dev/null differ diff --git a/build/images/face/55.gif b/build/images/face/55.gif deleted file mode 100644 index 4351083ac..000000000 Binary files a/build/images/face/55.gif and /dev/null differ diff --git a/build/images/face/56.gif b/build/images/face/56.gif deleted file mode 100644 index e0eff222b..000000000 Binary files a/build/images/face/56.gif and /dev/null differ diff --git a/build/images/face/57.gif b/build/images/face/57.gif deleted file mode 100644 index 0bf130f0d..000000000 Binary files a/build/images/face/57.gif and /dev/null differ diff --git a/build/images/face/58.gif b/build/images/face/58.gif deleted file mode 100644 index 0f065087d..000000000 Binary files a/build/images/face/58.gif and /dev/null differ diff --git a/build/images/face/59.gif b/build/images/face/59.gif deleted file mode 100644 index 7081e4f02..000000000 Binary files a/build/images/face/59.gif and /dev/null differ diff --git a/build/images/face/6.gif b/build/images/face/6.gif deleted file mode 100644 index f7715bf52..000000000 Binary files a/build/images/face/6.gif and /dev/null differ diff --git a/build/images/face/60.gif b/build/images/face/60.gif deleted file mode 100644 index 6e15f89d7..000000000 Binary files a/build/images/face/60.gif and /dev/null differ diff --git a/build/images/face/61.gif b/build/images/face/61.gif deleted file mode 100644 index f092d7e35..000000000 Binary files a/build/images/face/61.gif and /dev/null differ diff --git a/build/images/face/62.gif b/build/images/face/62.gif deleted file mode 100644 index 7fe49840b..000000000 Binary files a/build/images/face/62.gif and /dev/null differ diff --git a/build/images/face/63.gif b/build/images/face/63.gif deleted file mode 100644 index cf8e23e5b..000000000 Binary files a/build/images/face/63.gif and /dev/null differ diff --git a/build/images/face/64.gif b/build/images/face/64.gif deleted file mode 100644 index a7797198a..000000000 Binary files a/build/images/face/64.gif and /dev/null differ diff --git a/build/images/face/65.gif b/build/images/face/65.gif deleted file mode 100644 index 7bb98f2d8..000000000 Binary files a/build/images/face/65.gif and /dev/null differ diff --git a/build/images/face/66.gif b/build/images/face/66.gif deleted file mode 100644 index bb6d07750..000000000 Binary files a/build/images/face/66.gif and /dev/null differ diff --git a/build/images/face/67.gif b/build/images/face/67.gif deleted file mode 100644 index 6e33f7c4f..000000000 Binary files a/build/images/face/67.gif and /dev/null differ diff --git a/build/images/face/68.gif b/build/images/face/68.gif deleted file mode 100644 index 1a6c400d2..000000000 Binary files a/build/images/face/68.gif and /dev/null differ diff --git a/build/images/face/69.gif b/build/images/face/69.gif deleted file mode 100644 index a02f0b223..000000000 Binary files a/build/images/face/69.gif and /dev/null differ diff --git a/build/images/face/7.gif b/build/images/face/7.gif deleted file mode 100644 index e6d4db805..000000000 Binary files a/build/images/face/7.gif and /dev/null differ diff --git a/build/images/face/70.gif b/build/images/face/70.gif deleted file mode 100644 index 416c5c14a..000000000 Binary files a/build/images/face/70.gif and /dev/null differ diff --git a/build/images/face/71.gif b/build/images/face/71.gif deleted file mode 100644 index c17d60cbd..000000000 Binary files a/build/images/face/71.gif and /dev/null differ diff --git a/build/images/face/8.gif b/build/images/face/8.gif deleted file mode 100644 index 66f967b48..000000000 Binary files a/build/images/face/8.gif and /dev/null differ diff --git a/build/images/face/9.gif b/build/images/face/9.gif deleted file mode 100644 index 60447400d..000000000 Binary files a/build/images/face/9.gif and /dev/null differ diff --git a/build/lay/dest/layui.all.js b/build/lay/dest/layui.all.js deleted file mode 100644 index 8c64407b7..000000000 --- a/build/lay/dest/layui.all.js +++ /dev/null @@ -1,5 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;!function(e){"use strict";var t=function(){this.v="1.0.9_rls"};t.fn=t.prototype;var n=document,o=t.fn.cache={},i=function(){var e=n.scripts,t=e[e.length-1].src;return t.substring(0,t.lastIndexOf("/")+1)}(),r=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),l={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",tree:"modules/tree",table:"modules/table",element:"modules/element",util:"modules/util",flow:"modules/flow",carousel:"modules/carousel",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"dest/layui.all"};o.modules={},o.status={},o.timeout=10,o.event={},t.fn.define=function(e,t){var n=this,i="function"==typeof e,r=function(){return"function"==typeof t&&t(function(e,t){layui[e]=t,o.status[e]=!0}),this};return i&&(t=e,e=[]),layui["layui.all"]||!layui["layui.all"]&&layui["layui.mobile"]?r.call(n):(n.use(e,r),n)},t.fn.use=function(e,t,u){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[m]=t,y.removeChild(v),function i(){return++p>1e3*o.timeout/4?r(m+" is not a valid module"):void(o.status[m]?c():setTimeout(i,4))}())}function c(){u.push(layui[m]),e.length>1?f.use(e.slice(1),t,u):"function"==typeof t&&t.apply(layui,u)}var f=this,d=o.dir=o.dir?o.dir:i,y=n.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(f.each(e,function(t,n){"jquery"===n&&e.splice(t,1)}),layui.jquery=jQuery);var m=e[0],p=0;if(u=u||[],o.host=o.host||(d.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&l[m]||!layui["layui.all"]&&layui["layui.mobile"]&&l[m])return c(),f;var v=n.createElement("script"),h=(l[m]?d+"lay/":o.base||"")+(f.modules[m]||m)+".js";return v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),o.modules[m]?!function g(){return++p>1e3*o.timeout/4?r(m+" is not a valid module"):void("string"==typeof o.modules[m]&&o.status[m]?c():setTimeout(g,4))}():(y.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)})),o.modules[m]=h,f},t.fn.getStyle=function(t,n){var o=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return o[o.getPropertyValue?"getPropertyValue":"getAttribute"](n)},t.fn.link=function(e,t,i){var a=this,l=n.createElement("link"),u=n.getElementsByTagName("head")[0];"string"==typeof t&&(i=t);var s=(i||e).replace(/\.|\//g,""),c=l.id="layuicss-"+s,f=0;return l.rel="stylesheet",l.href=e+(o.debug?"?v="+(new Date).getTime():""),l.media="all",n.getElementById(c)||u.appendChild(l),"function"!=typeof t?a:(function d(){return++f>1e3*o.timeout/100?r(e+" timeout"):void(1989===parseInt(a.getStyle(n.getElementById(c),"width"))?function(){t()}():setTimeout(d,100))}(),a)},t.fn.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},t.fn.img=function(e,t,n){var o=new Image;return o.src=e,o.complete?t(o):(o.onload=function(){o.onload=null,t(o)},void(o.onerror=function(e){o.onerror=null,n(e)}))},t.fn.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},t.fn.modules=function(){var e={};for(var t in l)e[t]=l[t];return e}(),t.fn.extend=function(e){var t=this;e=e||{};for(var n in e)t[n]||t.modules[n]?r("模块名 "+n+" 已被占用"):t.modules[n]=e[n];return t},t.fn.router=function(e){var t=this,e=e||location.hash,n={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,"").replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),n.search[t[0]]=t[1]}():n.path.push(t)}),n):n},t.fn.data=function(t,n){if(t=t||"layui",e.JSON&&e.JSON.parse){if(null===n)return delete localStorage[t];n="object"==typeof n?n:{key:n};try{var o=JSON.parse(localStorage[t])}catch(i){var o={}}return n.value&&(o[n.key]=n.value),n.remove&&delete o[n.key],localStorage[t]=JSON.stringify(o),n.key?o[n.key]:o}},t.fn.device=function(t){var n=navigator.userAgent.toLowerCase(),o=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(n.match(t)||[])[1],e||!1},i={os:function(){return/windows/.test(n)?"windows":/linux/.test(n)?"linux":/mac/.test(n)?"mac":/iphone|ipod|ipad|ios/.test(n)?"ios":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((n.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:o("micromessenger")};return t&&!i[t]&&(i[t]=o(t)),i.android=/android/.test(n),i.ios="ios"===i.os,i},t.fn.hint=function(){return{error:r}},t.fn.each=function(e,t){var n,o=this;if("function"!=typeof t)return o;if(e=e||[],e.constructor===Object){for(n in e)if(t.call(e[n],n,e[n]))break}else for(n=0;n/g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var n="Laytpl Error:";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e}},c=n.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=c("^"+r.open+"#",""),l=c(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(c(r.open+"#"),r.open+"# ").replace(c(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(/(?="|')/g,"\\").replace(n.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(n.query(1),function(e){var n='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(c(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),n='"+_escape_('),n+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,n.escape)}catch(u){return delete o.cache,n.error(u,p)}},t.pt.render=function(e,r){var c,t=this;return e?(c=t.cache?t.cache(e,n.escape):t.parse(t.tpl,e),r?void r(c):c):n.error("no data")};var o=function(e){return"string"!=typeof e?n.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var n in e)r[n]=e[n]},o.v="1.2.0",e("laytpl",o)});layui.define(function(a){"use strict";function t(a){new p(a)}var e=document,r="getElementById",n="getElementsByTagName",s=0,p=function(a){var t=this,e=t.config=a||{};e.item=s++,t.render(!0)};p.on=function(a,t,e){return a.attachEvent?a.attachEvent("on"+t,function(){e.call(a,window.even)}):a.addEventListener(t,e,!1),p},p.prototype.type=function(){var a=this.config;if("object"==typeof a.cont)return void 0===a.cont.length?2:3},p.prototype.view=function(){var a=this,t=a.config,e=[],r={};if(t.pages=0|t.pages,t.curr=0|t.curr||1,t.groups="groups"in t?0|t.groups:5,t.first="first"in t?t.first:"首页",t.last="last"in t?t.last:"末页",t.prev="prev"in t?t.prev:"上一页",t.next="next"in t?t.next:"下一页",t.pages<=1)return"";for(t.groups>t.pages&&(t.groups=t.pages),r.index=Math.ceil((t.curr+(t.groups>1&&t.groups!==t.pages?1:0))/(0===t.groups?1:t.groups)),t.curr>1&&t.prev&&e.push(''+t.prev+""),r.index>1&&t.first&&0!==t.groups&&e.push(''+t.first+""),r.poor=Math.floor((t.groups-1)/2),r.start=r.index>1?t.curr-r.poor:1,r.end=r.index>1?function(){var a=t.curr+(t.groups-r.poor-1);return a>t.pages?t.pages:a}():t.groups,r.end-r.start"+r.start+""):e.push(''+r.start+"");return t.pages>t.groups&&r.end'+t.last+""),r.flow=!t.prev&&0===t.groups,(t.curr!==t.pages&&t.next||r.flow)&&e.push(function(){return r.flow&&t.curr===t.pages?''+t.next+"":''+t.next+""}()),'
'+e.join("")+function(){return t.skip?'到第 ':""}()+"
"},p.prototype.jump=function(a){if(a){for(var t=this,e=t.config,r=a.children,s=a[n]("button")[0],i=a[n]("input")[0],u=0,o=r.length;un.maxs[0]?s=["y",1]:e>=n.mins[0]&&e<=n.maxs[0]&&(e==n.mins[0]&&(tn.maxs[1]?s=["m",1]:t==n.maxs[1]&&a>n.maxs[2]&&(s=["d",1]))),s},n.timeVoid=function(e,t){if(n.ymd[1]+1==n.mins[1]&&n.ymd[2]==n.mins[2]){if(0===t&&en.maxs[3])return 1;if(1===t&&e>n.maxs[4])return 1;if(2===t&&e>n.maxs[5])return 1}if(e>(t?59:23))return 1},n.check=function(){var e=n.options.format.replace(/YYYY|MM|DD|hh|mm|ss/g,"\\d+\\").replace(/\\$/g,""),t=new RegExp(e),a=n.elem[d.elemv],s=a.match(/\d+/g)||[],i=n.checkVoid(s[0],s[1],s[2]);if(""!==a.replace(/\s/g,"")){if(!t.test(a))return n.elem[d.elemv]="",n.msg("日期不符合格式,请重新选择。"),1;if(i[0])return n.elem[d.elemv]="",n.msg("日期不在有效期内,请重新选择。"),1;i.value=n.elem[d.elemv].match(t).join(),s=i.value.match(/\d+/g),s[1]<1?(s[1]=1,i.auto=1):s[1]>12?(s[1]=12,i.auto=1):s[1].length<2&&(i.auto=1),s[2]<1?(s[2]=1,i.auto=1):s[2]>n.months[(0|s[1])-1]?(s[2]=31,i.auto=1):s[2].length<2&&(i.auto=1),s.length>3&&(n.timeVoid(s[3],0)&&(i.auto=1),n.timeVoid(s[4],1)&&(i.auto=1),n.timeVoid(s[5],2)&&(i.auto=1)),i.auto?n.creation([s[0],0|s[1],0|s[2]],1):i.value!==n.elem[d.elemv]&&(n.elem[d.elemv]=i.value)}},n.months=[31,null,31,30,31,30,31,31,30,31,30,31],n.viewDate=function(e,t,a){var s=(n.query,{}),i=new Date;e<(0|n.mins[0])&&(e=0|n.mins[0]),e>(0|n.maxs[0])&&(e=0|n.maxs[0]),i.setFullYear(e,t,a),s.ymd=[i.getFullYear(),i.getMonth(),i.getDate()],n.months[1]=n.isleap(s.ymd[0])?29:28,i.setFullYear(s.ymd[0],s.ymd[1],1),s.FDay=i.getDay(),s.PDay=n.months[0===t?11:t-1]-s.FDay+1,s.NDay=1,n.each(d.tds,function(e,t){var a,i=s.ymd[0],o=s.ymd[1]+1;t.className="",e=s.FDay&&e'+e+"年":'
  • '+(e-7+t)+"年
  • "}),t("#laydate_ys").innerHTML=a,n.each(t("#laydate_ys li"),function(e,t){"y"===n.checkVoid(t.getAttribute("y"))[0]?n.addClass(t,d[1]):n.on(t,"click",function(e){n.stopmp(e).reshow(),n.viewDate(0|this.getAttribute("y"),n.ymd[1],n.ymd[2])})})},n.initDate=function(){var e=(n.query,new Date),t=n.elem[d.elemv].match(/\d+/g)||[];t.length<3&&(t=n.options.start.match(/\d+/g)||[],t.length<3&&(t=[e.getFullYear(),e.getMonth()+1,e.getDate()])),n.inymd=t,n.viewDate(t[0],t[1]-1,t[2])},n.iswrite=function(){var e=n.query,t={time:e("#laydate_hms")};n.shde(t.time,!n.options.istime),n.shde(d.oclear,!("isclear"in n.options?n.options.isclear:1)),n.shde(d.otoday,!("istoday"in n.options?n.options.istoday:1)),n.shde(d.ok,!("issure"in n.options?n.options.issure:1))},n.orien=function(e,t){var a,s=n.elem.getBoundingClientRect();e.style.left=s.left+(t?0:n.scroll(1))+"px",a=s.bottom+e.offsetHeight/1.5<=n.winarea()?s.bottom-1:s.top>e.offsetHeight/1.5?s.top-e.offsetHeight+1:n.winarea()-e.offsetHeight,e.style.top=Math.max(a+(t?0:n.scroll()),1)+"px"},n.follow=function(e){n.options.fixed?(e.style.position="fixed",n.orien(e,1)):(e.style.position="absolute",n.orien(e))},n.viewtb=function(){var e,t=[],a=["日","一","二","三","四","五","六"],o={},d=s[i]("table"),r=s[i]("thead");return r.appendChild(s[i]("tr")),o.creath=function(e){var t=s[i]("th");t.innerHTML=a[e],r[l]("tr")[0].appendChild(t),t=null},n.each(new Array(6),function(a){t.push([]),e=d.insertRow(0),n.each(new Array(7),function(n){t[a][n]=0,0===a&&o.creath(n),e.insertCell(n)})}),d.insertBefore(r,d.children[0]),d.id=d.className="laydate_table",e=t=null,d.outerHTML.toLowerCase()}(),n.view=function(e,t){var o,l=n.query,r={};t=t||e,n.elem=e,n.options=t,n.options.format||(n.options.format=a.format),n.options.start=n.options.start||"",n.mm=r.mm=[n.options.min||a.min,n.options.max||a.max],n.mins=r.mm[0].match(/\d+/g),n.maxs=r.mm[1].match(/\d+/g),n.box?n.shde(n.box):(o=s[i]("div"),o.id=d[0],o.className=d[0],o.style.cssText="position: absolute;",o.setAttribute("name","laydate-v"+laydate.v),o.innerHTML=r.html='
      '+function(){var e="";return n.each(new Array(12),function(t){e+=''+n.digit(t+1)+"月"}),e}()+"
      "+n.viewtb+'",s.body.appendChild(o),n.box=l("#"+d[0]),n.events(),o=null),n.follow(n.box),t.zIndex?n.box.style.zIndex=t.zIndex:n.removeCssAttr(n.box,"z-index"),n.stopMosup("click",n.box),n.initDate(),n.iswrite(),n.check()},n.reshow=function(){return n.each(n.query("#"+d[0]+" .laydate_show"),function(e,t){n.removeClass(t,"laydate_show")}),this},n.close=function(){n.reshow(),n.shde(n.query("#"+d[0]),1),n.elem=null},n.parse=function(e,t,s){return e=e.concat(t),s=s||(n.options?n.options.format:a.format),s.replace(/YYYY|MM|DD|hh|mm|ss/g,function(t,a){return e.index=0|++e.index,n.digit(e[e.index])})},n.creation=function(e,t){var a=(n.query,n.hmsin),s=n.parse(e,[a[0].value,a[1].value,a[2].value]);n.elem[d.elemv]=s,t||(n.close(),"function"==typeof n.options.choose&&n.options.choose(s))},n.events=function(){var e=n.query,a={box:"#"+d[0]};n.addClass(s.body,"laydate_body"),d.tds=e("#laydate_table td"),d.mms=e("#laydate_ms span"),d.year=e("#laydate_y"),d.month=e("#laydate_m"),n.each(e(a.box+" .laydate_ym"),function(e,t){n.on(t,"click",function(t){n.stopmp(t).reshow(),n.addClass(this[l]("div")[0],"laydate_show"),e||(a.YY=parseInt(d.year.value),n.viewYears(a.YY))})}),n.on(e(a.box),"click",function(){n.reshow()}),a.tabYear=function(e){0===e?n.ymd[0]--:1===e?n.ymd[0]++:2===e?a.YY-=14:a.YY+=14,e<2?(n.viewDate(n.ymd[0],n.ymd[1],n.ymd[2]),n.reshow()):n.viewYears(a.YY)},n.each(e("#laydate_YY .laydate_tab"),function(e,t){n.on(t,"click",function(t){n.stopmp(t),a.tabYear(e)})}),a.tabMonth=function(e){e?(n.ymd[1]++,12===n.ymd[1]&&(n.ymd[0]++,n.ymd[1]=0)):(n.ymd[1]--,n.ymd[1]===-1&&(n.ymd[0]--,n.ymd[1]=11)),n.viewDate(n.ymd[0],n.ymd[1],n.ymd[2])},n.each(e("#laydate_MM .laydate_tab"),function(e,t){n.on(t,"click",function(t){n.stopmp(t).reshow(),a.tabMonth(e)})}),n.each(e("#laydate_ms span"),function(e,t){n.on(t,"click",function(e){n.stopmp(e).reshow(),n.hasClass(this,d[1])||n.viewDate(n.ymd[0],0|this.getAttribute("m"),n.ymd[2])})}),n.each(e("#laydate_table td"),function(e,t){n.on(t,"click",function(e){n.hasClass(this,d[1])||(n.stopmp(e),n.creation([0|this.getAttribute("y"),0|this.getAttribute("m"),0|this.getAttribute("d")]))})}),d.oclear=e("#laydate_clear"),n.on(d.oclear,"click",function(){n.elem[d.elemv]="",n.close()}),d.otoday=e("#laydate_today"),n.on(d.otoday,"click",function(){var e=new Date;n.creation([e.getFullYear(),e.getMonth()+1,e.getDate()])}),d.ok=e("#laydate_ok"),n.on(d.ok,"click",function(){n.valid&&n.creation([n.ymd[0],n.ymd[1]+1,n.ymd[2]])}),a.times=e("#laydate_time"),n.hmsin=a.hmsin=e("#laydate_hms input"),a.hmss=["小时","分钟","秒数"],a.hmsarr=[],n.msg=function(t,s){var i='
      '+(s||"提示")+"×
      ";"string"==typeof t?(i+="

      "+t+"

      ",n.shde(e("#"+d[0])),n.removeClass(a.times,"laydate_time1").addClass(a.times,"laydate_msg")):(a.hmsarr[t]?i=a.hmsarr[t]:(i+='
      ',n.each(new Array(0===t?24:60),function(e){i+=""+e+""}),i+="
      ",a.hmsarr[t]=i),n.removeClass(a.times,"laydate_msg"),n[0===t?"removeClass":"addClass"](a.times,"laydate_time1")),n.addClass(a.times,"laydate_show"),a.times.innerHTML=i},a.hmson=function(t,a){var s=e("#laydate_hmsno span"),i=n.valid?null:1;n.each(s,function(e,s){i?n.addClass(s,d[1]):n.timeVoid(e,a)?n.addClass(s,d[1]):n.on(s,"click",function(e){n.hasClass(this,d[1])||(t.value=n.digit(0|this.innerHTML))})}),n.addClass(s[0|t.value],"laydate_click")},n.each(a.hmsin,function(e,t){n.on(t,"click",function(t){n.stopmp(t).reshow(),n.msg(e,a.hmss[e]),a.hmson(this,e)})}),n.on(s,"mouseup",function(){var t=e("#"+d[0]);t&&"none"!==t.style.display&&(n.check()||n.close())}).on(s,"keydown",function(e){e=e||t.event;var a=e.keyCode;13===a&&n.elem&&n.creation([n.ymd[0],n.ymd[1]+1,n.ymd[2]])})},laydate.reset=function(){n.box&&n.elem&&n.follow(n.box)},laydate.now=function(e,t){var a=new Date(0|e?function(e){return e<864e5?+new Date+864e5*e:e}(parseInt(e)):+new Date);return n.parse([a.getFullYear(),a.getMonth()+1,a.getDate()],[a.getHours(),a.getMinutes(),a.getSeconds()],t)},layui.addcss("modules/laydate/laydate.css",function(){},"laydatecss"),e("laydate",laydate)});!function(e,t){"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(e,t){function n(e){var t=!!e&&"length"in e&&e.length,n=pe.type(e);return"function"!==n&&!pe.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener("DOMContentLoaded",s),e.removeEventListener("load",s)):(re.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(re.addEventListener||"load"===e.event.type||"complete"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(_e,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if(("data"!==t||!pe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||"string"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),"object"!=typeof t&&"function"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,"")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?"":"px"),c=(pe.cssNumber[t]||"px"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||".5",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}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}function p(e){var t=ze.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,"globalEval",!t||pe._data(t[r],"globalEval"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,"input"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),"script"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||"")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(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)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,"table")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function C(e){return e.type=(null!==pe.find.attr(e,"type"))+"/"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r1&&"string"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,"script"),C),a=s.length;c")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a=0&&n=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||"object"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,"constructor")&&!ce.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ue[le.call(e)]||"object":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,"ms-").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;iT.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h="0",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG("*",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P="sizzle"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),ce=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(oe),de=new RegExp("^"+re+"$"),pe={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,xe=/'|\\/g,be=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),we=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)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Te,!1):n.attachEvent&&n.attachEvent("onunload",Te)),w.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment("")),!e.getElementsByTagName("*").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+P+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||F.push(".#.+[+~]")}),i(function(e){var t=H.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),M.push("!=",oe)}),F=F.length&&new RegExp(F.join("|")),M=M.length&&new RegExp(M.join("|")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.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)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,"='$1']"),w.matchesSelector&&_&&!X[n+" "]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.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+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,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(be,we),e[3]=(e[3]||e[4]||e[5]||"").replace(be,we),"~="===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]||t.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]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=N(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(be,we).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ae," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}), -l=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!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,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.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:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split("").sort(U).join("")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement("div"))}),i(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[":"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,Ce=/^.[^:#\[\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t1?pe.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,"string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,"parentNode")},parentsUntil:function(e,t,n){return xe(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return xe(e,"nextSibling")},prevAll:function(e){return xe(e,"previousSibling")},nextUntil:function(e,t,n){return xe(e,"nextSibling",n)},prevUntil:function(e,t,n){return xe(e,"previousSibling",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\S+/g;pe.Callbacks=function(e){e="string"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n="",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[["resolve","done",pe.Callbacks("once memory"),"resolved"],["reject","fail",pe.Callbacks("once memory"),"rejected"],["notify","progress",pe.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler("ready"),pe(re).off("ready"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),"complete"===re.readyState||"loading"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener("DOMContentLoaded",s),e.addEventListener("load",s);else{re.attachEvent("onreadystatechange",s),e.attachEvent("onload",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll("left")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst="0"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName("body")[0],n&&n.style&&(t=re.createElement("div"),r=re.createElement("div"),r.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(r).appendChild(t),"undefined"!=typeof t.style.zoom&&(t.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement("div");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+" ").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute("classid")===t)},qe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,"parsedAttrs"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf("data-")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,"parsedAttrs",!0)}return i}return"object"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks("once memory").add(function(){pe._removeData(e,t+"queue"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length
      a",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName("tbody").length,fe.htmlSerialize=!!e.getElementsByTagName("link").length,fe.html5Clone="<:nav>"!==re.createElement("nav").cloneNode(!0).outerHTML,n.type="checkbox",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML="",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement("input"),n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,""],legend:[1,"
      ","
      "],area:[1,"",""],param:[1,"",""],thead:[1,"","
      "],tr:[2,"","
      "],col:[2,"","
      "],td:[3,"","
      "],_default:fe.htmlSerialize?[0,"",""]:[1,"X
      ","
      "]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|&#?\w+;/,Ve=/-1&&(h=p.split("."),p=h.shift(),h.sort()),a=p.indexOf(":")<0&&"on"+p,t=t[pe.expando]?t:new pe.Event(p,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,"events")||{})[t.type]&&pe._data(s,"handle"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,"events")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(r=[],n=0;n-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s]","i"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,nt=/\s*$/g,at=p(re),st=at.appendChild(re.createElement("div"));pe.extend({htmlPrefilter:function(e){return e.replace(tt,"<$1>")},clone:function(e,t,n){var r,i,o,a,s,u=pe.contains(e.ownerDocument,e);if(fe.html5Clone||pe.isXMLDoc(e)||!et.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(st.innerHTML=e.outerHTML,st.removeChild(o=st.firstChild)),!(fe.noCloneEvent&&fe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||pe.isXMLDoc(e)))for(r=h(o),s=h(e),a=0;null!=(i=s[a]);++a)r[a]&&k(i,r[a]);if(t)if(n)for(s=s||h(e),r=r||h(o),a=0;null!=(i=s[a]);a++)N(i,r[a]);else N(e,o);return r=h(o,"script"),r.length>0&&g(r,!u&&h(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=pe.expando,u=pe.cache,l=fe.attributes,c=pe.event.special;null!=(n=e[a]);a++)if((t||He(n))&&(i=n[s],o=i&&u[i])){if(o.events)for(r in o.events)c[r]?pe.event.remove(n,r):pe.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=void 0:n.removeAttribute(s),ne.push(i))}}}),pe.fn.extend({domManip:S,detach:function(e){return A(this,e,!0)},remove:function(e){return A(this,e)},text:function(e){return Pe(this,function(e){return void 0===e?pe.text(this):this.empty().append((this[0]&&this[0].ownerDocument||re).createTextNode(e))},null,e,arguments.length)},append:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.appendChild(e)}})},prepend:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&pe.cleanData(h(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&pe.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return pe.clone(this,e,t)})},html:function(e){return Pe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e)return 1===t.nodeType?t.innerHTML.replace(Ze,""):void 0;if("string"==typeof e&&!nt.test(e)&&(fe.htmlSerialize||!et.test(e))&&(fe.leadingWhitespace||!$e.test(e))&&!Xe[(We.exec(e)||["",""])[1].toLowerCase()]){e=pe.htmlPrefilter(e);try{for(;nt",t=l.getElementsByTagName("td"),t[0].style.cssText="margin:0;border:0;padding:0;display:none",o=0===t[0].offsetHeight,o&&(t[0].style.display="",t[1].style.display="none",o=0===t[0].offsetHeight)),f.removeChild(u)}var n,r,i,o,a,s,u=re.createElement("div"),l=re.createElement("div");l.style&&(l.style.cssText="float:left;opacity:.5",fe.opacity="0.5"===l.style.opacity,fe.cssFloat=!!l.style.cssFloat,l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",fe.clearCloneStyle="content-box"===l.style.backgroundClip,u=re.createElement("div"),u.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",l.innerHTML="",u.appendChild(l),fe.boxSizing=""===l.style.boxSizing||""===l.style.MozBoxSizing||""===l.style.WebkitBoxSizing,pe.extend(fe,{reliableHiddenOffsets:function(){return null==n&&t(),o},boxSizingReliable:function(){return null==n&&t(),i},pixelMarginRight:function(){return null==n&&t(),r},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),a},reliableMarginLeft:function(){return null==n&&t(),s}}))}();var ht,gt,mt=/^(top|right|bottom|left)$/;e.getComputedStyle?(ht=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n.getPropertyValue(t)||n[t]:void 0,""!==a&&void 0!==a||pe.contains(e.ownerDocument,e)||(a=pe.style(e,t)),n&&!fe.pixelMarginRight()&&ft.test(a)&&ct.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+""}):pt.currentStyle&&(ht=function(e){return e.currentStyle},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n[t]:void 0,null==a&&s&&s[t]&&(a=s[t]),ft.test(a)&&!mt.test(t)&&(r=s.left,i=e.runtimeStyle,o=i&&i.left,o&&(i.left=e.currentStyle.left),s.left="fontSize"===t?"1em":a,a=s.pixelLeft+"px",s.left=r,o&&(i.left=o)),void 0===a?a:a+""||"auto"});var yt=/alpha\([^)]*\)/i,vt=/opacity\s*=\s*([^)]*)/i,xt=/^(none|table(?!-c[ea]).+)/,bt=new RegExp("^("+Fe+")(.*)$","i"),wt={position:"absolute",visibility:"hidden",display:"block"},Tt={letterSpacing:"0",fontWeight:"400"},Ct=["Webkit","O","Moz","ms"],Et=re.createElement("div").style;pe.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=gt(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":fe.cssFloat?"cssFloat":"styleFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=pe.camelCase(t),u=e.style;if(t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:u[t];if(o=typeof n,"string"===o&&(i=Me.exec(n))&&i[1]&&(n=d(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(pe.cssNumber[s]?"":"px")),fe.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),!(a&&"set"in a&&void 0===(n=a.set(e,n,r)))))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o,a,s=pe.camelCase(t);return t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],a&&"get"in a&&(o=a.get(e,!0,n)),void 0===o&&(o=gt(e,t,r)),"normal"===o&&t in Tt&&(o=Tt[t]),""===n||n?(i=parseFloat(o),n===!0||isFinite(i)?i||0:o):o}}),pe.each(["height","width"],function(e,t){pe.cssHooks[t]={get:function(e,n,r){if(n)return xt.test(pe.css(e,"display"))&&0===e.offsetWidth?dt(e,wt,function(){return M(e,t,r)}):M(e,t,r)},set:function(e,n,r){var i=r&&ht(e);return _(e,n,r?F(e,t,r,fe.boxSizing&&"border-box"===pe.css(e,"boxSizing",!1,i),i):0)}}}),fe.opacity||(pe.cssHooks.opacity={get:function(e,t){return vt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=pe.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===pe.trim(o.replace(yt,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=yt.test(o)?o.replace(yt,i):o+" "+i)}}),pe.cssHooks.marginRight=L(fe.reliableMarginRight,function(e,t){if(t)return dt(e,{display:"inline-block"},gt,[e,"marginRight"])}),pe.cssHooks.marginLeft=L(fe.reliableMarginLeft,function(e,t){if(t)return(parseFloat(gt(e,"marginLeft"))||(pe.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-dt(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+"px"}),pe.each({margin:"",padding:"",border:"Width"},function(e,t){pe.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+Oe[r]+t]=o[r]||o[r-2]||o[0];return i}},ct.test(e)||(pe.cssHooks[e+t].set=_)}),pe.fn.extend({css:function(e,t){return Pe(this,function(e,t,n){var r,i,o={},a=0;if(pe.isArray(t)){for(r=ht(e),i=t.length;a1)},show:function(){return q(this,!0)},hide:function(){return q(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Re(this)?pe(this).show():pe(this).hide()})}}),pe.Tween=O,O.prototype={constructor:O,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||pe.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(pe.cssNumber[n]?"":"px")},cur:function(){var e=O.propHooks[this.prop];return e&&e.get?e.get(this):O.propHooks._default.get(this)},run:function(e){var t,n=O.propHooks[this.prop];return this.options.duration?this.pos=t=pe.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):O.propHooks._default.set(this),this}},O.prototype.init.prototype=O.prototype,O.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=pe.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){pe.fx.step[e.prop]?pe.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[pe.cssProps[e.prop]]&&!pe.cssHooks[e.prop]?e.elem[e.prop]=e.now:pe.style(e.elem,e.prop,e.now+e.unit)}}},O.propHooks.scrollTop=O.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},pe.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},pe.fx=O.prototype.init,pe.fx.step={};var Nt,kt,St=/^(?:toggle|show|hide)$/,At=/queueHooks$/;pe.Animation=pe.extend($,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,Me.exec(t),n),n}]},tweener:function(e,t){pe.isFunction(e)?(t=e,e=["*"]):e=e.match(De);for(var n,r=0,i=e.length;r
      a",e=n.getElementsByTagName("a")[0],t.setAttribute("type","checkbox"),n.appendChild(t),e=n.getElementsByTagName("a")[0],e.style.cssText="top:1px",fe.getSetAttribute="t"!==n.className,fe.style=/top/.test(e.getAttribute("style")),fe.hrefNormalized="/a"===e.getAttribute("href"),fe.checkOn=!!t.value,fe.optSelected=i.selected,fe.enctype=!!re.createElement("form").enctype,r.disabled=!0,fe.optDisabled=!i.disabled,t=re.createElement("input"),t.setAttribute("value",""),fe.input=""===t.getAttribute("value"),t.value="t",t.setAttribute("type","radio"),fe.radioValue="t"===t.value}();var Dt=/\r/g,jt=/[\x20\t\r\n\f]+/g;pe.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=pe.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,pe(this).val()):e,null==i?i="":"number"==typeof i?i+="":pe.isArray(i)&&(i=pe.map(i,function(e){return null==e?"":e+""})),t=pe.valHooks[this.type]||pe.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return t=pe.valHooks[i.type]||pe.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:(n=i.value,"string"==typeof n?n.replace(Dt,""):null==n?"":n)}}}),pe.extend({valHooks:{option:{get:function(e){var t=pe.find.attr(e,"value");return null!=t?t:pe.trim(pe.text(e)).replace(jt," ")}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||i<0,a=o?null:[],s=o?i+1:r.length,u=i<0?s:o?i:0;u-1)try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),pe.each(["radio","checkbox"],function(){pe.valHooks[this]={set:function(e,t){if(pe.isArray(t))return e.checked=pe.inArray(pe(e).val(),t)>-1}},fe.checkOn||(pe.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Lt,Ht,qt=pe.expr.attrHandle,_t=/^(?:checked|selected)$/i,Ft=fe.getSetAttribute,Mt=fe.input;pe.fn.extend({attr:function(e,t){return Pe(this,pe.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){pe.removeAttr(this,e)})}}),pe.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?pe.prop(e,t,n):(1===o&&pe.isXMLDoc(e)||(t=t.toLowerCase(),i=pe.attrHooks[t]||(pe.expr.match.bool.test(t)?Ht:Lt)),void 0!==n?null===n?void pe.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:(r=pe.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!fe.radioValue&&"radio"===t&&pe.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(De);if(o&&1===e.nodeType)for(;n=o[i++];)r=pe.propFix[n]||n,pe.expr.match.bool.test(n)?Mt&&Ft||!_t.test(n)?e[r]=!1:e[pe.camelCase("default-"+n)]=e[r]=!1:pe.attr(e,n,""),e.removeAttribute(Ft?n:r)}}),Ht={set:function(e,t,n){return t===!1?pe.removeAttr(e,n):Mt&&Ft||!_t.test(n)?e.setAttribute(!Ft&&pe.propFix[n]||n,n):e[pe.camelCase("default-"+n)]=e[n]=!0,n}},pe.each(pe.expr.match.bool.source.match(/\w+/g),function(e,t){var n=qt[t]||pe.find.attr;Mt&&Ft||!_t.test(t)?qt[t]=function(e,t,r){var i,o;return r||(o=qt[t],qt[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,qt[t]=o),i}:qt[t]=function(e,t,n){if(!n)return e[pe.camelCase("default-"+t)]?t.toLowerCase():null}}),Mt&&Ft||(pe.attrHooks.value={set:function(e,t,n){return pe.nodeName(e,"input")?void(e.defaultValue=t):Lt&&Lt.set(e,t,n)}}),Ft||(Lt={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+="","value"===n||t===e.getAttribute(n))return t}},qt.id=qt.name=qt.coords=function(e,t,n){var r;if(!n)return(r=e.getAttributeNode(t))&&""!==r.value?r.value:null},pe.valHooks.button={get:function(e,t){var n=e.getAttributeNode(t);if(n&&n.specified)return n.value},set:Lt.set},pe.attrHooks.contenteditable={set:function(e,t,n){Lt.set(e,""!==t&&t,n)}},pe.each(["width","height"],function(e,t){pe.attrHooks[t]={set:function(e,n){if(""===n)return e.setAttribute(t,"auto"),n}}})),fe.style||(pe.attrHooks.style={get:function(e){return e.style.cssText||void 0},set:function(e,t){return e.style.cssText=t+""}});var Ot=/^(?:input|select|textarea|button|object)$/i,Rt=/^(?:a|area)$/i;pe.fn.extend({prop:function(e,t){return Pe(this,pe.prop,e,t,arguments.length>1)},removeProp:function(e){return e=pe.propFix[e]||e,this.each(function(){try{this[e]=void 0,delete this[e]}catch(t){}})}}),pe.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&pe.isXMLDoc(e)||(t=pe.propFix[t]||t,i=pe.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=pe.find.attr(e,"tabindex");return t?parseInt(t,10):Ot.test(e.nodeName)||Rt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),fe.hrefNormalized||pe.each(["href","src"],function(e,t){pe.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),fe.optSelected||(pe.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),pe.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){pe.propFix[this.toLowerCase()]=this}),fe.enctype||(pe.propFix.enctype="encoding");var Pt=/[\t\r\n\f]/g;pe.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).addClass(e.call(this,t,z(this)))});if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).removeClass(e.call(this,t,z(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):pe.isFunction(e)?this.each(function(n){pe(this).toggleClass(e.call(this,n,z(this),t),t)}):this.each(function(){var t,r,i,o;if("string"===n)for(r=0,i=pe(this),o=e.match(De)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&"boolean"!==n||(t=z(this),t&&pe._data(this,"__className__",t),pe.attr(this,"class",t||e===!1?"":pe._data(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+z(n)+" ").replace(Pt," ").indexOf(t)>-1)return!0;return!1}}),pe.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){pe.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),pe.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var Bt=e.location,Wt=pe.now(),It=/\?/,$t=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;pe.parseJSON=function(t){if(e.JSON&&e.JSON.parse)return e.JSON.parse(t+"");var n,r=null,i=pe.trim(t+"");return i&&!pe.trim(i.replace($t,function(e,t,i,o){return n&&t&&(r=0),0===r?e:(n=i||t,r+=!o-!i,"")}))?Function("return "+i)():pe.error("Invalid JSON: "+t)},pe.parseXML=function(t){var n,r;if(!t||"string"!=typeof t)return null;try{e.DOMParser?(r=new e.DOMParser,n=r.parseFromString(t,"text/xml")):(n=new e.ActiveXObject("Microsoft.XMLDOM"),n.async="false",n.loadXML(t))}catch(i){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName("parsererror").length||pe.error("Invalid XML: "+t),n};var zt=/#.*$/,Xt=/([?&])_=[^&]*/,Ut=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Vt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Yt=/^(?:GET|HEAD)$/,Jt=/^\/\//,Gt=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Kt={},Qt={},Zt="*/".concat("*"),en=Bt.href,tn=Gt.exec(en.toLowerCase())||[];pe.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:en,type:"GET",isLocal:Vt.test(tn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Zt,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":pe.parseJSON,"text xml":pe.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?V(V(e,pe.ajaxSettings),t):V(pe.ajaxSettings,e)},ajaxPrefilter:X(Kt),ajaxTransport:X(Qt),ajax:function(t,n){function r(t,n,r,i){var o,f,v,x,w,C=n;2!==b&&(b=2,u&&e.clearTimeout(u),c=void 0,s=i||"",T.readyState=t>0?4:0,o=t>=200&&t<300||304===t,r&&(x=Y(d,T,r)),x=J(d,x,T,o),o?(d.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(pe.lastModified[a]=w),w=T.getResponseHeader("etag"),w&&(pe.etag[a]=w)),204===t||"HEAD"===d.type?C="nocontent":304===t?C="notmodified":(C=x.state,f=x.data,v=x.error,o=!v)):(v=C,!t&&C||(C="error",t<0&&(t=0))),T.status=t,T.statusText=(n||C)+"",o?g.resolveWith(p,[f,C,T]):g.rejectWith(p,[T,C,v]),T.statusCode(y),y=void 0,l&&h.trigger(o?"ajaxSuccess":"ajaxError",[T,d,o?f:v]),m.fireWith(p,[T,C]),l&&(h.trigger("ajaxComplete",[T,d]),--pe.active||pe.event.trigger("ajaxStop")))}"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,d=pe.ajaxSetup({},n),p=d.context||d,h=d.context&&(p.nodeType||p.jquery)?pe(p):pe.event,g=pe.Deferred(),m=pe.Callbacks("once memory"),y=d.statusCode||{},v={},x={},b=0,w="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!f)for(f={};t=Ut.exec(s);)f[t[1].toLowerCase()]=t[2];t=f[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?s:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=x[n]=x[n]||e,v[e]=t),this},overrideMimeType:function(e){return b||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)y[t]=[y[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||w;return c&&c.abort(t),r(0,t),this}};if(g.promise(T).complete=m.add,T.success=T.done,T.error=T.fail,d.url=((t||d.url||en)+"").replace(zt,"").replace(Jt,tn[1]+"//"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=pe.trim(d.dataType||"*").toLowerCase().match(De)||[""],null==d.crossDomain&&(i=Gt.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===tn[1]&&i[2]===tn[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(tn[3]||("http:"===tn[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=pe.param(d.data,d.traditional)),U(Kt,d,n,T),2===b)return T;l=pe.event&&d.global,l&&0===pe.active++&&pe.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Yt.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(It.test(a)?"&":"?")+d.data,delete d.data),d.cache===!1&&(d.url=Xt.test(a)?a.replace(Xt,"$1_="+Wt++):a+(It.test(a)?"&":"?")+"_="+Wt++)),d.ifModified&&(pe.lastModified[a]&&T.setRequestHeader("If-Modified-Since",pe.lastModified[a]),pe.etag[a]&&T.setRequestHeader("If-None-Match",pe.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&T.setRequestHeader("Content-Type",d.contentType),T.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+Zt+"; q=0.01":""):d.accepts["*"]);for(o in d.headers)T.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(p,T,d)===!1||2===b))return T.abort();w="abort";for(o in{success:1,error:1,complete:1})T[o](d[o]);if(c=U(Qt,d,n,T)){if(T.readyState=1,l&&h.trigger("ajaxSend",[T,d]),2===b)return T;d.async&&d.timeout>0&&(u=e.setTimeout(function(){T.abort("timeout")},d.timeout));try{b=1,c.send(v,r)}catch(C){if(!(b<2))throw C;r(-1,C)}}else r(-1,"No Transport");return T},getJSON:function(e,t,n){return pe.get(e,t,n,"json")},getScript:function(e,t){return pe.get(e,void 0,t,"script")}}),pe.each(["get","post"],function(e,t){pe[t]=function(e,n,r,i){return pe.isFunction(n)&&(i=i||r,r=n,n=void 0),pe.ajax(pe.extend({url:e,type:t,dataType:i,data:n,success:r},pe.isPlainObject(e)&&e))}}),pe._evalUrl=function(e){return pe.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},pe.fn.extend({wrapAll:function(e){if(pe.isFunction(e))return this.each(function(t){pe(this).wrapAll(e.call(this,t))});if(this[0]){var t=pe(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return pe.isFunction(e)?this.each(function(t){pe(this).wrapInner(e.call(this,t))}):this.each(function(){var t=pe(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=pe.isFunction(e);return this.each(function(n){pe(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){pe.nodeName(this,"body")||pe(this).replaceWith(this.childNodes)}).end()}}),pe.expr.filters.hidden=function(e){return fe.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:K(e)},pe.expr.filters.visible=function(e){return!pe.expr.filters.hidden(e)};var nn=/%20/g,rn=/\[\]$/,on=/\r?\n/g,an=/^(?:submit|button|image|reset|file)$/i,sn=/^(?:input|select|textarea|keygen)/i;pe.param=function(e,t){var n,r=[],i=function(e,t){t=pe.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=pe.ajaxSettings&&pe.ajaxSettings.traditional),pe.isArray(e)||e.jquery&&!pe.isPlainObject(e))pe.each(e,function(){i(this.name,this.value)});else for(n in e)Q(n,e[n],t,i);return r.join("&").replace(nn,"+")},pe.fn.extend({serialize:function(){return pe.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=pe.prop(this,"elements");return e?pe.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!pe(this).is(":disabled")&&sn.test(this.nodeName)&&!an.test(e)&&(this.checked||!Be.test(e))}).map(function(e,t){var n=pe(this).val();return null==n?null:pe.isArray(n)?pe.map(n,function(e){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),pe.ajaxSettings.xhr=void 0!==e.ActiveXObject?function(){return this.isLocal?ee():re.documentMode>8?Z():/^(get|post|head|put|delete|options)$/i.test(this.type)&&Z()||ee()}:Z;var un=0,ln={},cn=pe.ajaxSettings.xhr();e.attachEvent&&e.attachEvent("onunload",function(){for(var e in ln)ln[e](void 0,!0)}),fe.cors=!!cn&&"withCredentials"in cn,cn=fe.ajax=!!cn,cn&&pe.ajaxTransport(function(t){if(!t.crossDomain||fe.cors){var n;return{send:function(r,i){var o,a=t.xhr(),s=++un;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||r["X-Requested-With"]||(r["X-Requested-With"]="XMLHttpRequest");for(o in r)void 0!==r[o]&&a.setRequestHeader(o,r[o]+"");a.send(t.hasContent&&t.data||null),n=function(e,r){var o,u,l;if(n&&(r||4===a.readyState))if(delete ln[s],n=void 0,a.onreadystatechange=pe.noop,r)4!==a.readyState&&a.abort();else{l={},o=a.status,"string"==typeof a.responseText&&(l.text=a.responseText);try{u=a.statusText}catch(c){u=""}o||!t.isLocal||t.crossDomain?1223===o&&(o=204):o=l.text?200:404}l&&i(o,u,l,a.getAllResponseHeaders())},t.async?4===a.readyState?e.setTimeout(n):a.onreadystatechange=ln[s]=n:n()},abort:function(){n&&n(void 0,!0)}}}}),pe.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 pe.globalEval(e),e}}}),pe.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),pe.ajaxTransport("script",function(e){if(e.crossDomain){var t,n=re.head||pe("head")[0]||re.documentElement;return{send:function(r,i){t=re.createElement("script"),t.async=!0,e.scriptCharset&&(t.charset=e.scriptCharset),t.src=e.url,t.onload=t.onreadystatechange=function(e,n){(n||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),t=null,n||i(200,"success"))},n.insertBefore(t,n.firstChild)},abort:function(){t&&t.onload(void 0,!0)}}}});var fn=[],dn=/(=)\?(?=&|$)|\?\?/;pe.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=fn.pop()||pe.expando+"_"+Wt++;return this[e]=!0,e}}),pe.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,a,s=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&0===(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=pe.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(It.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return a||pe.error(i+" was not called"),a[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?pe(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,fn.push(i)),a&&pe.isFunction(o)&&o(a[0]),a=o=void 0}),"script"}),pe.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||re;var r=Te.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=y([e],t,i),i&&i.length&&pe(i).remove(),pe.merge([],r.childNodes))};var pn=pe.fn.load;return pe.fn.load=function(e,t,n){if("string"!=typeof e&&pn)return pn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=pe.trim(e.slice(s,e.length)),e=e.slice(0,s)),pe.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&pe.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?pe("
      ").append(pe.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},pe.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){pe.fn[t]=function(e){return this.on(t,e)}}),pe.expr.filters.animated=function(e){return pe.grep(pe.timers,function(t){return e===t.elem}).length},pe.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=pe.css(e,"position"),f=pe(e),d={};"static"===c&&(e.style.position="relative"),s=f.offset(),o=pe.css(e,"top"),u=pe.css(e,"left"),l=("absolute"===c||"fixed"===c)&&pe.inArray("auto",[o,u])>-1,l?(r=f.position(),a=r.top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),pe.isFunction(t)&&(t=t.call(e,n,pe.extend({},s))),null!=t.top&&(d.top=t.top-s.top+a),null!=t.left&&(d.left=t.left-s.left+i),"using"in t?t.using.call(e,d):f.css(d)}},pe.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){pe.offset.setOffset(this,e,t)});var t,n,r={top:0,left:0},i=this[0],o=i&&i.ownerDocument;if(o)return t=o.documentElement,pe.contains(t,i)?("undefined"!=typeof i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=te(o),{top:r.top+(n.pageYOffset||t.scrollTop)-(t.clientTop||0),left:r.left+(n.pageXOffset||t.scrollLeft)-(t.clientLeft||0)}):r},position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===pe.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),pe.nodeName(e[0],"html")||(n=e.offset()),n.top+=pe.css(e[0],"borderTopWidth",!0),n.left+=pe.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-pe.css(r,"marginTop",!0),left:t.left-n.left-pe.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){ -for(var e=this.offsetParent;e&&!pe.nodeName(e,"html")&&"static"===pe.css(e,"position");)e=e.offsetParent;return e||pt})}}),pe.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n=/Y/.test(t);pe.fn[e]=function(r){return Pe(this,function(e,r,i){var o=te(e);return void 0===i?o?t in o?o[t]:o.document.documentElement[r]:e[r]:void(o?o.scrollTo(n?pe(o).scrollLeft():i,n?i:pe(o).scrollTop()):e[r]=i)},e,r,arguments.length,null)}}),pe.each(["top","left"],function(e,t){pe.cssHooks[t]=L(fe.pixelPosition,function(e,n){if(n)return n=gt(e,t),ft.test(n)?pe(e).position()[t]+"px":n})}),pe.each({Height:"height",Width:"width"},function(e,t){pe.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){pe.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),a=n||(r===!0||i===!0?"margin":"border");return Pe(this,function(t,n,r){var i;return pe.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):void 0===r?pe.css(t,n,a):pe.style(t,n,r,a)},t,o?r:void 0,o,null)}})}),pe.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),pe.fn.size=function(){return this.length},pe.fn.andSelf=pe.fn.addBack,layui.define(function(e){e("jquery",pe)}),pe});!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.scripts,t=e[e.length-1],i=t.src;if(!t.getAttribute("merge"))return i.substring(0,i.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"]},r={v:"3.0.3",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):r.link("skin/"+e.extend),this):this},link:function(t,n,a){if(r.path){var o=i("head")[0],s=document.createElement("link");"string"==typeof n&&(a=n);var l=(a||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,i("#"+f)[0]||o.appendChild(s),"function"==typeof n&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(i("#"+f).css("width"))?n():setTimeout(u,100))}()}},ready:function(e){var t="skinlayercss",i="303";return a?layui.addcss("modules/layer/default/layer.css?v="+r.v+i,e,t):r.link("skin/default/layer.css?v="+r.v+i,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
      '+(f?r.title[0]:r.title)+"
      ":"";return r.zIndex=s,t([r.shade?'
      ':"",'
      '+(e&&2!=r.type?"":u)+'
      '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
      '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
      '+e+"
      "}():"")+(r.resize?'':"")+"
      "],u,i('
      ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"http://layer.layui.com","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]&&e.layero.addClass(l.anim[t.anim]),t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){function t(e){e=s.find(e),e.height(f[1]-c-u-2*(0|parseFloat(e.css("padding-top"))))}var a=this,o=a.config,s=i("#"+l[0]+e);""===o.area[0]&&o.maxWidth>0&&(r.ie&&r.ie<8&&o.btn&&s.width(s.innerWidth()),s.outerWidth()>o.maxWidth&&s.width(o.maxWidth));var f=[s.innerWidth(),s.innerHeight()],c=s.find(l[1]).outerHeight()||0,u=s.find("."+l[6]).outerHeight()||0;switch(o.type){case 2:t("iframe");break;default:""===o.area[1]?o.fixed&&f[1]>=n.height()&&(f[1]=n.height(),t("."+l[5])):t("."+l[5])}return a},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass(a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(e){s=e.find(".layui-layer-input"),s.focus(),"function"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,n="";if(e>0)for(n=''+t[0].title+"";i"+t[i].title+"";return n}(),content:'
        '+function(){var e=t.length,i=1,n="";if(e>0)for(n='
      • '+(t[0].content||"no content")+"
      • ";i'+(t[i].content||"no content")+"";return n}()+"
      ",success:function(t){var a=t.find(".layui-layer-title").children(),o=t.find(".layui-layer-tabmain").children();a.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var n=i(this),a=n.index();n.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow"),o.eq(a).show().siblings().hide(),"function"==typeof e.change&&e.change(a)}),"function"==typeof n&&n(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
      '+(u.length>1?'':"")+'
      '+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
      ",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
      是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.jquery),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window);layui.define("jquery",function(i){"use strict";var a=layui.jquery,t=(layui.hint(),layui.device()),l="element",e="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(i){var t=this;return a.extend(!0,t.config,i),t},s.prototype.on=function(i,a){return layui.onevent(l,i,a)},s.prototype.tabAdd=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=e.children(".layui-tab-content");return n.append('
    • '+(t.title||"unnaming")+"
    • "),s.append('
      '+(t.content||"")+"
      "),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.find('>li[lay-id="'+t+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.find('>li[lay-id="'+t+'"]');return f.tabClick(null,null,s),this},s.prototype.progress=function(i,t){var l="layui-progress",e=a("."+l+"[lay-filter="+i+"]"),n=e.find("."+l+"-bar"),s=n.find("."+l+"-text");return n.css("width",t),s.text(t),this};var o=".layui-nav",c="layui-nav-item",r="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",h="layui-nav-more",y="layui-anim layui-anim-upbit",f={tabClick:function(i,t,s){var o=s||a(this),t=t||o.parent().children("li").index(o),c=o.parents(".layui-tab").eq(0),r=c.children(".layui-tab-content").children(".layui-tab-item"),u=c.attr("lay-filter");o.addClass(e).siblings().removeClass(e),r.eq(t).addClass(n).siblings().removeClass(n),layui.event.call(this,l,"tab("+u+")",{elem:c,index:t})},tabDelete:function(i,t){var l=t||a(this).parent(),n=l.index(),s=l.parents(".layui-tab").eq(0),o=s.children(".layui-tab-content").children(".layui-tab-item");l.hasClass(e)&&(l.next()[0]?f.tabClick.call(l.next()[0],null,n+1):l.prev()[0]&&f.tabClick.call(l.prev()[0],null,n-1)),l.remove(),o.eq(n).remove(),setTimeout(function(){f.tabAuto()},50)},tabAuto:function(){var i="layui-tab-more",l="layui-tab-bar",e="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),c=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),r=a('');if(n===window&&8!=t.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var i=a(this);if(!i.find("."+e)[0]){var t=a('');t.on("click",f.tabDelete),i.append(t)}}),o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+l)[0])return;o.append(r),s.attr("overflow",""),r.on("click",function(a){o[this.title?"removeClass":"addClass"](i),this.title=this.title?"":"收缩"})}else o.find("."+l).remove(),s.removeAttr("overflow")})},hideTabMore:function(i){var t=a(".layui-tab-title");i!==!0&&"tabmore"===a(i.target).attr("lay-stope")||(t.removeClass("layui-tab-more"),t.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var i=a(this),t=i.parents(o),n=t.attr("lay-filter");i.find("."+d)[0]||(t.find("."+e).removeClass(e),i.addClass(e),layui.event.call(this,l,"nav("+n+")",i))},clickChild:function(){var i=a(this),t=i.parents(o),n=t.attr("lay-filter");t.find("."+e).removeClass(e),i.addClass(e),layui.event.call(this,l,"nav("+n+")",i)},showChild:function(){var i=a(this),t=i.parents(o),l=i.parent(),e=i.siblings("."+d);t.hasClass(u)&&(e.removeClass(y),l["none"===e.css("display")?"addClass":"removeClass"](c+"ed"))},collapse:function(){var i=a(this),t=i.find(".layui-colla-icon"),e=i.siblings(".layui-colla-content"),s=i.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),c="none"===e.css("display");if("string"==typeof s.attr("lay-accordion")){var r=s.children(".layui-colla-item").children("."+n);r.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),r.removeClass(n)}e[c?"addClass":"removeClass"](n),t.html(c?"":""),layui.event.call(this,l,"collapse("+o+")",{title:i,content:e,show:c})}};s.prototype.init=function(i){var l={tab:function(){f.tabAuto.call({})},nav:function(){var i,l,e,s=200,p=function(o,c){var r=a(this),f=r.find("."+d);c.hasClass(u)?o.css({top:r.position().top,height:r.children("a").height(),opacity:1}):(f.addClass(y),o.css({left:r.position().left+parseFloat(r.css("marginLeft")),top:r.position().top+r.height()-5}),i=setTimeout(function(){o.css({width:r.width(),opacity:1})},t.ie&&t.ie<10?0:s),clearTimeout(e),"block"===f.css("display")&&clearTimeout(l),l=setTimeout(function(){f.addClass(n),r.find("."+h).addClass(h+"d")},300))};a(o).each(function(){var t=a(this),o=a(''),y=t.find("."+c);t.find("."+r)[0]||(t.append(o),y.on("mouseenter",function(){p.call(this,o,t)}).on("mouseleave",function(){t.hasClass(u)||(clearTimeout(l),l=setTimeout(function(){t.find("."+d).removeClass(n),t.find("."+h).removeClass(h+"d")},300))}),t.on("mouseleave",function(){clearTimeout(i),e=setTimeout(function(){t.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},s)})),y.each(function(){var i=a(this),t=i.find("."+d);if(t[0]&&!i.find("."+h)[0]){var l=i.children("a");l.append('')}i.off("click",f.clickThis).on("click",f.clickThis),i.children("a").off("click",f.showChild).on("click",f.showChild),t.children("dd").off("click",f.clickChild).on("click",f.clickChild)})})},breadcrumb:function(){var i=".layui-breadcrumb";a(i).each(function(){var i=a(this),t=i.attr("lay-separator")||">",l=i.find("a");l.find(".layui-box")[0]||(l.each(function(i){i!==l.length-1&&a(this).append(''+t+"")}),i.css("visibility","visible"))})},progress:function(){var i="layui-progress";a("."+i).each(function(){var t=a(this),l=t.find(".layui-progress-bar"),e=l.attr("lay-percent");l.css("width",e),t.attr("lay-showPercent")&&setTimeout(function(){var a=Math.round(l.width()/t.width()*100);a>100&&(a=100),l.html(''+a+"%")},350)})},collapse:function(){var i="layui-collapse";a("."+i).each(function(){var i=a(this).find(".layui-colla-item");i.each(function(){var i=a(this),t=i.find(".layui-colla-title"),l=i.find(".layui-colla-content"),e="none"===l.css("display");t.find(".layui-colla-icon").remove(),t.append(''+(e?"":"")+""),t.off("click",f.collapse).on("click",f.collapse)})})}};return layui.each(l,function(i,a){a()})};var p=new s,v=a(document);p.init();var b=".layui-tab-title li";v.on("click",b,f.tabClick),v.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),i(l,function(i){return p.set(i)})});layui.define("layer",function(e){"use strict";var a=layui.jquery,t=layui.layer,i=(layui.device(),"layui-upload-enter"),n="layui-upload-iframe",r={icon:2,shift:6},o={file:"文件",video:"视频",audio:"音频"},s=function(e){this.options=e};s.prototype.init=function(){var e=this,t=e.options,r=a("body"),s=a(t.elem||".layui-upload-file"),u=a('');return a("#"+n)[0]||r.append(u),s.each(function(r,s){s=a(s);var u='
      ',l=s.attr("lay-type")||t.type;t.unwrap||(u='
      '+u+''+(s.attr("lay-title")||t.title||"上传"+(o[l]||"图片"))+"
      "),u=a(u),t.unwrap||u.on("dragover",function(e){e.preventDefault(),a(this).addClass(i)}).on("dragleave",function(){a(this).removeClass(i)}).on("drop",function(){a(this).removeClass(i)}),s.parent("form").attr("target")===n&&(t.unwrap?s.unwrap():(s.parent().next().remove(),s.unwrap().unwrap())),s.wrap(u),s.off("change").on("change",function(){e.action(this,l)})})},s.prototype.action=function(e,i){var o=this,s=o.options,u=e.value,l=a(e),p=l.attr("lay-ext")||s.ext||"";if(u){switch(i){case"file":if(p&&!RegExp("\\w\\.("+p+")$","i").test(escape(u)))return t.msg("不支持该文件格式",r),e.value="";break;case"video":if(!RegExp("\\w\\.("+(p||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(u)))return t.msg("不支持该视频格式",r),e.value="";break;case"audio":if(!RegExp("\\w\\.("+(p||"mp3|wav|mid")+")$","i").test(escape(u)))return t.msg("不支持该音频格式",r),e.value="";break;default:if(!RegExp("\\w\\.("+(p||"jpg|png|gif|bmp|jpeg")+")$","i").test(escape(u)))return t.msg("不支持该图片格式",r),e.value=""}s.before&&s.before(e),l.parent().submit();var c=a("#"+n),f=setInterval(function(){var a;try{a=c.contents().find("body").text()}catch(i){t.msg("上传接口存在跨域",r),clearInterval(f)}if(a){clearInterval(f),c.contents().find("body").html("");try{a=JSON.parse(a)}catch(i){return a={},t.msg("请对上传接口返回JSON字符",r)}"function"==typeof s.success&&s.success(a,e)}},30);e.value=""}},e("upload",function(e){var a=new s(e=e||{});a.init()})});layui.define("layer",function(e){"use strict";var i=layui.jquery,t=layui.layer,a=layui.hint(),n=layui.device(),l="form",r=".layui-form",s="layui-this",o="layui-hide",c="layui-disabled",u=function(){this.config={verify:{required:[/[\S]+/,"必填项不能为空"],phone:[/^1\d{10}$/,"请输入正确的手机号"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"邮箱格式不正确"],url:[/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/,"链接格式不正确"],number:[/^\d+$/,"只能填写数字"],date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"日期格式不正确"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"请输入正确的身份证号"]}}};u.prototype.set=function(e){var t=this;return i.extend(!0,t.config,e),t},u.prototype.verify=function(e){var t=this;return i.extend(!0,t.config.verify,e),t},u.prototype.on=function(e,i){return layui.onevent(l,e,i)},u.prototype.render=function(e){var t=this,n={select:function(){var e,t="请选择",a="layui-form-select",n="layui-select-title",u="layui-select-none",d="",f=i(r).find("select"),y=function(t,l){i(t.target).parent().hasClass(n)&&!l||(i("."+a).removeClass(a+"ed"),e&&d&&e.val(d)),e=null},v=function(t,r,f){var v=i(this),h=t.find("."+n),p=h.find("input"),m=t.find("dl"),k=m.children("dd");if(!r){var b=function(){t.addClass(a+"ed"),k.removeClass(o)},x=function(){t.removeClass(a+"ed"),p.blur(),g(p.val(),function(e){e&&(d=m.find("."+s).html(),p&&p.val(d))})};h.on("click",function(e){t.hasClass(a+"ed")?x():(y(e,!0),b()),m.find("."+u).remove()}),h.find(".layui-edge").on("click",function(){p.focus()}),p.on("keyup",function(e){var i=e.keyCode;9===i&&b()}).on("keydown",function(e){var i=e.keyCode;9===i?x():13===i&&e.preventDefault()});var g=function(e,t,a){var n=0;layui.each(k,function(){var t=i(this),l=t.text(),r=l.indexOf(e)===-1;(""===e||"blur"===a?e!==l:r)&&n++,"keyup"===a&&t[r?"addClass":"removeClass"](o)});var l=n===k.length;return t(l),l},C=function(e){var i=this.value,t=e.keyCode;return 9!==t&&13!==t&&37!==t&&38!==t&&39!==t&&40!==t&&(g(i,function(e){e?m.find("."+u)[0]||m.append('

      无匹配项

      '):m.find("."+u).remove()},"keyup"),void(""===i&&m.find("."+u).remove()))};f&&p.on("keyup",C).on("blur",function(i){e=p,d=m.find("."+s).html(),setTimeout(function(){g(p.val(),function(e){e&&!d&&p.val("")},"blur")},200)}),k.on("click",function(){var e=i(this),a=e.attr("lay-value"),n=v.attr("lay-filter");return!e.hasClass(c)&&(v.val(a).removeClass("layui-form-danger"),p.val(e.text()),e.addClass(s).siblings().removeClass(s),layui.event.call(this,l,"select("+n+")",{elem:v[0],value:a,othis:t}),x(),!1)}),t.find("dl>dt").on("click",function(e){return!1}),i(document).off("click",y).on("click",y)}};f.each(function(e,l){var r=i(this),o=r.next("."+a),u=this.disabled,d=l.value,f=i(l.options[l.selectedIndex]);if("string"==typeof r.attr("lay-ignore"))return r.show();var y="string"==typeof r.attr("lay-search"),h=i(['
      ','
      ','
      ','
      '+function(e){var i=[];return layui.each(e,function(e,t){(0!==e||t.value)&&("optgroup"===t.tagName.toLowerCase()?i.push("
      "+t.label+"
      "):i.push('
      '+t.innerHTML+"
      "))}),i.join("")}(r.find("*"))+"
      ","
      "].join(""));o[0]&&o.remove(),r.after(h),v.call(this,h,u,y)})},checkbox:function(){var e={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},t=i(r).find("input[type=checkbox]"),a=function(e,t){var a=i(this);e.on("click",function(){var i=a.attr("lay-filter"),n=(a.attr("lay-text")||"").split("|");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(t[1]).find("em").text(n[1])):(a[0].checked=!0,e.addClass(t[1]).find("em").text(n[0])),layui.event.call(a[0],l,t[2]+"("+i+")",{elem:a[0],value:a[0].value,othis:e}))})};t.each(function(t,n){var l=i(this),r=l.attr("lay-skin"),s=(l.attr("lay-text")||"").split("|"),o=this.disabled;"switch"===r&&(r="_"+r);var u=e[r]||e.checkbox;if("string"==typeof l.attr("lay-ignore"))return l.show();var d=l.next("."+u[0]),f=i(['
      ',{_switch:""+((n.checked?s[0]:s[1])||"")+""}[r]||(n.title.replace(/\s/g,"")?""+n.title+"":"")+''+(r?"":"")+"","
      "].join(""));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e="layui-form-radio",t=["",""],a=i(r).find("input[type=radio]"),n=function(a){var n=i(this),s="layui-anim-scaleSpring";a.on("click",function(){var o=n[0].name,c=n.parents(r),u=n.attr("lay-filter"),d=c.find("input[name="+o.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(d,function(){var a=i(this).next("."+e);this.checked=!1,a.removeClass(e+"ed"),a.find(".layui-icon").removeClass(s).html(t[1])}),n[0].checked=!0,a.addClass(e+"ed"),a.find(".layui-icon").addClass(s).html(t[0]),layui.event.call(n[0],l,"radio("+u+")",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=i(this),s=r.next("."+e),o=this.disabled;if("string"==typeof r.attr("lay-ignore"))return r.show();var u=i(['
      ',''+t[l.checked?0:1]+"",""+(l.title||"未命名")+"","
      "].join(""));s[0]&&s.remove(),r.after(u),n.call(this,u)})}};return e?n[e]?n[e]():a.error("不支持的"+e+"表单渲染"):layui.each(n,function(e,i){i()}),t};var d=function(){var e=i(this),a=f.config.verify,s=null,o="layui-form-danger",c={},u=e.parents(r),d=u.find("*[lay-verify]"),y=e.parents("form")[0],v=u.find("input,select,textarea"),h=e.attr("lay-filter");return layui.each(d,function(e,l){var r=i(this),c=r.attr("lay-verify").split("|"),u="",d=r.val();if(r.removeClass(o),layui.each(c,function(e,i){var c="function"==typeof a[i];if(a[i]&&(c?u=a[i](d,l):!a[i][0].test(d)))return t.msg(u||a[i][1],{icon:5,shift:6}),n.android||n.ios||l.focus(),r.addClass(o),s=!0}),s)return s}),!s&&(layui.each(v,function(e,i){i.name&&(/^checkbox|radio$/.test(i.type)&&!i.checked||(c[i.name]=i.value))}),layui.event.call(this,l,"submit("+h+")",{elem:this,form:y,field:c}))},f=new u,y=i(document);f.render(),y.on("reset",r,function(){setTimeout(function(){f.render()},50)}),y.on("submit",r,d).on("click","*[lay-submit]",d),e(l,function(e){return f.set(e)})});layui.define("jquery",function(e){"use strict";var o=layui.jquery,a=layui.hint(),r="layui-tree-enter",i=function(e){this.options=e},t={arrow:["",""],checkbox:["",""],radio:["",""],branch:["",""],leaf:""};i.prototype.init=function(e){var o=this;e.addClass("layui-box layui-tree"),o.options.skin&&e.addClass("layui-tree-skin-"+o.options.skin),o.tree(e),o.on(e)},i.prototype.tree=function(e,a){var r=this,i=r.options,n=a||i.nodes;layui.each(n,function(a,n){var l=n.children&&n.children.length>0,c=o('
        '),s=o(["
      • ",function(){return l?''+(n.spread?t.arrow[1]:t.arrow[0])+"":""}(),function(){return i.check?''+("checkbox"===i.check?t.checkbox[0]:"radio"===i.check?t.radio[0]:"")+"":""}(),function(){return'"+(''+(l?n.spread?t.branch[1]:t.branch[0]:t.leaf)+"")+(""+(n.name||"未命名")+"")}(),"
      • "].join(""));l&&(s.append(c),r.tree(c,n.children)),e.append(s),"function"==typeof i.click&&r.click(s,n),r.spread(s,n),i.drag&&r.drag(s,n)})},i.prototype.click=function(e,o){var a=this,r=a.options;e.children("a").on("click",function(e){layui.stope(e),r.click(o)})},i.prototype.spread=function(e,o){var a=this,r=(a.options,e.children(".layui-tree-spread")),i=e.children("ul"),n=e.children("a"),l=function(){e.data("spread")?(e.data("spread",null),i.removeClass("layui-show"),r.html(t.arrow[0]),n.find(".layui-icon").html(t.branch[0])):(e.data("spread",!0),i.addClass("layui-show"),r.html(t.arrow[1]),n.find(".layui-icon").html(t.branch[1]))};i[0]&&(r.on("click",l),n.on("dblclick",l))},i.prototype.on=function(e){var a=this,i=a.options,t="layui-tree-drag";e.find("i").on("selectstart",function(e){return!1}),i.drag&&o(document).on("mousemove",function(e){var r=a.move;if(r.from){var i=(r.to,o('
        '));e.preventDefault(),o("."+t)[0]||o("body").append(i);var n=o("."+t)[0]?o("."+t):i;n.addClass("layui-show").html(r.from.elem.children("a").html()),n.css({left:e.pageX+10,top:e.pageY+10})}}).on("mouseup",function(){var e=a.move;e.from&&(e.from.elem.children("a").removeClass(r),e.to&&e.to.elem.children("a").removeClass(r),a.move={},o("."+t).remove())})},i.prototype.move={},i.prototype.drag=function(e,a){var i=this,t=(i.options,e.children("a")),n=function(){var t=o(this),n=i.move;n.from&&(n.to={item:a,elem:e},t.addClass(r))};t.on("mousedown",function(){var o=i.move;o.from={item:a,elem:e}}),t.on("mouseenter",n).on("mousemove",n).on("mouseleave",function(){var e=o(this),a=i.move;a.from&&(delete a.to,e.removeClass(r))})},e("tree",function(e){var r=new i(e=e||{}),t=o(e.elem);return t[0]?void r.init(t):a.error("layui.tree 没有找到"+e.elem+"元素")})});layui.define("jquery",function(l){"use strict";var o=layui.jquery,i={fixbar:function(l){l=l||{},l.bgcolor=l.bgcolor?"background-color:"+l.bgcolor:"";var i,a,c="layui-fixbar-top",t=[l.bar1===!0?"":l.bar1,l.bar2===!0?"":l.bar2,""],r=o(['
          ',l.bar1?'
        • '+t[0]+"
        • ":"",l.bar2?'
        • '+t[1]+"
        • ":"",'
        • '+t[2]+"
        • ","
        "].join("")),e=r.find("."+c),s=function(){var i=o(document).scrollTop();i>=(l.showHeight||200)?a||(e.show(),a=1):a&&(e.hide(),a=0)};o(".layui-fixbar")[0]||("object"==typeof l.css&&r.css(l.css),o("body").append(r),s(),r.find("li").on("click",function(){var i=o(this),a=i.attr("lay-type");"top"===a&&o("html,body").animate({scrollTop:0},200),l.click&&l.click.call(this,a)}),o(document).on("scroll",function(){i&&clearTimeout(i),i=setTimeout(function(){s()},100)}))}};l("util",i)});layui.define("jquery",function(e){"use strict";var l=layui.jquery,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var u=l(e.elem);if(u[0]){var f=l(e.scrollElem||document),m=e.mb||50,s=!("isAuto"in e)||e.isAuto,y=e.end||"没有更多了",v=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");u.find(".layui-flow-more")[0]||u.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(y):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(f.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=v?e.height():l(window).height(),n=v?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=m&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var f=e.attr("lay-src");layui.img(f,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",f).removeAttr("lay-src"),l[0]&&u(l),i++})}},u=function(e,o){var u=a?(o||n).height():l(window).height(),f=n.scrollTop(),m=f+u;if(t.lazyimg.elem=l(r),e)c(e,u);else for(var s=0;sm)break}};if(u(),!o){var f;n.on("scroll",function(){var e=l(this);f&&clearTimeout(f),f=setTimeout(function(){u(null,e)},50)}),o=!0}return u},e("flow",new o)});layui.define(["layer","form"],function(t){"use strict";var e=layui.jquery,i=layui.layer,a=layui.form(),l=(layui.hint(),layui.device()),n="layedit",o="layui-show",r="layui-disabled",c=function(){var t=this;t.index=0,t.config={tool:["strong","italic","underline","del","|","left","center","right","|","link","unlink","face","image"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r="layui-layedit",c=e("#"+t),u="LAY_layedit_"+ ++a.index,d=c.next("."+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join("")}(),m=e(['
        ','
        '+f+"
        ",'
        ','',"
        ","
        "].join(""));return l.ie&&l.ie<8?c.removeClass("layui-hide").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass("layui-hide").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e("#"+i[1].attr("textarea"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find("iframe");n.css({height:a.height}).on("load",function(){var o=n.contents(),r=n.prop("contentWindow"),c=o.find("head"),s=e([""].join("")),u=o.find("body");c.append(s),u.attr("contenteditable","true").css({"min-height":a.height}).html(i.value||""),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e("#LAY_layedit_"+t),a=i.prop("contentWindow");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on("keydown",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if("pre"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg("请暂时用shift+enter"),!1}r.execCommand("formatBlock",!1,"

        ")}}),e(n).parents("form").on("submit",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on("paste",function(e){r.execCommand("formatBlock",!1,"

        "),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),e(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute("text"),l.selection){var r=a.text||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop("outerHTML")),a.select()}else{var r=a.toString()||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l="layedit-tool-active",n=p(m(a)),o=function(e){return t.find(".layedit-tool-"+e)};i&&i[i.hasClass(l)?"removeClass":"addClass"](l),t.find(">i").removeClass(l),o("unlink").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||o("b").addClass(l),"i"!==t&&"em"!==t||o("i").addClass(l),"u"===t&&o("u").addClass(l),"strike"===t&&o("d").addClass(l),"p"===t&&("center"===e?o("center").addClass(l):"right"===e?o("right").addClass(l):o("left").addClass(l)),"a"===t&&(o("link").addClass(l),o("unlink").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr("href"),target:l.attr("target")},function(e){var a=l[0];"A"===a.tagName?a.href=e.url:v.call(t,"a",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand("unlink")},face:function(e){x.call(this,function(i){v.call(t,"img",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use("upload",function(o){var r=l.uploadImage||{};o({url:r.url,method:r.type,elem:e(n).find("input")[0],unwrap:!0,success:function(e){0==e.code?(e.data=e.data||{},v.call(t,"img",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||"上传失败")}})})},code:function(e){k.call(o,function(i){v.call(t,"pre",{text:i.code,"lay-lang":i.lang},e)})},help:function(){i.open({type:2,title:"帮助",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["http://www.layui.com/about/layedit/help.html","no"]})}},s=a.find(".layui-layedit-tool"),u=function(){var i=e(this),a=i.attr("layedit-event"),l=i.attr("lay-command");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

        "),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(">i").on("mousedown",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)||u.call(this)}).on("click",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)&&u.call(this)}),o.on("click",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"超链接",skin:"layui-layer-msg",content:['

          ','
        • ','','
          ','',"
          ","
        • ",'
        • ','','
          ','",'","
          ","
        • ",'
        • ','','',"
        • ","
        "].join(""),success:function(t,n){var o="submit(layedit-link-yes)";a.render("radio"),t.find(".layui-btn-primary").on("click",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+"images/face/"+t+".gif"}),e}();return x.hide=x.hide||function(t){"face"!==e(t.target).attr("layedit-event")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('
      • '+e+'
      • ')}),'
          '+t.join("")+"
        "}(),this,{tips:1,time:0,skin:"layui-box layui-util-face",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(".layui-clear>li").on("click",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off("click",x.hide).on("click",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"插入代码",skin:"layui-layer-msg",content:['
          ','
        • ','','
          ','","
          ","
        • ",'
        • ','','
          ','',"
          ","
        • ",'
        • ','','',"
        • ","
        "].join(""),success:function(l,n){var o="submit(layedit-code-yes)";a.render("select"),l.find(".layui-btn-primary").on("click",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},w=new c;t(n,w)});layui.define("jquery",function(e){"use strict";var a=layui.jquery,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('
        1. '+o.replace(/[\r\t\n]+/g,"
        2. ")+"
        "),c.find(">.layui-code-h3")[0]||c.prepend('

        '+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"

        ");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss"); \ No newline at end of file diff --git a/build/lay/modules/code.js b/build/lay/modules/code.js deleted file mode 100644 index 1e41610b9..000000000 --- a/build/lay/modules/code.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("jquery",function(e){"use strict";var a=layui.jquery,l="http://www.layui.com/doc/modules/code.html";e("code",function(e){var t=[];e=e||{},e.elem=a(e.elem||".layui-code"),e.about=!("about"in e)||e.about,e.elem.each(function(){t.push(this)}),layui.each(t.reverse(),function(t,i){var c=a(i),o=c.html();(c.attr("lay-encode")||e.encode)&&(o=o.replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")),c.html('
        1. '+o.replace(/[\r\t\n]+/g,"
        2. ")+"
        "),c.find(">.layui-code-h3")[0]||c.prepend('

        '+(c.attr("lay-title")||e.title||"code")+(e.about?'layui.code':"")+"

        ");var d=c.find(">.layui-code-ol");c.addClass("layui-box layui-code-view"),(c.attr("lay-skin")||e.skin)&&c.addClass("layui-code-"+(c.attr("lay-skin")||e.skin)),(d.find("li").length/100|0)>0&&d.css("margin-left",(d.find("li").length/100|0)+"px"),(c.attr("lay-height")||e.height)&&d.css("max-height",c.attr("lay-height")||e.height)})})}).addcss("modules/code.css","skincodecss"); \ No newline at end of file diff --git a/build/lay/modules/element.js b/build/lay/modules/element.js deleted file mode 100644 index e72432415..000000000 --- a/build/lay/modules/element.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("jquery",function(i){"use strict";var a=layui.jquery,t=(layui.hint(),layui.device()),l="element",e="layui-this",n="layui-show",s=function(){this.config={}};s.prototype.set=function(i){var t=this;return a.extend(!0,t.config,i),t},s.prototype.on=function(i,a){return layui.onevent(l,i,a)},s.prototype.tabAdd=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=e.children(".layui-tab-content");return n.append('
      • '+(t.title||"unnaming")+"
      • "),s.append('
        '+(t.content||"")+"
        "),f.hideTabMore(!0),f.tabAuto(),this},s.prototype.tabDelete=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.find('>li[lay-id="'+t+'"]');return f.tabDelete(null,s),this},s.prototype.tabChange=function(i,t){var l=".layui-tab-title",e=a(".layui-tab[lay-filter="+i+"]"),n=e.children(l),s=n.find('>li[lay-id="'+t+'"]');return f.tabClick(null,null,s),this},s.prototype.progress=function(i,t){var l="layui-progress",e=a("."+l+"[lay-filter="+i+"]"),n=e.find("."+l+"-bar"),s=n.find("."+l+"-text");return n.css("width",t),s.text(t),this};var o=".layui-nav",c="layui-nav-item",r="layui-nav-bar",u="layui-nav-tree",d="layui-nav-child",h="layui-nav-more",y="layui-anim layui-anim-upbit",f={tabClick:function(i,t,s){var o=s||a(this),t=t||o.parent().children("li").index(o),c=o.parents(".layui-tab").eq(0),r=c.children(".layui-tab-content").children(".layui-tab-item"),u=c.attr("lay-filter");o.addClass(e).siblings().removeClass(e),r.eq(t).addClass(n).siblings().removeClass(n),layui.event.call(this,l,"tab("+u+")",{elem:c,index:t})},tabDelete:function(i,t){var l=t||a(this).parent(),n=l.index(),s=l.parents(".layui-tab").eq(0),o=s.children(".layui-tab-content").children(".layui-tab-item");l.hasClass(e)&&(l.next()[0]?f.tabClick.call(l.next()[0],null,n+1):l.prev()[0]&&f.tabClick.call(l.prev()[0],null,n-1)),l.remove(),o.eq(n).remove(),setTimeout(function(){f.tabAuto()},50)},tabAuto:function(){var i="layui-tab-more",l="layui-tab-bar",e="layui-tab-close",n=this;a(".layui-tab").each(function(){var s=a(this),o=s.children(".layui-tab-title"),c=(s.children(".layui-tab-content").children(".layui-tab-item"),'lay-stope="tabmore"'),r=a('');if(n===window&&8!=t.ie&&f.hideTabMore(!0),s.attr("lay-allowClose")&&o.find("li").each(function(){var i=a(this);if(!i.find("."+e)[0]){var t=a('');t.on("click",f.tabDelete),i.append(t)}}),o.prop("scrollWidth")>o.outerWidth()+1){if(o.find("."+l)[0])return;o.append(r),s.attr("overflow",""),r.on("click",function(a){o[this.title?"removeClass":"addClass"](i),this.title=this.title?"":"收缩"})}else o.find("."+l).remove(),s.removeAttr("overflow")})},hideTabMore:function(i){var t=a(".layui-tab-title");i!==!0&&"tabmore"===a(i.target).attr("lay-stope")||(t.removeClass("layui-tab-more"),t.find(".layui-tab-bar").attr("title",""))},clickThis:function(){var i=a(this),t=i.parents(o),n=t.attr("lay-filter");i.find("."+d)[0]||(t.find("."+e).removeClass(e),i.addClass(e),layui.event.call(this,l,"nav("+n+")",i))},clickChild:function(){var i=a(this),t=i.parents(o),n=t.attr("lay-filter");t.find("."+e).removeClass(e),i.addClass(e),layui.event.call(this,l,"nav("+n+")",i)},showChild:function(){var i=a(this),t=i.parents(o),l=i.parent(),e=i.siblings("."+d);t.hasClass(u)&&(e.removeClass(y),l["none"===e.css("display")?"addClass":"removeClass"](c+"ed"))},collapse:function(){var i=a(this),t=i.find(".layui-colla-icon"),e=i.siblings(".layui-colla-content"),s=i.parents(".layui-collapse").eq(0),o=s.attr("lay-filter"),c="none"===e.css("display");if("string"==typeof s.attr("lay-accordion")){var r=s.children(".layui-colla-item").children("."+n);r.siblings(".layui-colla-title").children(".layui-colla-icon").html(""),r.removeClass(n)}e[c?"addClass":"removeClass"](n),t.html(c?"":""),layui.event.call(this,l,"collapse("+o+")",{title:i,content:e,show:c})}};s.prototype.init=function(i){var l={tab:function(){f.tabAuto.call({})},nav:function(){var i,l,e,s=200,p=function(o,c){var r=a(this),f=r.find("."+d);c.hasClass(u)?o.css({top:r.position().top,height:r.children("a").height(),opacity:1}):(f.addClass(y),o.css({left:r.position().left+parseFloat(r.css("marginLeft")),top:r.position().top+r.height()-5}),i=setTimeout(function(){o.css({width:r.width(),opacity:1})},t.ie&&t.ie<10?0:s),clearTimeout(e),"block"===f.css("display")&&clearTimeout(l),l=setTimeout(function(){f.addClass(n),r.find("."+h).addClass(h+"d")},300))};a(o).each(function(){var t=a(this),o=a(''),y=t.find("."+c);t.find("."+r)[0]||(t.append(o),y.on("mouseenter",function(){p.call(this,o,t)}).on("mouseleave",function(){t.hasClass(u)||(clearTimeout(l),l=setTimeout(function(){t.find("."+d).removeClass(n),t.find("."+h).removeClass(h+"d")},300))}),t.on("mouseleave",function(){clearTimeout(i),e=setTimeout(function(){t.hasClass(u)?o.css({height:0,top:o.position().top+o.height()/2,opacity:0}):o.css({width:0,left:o.position().left+o.width()/2,opacity:0})},s)})),y.each(function(){var i=a(this),t=i.find("."+d);if(t[0]&&!i.find("."+h)[0]){var l=i.children("a");l.append('')}i.off("click",f.clickThis).on("click",f.clickThis),i.children("a").off("click",f.showChild).on("click",f.showChild),t.children("dd").off("click",f.clickChild).on("click",f.clickChild)})})},breadcrumb:function(){var i=".layui-breadcrumb";a(i).each(function(){var i=a(this),t=i.attr("lay-separator")||">",l=i.find("a");l.find(".layui-box")[0]||(l.each(function(i){i!==l.length-1&&a(this).append(''+t+"")}),i.css("visibility","visible"))})},progress:function(){var i="layui-progress";a("."+i).each(function(){var t=a(this),l=t.find(".layui-progress-bar"),e=l.attr("lay-percent");l.css("width",e),t.attr("lay-showPercent")&&setTimeout(function(){var a=Math.round(l.width()/t.width()*100);a>100&&(a=100),l.html(''+a+"%")},350)})},collapse:function(){var i="layui-collapse";a("."+i).each(function(){var i=a(this).find(".layui-colla-item");i.each(function(){var i=a(this),t=i.find(".layui-colla-title"),l=i.find(".layui-colla-content"),e="none"===l.css("display");t.find(".layui-colla-icon").remove(),t.append(''+(e?"":"")+""),t.off("click",f.collapse).on("click",f.collapse)})})}};return layui.each(l,function(i,a){a()})};var p=new s,v=a(document);p.init();var b=".layui-tab-title li";v.on("click",b,f.tabClick),v.on("click",f.hideTabMore),a(window).on("resize",f.tabAuto),i(l,function(i){return p.set(i)})}); \ No newline at end of file diff --git a/build/lay/modules/flow.js b/build/lay/modules/flow.js deleted file mode 100644 index 295d08464..000000000 --- a/build/lay/modules/flow.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("jquery",function(e){"use strict";var l=layui.jquery,o=function(e){},t='';o.prototype.load=function(e){var o,i,n,r,a=this,c=0;e=e||{};var u=l(e.elem);if(u[0]){var f=l(e.scrollElem||document),m=e.mb||50,s=!("isAuto"in e)||e.isAuto,y=e.end||"没有更多了",v=e.scrollElem&&e.scrollElem!==document,d="加载更多",h=l('");u.find(".layui-flow-more")[0]||u.append(h);var p=function(e,t){e=l(e),h.before(e),t=0==t||null,t?h.html(y):h.find("a").html(d),i=t,o=null,n&&n()},g=function(){o=!0,h.find("a").html(t),"function"==typeof e.done&&e.done(++c,p)};if(g(),h.find("a").on("click",function(){l(this);i||o||g()}),e.isLazyimg)var n=a.lazyimg({elem:e.elem+" img",scrollElem:e.scrollElem});return s?(f.on("scroll",function(){var e=l(this),t=e.scrollTop();r&&clearTimeout(r),i||(r=setTimeout(function(){var i=v?e.height():l(window).height(),n=v?e.prop("scrollHeight"):document.documentElement.scrollHeight;n-t-i<=m&&(o||g())},100))}),a):a}},o.prototype.lazyimg=function(e){var o,t=this,i=0;e=e||{};var n=l(e.scrollElem||document),r=e.elem||"img",a=e.scrollElem&&e.scrollElem!==document,c=function(e,l){var o=n.scrollTop(),r=o+l,c=a?function(){return e.offset().top-n.offset().top+o}():e.offset().top;if(c>=o&&c<=r&&!e.attr("src")){var f=e.attr("lay-src");layui.img(f,function(){var l=t.lazyimg.elem.eq(i);e.attr("src",f).removeAttr("lay-src"),l[0]&&u(l),i++})}},u=function(e,o){var u=a?(o||n).height():l(window).height(),f=n.scrollTop(),m=f+u;if(t.lazyimg.elem=l(r),e)c(e,u);else for(var s=0;sm)break}};if(u(),!o){var f;n.on("scroll",function(){var e=l(this);f&&clearTimeout(f),f=setTimeout(function(){u(null,e)},50)}),o=!0}return u},e("flow",new o)}); \ No newline at end of file diff --git a/build/lay/modules/form.js b/build/lay/modules/form.js deleted file mode 100644 index a47339a33..000000000 --- a/build/lay/modules/form.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("layer",function(e){"use strict";var i=layui.jquery,t=layui.layer,a=layui.hint(),n=layui.device(),l="form",r=".layui-form",s="layui-this",o="layui-hide",c="layui-disabled",u=function(){this.config={verify:{required:[/[\S]+/,"必填项不能为空"],phone:[/^1\d{10}$/,"请输入正确的手机号"],email:[/^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/,"邮箱格式不正确"],url:[/(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/,"链接格式不正确"],number:[/^\d+$/,"只能填写数字"],date:[/^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/,"日期格式不正确"],identity:[/(^\d{15}$)|(^\d{17}(x|X|\d)$)/,"请输入正确的身份证号"]}}};u.prototype.set=function(e){var t=this;return i.extend(!0,t.config,e),t},u.prototype.verify=function(e){var t=this;return i.extend(!0,t.config.verify,e),t},u.prototype.on=function(e,i){return layui.onevent(l,e,i)},u.prototype.render=function(e){var t=this,n={select:function(){var e,t="请选择",a="layui-form-select",n="layui-select-title",u="layui-select-none",d="",f=i(r).find("select"),y=function(t,l){i(t.target).parent().hasClass(n)&&!l||(i("."+a).removeClass(a+"ed"),e&&d&&e.val(d)),e=null},v=function(t,r,f){var v=i(this),h=t.find("."+n),p=h.find("input"),m=t.find("dl"),k=m.children("dd");if(!r){var b=function(){t.addClass(a+"ed"),k.removeClass(o)},x=function(){t.removeClass(a+"ed"),p.blur(),g(p.val(),function(e){e&&(d=m.find("."+s).html(),p&&p.val(d))})};h.on("click",function(e){t.hasClass(a+"ed")?x():(y(e,!0),b()),m.find("."+u).remove()}),h.find(".layui-edge").on("click",function(){p.focus()}),p.on("keyup",function(e){var i=e.keyCode;9===i&&b()}).on("keydown",function(e){var i=e.keyCode;9===i?x():13===i&&e.preventDefault()});var g=function(e,t,a){var n=0;layui.each(k,function(){var t=i(this),l=t.text(),r=l.indexOf(e)===-1;(""===e||"blur"===a?e!==l:r)&&n++,"keyup"===a&&t[r?"addClass":"removeClass"](o)});var l=n===k.length;return t(l),l},C=function(e){var i=this.value,t=e.keyCode;return 9!==t&&13!==t&&37!==t&&38!==t&&39!==t&&40!==t&&(g(i,function(e){e?m.find("."+u)[0]||m.append('

        无匹配项

        '):m.find("."+u).remove()},"keyup"),void(""===i&&m.find("."+u).remove()))};f&&p.on("keyup",C).on("blur",function(i){e=p,d=m.find("."+s).html(),setTimeout(function(){g(p.val(),function(e){e&&!d&&p.val("")},"blur")},200)}),k.on("click",function(){var e=i(this),a=e.attr("lay-value"),n=v.attr("lay-filter");return!e.hasClass(c)&&(v.val(a).removeClass("layui-form-danger"),p.val(e.text()),e.addClass(s).siblings().removeClass(s),layui.event.call(this,l,"select("+n+")",{elem:v[0],value:a,othis:t}),x(),!1)}),t.find("dl>dt").on("click",function(e){return!1}),i(document).off("click",y).on("click",y)}};f.each(function(e,l){var r=i(this),o=r.next("."+a),u=this.disabled,d=l.value,f=i(l.options[l.selectedIndex]);if("string"==typeof r.attr("lay-ignore"))return r.show();var y="string"==typeof r.attr("lay-search"),h=i(['
        ','
        ','
        ','
        '+function(e){var i=[];return layui.each(e,function(e,t){(0!==e||t.value)&&("optgroup"===t.tagName.toLowerCase()?i.push("
        "+t.label+"
        "):i.push('
        '+t.innerHTML+"
        "))}),i.join("")}(r.find("*"))+"
        ","
        "].join(""));o[0]&&o.remove(),r.after(h),v.call(this,h,u,y)})},checkbox:function(){var e={checkbox:["layui-form-checkbox","layui-form-checked","checkbox"],_switch:["layui-form-switch","layui-form-onswitch","switch"]},t=i(r).find("input[type=checkbox]"),a=function(e,t){var a=i(this);e.on("click",function(){var i=a.attr("lay-filter"),n=(a.attr("lay-text")||"").split("|");a[0].disabled||(a[0].checked?(a[0].checked=!1,e.removeClass(t[1]).find("em").text(n[1])):(a[0].checked=!0,e.addClass(t[1]).find("em").text(n[0])),layui.event.call(a[0],l,t[2]+"("+i+")",{elem:a[0],value:a[0].value,othis:e}))})};t.each(function(t,n){var l=i(this),r=l.attr("lay-skin"),s=(l.attr("lay-text")||"").split("|"),o=this.disabled;"switch"===r&&(r="_"+r);var u=e[r]||e.checkbox;if("string"==typeof l.attr("lay-ignore"))return l.show();var d=l.next("."+u[0]),f=i(['
        ',{_switch:""+((n.checked?s[0]:s[1])||"")+""}[r]||(n.title.replace(/\s/g,"")?""+n.title+"":"")+''+(r?"":"")+"","
        "].join(""));d[0]&&d.remove(),l.after(f),a.call(this,f,u)})},radio:function(){var e="layui-form-radio",t=["",""],a=i(r).find("input[type=radio]"),n=function(a){var n=i(this),s="layui-anim-scaleSpring";a.on("click",function(){var o=n[0].name,c=n.parents(r),u=n.attr("lay-filter"),d=c.find("input[name="+o.replace(/(\.|#|\[|\])/g,"\\$1")+"]");n[0].disabled||(layui.each(d,function(){var a=i(this).next("."+e);this.checked=!1,a.removeClass(e+"ed"),a.find(".layui-icon").removeClass(s).html(t[1])}),n[0].checked=!0,a.addClass(e+"ed"),a.find(".layui-icon").addClass(s).html(t[0]),layui.event.call(n[0],l,"radio("+u+")",{elem:n[0],value:n[0].value,othis:a}))})};a.each(function(a,l){var r=i(this),s=r.next("."+e),o=this.disabled;if("string"==typeof r.attr("lay-ignore"))return r.show();var u=i(['
        ',''+t[l.checked?0:1]+"",""+(l.title||"未命名")+"","
        "].join(""));s[0]&&s.remove(),r.after(u),n.call(this,u)})}};return e?n[e]?n[e]():a.error("不支持的"+e+"表单渲染"):layui.each(n,function(e,i){i()}),t};var d=function(){var e=i(this),a=f.config.verify,s=null,o="layui-form-danger",c={},u=e.parents(r),d=u.find("*[lay-verify]"),y=e.parents("form")[0],v=u.find("input,select,textarea"),h=e.attr("lay-filter");return layui.each(d,function(e,l){var r=i(this),c=r.attr("lay-verify").split("|"),u="",d=r.val();if(r.removeClass(o),layui.each(c,function(e,i){var c="function"==typeof a[i];if(a[i]&&(c?u=a[i](d,l):!a[i][0].test(d)))return t.msg(u||a[i][1],{icon:5,shift:6}),n.android||n.ios||l.focus(),r.addClass(o),s=!0}),s)return s}),!s&&(layui.each(v,function(e,i){i.name&&(/^checkbox|radio$/.test(i.type)&&!i.checked||(c[i.name]=i.value))}),layui.event.call(this,l,"submit("+h+")",{elem:this,form:y,field:c}))},f=new u,y=i(document);f.render(),y.on("reset",r,function(){setTimeout(function(){f.render()},50)}),y.on("submit",r,d).on("click","*[lay-submit]",d),e(l,function(e){return f.set(e)})}); \ No newline at end of file diff --git a/build/lay/modules/jquery.js b/build/lay/modules/jquery.js deleted file mode 100644 index 015155e29..000000000 --- a/build/lay/modules/jquery.js +++ /dev/null @@ -1,5 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;!function(e,t){"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(e,t){function n(e){var t=!!e&&"length"in e&&e.length,n=pe.type(e);return"function"!==n&&!pe.isWindow(e)&&("array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)}function r(e,t,n){if(pe.isFunction(t))return pe.grep(e,function(e,r){return!!t.call(e,r,e)!==n});if(t.nodeType)return pe.grep(e,function(e){return e===t!==n});if("string"==typeof t){if(Ce.test(t))return pe.filter(t,e,n);t=pe.filter(t,e)}return pe.grep(e,function(e){return pe.inArray(e,t)>-1!==n})}function i(e,t){do e=e[t];while(e&&1!==e.nodeType);return e}function o(e){var t={};return pe.each(e.match(De)||[],function(e,n){t[n]=!0}),t}function a(){re.addEventListener?(re.removeEventListener("DOMContentLoaded",s),e.removeEventListener("load",s)):(re.detachEvent("onreadystatechange",s),e.detachEvent("onload",s))}function s(){(re.addEventListener||"load"===e.event.type||"complete"===re.readyState)&&(a(),pe.ready())}function u(e,t,n){if(void 0===n&&1===e.nodeType){var r="data-"+t.replace(_e,"-$1").toLowerCase();if(n=e.getAttribute(r),"string"==typeof n){try{n="true"===n||"false"!==n&&("null"===n?null:+n+""===n?+n:qe.test(n)?pe.parseJSON(n):n)}catch(i){}pe.data(e,t,n)}else n=void 0}return n}function l(e){var t;for(t in e)if(("data"!==t||!pe.isEmptyObject(e[t]))&&"toJSON"!==t)return!1;return!0}function c(e,t,n,r){if(He(e)){var i,o,a=pe.expando,s=e.nodeType,u=s?pe.cache:e,l=s?e[a]:e[a]&&a;if(l&&u[l]&&(r||u[l].data)||void 0!==n||"string"!=typeof t)return l||(l=s?e[a]=ne.pop()||pe.guid++:a),u[l]||(u[l]=s?{}:{toJSON:pe.noop}),"object"!=typeof t&&"function"!=typeof t||(r?u[l]=pe.extend(u[l],t):u[l].data=pe.extend(u[l].data,t)),o=u[l],r||(o.data||(o.data={}),o=o.data),void 0!==n&&(o[pe.camelCase(t)]=n),"string"==typeof t?(i=o[t],null==i&&(i=o[pe.camelCase(t)])):i=o,i}}function f(e,t,n){if(He(e)){var r,i,o=e.nodeType,a=o?pe.cache:e,s=o?e[pe.expando]:pe.expando;if(a[s]){if(t&&(r=n?a[s]:a[s].data)){pe.isArray(t)?t=t.concat(pe.map(t,pe.camelCase)):t in r?t=[t]:(t=pe.camelCase(t),t=t in r?[t]:t.split(" ")),i=t.length;for(;i--;)delete r[t[i]];if(n?!l(r):!pe.isEmptyObject(r))return}(n||(delete a[s].data,l(a[s])))&&(o?pe.cleanData([e],!0):fe.deleteExpando||a!=a.window?delete a[s]:a[s]=void 0)}}}function d(e,t,n,r){var i,o=1,a=20,s=r?function(){return r.cur()}:function(){return pe.css(e,t,"")},u=s(),l=n&&n[3]||(pe.cssNumber[t]?"":"px"),c=(pe.cssNumber[t]||"px"!==l&&+u)&&Me.exec(pe.css(e,t));if(c&&c[3]!==l){l=l||c[3],n=n||[],c=+u||1;do o=o||".5",c/=o,pe.style(e,t,c+l);while(o!==(o=s()/u)&&1!==o&&--a)}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}function p(e){var t=ze.split("|"),n=e.createDocumentFragment();if(n.createElement)for(;t.length;)n.createElement(t.pop());return n}function h(e,t){var n,r,i=0,o="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):void 0;if(!o)for(o=[],n=e.childNodes||e;null!=(r=n[i]);i++)!t||pe.nodeName(r,t)?o.push(r):pe.merge(o,h(r,t));return void 0===t||t&&pe.nodeName(e,t)?pe.merge([e],o):o}function g(e,t){for(var n,r=0;null!=(n=e[r]);r++)pe._data(n,"globalEval",!t||pe._data(t[r],"globalEval"))}function m(e){Be.test(e.type)&&(e.defaultChecked=e.checked)}function y(e,t,n,r,i){for(var o,a,s,u,l,c,f,d=e.length,y=p(t),v=[],x=0;x"!==f[1]||Ve.test(a)?0:u:u.firstChild,o=a&&a.childNodes.length;o--;)pe.nodeName(c=a.childNodes[o],"tbody")&&!c.childNodes.length&&a.removeChild(c);for(pe.merge(v,u.childNodes),u.textContent="";u.firstChild;)u.removeChild(u.firstChild);u=y.lastChild}else v.push(t.createTextNode(a));for(u&&y.removeChild(u),fe.appendChecked||pe.grep(h(v,"input"),m),x=0;a=v[x++];)if(r&&pe.inArray(a,r)>-1)i&&i.push(a);else if(s=pe.contains(a.ownerDocument,a),u=h(y.appendChild(a),"script"),s&&g(u),n)for(o=0;a=u[o++];)Ie.test(a.type||"")&&n.push(a);return u=null,y}function v(){return!0}function x(){return!1}function b(){try{return re.activeElement}catch(e){}}function w(e,t,n,r,i,o){var a,s;if("object"==typeof t){"string"!=typeof n&&(r=r||n,n=void 0);for(s in t)w(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)),i===!1)i=x;else if(!i)return e;return 1===o&&(a=i,i=function(e){return pe().off(e),a.apply(this,arguments)},i.guid=a.guid||(a.guid=pe.guid++)),e.each(function(){pe.event.add(this,t,i,r,n)})}function T(e,t){return pe.nodeName(e,"table")&&pe.nodeName(11!==t.nodeType?t:t.firstChild,"tr")?e.getElementsByTagName("tbody")[0]||e.appendChild(e.ownerDocument.createElement("tbody")):e}function C(e){return e.type=(null!==pe.find.attr(e,"type"))+"/"+e.type,e}function E(e){var t=it.exec(e.type);return t?e.type=t[1]:e.removeAttribute("type"),e}function N(e,t){if(1===t.nodeType&&pe.hasData(e)){var n,r,i,o=pe._data(e),a=pe._data(t,o),s=o.events;if(s){delete a.handle,a.events={};for(n in s)for(r=0,i=s[n].length;r1&&"string"==typeof p&&!fe.checkClone&&rt.test(p))return e.each(function(i){var o=e.eq(i);g&&(t[0]=p.call(this,i,o.html())),S(o,t,n,r)});if(f&&(l=y(t,e[0].ownerDocument,!1,e,r),i=l.firstChild,1===l.childNodes.length&&(l=i),i||r)){for(s=pe.map(h(l,"script"),C),a=s.length;c")).appendTo(t.documentElement),t=(ut[0].contentWindow||ut[0].contentDocument).document,t.write(),t.close(),n=D(e,t),ut.detach()),lt[e]=n),n}function L(e,t){return{get:function(){return e()?void delete this.get:(this.get=t).apply(this,arguments)}}}function H(e){if(e in Et)return e;for(var t=e.charAt(0).toUpperCase()+e.slice(1),n=Ct.length;n--;)if(e=Ct[n]+t,e in Et)return e}function q(e,t){for(var n,r,i,o=[],a=0,s=e.length;a=0&&n=0},isEmptyObject:function(e){var t;for(t in e)return!1;return!0},isPlainObject:function(e){var t;if(!e||"object"!==pe.type(e)||e.nodeType||pe.isWindow(e))return!1;try{if(e.constructor&&!ce.call(e,"constructor")&&!ce.call(e.constructor.prototype,"isPrototypeOf"))return!1}catch(n){return!1}if(!fe.ownFirst)for(t in e)return ce.call(e,t);for(t in e);return void 0===t||ce.call(e,t)},type:function(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?ue[le.call(e)]||"object":typeof e},globalEval:function(t){t&&pe.trim(t)&&(e.execScript||function(t){e.eval.call(e,t)})(t)},camelCase:function(e){return e.replace(ge,"ms-").replace(me,ye)},nodeName:function(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()},each:function(e,t){var r,i=0;if(n(e))for(r=e.length;iT.cacheLength&&delete e[t.shift()],e[n+" "]=r}var t=[];return e}function r(e){return e[P]=!0,e}function i(e){var t=H.createElement("div");try{return!!e(t)}catch(n){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function o(e,t){for(var n=e.split("|"),r=n.length;r--;)T.attrHandle[n[r]]=t}function a(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&(~t.sourceIndex||V)-(~e.sourceIndex||V);if(r)return r;if(n)for(;n=n.nextSibling;)if(n===t)return-1;return e?1:-1}function s(e){return function(t){var n=t.nodeName.toLowerCase();return"input"===n&&t.type===e}}function u(e){return function(t){var n=t.nodeName.toLowerCase();return("input"===n||"button"===n)&&t.type===e}}function l(e){return r(function(t){return t=+t,r(function(n,r){for(var i,o=e([],n.length,t),a=o.length;a--;)n[i=o[a]]&&(n[i]=!(r[i]=n[i]))})})}function c(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}function f(){}function d(e){for(var t=0,n=e.length,r="";t1?function(t,n,r){for(var i=e.length;i--;)if(!e[i](t,n,r))return!1;return!0}:e[0]}function g(e,n,r){for(var i=0,o=n.length;i-1&&(r[l]=!(a[l]=f))}}else x=m(x===a?x.splice(h,x.length):x),o?o(null,a,x,u):Q.apply(a,x)})}function v(e){for(var t,n,r,i=e.length,o=T.relative[e[0].type],a=o||T.relative[" "],s=o?1:0,u=p(function(e){return e===t},a,!0),l=p(function(e){return ee(t,e)>-1},a,!0),c=[function(e,n,r){var i=!o&&(r||n!==A)||((t=n).nodeType?u(e,n,r):l(e,n,r));return t=null,i}];s1&&h(c),s>1&&d(e.slice(0,s-1).concat({value:" "===e[s-2].type?"*":""})).replace(se,"$1"),n,s0,o=e.length>0,a=function(r,a,s,u,l){var c,f,d,p=0,h="0",g=r&&[],y=[],v=A,x=r||o&&T.find.TAG("*",l),b=W+=null==v?1:Math.random()||.1,w=x.length;for(l&&(A=a===H||a||l);h!==w&&null!=(c=x[h]);h++){if(o&&c){for(f=0,a||c.ownerDocument===H||(L(c),s=!_);d=e[f++];)if(d(c,a||H,s)){u.push(c);break}l&&(W=b)}i&&((c=!d&&c)&&p--,r&&g.push(c))}if(p+=h,i&&h!==p){for(f=0;d=n[f++];)d(g,y,a,s);if(r){if(p>0)for(;h--;)g[h]||y[h]||(y[h]=G.call(u));y=m(y)}Q.apply(u,y),l&&!r&&y.length>0&&p+n.length>1&&t.uniqueSort(u)}return l&&(W=b,A=v),g};return i?r(a):a}var b,w,T,C,E,N,k,S,A,D,j,L,H,q,_,F,M,O,R,P="sizzle"+1*new Date,B=e.document,W=0,I=0,$=n(),z=n(),X=n(),U=function(e,t){return e===t&&(j=!0),0},V=1<<31,Y={}.hasOwnProperty,J=[],G=J.pop,K=J.push,Q=J.push,Z=J.slice,ee=function(e,t){for(var n=0,r=e.length;n+~]|"+ne+")"+ne+"*"),ce=new RegExp("="+ne+"*([^\\]'\"]*?)"+ne+"*\\]","g"),fe=new RegExp(oe),de=new RegExp("^"+re+"$"),pe={ID:new RegExp("^#("+re+")"),CLASS:new RegExp("^\\.("+re+")"),TAG:new RegExp("^("+re+"|[*])"),ATTR:new RegExp("^"+ie),PSEUDO:new RegExp("^"+oe),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+ne+"*(even|odd|(([+-]|)(\\d*)n|)"+ne+"*(?:([+-]|)"+ne+"*(\\d+)|))"+ne+"*\\)|)","i"),bool:new RegExp("^(?:"+te+")$","i"),needsContext:new RegExp("^"+ne+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+ne+"*((?:-\\d)?\\d*)"+ne+"*\\)|)(?=[^-]|$)","i")},he=/^(?:input|select|textarea|button)$/i,ge=/^h\d$/i,me=/^[^{]+\{\s*\[native \w/,ye=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ve=/[+~]/,xe=/'|\\/g,be=new RegExp("\\\\([\\da-f]{1,6}"+ne+"?|("+ne+")|.)","ig"),we=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)},Te=function(){L()};try{Q.apply(J=Z.call(B.childNodes),B.childNodes),J[B.childNodes.length].nodeType}catch(Ce){Q={apply:J.length?function(e,t){K.apply(e,Z.call(t))}:function(e,t){for(var n=e.length,r=0;e[n++]=t[r++];);e.length=n-1}}}w=t.support={},E=t.isXML=function(e){var t=e&&(e.ownerDocument||e).documentElement;return!!t&&"HTML"!==t.nodeName},L=t.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:B;return r!==H&&9===r.nodeType&&r.documentElement?(H=r,q=H.documentElement,_=!E(H),(n=H.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",Te,!1):n.attachEvent&&n.attachEvent("onunload",Te)),w.attributes=i(function(e){return e.className="i",!e.getAttribute("className")}),w.getElementsByTagName=i(function(e){return e.appendChild(H.createComment("")),!e.getElementsByTagName("*").length}),w.getElementsByClassName=me.test(H.getElementsByClassName),w.getById=i(function(e){return q.appendChild(e).id=P,!H.getElementsByName||!H.getElementsByName(P).length}),w.getById?(T.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&_){var n=t.getElementById(e);return n?[n]:[]}},T.filter.ID=function(e){var t=e.replace(be,we);return function(e){return e.getAttribute("id")===t}}):(delete T.find.ID,T.filter.ID=function(e){var t=e.replace(be,we);return function(e){var n="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}}),T.find.TAG=w.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):w.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){for(;n=o[i++];)1===n.nodeType&&r.push(n);return r}return o},T.find.CLASS=w.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&_)return t.getElementsByClassName(e)},M=[],F=[],(w.qsa=me.test(H.querySelectorAll))&&(i(function(e){q.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&F.push("[*^$]="+ne+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||F.push("\\["+ne+"*(?:value|"+te+")"),e.querySelectorAll("[id~="+P+"-]").length||F.push("~="),e.querySelectorAll(":checked").length||F.push(":checked"),e.querySelectorAll("a#"+P+"+*").length||F.push(".#.+[+~]")}),i(function(e){var t=H.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&F.push("name"+ne+"*[*^$|!~]?="),e.querySelectorAll(":enabled").length||F.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),F.push(",.*:")})),(w.matchesSelector=me.test(O=q.matches||q.webkitMatchesSelector||q.mozMatchesSelector||q.oMatchesSelector||q.msMatchesSelector))&&i(function(e){w.disconnectedMatch=O.call(e,"div"),O.call(e,"[s!='']:x"),M.push("!=",oe)}),F=F.length&&new RegExp(F.join("|")),M=M.length&&new RegExp(M.join("|")),t=me.test(q.compareDocumentPosition),R=t||me.test(q.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)for(;t=t.parentNode;)if(t===e)return!0;return!1},U=t?function(e,t){if(e===t)return j=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n?n:(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1,1&n||!w.sortDetached&&t.compareDocumentPosition(e)===n?e===H||e.ownerDocument===B&&R(B,e)?-1:t===H||t.ownerDocument===B&&R(B,t)?1:D?ee(D,e)-ee(D,t):0:4&n?-1:1)}:function(e,t){if(e===t)return j=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,s=[e],u=[t];if(!i||!o)return e===H?-1:t===H?1:i?-1:o?1:D?ee(D,e)-ee(D,t):0;if(i===o)return a(e,t);for(n=e;n=n.parentNode;)s.unshift(n);for(n=t;n=n.parentNode;)u.unshift(n);for(;s[r]===u[r];)r++;return r?a(s[r],u[r]):s[r]===B?-1:u[r]===B?1:0},H):H},t.matches=function(e,n){return t(e,null,null,n)},t.matchesSelector=function(e,n){if((e.ownerDocument||e)!==H&&L(e),n=n.replace(ce,"='$1']"),w.matchesSelector&&_&&!X[n+" "]&&(!M||!M.test(n))&&(!F||!F.test(n)))try{var r=O.call(e,n);if(r||w.disconnectedMatch||e.document&&11!==e.document.nodeType)return r}catch(i){}return t(n,H,null,[e]).length>0},t.contains=function(e,t){return(e.ownerDocument||e)!==H&&L(e),R(e,t)},t.attr=function(e,t){(e.ownerDocument||e)!==H&&L(e);var n=T.attrHandle[t.toLowerCase()],r=n&&Y.call(T.attrHandle,t.toLowerCase())?n(e,t,!_):void 0;return void 0!==r?r:w.attributes||!_?e.getAttribute(t):(r=e.getAttributeNode(t))&&r.specified?r.value:null},t.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},t.uniqueSort=function(e){var t,n=[],r=0,i=0;if(j=!w.detectDuplicates,D=!w.sortStable&&e.slice(0),e.sort(U),j){for(;t=e[i++];)t===e[i]&&(r=n.push(i));for(;r--;)e.splice(n[r],1)}return D=null,e},C=t.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+=C(e)}else if(3===i||4===i)return e.nodeValue}else for(;t=e[r++];)n+=C(t);return n},T=t.selectors={cacheLength:50,createPseudo:r,match:pe,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(be,we),e[3]=(e[3]||e[4]||e[5]||"").replace(be,we),"~="===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]||t.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]&&t.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return pe.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&fe.test(n)&&(t=N(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(be,we).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=$[e+" "];return t||(t=new RegExp("(^|"+ne+")"+e+"("+ne+"|$)"))&&$(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,n,r){return function(i){var o=t.attr(i,e);return null==o?"!="===n:!n||(o+="","="===n?o===r:"!="===n?o!==r:"^="===n?r&&0===o.indexOf(r):"*="===n?r&&o.indexOf(r)>-1:"$="===n?r&&o.slice(-r.length)===r:"~="===n?(" "+o.replace(ae," ")+" ").indexOf(r)>-1:"|="===n&&(o===r||o.slice(0,r.length+1)===r+"-"))}},CHILD:function(e,t,n,r,i){var o="nth"!==e.slice(0,3),a="last"!==e.slice(-4),s="of-type"===t;return 1===r&&0===i?function(e){return!!e.parentNode}:function(t,n,u){var l,c,f,d,p,h,g=o!==a?"nextSibling":"previousSibling",m=t.parentNode,y=s&&t.nodeName.toLowerCase(),v=!u&&!s,x=!1;if(m){if(o){for(;g;){for(d=t;d=d[g];)if(s?d.nodeName.toLowerCase()===y:1===d.nodeType)return!1;h=g="only"===e&&!h&&"nextSibling"}return!0}if(h=[a?m.firstChild:m.lastChild],a&&v){for(d=m,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}), -l=c[e]||[],p=l[0]===W&&l[1],x=p&&l[2],d=p&&m.childNodes[p];d=++p&&d&&d[g]||(x=p=0)||h.pop();)if(1===d.nodeType&&++x&&d===t){c[e]=[W,p,x];break}}else if(v&&(d=t,f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),l=c[e]||[],p=l[0]===W&&l[1],x=p),x===!1)for(;(d=++p&&d&&d[g]||(x=p=0)||h.pop())&&((s?d.nodeName.toLowerCase()!==y:1!==d.nodeType)||!++x||(v&&(f=d[P]||(d[P]={}),c=f[d.uniqueID]||(f[d.uniqueID]={}),c[e]=[W,x]),d!==t)););return x-=i,x===r||x%r===0&&x/r>=0}}},PSEUDO:function(e,n){var i,o=T.pseudos[e]||T.setFilters[e.toLowerCase()]||t.error("unsupported pseudo: "+e);return o[P]?o(n):o.length>1?(i=[e,e,"",n],T.setFilters.hasOwnProperty(e.toLowerCase())?r(function(e,t){for(var r,i=o(e,n),a=i.length;a--;)r=ee(e,i[a]),e[r]=!(t[r]=i[a])}):function(e){return o(e,0,i)}):o}},pseudos:{not:r(function(e){var t=[],n=[],i=k(e.replace(se,"$1"));return i[P]?r(function(e,t,n,r){for(var o,a=i(e,null,r,[]),s=e.length;s--;)(o=a[s])&&(e[s]=!(t[s]=o))}):function(e,r,o){return t[0]=e,i(t,null,o,n),t[0]=null,!n.pop()}}),has:r(function(e){return function(n){return t(e,n).length>0}}),contains:r(function(e){return e=e.replace(be,we),function(t){return(t.textContent||t.innerText||C(t)).indexOf(e)>-1}}),lang:r(function(e){return de.test(e||"")||t.error("unsupported lang: "+e),e=e.replace(be,we).toLowerCase(),function(t){var n;do if(n=_?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return n=n.toLowerCase(),n===e||0===n.indexOf(e+"-");while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===q},focus:function(e){return e===H.activeElement&&(!H.hasFocus||H.hasFocus())&&!!(e.type||e.href||~e.tabIndex)},enabled:function(e){return e.disabled===!1},disabled:function(e){return e.disabled===!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,e.selected===!0},empty:function(e){for(e=e.firstChild;e;e=e.nextSibling)if(e.nodeType<6)return!1;return!0},parent:function(e){return!T.pseudos.empty(e)},header:function(e){return ge.test(e.nodeName)},input:function(e){return he.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:l(function(){return[0]}),last:l(function(e,t){return[t-1]}),eq:l(function(e,t,n){return[n<0?n+t:n]}),even:l(function(e,t){for(var n=0;n=0;)e.push(r);return e}),gt:l(function(e,t,n){for(var r=n<0?n+t:n;++r2&&"ID"===(a=o[0]).type&&w.getById&&9===t.nodeType&&_&&T.relative[o[1].type]){if(t=(T.find.ID(a.matches[0].replace(be,we),t)||[])[0],!t)return n;l&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(i=pe.needsContext.test(e)?0:o.length;i--&&(a=o[i],!T.relative[s=a.type]);)if((u=T.find[s])&&(r=u(a.matches[0].replace(be,we),ve.test(o[0].type)&&c(t.parentNode)||t))){if(o.splice(i,1),e=r.length&&d(o),!e)return Q.apply(n,r),n;break}}return(l||k(e,f))(r,t,!_,n,!t||ve.test(e)&&c(t.parentNode)||t),n},w.sortStable=P.split("").sort(U).join("")===P,w.detectDuplicates=!!j,L(),w.sortDetached=i(function(e){return 1&e.compareDocumentPosition(H.createElement("div"))}),i(function(e){return e.innerHTML="","#"===e.firstChild.getAttribute("href")})||o("type|href|height|width",function(e,t,n){if(!n)return e.getAttribute(t,"type"===t.toLowerCase()?1:2)}),w.attributes&&i(function(e){return e.innerHTML="",e.firstChild.setAttribute("value",""),""===e.firstChild.getAttribute("value")})||o("value",function(e,t,n){if(!n&&"input"===e.nodeName.toLowerCase())return e.defaultValue}),i(function(e){return null==e.getAttribute("disabled")})||o(te,function(e,t,n){var r;if(!n)return e[t]===!0?t.toLowerCase():(r=e.getAttributeNode(t))&&r.specified?r.value:null}),t}(e);pe.find=ve,pe.expr=ve.selectors,pe.expr[":"]=pe.expr.pseudos,pe.uniqueSort=pe.unique=ve.uniqueSort,pe.text=ve.getText,pe.isXMLDoc=ve.isXML,pe.contains=ve.contains;var xe=function(e,t,n){for(var r=[],i=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(i&&pe(e).is(n))break;r.push(e)}return r},be=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},we=pe.expr.match.needsContext,Te=/^<([\w-]+)\s*\/?>(?:<\/\1>|)$/,Ce=/^.[^:#\[\.,]*$/;pe.filter=function(e,t,n){var r=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===r.nodeType?pe.find.matchesSelector(r,e)?[r]:[]:pe.find.matches(e,pe.grep(t,function(e){return 1===e.nodeType}))},pe.fn.extend({find:function(e){var t,n=[],r=this,i=r.length;if("string"!=typeof e)return this.pushStack(pe(e).filter(function(){for(t=0;t1?pe.unique(n):n),n.selector=this.selector?this.selector+" "+e:e,n},filter:function(e){return this.pushStack(r(this,e||[],!1))},not:function(e){return this.pushStack(r(this,e||[],!0))},is:function(e){return!!r(this,"string"==typeof e&&we.test(e)?pe(e):e||[],!1).length}});var Ee,Ne=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/,ke=pe.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||Ee,"string"==typeof e){if(r="<"===e.charAt(0)&&">"===e.charAt(e.length-1)&&e.length>=3?[null,e,null]:Ne.exec(e),!r||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof pe?t[0]:t,pe.merge(this,pe.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:re,!0)),Te.test(r[1])&&pe.isPlainObject(t))for(r in t)pe.isFunction(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}if(i=re.getElementById(r[2]),i&&i.parentNode){if(i.id!==r[2])return Ee.find(e);this.length=1,this[0]=i}return this.context=re,this.selector=e,this}return e.nodeType?(this.context=this[0]=e,this.length=1,this):pe.isFunction(e)?"undefined"!=typeof n.ready?n.ready(e):e(pe):(void 0!==e.selector&&(this.selector=e.selector,this.context=e.context),pe.makeArray(e,this))};ke.prototype=pe.fn,Ee=pe(re);var Se=/^(?:parents|prev(?:Until|All))/,Ae={children:!0,contents:!0,next:!0,prev:!0};pe.fn.extend({has:function(e){var t,n=pe(e,this),r=n.length;return this.filter(function(){for(t=0;t-1:1===n.nodeType&&pe.find.matchesSelector(n,e))){o.push(n);break}return this.pushStack(o.length>1?pe.uniqueSort(o):o)},index:function(e){return e?"string"==typeof e?pe.inArray(this[0],pe(e)):pe.inArray(e.jquery?e[0]:e,this):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(pe.uniqueSort(pe.merge(this.get(),pe(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),pe.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return xe(e,"parentNode")},parentsUntil:function(e,t,n){return xe(e,"parentNode",n)},next:function(e){return i(e,"nextSibling")},prev:function(e){return i(e,"previousSibling")},nextAll:function(e){return xe(e,"nextSibling")},prevAll:function(e){return xe(e,"previousSibling")},nextUntil:function(e,t,n){return xe(e,"nextSibling",n)},prevUntil:function(e,t,n){return xe(e,"previousSibling",n)},siblings:function(e){return be((e.parentNode||{}).firstChild,e)},children:function(e){return be(e.firstChild)},contents:function(e){return pe.nodeName(e,"iframe")?e.contentDocument||e.contentWindow.document:pe.merge([],e.childNodes)}},function(e,t){pe.fn[e]=function(n,r){var i=pe.map(this,t,n);return"Until"!==e.slice(-5)&&(r=n),r&&"string"==typeof r&&(i=pe.filter(r,i)),this.length>1&&(Ae[e]||(i=pe.uniqueSort(i)),Se.test(e)&&(i=i.reverse())),this.pushStack(i)}});var De=/\S+/g;pe.Callbacks=function(e){e="string"==typeof e?o(e):pe.extend({},e);var t,n,r,i,a=[],s=[],u=-1,l=function(){for(i=e.once,r=t=!0;s.length;u=-1)for(n=s.shift();++u-1;)a.splice(n,1),n<=u&&u--}),this},has:function(e){return e?pe.inArray(e,a)>-1:a.length>0},empty:function(){return a&&(a=[]),this},disable:function(){return i=s=[],a=n="",this},disabled:function(){return!a},lock:function(){return i=!0,n||c.disable(),this},locked:function(){return!!i},fireWith:function(e,n){return i||(n=n||[],n=[e,n.slice?n.slice():n],s.push(n),t||l()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!r}};return c},pe.extend({Deferred:function(e){var t=[["resolve","done",pe.Callbacks("once memory"),"resolved"],["reject","fail",pe.Callbacks("once memory"),"rejected"],["notify","progress",pe.Callbacks("memory")]],n="pending",r={state:function(){return n},always:function(){return i.done(arguments).fail(arguments),this},then:function(){var e=arguments;return pe.Deferred(function(n){pe.each(t,function(t,o){var a=pe.isFunction(e[t])&&e[t];i[o[1]](function(){var e=a&&a.apply(this,arguments);e&&pe.isFunction(e.promise)?e.promise().progress(n.notify).done(n.resolve).fail(n.reject):n[o[0]+"With"](this===r?n.promise():this,a?[e]:arguments)})}),e=null}).promise()},promise:function(e){return null!=e?pe.extend(e,r):r}},i={};return r.pipe=r.then,pe.each(t,function(e,o){var a=o[2],s=o[3];r[o[1]]=a.add,s&&a.add(function(){n=s},t[1^e][2].disable,t[2][2].lock),i[o[0]]=function(){return i[o[0]+"With"](this===i?r:this,arguments),this},i[o[0]+"With"]=a.fireWith}),r.promise(i),e&&e.call(i,i),i},when:function(e){var t,n,r,i=0,o=ie.call(arguments),a=o.length,s=1!==a||e&&pe.isFunction(e.promise)?a:0,u=1===s?e:pe.Deferred(),l=function(e,n,r){return function(i){n[e]=this,r[e]=arguments.length>1?ie.call(arguments):i,r===t?u.notifyWith(n,r):--s||u.resolveWith(n,r)}};if(a>1)for(t=new Array(a),n=new Array(a),r=new Array(a);i0||(je.resolveWith(re,[pe]),pe.fn.triggerHandler&&(pe(re).triggerHandler("ready"),pe(re).off("ready"))))}}),pe.ready.promise=function(t){if(!je)if(je=pe.Deferred(),"complete"===re.readyState||"loading"!==re.readyState&&!re.documentElement.doScroll)e.setTimeout(pe.ready);else if(re.addEventListener)re.addEventListener("DOMContentLoaded",s),e.addEventListener("load",s);else{re.attachEvent("onreadystatechange",s),e.attachEvent("onload",s);var n=!1;try{n=null==e.frameElement&&re.documentElement}catch(r){}n&&n.doScroll&&!function i(){if(!pe.isReady){try{n.doScroll("left")}catch(t){return e.setTimeout(i,50)}a(),pe.ready()}}()}return je.promise(t)},pe.ready.promise();var Le;for(Le in pe(fe))break;fe.ownFirst="0"===Le,fe.inlineBlockNeedsLayout=!1,pe(function(){var e,t,n,r;n=re.getElementsByTagName("body")[0],n&&n.style&&(t=re.createElement("div"),r=re.createElement("div"),r.style.cssText="position:absolute;border:0;width:0;height:0;top:0;left:-9999px",n.appendChild(r).appendChild(t),"undefined"!=typeof t.style.zoom&&(t.style.cssText="display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1",fe.inlineBlockNeedsLayout=e=3===t.offsetWidth,e&&(n.style.zoom=1)),n.removeChild(r))}),function(){var e=re.createElement("div");fe.deleteExpando=!0;try{delete e.test}catch(t){fe.deleteExpando=!1}e=null}();var He=function(e){var t=pe.noData[(e.nodeName+" ").toLowerCase()],n=+e.nodeType||1;return(1===n||9===n)&&(!t||t!==!0&&e.getAttribute("classid")===t)},qe=/^(?:\{[\w\W]*\}|\[[\w\W]*\])$/,_e=/([A-Z])/g;pe.extend({cache:{},noData:{"applet ":!0,"embed ":!0,"object ":"clsid:D27CDB6E-AE6D-11cf-96B8-444553540000"},hasData:function(e){return e=e.nodeType?pe.cache[e[pe.expando]]:e[pe.expando],!!e&&!l(e)},data:function(e,t,n){return c(e,t,n)},removeData:function(e,t){return f(e,t)},_data:function(e,t,n){return c(e,t,n,!0)},_removeData:function(e,t){return f(e,t,!0)}}),pe.fn.extend({data:function(e,t){var n,r,i,o=this[0],a=o&&o.attributes;if(void 0===e){if(this.length&&(i=pe.data(o),1===o.nodeType&&!pe._data(o,"parsedAttrs"))){for(n=a.length;n--;)a[n]&&(r=a[n].name,0===r.indexOf("data-")&&(r=pe.camelCase(r.slice(5)),u(o,r,i[r])));pe._data(o,"parsedAttrs",!0)}return i}return"object"==typeof e?this.each(function(){pe.data(this,e)}):arguments.length>1?this.each(function(){pe.data(this,e,t)}):o?u(o,e,pe.data(o,e)):void 0},removeData:function(e){return this.each(function(){pe.removeData(this,e)})}}),pe.extend({queue:function(e,t,n){var r;if(e)return t=(t||"fx")+"queue",r=pe._data(e,t),n&&(!r||pe.isArray(n)?r=pe._data(e,t,pe.makeArray(n)):r.push(n)),r||[]},dequeue:function(e,t){t=t||"fx";var n=pe.queue(e,t),r=n.length,i=n.shift(),o=pe._queueHooks(e,t),a=function(){pe.dequeue(e,t)};"inprogress"===i&&(i=n.shift(),r--),i&&("fx"===t&&n.unshift("inprogress"),delete o.stop,i.call(e,a,o)),!r&&o&&o.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return pe._data(e,n)||pe._data(e,n,{empty:pe.Callbacks("once memory").add(function(){pe._removeData(e,t+"queue"),pe._removeData(e,n)})})}}),pe.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length
        a",fe.leadingWhitespace=3===e.firstChild.nodeType,fe.tbody=!e.getElementsByTagName("tbody").length,fe.htmlSerialize=!!e.getElementsByTagName("link").length,fe.html5Clone="<:nav>"!==re.createElement("nav").cloneNode(!0).outerHTML,n.type="checkbox",n.checked=!0,t.appendChild(n),fe.appendChecked=n.checked,e.innerHTML="",fe.noCloneChecked=!!e.cloneNode(!0).lastChild.defaultValue,t.appendChild(e),n=re.createElement("input"),n.setAttribute("type","radio"),n.setAttribute("checked","checked"),n.setAttribute("name","t"),e.appendChild(n),fe.checkClone=e.cloneNode(!0).cloneNode(!0).lastChild.checked,fe.noCloneEvent=!!e.addEventListener,e[pe.expando]=1,fe.attributes=!e.getAttribute(pe.expando)}();var Xe={option:[1,""],legend:[1,"
        ","
        "],area:[1,"",""],param:[1,"",""],thead:[1,"","
        "],tr:[2,"","
        "],col:[2,"","
        "],td:[3,"","
        "],_default:fe.htmlSerialize?[0,"",""]:[1,"X
        ","
        "]};Xe.optgroup=Xe.option,Xe.tbody=Xe.tfoot=Xe.colgroup=Xe.caption=Xe.thead,Xe.th=Xe.td;var Ue=/<|&#?\w+;/,Ve=/-1&&(h=p.split("."),p=h.shift(),h.sort()),a=p.indexOf(":")<0&&"on"+p,t=t[pe.expando]?t:new pe.Event(p,"object"==typeof t&&t),t.isTrigger=i?2:3,t.namespace=h.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=r),n=null==n?[t]:pe.makeArray(n,[t]),l=pe.event.special[p]||{},i||!l.trigger||l.trigger.apply(r,n)!==!1)){if(!i&&!l.noBubble&&!pe.isWindow(r)){for(u=l.delegateType||p,Ke.test(u+p)||(s=s.parentNode);s;s=s.parentNode)d.push(s),c=s;c===(r.ownerDocument||re)&&d.push(c.defaultView||c.parentWindow||e)}for(f=0;(s=d[f++])&&!t.isPropagationStopped();)t.type=f>1?u:l.bindType||p,o=(pe._data(s,"events")||{})[t.type]&&pe._data(s,"handle"),o&&o.apply(s,n),o=a&&s[a],o&&o.apply&&He(s)&&(t.result=o.apply(s,n),t.result===!1&&t.preventDefault());if(t.type=p,!i&&!t.isDefaultPrevented()&&(!l._default||l._default.apply(d.pop(),n)===!1)&&He(r)&&a&&r[p]&&!pe.isWindow(r)){c=r[a],c&&(r[a]=null),pe.event.triggered=p;try{r[p]()}catch(g){}pe.event.triggered=void 0,c&&(r[a]=c)}return t.result}},dispatch:function(e){e=pe.event.fix(e);var t,n,r,i,o,a=[],s=ie.call(arguments),u=(pe._data(this,"events")||{})[e.type]||[],l=pe.event.special[e.type]||{};if(s[0]=e,e.delegateTarget=this,!l.preDispatch||l.preDispatch.call(this,e)!==!1){for(a=pe.event.handlers.call(this,e,u),t=0;(i=a[t++])&&!e.isPropagationStopped();)for(e.currentTarget=i.elem,n=0;(o=i.handlers[n++])&&!e.isImmediatePropagationStopped();)e.rnamespace&&!e.rnamespace.test(o.namespace)||(e.handleObj=o,e.data=o.data,r=((pe.event.special[o.origType]||{}).handle||o.handler).apply(i.elem,s),void 0!==r&&(e.result=r)===!1&&(e.preventDefault(),e.stopPropagation()));return l.postDispatch&&l.postDispatch.call(this,e),e.result}},handlers:function(e,t){var n,r,i,o,a=[],s=t.delegateCount,u=e.target;if(s&&u.nodeType&&("click"!==e.type||isNaN(e.button)||e.button<1))for(;u!=this;u=u.parentNode||this)if(1===u.nodeType&&(u.disabled!==!0||"click"!==e.type)){for(r=[],n=0;n-1:pe.find(i,this,null,[u]).length),r[i]&&r.push(o);r.length&&a.push({elem:u,handlers:r})}return s]","i"),tt=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi,nt=/\s*$/g,at=p(re),st=at.appendChild(re.createElement("div"));pe.extend({htmlPrefilter:function(e){return e.replace(tt,"<$1>")},clone:function(e,t,n){var r,i,o,a,s,u=pe.contains(e.ownerDocument,e);if(fe.html5Clone||pe.isXMLDoc(e)||!et.test("<"+e.nodeName+">")?o=e.cloneNode(!0):(st.innerHTML=e.outerHTML,st.removeChild(o=st.firstChild)),!(fe.noCloneEvent&&fe.noCloneChecked||1!==e.nodeType&&11!==e.nodeType||pe.isXMLDoc(e)))for(r=h(o),s=h(e),a=0;null!=(i=s[a]);++a)r[a]&&k(i,r[a]);if(t)if(n)for(s=s||h(e),r=r||h(o),a=0;null!=(i=s[a]);a++)N(i,r[a]);else N(e,o);return r=h(o,"script"),r.length>0&&g(r,!u&&h(e,"script")),r=s=i=null,o},cleanData:function(e,t){for(var n,r,i,o,a=0,s=pe.expando,u=pe.cache,l=fe.attributes,c=pe.event.special;null!=(n=e[a]);a++)if((t||He(n))&&(i=n[s],o=i&&u[i])){if(o.events)for(r in o.events)c[r]?pe.event.remove(n,r):pe.removeEvent(n,r,o.handle);u[i]&&(delete u[i],l||"undefined"==typeof n.removeAttribute?n[s]=void 0:n.removeAttribute(s),ne.push(i))}}}),pe.fn.extend({domManip:S,detach:function(e){return A(this,e,!0)},remove:function(e){return A(this,e)},text:function(e){return Pe(this,function(e){return void 0===e?pe.text(this):this.empty().append((this[0]&&this[0].ownerDocument||re).createTextNode(e))},null,e,arguments.length)},append:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.appendChild(e)}})},prepend:function(){return S(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=T(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return S(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this.nextSibling)})},empty:function(){for(var e,t=0;null!=(e=this[t]);t++){for(1===e.nodeType&&pe.cleanData(h(e,!1));e.firstChild;)e.removeChild(e.firstChild);e.options&&pe.nodeName(e,"select")&&(e.options.length=0)}return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return pe.clone(this,e,t)})},html:function(e){return Pe(this,function(e){var t=this[0]||{},n=0,r=this.length;if(void 0===e)return 1===t.nodeType?t.innerHTML.replace(Ze,""):void 0;if("string"==typeof e&&!nt.test(e)&&(fe.htmlSerialize||!et.test(e))&&(fe.leadingWhitespace||!$e.test(e))&&!Xe[(We.exec(e)||["",""])[1].toLowerCase()]){e=pe.htmlPrefilter(e);try{for(;nt",t=l.getElementsByTagName("td"),t[0].style.cssText="margin:0;border:0;padding:0;display:none",o=0===t[0].offsetHeight,o&&(t[0].style.display="",t[1].style.display="none",o=0===t[0].offsetHeight)),f.removeChild(u)}var n,r,i,o,a,s,u=re.createElement("div"),l=re.createElement("div");l.style&&(l.style.cssText="float:left;opacity:.5",fe.opacity="0.5"===l.style.opacity,fe.cssFloat=!!l.style.cssFloat,l.style.backgroundClip="content-box",l.cloneNode(!0).style.backgroundClip="",fe.clearCloneStyle="content-box"===l.style.backgroundClip,u=re.createElement("div"),u.style.cssText="border:0;width:8px;height:0;top:0;left:-9999px;padding:0;margin-top:1px;position:absolute",l.innerHTML="",u.appendChild(l),fe.boxSizing=""===l.style.boxSizing||""===l.style.MozBoxSizing||""===l.style.WebkitBoxSizing,pe.extend(fe,{reliableHiddenOffsets:function(){return null==n&&t(),o},boxSizingReliable:function(){return null==n&&t(),i},pixelMarginRight:function(){return null==n&&t(),r},pixelPosition:function(){return null==n&&t(),n},reliableMarginRight:function(){return null==n&&t(),a},reliableMarginLeft:function(){return null==n&&t(),s}}))}();var ht,gt,mt=/^(top|right|bottom|left)$/;e.getComputedStyle?(ht=function(t){var n=t.ownerDocument.defaultView;return n&&n.opener||(n=e),n.getComputedStyle(t)},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n.getPropertyValue(t)||n[t]:void 0,""!==a&&void 0!==a||pe.contains(e.ownerDocument,e)||(a=pe.style(e,t)),n&&!fe.pixelMarginRight()&&ft.test(a)&&ct.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+""}):pt.currentStyle&&(ht=function(e){return e.currentStyle},gt=function(e,t,n){var r,i,o,a,s=e.style;return n=n||ht(e),a=n?n[t]:void 0,null==a&&s&&s[t]&&(a=s[t]),ft.test(a)&&!mt.test(t)&&(r=s.left,i=e.runtimeStyle,o=i&&i.left,o&&(i.left=e.currentStyle.left),s.left="fontSize"===t?"1em":a,a=s.pixelLeft+"px",s.left=r,o&&(i.left=o)),void 0===a?a:a+""||"auto"});var yt=/alpha\([^)]*\)/i,vt=/opacity\s*=\s*([^)]*)/i,xt=/^(none|table(?!-c[ea]).+)/,bt=new RegExp("^("+Fe+")(.*)$","i"),wt={position:"absolute",visibility:"hidden",display:"block"},Tt={letterSpacing:"0",fontWeight:"400"},Ct=["Webkit","O","Moz","ms"],Et=re.createElement("div").style;pe.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=gt(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,columnCount:!0,fillOpacity:!0,flexGrow:!0,flexShrink:!0,fontWeight:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,widows:!0,zIndex:!0,zoom:!0},cssProps:{"float":fe.cssFloat?"cssFloat":"styleFloat"},style:function(e,t,n,r){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var i,o,a,s=pe.camelCase(t),u=e.style;if(t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],void 0===n)return a&&"get"in a&&void 0!==(i=a.get(e,!1,r))?i:u[t];if(o=typeof n,"string"===o&&(i=Me.exec(n))&&i[1]&&(n=d(e,t,i),o="number"),null!=n&&n===n&&("number"===o&&(n+=i&&i[3]||(pe.cssNumber[s]?"":"px")),fe.clearCloneStyle||""!==n||0!==t.indexOf("background")||(u[t]="inherit"),!(a&&"set"in a&&void 0===(n=a.set(e,n,r)))))try{u[t]=n}catch(l){}}},css:function(e,t,n,r){var i,o,a,s=pe.camelCase(t);return t=pe.cssProps[s]||(pe.cssProps[s]=H(s)||s),a=pe.cssHooks[t]||pe.cssHooks[s],a&&"get"in a&&(o=a.get(e,!0,n)),void 0===o&&(o=gt(e,t,r)),"normal"===o&&t in Tt&&(o=Tt[t]),""===n||n?(i=parseFloat(o),n===!0||isFinite(i)?i||0:o):o}}),pe.each(["height","width"],function(e,t){pe.cssHooks[t]={get:function(e,n,r){if(n)return xt.test(pe.css(e,"display"))&&0===e.offsetWidth?dt(e,wt,function(){return M(e,t,r)}):M(e,t,r)},set:function(e,n,r){var i=r&&ht(e);return _(e,n,r?F(e,t,r,fe.boxSizing&&"border-box"===pe.css(e,"boxSizing",!1,i),i):0)}}}),fe.opacity||(pe.cssHooks.opacity={get:function(e,t){return vt.test((t&&e.currentStyle?e.currentStyle.filter:e.style.filter)||"")?.01*parseFloat(RegExp.$1)+"":t?"1":""},set:function(e,t){var n=e.style,r=e.currentStyle,i=pe.isNumeric(t)?"alpha(opacity="+100*t+")":"",o=r&&r.filter||n.filter||"";n.zoom=1,(t>=1||""===t)&&""===pe.trim(o.replace(yt,""))&&n.removeAttribute&&(n.removeAttribute("filter"),""===t||r&&!r.filter)||(n.filter=yt.test(o)?o.replace(yt,i):o+" "+i)}}),pe.cssHooks.marginRight=L(fe.reliableMarginRight,function(e,t){if(t)return dt(e,{display:"inline-block"},gt,[e,"marginRight"])}),pe.cssHooks.marginLeft=L(fe.reliableMarginLeft,function(e,t){if(t)return(parseFloat(gt(e,"marginLeft"))||(pe.contains(e.ownerDocument,e)?e.getBoundingClientRect().left-dt(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}):0))+"px"}),pe.each({margin:"",padding:"",border:"Width"},function(e,t){pe.cssHooks[e+t]={expand:function(n){for(var r=0,i={},o="string"==typeof n?n.split(" "):[n];r<4;r++)i[e+Oe[r]+t]=o[r]||o[r-2]||o[0];return i}},ct.test(e)||(pe.cssHooks[e+t].set=_)}),pe.fn.extend({css:function(e,t){return Pe(this,function(e,t,n){var r,i,o={},a=0;if(pe.isArray(t)){for(r=ht(e),i=t.length;a1)},show:function(){return q(this,!0)},hide:function(){return q(this)},toggle:function(e){return"boolean"==typeof e?e?this.show():this.hide():this.each(function(){Re(this)?pe(this).show():pe(this).hide()})}}),pe.Tween=O,O.prototype={constructor:O,init:function(e,t,n,r,i,o){this.elem=e,this.prop=n,this.easing=i||pe.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=r,this.unit=o||(pe.cssNumber[n]?"":"px")},cur:function(){var e=O.propHooks[this.prop];return e&&e.get?e.get(this):O.propHooks._default.get(this)},run:function(e){var t,n=O.propHooks[this.prop];return this.options.duration?this.pos=t=pe.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):O.propHooks._default.set(this),this}},O.prototype.init.prototype=O.prototype,O.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=pe.css(e.elem,e.prop,""),t&&"auto"!==t?t:0)},set:function(e){pe.fx.step[e.prop]?pe.fx.step[e.prop](e):1!==e.elem.nodeType||null==e.elem.style[pe.cssProps[e.prop]]&&!pe.cssHooks[e.prop]?e.elem[e.prop]=e.now:pe.style(e.elem,e.prop,e.now+e.unit)}}},O.propHooks.scrollTop=O.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},pe.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},pe.fx=O.prototype.init,pe.fx.step={};var Nt,kt,St=/^(?:toggle|show|hide)$/,At=/queueHooks$/;pe.Animation=pe.extend($,{tweeners:{"*":[function(e,t){var n=this.createTween(e,t);return d(n.elem,e,Me.exec(t),n),n}]},tweener:function(e,t){pe.isFunction(e)?(t=e,e=["*"]):e=e.match(De);for(var n,r=0,i=e.length;r
        a",e=n.getElementsByTagName("a")[0],t.setAttribute("type","checkbox"),n.appendChild(t),e=n.getElementsByTagName("a")[0],e.style.cssText="top:1px",fe.getSetAttribute="t"!==n.className,fe.style=/top/.test(e.getAttribute("style")),fe.hrefNormalized="/a"===e.getAttribute("href"),fe.checkOn=!!t.value,fe.optSelected=i.selected,fe.enctype=!!re.createElement("form").enctype,r.disabled=!0,fe.optDisabled=!i.disabled,t=re.createElement("input"),t.setAttribute("value",""),fe.input=""===t.getAttribute("value"),t.value="t",t.setAttribute("type","radio"),fe.radioValue="t"===t.value}();var Dt=/\r/g,jt=/[\x20\t\r\n\f]+/g;pe.fn.extend({val:function(e){var t,n,r,i=this[0];{if(arguments.length)return r=pe.isFunction(e),this.each(function(n){var i;1===this.nodeType&&(i=r?e.call(this,n,pe(this).val()):e,null==i?i="":"number"==typeof i?i+="":pe.isArray(i)&&(i=pe.map(i,function(e){return null==e?"":e+""})),t=pe.valHooks[this.type]||pe.valHooks[this.nodeName.toLowerCase()],t&&"set"in t&&void 0!==t.set(this,i,"value")||(this.value=i))});if(i)return t=pe.valHooks[i.type]||pe.valHooks[i.nodeName.toLowerCase()],t&&"get"in t&&void 0!==(n=t.get(i,"value"))?n:(n=i.value,"string"==typeof n?n.replace(Dt,""):null==n?"":n)}}}),pe.extend({valHooks:{option:{get:function(e){var t=pe.find.attr(e,"value");return null!=t?t:pe.trim(pe.text(e)).replace(jt," ")}},select:{get:function(e){for(var t,n,r=e.options,i=e.selectedIndex,o="select-one"===e.type||i<0,a=o?null:[],s=o?i+1:r.length,u=i<0?s:o?i:0;u-1)try{r.selected=n=!0}catch(s){r.scrollHeight}else r.selected=!1;return n||(e.selectedIndex=-1),i}}}}),pe.each(["radio","checkbox"],function(){pe.valHooks[this]={set:function(e,t){if(pe.isArray(t))return e.checked=pe.inArray(pe(e).val(),t)>-1}},fe.checkOn||(pe.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var Lt,Ht,qt=pe.expr.attrHandle,_t=/^(?:checked|selected)$/i,Ft=fe.getSetAttribute,Mt=fe.input;pe.fn.extend({attr:function(e,t){return Pe(this,pe.attr,e,t,arguments.length>1)},removeAttr:function(e){return this.each(function(){pe.removeAttr(this,e)})}}),pe.extend({attr:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return"undefined"==typeof e.getAttribute?pe.prop(e,t,n):(1===o&&pe.isXMLDoc(e)||(t=t.toLowerCase(),i=pe.attrHooks[t]||(pe.expr.match.bool.test(t)?Ht:Lt)),void 0!==n?null===n?void pe.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:(r=pe.find.attr(e,t),null==r?void 0:r))},attrHooks:{type:{set:function(e,t){if(!fe.radioValue&&"radio"===t&&pe.nodeName(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,r,i=0,o=t&&t.match(De);if(o&&1===e.nodeType)for(;n=o[i++];)r=pe.propFix[n]||n,pe.expr.match.bool.test(n)?Mt&&Ft||!_t.test(n)?e[r]=!1:e[pe.camelCase("default-"+n)]=e[r]=!1:pe.attr(e,n,""),e.removeAttribute(Ft?n:r)}}),Ht={set:function(e,t,n){return t===!1?pe.removeAttr(e,n):Mt&&Ft||!_t.test(n)?e.setAttribute(!Ft&&pe.propFix[n]||n,n):e[pe.camelCase("default-"+n)]=e[n]=!0,n}},pe.each(pe.expr.match.bool.source.match(/\w+/g),function(e,t){var n=qt[t]||pe.find.attr;Mt&&Ft||!_t.test(t)?qt[t]=function(e,t,r){var i,o;return r||(o=qt[t],qt[t]=i,i=null!=n(e,t,r)?t.toLowerCase():null,qt[t]=o),i}:qt[t]=function(e,t,n){if(!n)return e[pe.camelCase("default-"+t)]?t.toLowerCase():null}}),Mt&&Ft||(pe.attrHooks.value={set:function(e,t,n){return pe.nodeName(e,"input")?void(e.defaultValue=t):Lt&&Lt.set(e,t,n)}}),Ft||(Lt={set:function(e,t,n){var r=e.getAttributeNode(n);if(r||e.setAttributeNode(r=e.ownerDocument.createAttribute(n)),r.value=t+="","value"===n||t===e.getAttribute(n))return t}},qt.id=qt.name=qt.coords=function(e,t,n){var r;if(!n)return(r=e.getAttributeNode(t))&&""!==r.value?r.value:null},pe.valHooks.button={get:function(e,t){var n=e.getAttributeNode(t);if(n&&n.specified)return n.value},set:Lt.set},pe.attrHooks.contenteditable={set:function(e,t,n){Lt.set(e,""!==t&&t,n)}},pe.each(["width","height"],function(e,t){pe.attrHooks[t]={set:function(e,n){if(""===n)return e.setAttribute(t,"auto"),n}}})),fe.style||(pe.attrHooks.style={get:function(e){return e.style.cssText||void 0},set:function(e,t){return e.style.cssText=t+""}});var Ot=/^(?:input|select|textarea|button|object)$/i,Rt=/^(?:a|area)$/i;pe.fn.extend({prop:function(e,t){return Pe(this,pe.prop,e,t,arguments.length>1)},removeProp:function(e){return e=pe.propFix[e]||e,this.each(function(){try{this[e]=void 0,delete this[e]}catch(t){}})}}),pe.extend({prop:function(e,t,n){var r,i,o=e.nodeType;if(3!==o&&8!==o&&2!==o)return 1===o&&pe.isXMLDoc(e)||(t=pe.propFix[t]||t,i=pe.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=pe.find.attr(e,"tabindex");return t?parseInt(t,10):Ot.test(e.nodeName)||Rt.test(e.nodeName)&&e.href?0:-1}}},propFix:{"for":"htmlFor","class":"className"}}),fe.hrefNormalized||pe.each(["href","src"],function(e,t){pe.propHooks[t]={get:function(e){return e.getAttribute(t,4)}}}),fe.optSelected||(pe.propHooks.selected={get:function(e){var t=e.parentNode;return t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex),null},set:function(e){var t=e.parentNode;t&&(t.selectedIndex,t.parentNode&&t.parentNode.selectedIndex)}}),pe.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){pe.propFix[this.toLowerCase()]=this}),fe.enctype||(pe.propFix.enctype="encoding");var Pt=/[\t\r\n\f]/g;pe.fn.extend({addClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).addClass(e.call(this,t,z(this)))});if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)r.indexOf(" "+o+" ")<0&&(r+=o+" ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},removeClass:function(e){var t,n,r,i,o,a,s,u=0;if(pe.isFunction(e))return this.each(function(t){pe(this).removeClass(e.call(this,t,z(this)))});if(!arguments.length)return this.attr("class","");if("string"==typeof e&&e)for(t=e.match(De)||[];n=this[u++];)if(i=z(n),r=1===n.nodeType&&(" "+i+" ").replace(Pt," ")){for(a=0;o=t[a++];)for(;r.indexOf(" "+o+" ")>-1;)r=r.replace(" "+o+" "," ");s=pe.trim(r),i!==s&&pe.attr(n,"class",s)}return this},toggleClass:function(e,t){var n=typeof e;return"boolean"==typeof t&&"string"===n?t?this.addClass(e):this.removeClass(e):pe.isFunction(e)?this.each(function(n){pe(this).toggleClass(e.call(this,n,z(this),t),t)}):this.each(function(){var t,r,i,o;if("string"===n)for(r=0,i=pe(this),o=e.match(De)||[];t=o[r++];)i.hasClass(t)?i.removeClass(t):i.addClass(t);else void 0!==e&&"boolean"!==n||(t=z(this),t&&pe._data(this,"__className__",t),pe.attr(this,"class",t||e===!1?"":pe._data(this,"__className__")||""))})},hasClass:function(e){var t,n,r=0;for(t=" "+e+" ";n=this[r++];)if(1===n.nodeType&&(" "+z(n)+" ").replace(Pt," ").indexOf(t)>-1)return!0;return!1}}),pe.each("blur focus focusin focusout load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup error contextmenu".split(" "),function(e,t){pe.fn[t]=function(e,n){return arguments.length>0?this.on(t,null,e,n):this.trigger(t)}}),pe.fn.extend({hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}});var Bt=e.location,Wt=pe.now(),It=/\?/,$t=/(,)|(\[|{)|(}|])|"(?:[^"\\\r\n]|\\["\\\/bfnrt]|\\u[\da-fA-F]{4})*"\s*:?|true|false|null|-?(?!0\d)\d+(?:\.\d+|)(?:[eE][+-]?\d+|)/g;pe.parseJSON=function(t){if(e.JSON&&e.JSON.parse)return e.JSON.parse(t+"");var n,r=null,i=pe.trim(t+"");return i&&!pe.trim(i.replace($t,function(e,t,i,o){return n&&t&&(r=0),0===r?e:(n=i||t,r+=!o-!i,"")}))?Function("return "+i)():pe.error("Invalid JSON: "+t)},pe.parseXML=function(t){var n,r;if(!t||"string"!=typeof t)return null;try{e.DOMParser?(r=new e.DOMParser,n=r.parseFromString(t,"text/xml")):(n=new e.ActiveXObject("Microsoft.XMLDOM"),n.async="false",n.loadXML(t))}catch(i){n=void 0}return n&&n.documentElement&&!n.getElementsByTagName("parsererror").length||pe.error("Invalid XML: "+t),n};var zt=/#.*$/,Xt=/([?&])_=[^&]*/,Ut=/^(.*?):[ \t]*([^\r\n]*)\r?$/gm,Vt=/^(?:about|app|app-storage|.+-extension|file|res|widget):$/,Yt=/^(?:GET|HEAD)$/,Jt=/^\/\//,Gt=/^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,Kt={},Qt={},Zt="*/".concat("*"),en=Bt.href,tn=Gt.exec(en.toLowerCase())||[];pe.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:en,type:"GET",isLocal:Vt.test(tn[1]),global:!0,processData:!0,async:!0,contentType:"application/x-www-form-urlencoded; charset=UTF-8",accepts:{"*":Zt,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":pe.parseJSON,"text xml":pe.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?V(V(e,pe.ajaxSettings),t):V(pe.ajaxSettings,e)},ajaxPrefilter:X(Kt),ajaxTransport:X(Qt),ajax:function(t,n){function r(t,n,r,i){var o,f,v,x,w,C=n;2!==b&&(b=2,u&&e.clearTimeout(u),c=void 0,s=i||"",T.readyState=t>0?4:0,o=t>=200&&t<300||304===t,r&&(x=Y(d,T,r)),x=J(d,x,T,o),o?(d.ifModified&&(w=T.getResponseHeader("Last-Modified"),w&&(pe.lastModified[a]=w),w=T.getResponseHeader("etag"),w&&(pe.etag[a]=w)),204===t||"HEAD"===d.type?C="nocontent":304===t?C="notmodified":(C=x.state,f=x.data,v=x.error,o=!v)):(v=C,!t&&C||(C="error",t<0&&(t=0))),T.status=t,T.statusText=(n||C)+"",o?g.resolveWith(p,[f,C,T]):g.rejectWith(p,[T,C,v]),T.statusCode(y),y=void 0,l&&h.trigger(o?"ajaxSuccess":"ajaxError",[T,d,o?f:v]),m.fireWith(p,[T,C]),l&&(h.trigger("ajaxComplete",[T,d]),--pe.active||pe.event.trigger("ajaxStop")))}"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,o,a,s,u,l,c,f,d=pe.ajaxSetup({},n),p=d.context||d,h=d.context&&(p.nodeType||p.jquery)?pe(p):pe.event,g=pe.Deferred(),m=pe.Callbacks("once memory"),y=d.statusCode||{},v={},x={},b=0,w="canceled",T={readyState:0,getResponseHeader:function(e){var t;if(2===b){if(!f)for(f={};t=Ut.exec(s);)f[t[1].toLowerCase()]=t[2];t=f[e.toLowerCase()]}return null==t?null:t},getAllResponseHeaders:function(){return 2===b?s:null},setRequestHeader:function(e,t){var n=e.toLowerCase();return b||(e=x[n]=x[n]||e,v[e]=t),this},overrideMimeType:function(e){return b||(d.mimeType=e),this},statusCode:function(e){var t;if(e)if(b<2)for(t in e)y[t]=[y[t],e[t]];else T.always(e[T.status]);return this},abort:function(e){var t=e||w;return c&&c.abort(t),r(0,t),this}};if(g.promise(T).complete=m.add,T.success=T.done,T.error=T.fail,d.url=((t||d.url||en)+"").replace(zt,"").replace(Jt,tn[1]+"//"),d.type=n.method||n.type||d.method||d.type,d.dataTypes=pe.trim(d.dataType||"*").toLowerCase().match(De)||[""],null==d.crossDomain&&(i=Gt.exec(d.url.toLowerCase()),d.crossDomain=!(!i||i[1]===tn[1]&&i[2]===tn[2]&&(i[3]||("http:"===i[1]?"80":"443"))===(tn[3]||("http:"===tn[1]?"80":"443")))),d.data&&d.processData&&"string"!=typeof d.data&&(d.data=pe.param(d.data,d.traditional)),U(Kt,d,n,T),2===b)return T;l=pe.event&&d.global,l&&0===pe.active++&&pe.event.trigger("ajaxStart"),d.type=d.type.toUpperCase(),d.hasContent=!Yt.test(d.type),a=d.url,d.hasContent||(d.data&&(a=d.url+=(It.test(a)?"&":"?")+d.data,delete d.data),d.cache===!1&&(d.url=Xt.test(a)?a.replace(Xt,"$1_="+Wt++):a+(It.test(a)?"&":"?")+"_="+Wt++)),d.ifModified&&(pe.lastModified[a]&&T.setRequestHeader("If-Modified-Since",pe.lastModified[a]),pe.etag[a]&&T.setRequestHeader("If-None-Match",pe.etag[a])),(d.data&&d.hasContent&&d.contentType!==!1||n.contentType)&&T.setRequestHeader("Content-Type",d.contentType),T.setRequestHeader("Accept",d.dataTypes[0]&&d.accepts[d.dataTypes[0]]?d.accepts[d.dataTypes[0]]+("*"!==d.dataTypes[0]?", "+Zt+"; q=0.01":""):d.accepts["*"]);for(o in d.headers)T.setRequestHeader(o,d.headers[o]);if(d.beforeSend&&(d.beforeSend.call(p,T,d)===!1||2===b))return T.abort();w="abort";for(o in{success:1,error:1,complete:1})T[o](d[o]);if(c=U(Qt,d,n,T)){if(T.readyState=1,l&&h.trigger("ajaxSend",[T,d]),2===b)return T;d.async&&d.timeout>0&&(u=e.setTimeout(function(){T.abort("timeout")},d.timeout));try{b=1,c.send(v,r)}catch(C){if(!(b<2))throw C;r(-1,C)}}else r(-1,"No Transport");return T},getJSON:function(e,t,n){return pe.get(e,t,n,"json")},getScript:function(e,t){return pe.get(e,void 0,t,"script")}}),pe.each(["get","post"],function(e,t){pe[t]=function(e,n,r,i){return pe.isFunction(n)&&(i=i||r,r=n,n=void 0),pe.ajax(pe.extend({url:e,type:t,dataType:i,data:n,success:r},pe.isPlainObject(e)&&e))}}),pe._evalUrl=function(e){return pe.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,"throws":!0})},pe.fn.extend({wrapAll:function(e){if(pe.isFunction(e))return this.each(function(t){pe(this).wrapAll(e.call(this,t))});if(this[0]){var t=pe(e,this[0].ownerDocument).eq(0).clone(!0);this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstChild&&1===e.firstChild.nodeType;)e=e.firstChild;return e}).append(this)}return this},wrapInner:function(e){return pe.isFunction(e)?this.each(function(t){pe(this).wrapInner(e.call(this,t))}):this.each(function(){var t=pe(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=pe.isFunction(e);return this.each(function(n){pe(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(){return this.parent().each(function(){pe.nodeName(this,"body")||pe(this).replaceWith(this.childNodes)}).end()}}),pe.expr.filters.hidden=function(e){return fe.reliableHiddenOffsets()?e.offsetWidth<=0&&e.offsetHeight<=0&&!e.getClientRects().length:K(e)},pe.expr.filters.visible=function(e){return!pe.expr.filters.hidden(e)};var nn=/%20/g,rn=/\[\]$/,on=/\r?\n/g,an=/^(?:submit|button|image|reset|file)$/i,sn=/^(?:input|select|textarea|keygen)/i;pe.param=function(e,t){var n,r=[],i=function(e,t){t=pe.isFunction(t)?t():null==t?"":t,r[r.length]=encodeURIComponent(e)+"="+encodeURIComponent(t)};if(void 0===t&&(t=pe.ajaxSettings&&pe.ajaxSettings.traditional),pe.isArray(e)||e.jquery&&!pe.isPlainObject(e))pe.each(e,function(){i(this.name,this.value)});else for(n in e)Q(n,e[n],t,i);return r.join("&").replace(nn,"+")},pe.fn.extend({serialize:function(){return pe.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=pe.prop(this,"elements");return e?pe.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!pe(this).is(":disabled")&&sn.test(this.nodeName)&&!an.test(e)&&(this.checked||!Be.test(e))}).map(function(e,t){var n=pe(this).val();return null==n?null:pe.isArray(n)?pe.map(n,function(e){return{name:t.name,value:e.replace(on,"\r\n")}}):{name:t.name,value:n.replace(on,"\r\n")}}).get()}}),pe.ajaxSettings.xhr=void 0!==e.ActiveXObject?function(){return this.isLocal?ee():re.documentMode>8?Z():/^(get|post|head|put|delete|options)$/i.test(this.type)&&Z()||ee()}:Z;var un=0,ln={},cn=pe.ajaxSettings.xhr();e.attachEvent&&e.attachEvent("onunload",function(){for(var e in ln)ln[e](void 0,!0)}),fe.cors=!!cn&&"withCredentials"in cn,cn=fe.ajax=!!cn,cn&&pe.ajaxTransport(function(t){if(!t.crossDomain||fe.cors){var n;return{send:function(r,i){var o,a=t.xhr(),s=++un;if(a.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)a[o]=t.xhrFields[o];t.mimeType&&a.overrideMimeType&&a.overrideMimeType(t.mimeType),t.crossDomain||r["X-Requested-With"]||(r["X-Requested-With"]="XMLHttpRequest");for(o in r)void 0!==r[o]&&a.setRequestHeader(o,r[o]+"");a.send(t.hasContent&&t.data||null),n=function(e,r){var o,u,l;if(n&&(r||4===a.readyState))if(delete ln[s],n=void 0,a.onreadystatechange=pe.noop,r)4!==a.readyState&&a.abort();else{l={},o=a.status,"string"==typeof a.responseText&&(l.text=a.responseText);try{u=a.statusText}catch(c){u=""}o||!t.isLocal||t.crossDomain?1223===o&&(o=204):o=l.text?200:404}l&&i(o,u,l,a.getAllResponseHeaders())},t.async?4===a.readyState?e.setTimeout(n):a.onreadystatechange=ln[s]=n:n()},abort:function(){n&&n(void 0,!0)}}}}),pe.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 pe.globalEval(e),e}}}),pe.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET",e.global=!1)}),pe.ajaxTransport("script",function(e){if(e.crossDomain){var t,n=re.head||pe("head")[0]||re.documentElement;return{send:function(r,i){t=re.createElement("script"),t.async=!0,e.scriptCharset&&(t.charset=e.scriptCharset),t.src=e.url,t.onload=t.onreadystatechange=function(e,n){(n||!t.readyState||/loaded|complete/.test(t.readyState))&&(t.onload=t.onreadystatechange=null,t.parentNode&&t.parentNode.removeChild(t),t=null,n||i(200,"success"))},n.insertBefore(t,n.firstChild)},abort:function(){t&&t.onload(void 0,!0)}}}});var fn=[],dn=/(=)\?(?=&|$)|\?\?/;pe.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=fn.pop()||pe.expando+"_"+Wt++;return this[e]=!0,e}}),pe.ajaxPrefilter("json jsonp",function(t,n,r){var i,o,a,s=t.jsonp!==!1&&(dn.test(t.url)?"url":"string"==typeof t.data&&0===(t.contentType||"").indexOf("application/x-www-form-urlencoded")&&dn.test(t.data)&&"data");if(s||"jsonp"===t.dataTypes[0])return i=t.jsonpCallback=pe.isFunction(t.jsonpCallback)?t.jsonpCallback():t.jsonpCallback,s?t[s]=t[s].replace(dn,"$1"+i):t.jsonp!==!1&&(t.url+=(It.test(t.url)?"&":"?")+t.jsonp+"="+i),t.converters["script json"]=function(){return a||pe.error(i+" was not called"),a[0]},t.dataTypes[0]="json",o=e[i],e[i]=function(){a=arguments},r.always(function(){void 0===o?pe(e).removeProp(i):e[i]=o,t[i]&&(t.jsonpCallback=n.jsonpCallback,fn.push(i)),a&&pe.isFunction(o)&&o(a[0]),a=o=void 0}),"script"}),pe.parseHTML=function(e,t,n){if(!e||"string"!=typeof e)return null;"boolean"==typeof t&&(n=t,t=!1),t=t||re;var r=Te.exec(e),i=!n&&[];return r?[t.createElement(r[1])]:(r=y([e],t,i),i&&i.length&&pe(i).remove(),pe.merge([],r.childNodes))};var pn=pe.fn.load;return pe.fn.load=function(e,t,n){if("string"!=typeof e&&pn)return pn.apply(this,arguments);var r,i,o,a=this,s=e.indexOf(" ");return s>-1&&(r=pe.trim(e.slice(s,e.length)),e=e.slice(0,s)),pe.isFunction(t)?(n=t,t=void 0):t&&"object"==typeof t&&(i="POST"),a.length>0&&pe.ajax({url:e,type:i||"GET",dataType:"html",data:t}).done(function(e){o=arguments,a.html(r?pe("
        ").append(pe.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},pe.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){pe.fn[t]=function(e){return this.on(t,e)}}),pe.expr.filters.animated=function(e){return pe.grep(pe.timers,function(t){return e===t.elem}).length},pe.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l,c=pe.css(e,"position"),f=pe(e),d={};"static"===c&&(e.style.position="relative"),s=f.offset(),o=pe.css(e,"top"),u=pe.css(e,"left"),l=("absolute"===c||"fixed"===c)&&pe.inArray("auto",[o,u])>-1,l?(r=f.position(),a=r.top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),pe.isFunction(t)&&(t=t.call(e,n,pe.extend({},s))),null!=t.top&&(d.top=t.top-s.top+a),null!=t.left&&(d.left=t.left-s.left+i),"using"in t?t.using.call(e,d):f.css(d)}},pe.fn.extend({offset:function(e){if(arguments.length)return void 0===e?this:this.each(function(t){pe.offset.setOffset(this,e,t)});var t,n,r={top:0,left:0},i=this[0],o=i&&i.ownerDocument;if(o)return t=o.documentElement,pe.contains(t,i)?("undefined"!=typeof i.getBoundingClientRect&&(r=i.getBoundingClientRect()),n=te(o),{top:r.top+(n.pageYOffset||t.scrollTop)-(t.clientTop||0),left:r.left+(n.pageXOffset||t.scrollLeft)-(t.clientLeft||0)}):r},position:function(){if(this[0]){var e,t,n={top:0,left:0},r=this[0];return"fixed"===pe.css(r,"position")?t=r.getBoundingClientRect():(e=this.offsetParent(),t=this.offset(),pe.nodeName(e[0],"html")||(n=e.offset()),n.top+=pe.css(e[0],"borderTopWidth",!0),n.left+=pe.css(e[0],"borderLeftWidth",!0)),{top:t.top-n.top-pe.css(r,"marginTop",!0),left:t.left-n.left-pe.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){ -for(var e=this.offsetParent;e&&!pe.nodeName(e,"html")&&"static"===pe.css(e,"position");)e=e.offsetParent;return e||pt})}}),pe.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(e,t){var n=/Y/.test(t);pe.fn[e]=function(r){return Pe(this,function(e,r,i){var o=te(e);return void 0===i?o?t in o?o[t]:o.document.documentElement[r]:e[r]:void(o?o.scrollTo(n?pe(o).scrollLeft():i,n?i:pe(o).scrollTop()):e[r]=i)},e,r,arguments.length,null)}}),pe.each(["top","left"],function(e,t){pe.cssHooks[t]=L(fe.pixelPosition,function(e,n){if(n)return n=gt(e,t),ft.test(n)?pe(e).position()[t]+"px":n})}),pe.each({Height:"height",Width:"width"},function(e,t){pe.each({padding:"inner"+e,content:t,"":"outer"+e},function(n,r){pe.fn[r]=function(r,i){var o=arguments.length&&(n||"boolean"!=typeof r),a=n||(r===!0||i===!0?"margin":"border");return Pe(this,function(t,n,r){var i;return pe.isWindow(t)?t.document.documentElement["client"+e]:9===t.nodeType?(i=t.documentElement,Math.max(t.body["scroll"+e],i["scroll"+e],t.body["offset"+e],i["offset"+e],i["client"+e])):void 0===r?pe.css(t,n,a):pe.style(t,n,r,a)},t,o?r:void 0,o,null)}})}),pe.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)}}),pe.fn.size=function(){return this.length},pe.fn.andSelf=pe.fn.addBack,layui.define(function(e){e("jquery",pe)}),pe}); \ No newline at end of file diff --git a/build/lay/modules/laydate.js b/build/lay/modules/laydate.js deleted file mode 100644 index 40b83f4b1..000000000 --- a/build/lay/modules/laydate.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define(function(e){"use strict";var t=window,a={path:"",skin:"default",format:"YYYY-MM-DD",min:"1900-01-01 00:00:00",max:"2099-12-31 23:59:59",isv:!1,init:!0},n={},s=document,i="createElement",o="getElementById",l="getElementsByTagName",d=["laydate_box","laydate_void","laydate_click","LayDateSkin","skins/","/laydate.css"];t.laydate=function(e){return e=e||{},n.run(e),laydate},laydate.v="1.1",n.trim=function(e){return e=e||"",e.replace(/^\s|\s$/g,"").replace(/\s+/g," ")},n.digit=function(e){return e<10?"0"+(0|e):e},n.stopmp=function(e){return e=e||t.event,e.stopPropagation?e.stopPropagation():e.cancelBubble=!0,this},n.each=function(e,t){for(var a=0,n=e.length;an.maxs[0]?s=["y",1]:e>=n.mins[0]&&e<=n.maxs[0]&&(e==n.mins[0]&&(tn.maxs[1]?s=["m",1]:t==n.maxs[1]&&a>n.maxs[2]&&(s=["d",1]))),s},n.timeVoid=function(e,t){if(n.ymd[1]+1==n.mins[1]&&n.ymd[2]==n.mins[2]){if(0===t&&en.maxs[3])return 1;if(1===t&&e>n.maxs[4])return 1;if(2===t&&e>n.maxs[5])return 1}if(e>(t?59:23))return 1},n.check=function(){var e=n.options.format.replace(/YYYY|MM|DD|hh|mm|ss/g,"\\d+\\").replace(/\\$/g,""),t=new RegExp(e),a=n.elem[d.elemv],s=a.match(/\d+/g)||[],i=n.checkVoid(s[0],s[1],s[2]);if(""!==a.replace(/\s/g,"")){if(!t.test(a))return n.elem[d.elemv]="",n.msg("日期不符合格式,请重新选择。"),1;if(i[0])return n.elem[d.elemv]="",n.msg("日期不在有效期内,请重新选择。"),1;i.value=n.elem[d.elemv].match(t).join(),s=i.value.match(/\d+/g),s[1]<1?(s[1]=1,i.auto=1):s[1]>12?(s[1]=12,i.auto=1):s[1].length<2&&(i.auto=1),s[2]<1?(s[2]=1,i.auto=1):s[2]>n.months[(0|s[1])-1]?(s[2]=31,i.auto=1):s[2].length<2&&(i.auto=1),s.length>3&&(n.timeVoid(s[3],0)&&(i.auto=1),n.timeVoid(s[4],1)&&(i.auto=1),n.timeVoid(s[5],2)&&(i.auto=1)),i.auto?n.creation([s[0],0|s[1],0|s[2]],1):i.value!==n.elem[d.elemv]&&(n.elem[d.elemv]=i.value)}},n.months=[31,null,31,30,31,30,31,31,30,31,30,31],n.viewDate=function(e,t,a){var s=(n.query,{}),i=new Date;e<(0|n.mins[0])&&(e=0|n.mins[0]),e>(0|n.maxs[0])&&(e=0|n.maxs[0]),i.setFullYear(e,t,a),s.ymd=[i.getFullYear(),i.getMonth(),i.getDate()],n.months[1]=n.isleap(s.ymd[0])?29:28,i.setFullYear(s.ymd[0],s.ymd[1],1),s.FDay=i.getDay(),s.PDay=n.months[0===t?11:t-1]-s.FDay+1,s.NDay=1,n.each(d.tds,function(e,t){var a,i=s.ymd[0],o=s.ymd[1]+1;t.className="",e=s.FDay&&e'+e+"年":'
      • '+(e-7+t)+"年
      • "}),t("#laydate_ys").innerHTML=a,n.each(t("#laydate_ys li"),function(e,t){"y"===n.checkVoid(t.getAttribute("y"))[0]?n.addClass(t,d[1]):n.on(t,"click",function(e){n.stopmp(e).reshow(),n.viewDate(0|this.getAttribute("y"),n.ymd[1],n.ymd[2])})})},n.initDate=function(){var e=(n.query,new Date),t=n.elem[d.elemv].match(/\d+/g)||[];t.length<3&&(t=n.options.start.match(/\d+/g)||[],t.length<3&&(t=[e.getFullYear(),e.getMonth()+1,e.getDate()])),n.inymd=t,n.viewDate(t[0],t[1]-1,t[2])},n.iswrite=function(){var e=n.query,t={time:e("#laydate_hms")};n.shde(t.time,!n.options.istime),n.shde(d.oclear,!("isclear"in n.options?n.options.isclear:1)),n.shde(d.otoday,!("istoday"in n.options?n.options.istoday:1)),n.shde(d.ok,!("issure"in n.options?n.options.issure:1))},n.orien=function(e,t){var a,s=n.elem.getBoundingClientRect();e.style.left=s.left+(t?0:n.scroll(1))+"px",a=s.bottom+e.offsetHeight/1.5<=n.winarea()?s.bottom-1:s.top>e.offsetHeight/1.5?s.top-e.offsetHeight+1:n.winarea()-e.offsetHeight,e.style.top=Math.max(a+(t?0:n.scroll()),1)+"px"},n.follow=function(e){n.options.fixed?(e.style.position="fixed",n.orien(e,1)):(e.style.position="absolute",n.orien(e))},n.viewtb=function(){var e,t=[],a=["日","一","二","三","四","五","六"],o={},d=s[i]("table"),r=s[i]("thead");return r.appendChild(s[i]("tr")),o.creath=function(e){var t=s[i]("th");t.innerHTML=a[e],r[l]("tr")[0].appendChild(t),t=null},n.each(new Array(6),function(a){t.push([]),e=d.insertRow(0),n.each(new Array(7),function(n){t[a][n]=0,0===a&&o.creath(n),e.insertCell(n)})}),d.insertBefore(r,d.children[0]),d.id=d.className="laydate_table",e=t=null,d.outerHTML.toLowerCase()}(),n.view=function(e,t){var o,l=n.query,r={};t=t||e,n.elem=e,n.options=t,n.options.format||(n.options.format=a.format),n.options.start=n.options.start||"",n.mm=r.mm=[n.options.min||a.min,n.options.max||a.max],n.mins=r.mm[0].match(/\d+/g),n.maxs=r.mm[1].match(/\d+/g),n.box?n.shde(n.box):(o=s[i]("div"),o.id=d[0],o.className=d[0],o.style.cssText="position: absolute;",o.setAttribute("name","laydate-v"+laydate.v),o.innerHTML=r.html='
          '+function(){var e="";return n.each(new Array(12),function(t){e+=''+n.digit(t+1)+"月"}),e}()+"
          "+n.viewtb+'",s.body.appendChild(o),n.box=l("#"+d[0]),n.events(),o=null),n.follow(n.box),t.zIndex?n.box.style.zIndex=t.zIndex:n.removeCssAttr(n.box,"z-index"),n.stopMosup("click",n.box),n.initDate(),n.iswrite(),n.check()},n.reshow=function(){return n.each(n.query("#"+d[0]+" .laydate_show"),function(e,t){n.removeClass(t,"laydate_show")}),this},n.close=function(){n.reshow(),n.shde(n.query("#"+d[0]),1),n.elem=null},n.parse=function(e,t,s){return e=e.concat(t),s=s||(n.options?n.options.format:a.format),s.replace(/YYYY|MM|DD|hh|mm|ss/g,function(t,a){return e.index=0|++e.index,n.digit(e[e.index])})},n.creation=function(e,t){var a=(n.query,n.hmsin),s=n.parse(e,[a[0].value,a[1].value,a[2].value]);n.elem[d.elemv]=s,t||(n.close(),"function"==typeof n.options.choose&&n.options.choose(s))},n.events=function(){var e=n.query,a={box:"#"+d[0]};n.addClass(s.body,"laydate_body"),d.tds=e("#laydate_table td"),d.mms=e("#laydate_ms span"),d.year=e("#laydate_y"),d.month=e("#laydate_m"),n.each(e(a.box+" .laydate_ym"),function(e,t){n.on(t,"click",function(t){n.stopmp(t).reshow(),n.addClass(this[l]("div")[0],"laydate_show"),e||(a.YY=parseInt(d.year.value),n.viewYears(a.YY))})}),n.on(e(a.box),"click",function(){n.reshow()}),a.tabYear=function(e){0===e?n.ymd[0]--:1===e?n.ymd[0]++:2===e?a.YY-=14:a.YY+=14,e<2?(n.viewDate(n.ymd[0],n.ymd[1],n.ymd[2]),n.reshow()):n.viewYears(a.YY)},n.each(e("#laydate_YY .laydate_tab"),function(e,t){n.on(t,"click",function(t){n.stopmp(t),a.tabYear(e)})}),a.tabMonth=function(e){e?(n.ymd[1]++,12===n.ymd[1]&&(n.ymd[0]++,n.ymd[1]=0)):(n.ymd[1]--,n.ymd[1]===-1&&(n.ymd[0]--,n.ymd[1]=11)),n.viewDate(n.ymd[0],n.ymd[1],n.ymd[2])},n.each(e("#laydate_MM .laydate_tab"),function(e,t){n.on(t,"click",function(t){n.stopmp(t).reshow(),a.tabMonth(e)})}),n.each(e("#laydate_ms span"),function(e,t){n.on(t,"click",function(e){n.stopmp(e).reshow(),n.hasClass(this,d[1])||n.viewDate(n.ymd[0],0|this.getAttribute("m"),n.ymd[2])})}),n.each(e("#laydate_table td"),function(e,t){n.on(t,"click",function(e){n.hasClass(this,d[1])||(n.stopmp(e),n.creation([0|this.getAttribute("y"),0|this.getAttribute("m"),0|this.getAttribute("d")]))})}),d.oclear=e("#laydate_clear"),n.on(d.oclear,"click",function(){n.elem[d.elemv]="",n.close()}),d.otoday=e("#laydate_today"),n.on(d.otoday,"click",function(){var e=new Date;n.creation([e.getFullYear(),e.getMonth()+1,e.getDate()])}),d.ok=e("#laydate_ok"),n.on(d.ok,"click",function(){n.valid&&n.creation([n.ymd[0],n.ymd[1]+1,n.ymd[2]])}),a.times=e("#laydate_time"),n.hmsin=a.hmsin=e("#laydate_hms input"),a.hmss=["小时","分钟","秒数"],a.hmsarr=[],n.msg=function(t,s){var i='
          '+(s||"提示")+"×
          ";"string"==typeof t?(i+="

          "+t+"

          ",n.shde(e("#"+d[0])),n.removeClass(a.times,"laydate_time1").addClass(a.times,"laydate_msg")):(a.hmsarr[t]?i=a.hmsarr[t]:(i+='
          ',n.each(new Array(0===t?24:60),function(e){i+=""+e+""}),i+="
          ",a.hmsarr[t]=i),n.removeClass(a.times,"laydate_msg"),n[0===t?"removeClass":"addClass"](a.times,"laydate_time1")),n.addClass(a.times,"laydate_show"),a.times.innerHTML=i},a.hmson=function(t,a){var s=e("#laydate_hmsno span"),i=n.valid?null:1;n.each(s,function(e,s){i?n.addClass(s,d[1]):n.timeVoid(e,a)?n.addClass(s,d[1]):n.on(s,"click",function(e){n.hasClass(this,d[1])||(t.value=n.digit(0|this.innerHTML))})}),n.addClass(s[0|t.value],"laydate_click")},n.each(a.hmsin,function(e,t){n.on(t,"click",function(t){n.stopmp(t).reshow(),n.msg(e,a.hmss[e]),a.hmson(this,e)})}),n.on(s,"mouseup",function(){var t=e("#"+d[0]);t&&"none"!==t.style.display&&(n.check()||n.close())}).on(s,"keydown",function(e){e=e||t.event;var a=e.keyCode;13===a&&n.elem&&n.creation([n.ymd[0],n.ymd[1]+1,n.ymd[2]])})},laydate.reset=function(){n.box&&n.elem&&n.follow(n.box)},laydate.now=function(e,t){var a=new Date(0|e?function(e){return e<864e5?+new Date+864e5*e:e}(parseInt(e)):+new Date);return n.parse([a.getFullYear(),a.getMonth()+1,a.getDate()],[a.getHours(),a.getMinutes(),a.getSeconds()],t)},layui.addcss("modules/laydate/laydate.css",function(){},"laydatecss"),e("laydate",laydate)}); \ No newline at end of file diff --git a/build/lay/modules/layedit.js b/build/lay/modules/layedit.js deleted file mode 100644 index adac0f03c..000000000 --- a/build/lay/modules/layedit.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define(["layer","form"],function(t){"use strict";var e=layui.jquery,i=layui.layer,a=layui.form(),l=(layui.hint(),layui.device()),n="layedit",o="layui-show",r="layui-disabled",c=function(){var t=this;t.index=0,t.config={tool:["strong","italic","underline","del","|","left","center","right","|","link","unlink","face","image"],hideTool:[],height:280}};c.prototype.set=function(t){var i=this;return e.extend(!0,i.config,t),i},c.prototype.on=function(t,e){return layui.onevent(n,t,e)},c.prototype.build=function(t,i){i=i||{};var a=this,n=a.config,r="layui-layedit",c=e("#"+t),u="LAY_layedit_"+ ++a.index,d=c.next("."+r),y=e.extend({},n,i),f=function(){var t=[],e={};return layui.each(y.hideTool,function(t,i){e[i]=!0}),layui.each(y.tool,function(i,a){C[a]&&!e[a]&&t.push(C[a])}),t.join("")}(),m=e(['
          ','
          '+f+"
          ",'
          ','',"
          ","
          "].join(""));return l.ie&&l.ie<8?c.removeClass("layui-hide").addClass(o):(d[0]&&d.remove(),s.call(a,m,c[0],y),c.addClass("layui-hide").after(m),a.index)},c.prototype.getContent=function(t){var e=u(t);if(e[0])return d(e[0].document.body.innerHTML)},c.prototype.getText=function(t){var i=u(t);if(i[0])return e(i[0].document.body).text()},c.prototype.setContent=function(t,i,a){var l=u(t);l[0]&&(a?e(l[0].document.body).append(i):e(l[0].document.body).html(i),layedit.sync(t))},c.prototype.sync=function(t){var i=u(t);if(i[0]){var a=e("#"+i[1].attr("textarea"));a.val(d(i[0].document.body.innerHTML))}},c.prototype.getSelection=function(t){var e=u(t);if(e[0]){var i=m(e[0].document);return document.selection?i.text:i.toString()}};var s=function(t,i,a){var l=this,n=t.find("iframe");n.css({height:a.height}).on("load",function(){var o=n.contents(),r=n.prop("contentWindow"),c=o.find("head"),s=e([""].join("")),u=o.find("body");c.append(s),u.attr("contenteditable","true").css({"min-height":a.height}).html(i.value||""),y.apply(l,[r,n,i,a]),g.call(l,r,t,a)})},u=function(t){var i=e("#LAY_layedit_"+t),a=i.prop("contentWindow");return[a,i]},d=function(t){return 8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),t},y=function(t,a,n,o){var r=t.document,c=e(r.body);c.on("keydown",function(t){var e=t.keyCode;if(13===e){var a=m(r),l=p(a),n=l.parentNode;if("pre"===n.tagName.toLowerCase()){if(t.shiftKey)return;return i.msg("请暂时用shift+enter"),!1}r.execCommand("formatBlock",!1,"

          ")}}),e(n).parents("form").on("submit",function(){var t=c.html();8==l.ie&&(t=t.replace(/<.+>/g,function(t){return t.toLowerCase()})),n.value=t}),c.on("paste",function(e){r.execCommand("formatBlock",!1,"

          "),setTimeout(function(){f.call(t,c),n.value=c.html()},100)})},f=function(t){var i=this;i.document;t.find("*[style]").each(function(){var t=this.style.textAlign;this.removeAttribute("style"),e(this).css({"text-align":t||""})}),t.find("table").addClass("layui-table"),t.find("script,link").remove()},m=function(t){return t.selection?t.selection.createRange():t.getSelection().getRangeAt(0)},p=function(t){return t.endContainer||t.parentElement().childNodes[0]},v=function(t,i,a){var l=this.document,n=document.createElement(t);for(var o in i)n.setAttribute(o,i[o]);if(n.removeAttribute("text"),l.selection){var r=a.text||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.pasteHTML(e(n).prop("outerHTML")),a.select()}else{var r=a.toString()||i.text;if("a"===t&&!r)return;r&&(n.innerHTML=r),a.deleteContents(),a.insertNode(n)}},h=function(t,i){var a=this.document,l="layedit-tool-active",n=p(m(a)),o=function(e){return t.find(".layedit-tool-"+e)};i&&i[i.hasClass(l)?"removeClass":"addClass"](l),t.find(">i").removeClass(l),o("unlink").addClass(r),e(n).parents().each(function(){var t=this.tagName.toLowerCase(),e=this.style.textAlign;"b"!==t&&"strong"!==t||o("b").addClass(l),"i"!==t&&"em"!==t||o("i").addClass(l),"u"===t&&o("u").addClass(l),"strike"===t&&o("d").addClass(l),"p"===t&&("center"===e?o("center").addClass(l):"right"===e?o("right").addClass(l):o("left").addClass(l)),"a"===t&&(o("link").addClass(l),o("unlink").removeClass(r))})},g=function(t,a,l){var n=t.document,o=e(n.body),c={link:function(i){var a=p(i),l=e(a).parent();b.call(o,{href:l.attr("href"),target:l.attr("target")},function(e){var a=l[0];"A"===a.tagName?a.href=e.url:v.call(t,"a",{target:e.target,href:e.url,text:e.url},i)})},unlink:function(t){n.execCommand("unlink")},face:function(e){x.call(this,function(i){v.call(t,"img",{src:i.src,alt:i.alt},e)})},image:function(a){var n=this;layui.use("upload",function(o){var r=l.uploadImage||{};o({url:r.url,method:r.type,elem:e(n).find("input")[0],unwrap:!0,success:function(e){0==e.code?(e.data=e.data||{},v.call(t,"img",{src:e.data.src,alt:e.data.title},a)):i.msg(e.msg||"上传失败")}})})},code:function(e){k.call(o,function(i){v.call(t,"pre",{text:i.code,"lay-lang":i.lang},e)})},help:function(){i.open({type:2,title:"帮助",area:["600px","380px"],shadeClose:!0,shade:.1,skin:"layui-layer-msg",content:["http://www.layui.com/about/layedit/help.html","no"]})}},s=a.find(".layui-layedit-tool"),u=function(){var i=e(this),a=i.attr("layedit-event"),l=i.attr("lay-command");if(!i.hasClass(r)){o.focus();var u=m(n);u.commonAncestorContainer;l?(n.execCommand(l),/justifyLeft|justifyCenter|justifyRight/.test(l)&&n.execCommand("formatBlock",!1,"

          "),setTimeout(function(){o.focus()},10)):c[a]&&c[a].call(this,u),h.call(t,s,i)}},d=/image/;s.find(">i").on("mousedown",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)||u.call(this)}).on("click",function(){var t=e(this),i=t.attr("layedit-event");d.test(i)&&u.call(this)}),o.on("click",function(){h.call(t,s),i.close(x.index)})},b=function(t,e){var l=this,n=i.open({type:1,id:"LAY_layedit_link",area:"350px",shade:.05,shadeClose:!0,moveType:1,title:"超链接",skin:"layui-layer-msg",content:['

            ','
          • ','','
            ','',"
            ","
          • ",'
          • ','','
            ','",'","
            ","
          • ",'
          • ','','',"
          • ","
          "].join(""),success:function(t,n){var o="submit(layedit-link-yes)";a.render("radio"),t.find(".layui-btn-primary").on("click",function(){i.close(n),l.focus()}),a.on(o,function(t){i.close(b.index),e&&e(t.field)})}});b.index=n},x=function(t){var a=function(){var t=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(t,function(t,i){e[i]=layui.cache.dir+"images/face/"+t+".gif"}),e}();return x.hide=x.hide||function(t){"face"!==e(t.target).attr("layedit-event")&&i.close(x.index)},x.index=i.tips(function(){var t=[];return layui.each(a,function(e,i){t.push('
        • '+e+'
        • ')}),'
            '+t.join("")+"
          "}(),this,{tips:1,time:0,skin:"layui-box layui-util-face",maxWidth:500,success:function(l,n){l.css({marginTop:-4,marginLeft:-10}).find(".layui-clear>li").on("click",function(){t&&t({src:a[this.title],alt:this.title}),i.close(n)}),e(document).off("click",x.hide).on("click",x.hide)}})},k=function(t){var e=this,l=i.open({type:1,id:"LAY_layedit_code",area:"550px",shade:.05,shadeClose:!0,moveType:1,title:"插入代码",skin:"layui-layer-msg",content:['
            ','
          • ','','
            ','","
            ","
          • ",'
          • ','','
            ','',"
            ","
          • ",'
          • ','','',"
          • ","
          "].join(""),success:function(l,n){var o="submit(layedit-code-yes)";a.render("select"),l.find(".layui-btn-primary").on("click",function(){i.close(n),e.focus()}),a.on(o,function(e){i.close(k.index),t&&t(e.field)})}});k.index=l},C={html:'',strong:'',italic:'',underline:'',del:'',"|":'',left:'',center:'',right:'',link:'',unlink:'',face:'',image:'',code:'',help:''},w=new c;t(n,w)}); \ No newline at end of file diff --git a/build/lay/modules/layer.js b/build/lay/modules/layer.js deleted file mode 100644 index 321c5add2..000000000 --- a/build/lay/modules/layer.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;!function(e,t){"use strict";var i,n,a=e.layui&&layui.define,o={getPath:function(){var e=document.scripts,t=e[e.length-1],i=t.src;if(!t.getAttribute("merge"))return i.substring(0,i.lastIndexOf("/")+1)}(),config:{},end:{},minIndex:0,minLeft:[],btn:["确定","取消"],type:["dialog","page","iframe","loading","tips"]},r={v:"3.0.3",ie:function(){var t=navigator.userAgent.toLowerCase();return!!(e.ActiveXObject||"ActiveXObject"in e)&&((t.match(/msie\s(\d+)/)||[])[1]||"11")}(),index:e.layer&&e.layer.v?1e5:0,path:o.getPath,config:function(e,t){return e=e||{},r.cache=o.config=i.extend({},o.config,e),r.path=o.config.path||r.path,"string"==typeof e.extend&&(e.extend=[e.extend]),o.config.path&&r.ready(),e.extend?(a?layui.addcss("modules/layer/"+e.extend):r.link("skin/"+e.extend),this):this},link:function(t,n,a){if(r.path){var o=i("head")[0],s=document.createElement("link");"string"==typeof n&&(a=n);var l=(a||t).replace(/\.|\//g,""),f="layuicss-"+l,c=0;s.rel="stylesheet",s.href=r.path+t,s.id=f,i("#"+f)[0]||o.appendChild(s),"function"==typeof n&&!function u(){return++c>80?e.console&&console.error("layer.css: Invalid"):void(1989===parseInt(i("#"+f).css("width"))?n():setTimeout(u,100))}()}},ready:function(e){var t="skinlayercss",i="303";return a?layui.addcss("modules/layer/default/layer.css?v="+r.v+i,e,t):r.link("skin/default/layer.css?v="+r.v+i,e,t),this},alert:function(e,t,n){var a="function"==typeof t;return a&&(n=t),r.open(i.extend({content:e,yes:n},a?{}:t))},confirm:function(e,t,n,a){var s="function"==typeof t;return s&&(a=n,n=t),r.open(i.extend({content:e,btn:o.btn,yes:n,btn2:a},s?{}:t))},msg:function(e,n,a){var s="function"==typeof n,f=o.config.skin,c=(f?f+" "+f+"-msg":"")||"layui-layer-msg",u=l.anim.length-1;return s&&(a=n),r.open(i.extend({content:e,time:3e3,shade:!1,skin:c,title:!1,closeBtn:!1,btn:!1,resize:!1,end:a},s&&!o.config.skin?{skin:c+" layui-layer-hui",anim:u}:function(){return n=n||{},(n.icon===-1||n.icon===t&&!o.config.skin)&&(n.skin=c+" "+(n.skin||"layui-layer-hui")),n}()))},load:function(e,t){return r.open(i.extend({type:3,icon:e||0,resize:!1,shade:.01},t))},tips:function(e,t,n){return r.open(i.extend({type:4,content:[e,t],closeBtn:!1,time:3e3,shade:!1,resize:!1,fixed:!1,maxWidth:210},n))}},s=function(e){var t=this;t.index=++r.index,t.config=i.extend({},t.config,o.config,e),document.body?t.creat():setTimeout(function(){t.creat()},30)};s.pt=s.prototype;var l=["layui-layer",".layui-layer-title",".layui-layer-main",".layui-layer-dialog","layui-layer-iframe","layui-layer-content","layui-layer-btn","layui-layer-close"];l.anim=["layer-anim","layer-anim-01","layer-anim-02","layer-anim-03","layer-anim-04","layer-anim-05","layer-anim-06"],s.pt.config={type:0,shade:.3,fixed:!0,move:l[1],title:"信息",offset:"auto",area:"auto",closeBtn:1,time:0,zIndex:19891014,maxWidth:360,anim:0,isOutAnim:!0,icon:-1,moveType:1,resize:!0,scrollbar:!0,tips:2},s.pt.vessel=function(e,t){var n=this,a=n.index,r=n.config,s=r.zIndex+a,f="object"==typeof r.title,c=r.maxmin&&(1===r.type||2===r.type),u=r.title?'
          '+(f?r.title[0]:r.title)+"
          ":"";return r.zIndex=s,t([r.shade?'
          ':"",'
          '+(e&&2!=r.type?"":u)+'
          '+(0==r.type&&r.icon!==-1?'':"")+(1==r.type&&e?"":r.content||"")+'
          '+function(){var e=c?'':"";return r.closeBtn&&(e+=''),e}()+""+(r.btn?function(){var e="";"string"==typeof r.btn&&(r.btn=[r.btn]);for(var t=0,i=r.btn.length;t'+r.btn[t]+"";return'
          '+e+"
          "}():"")+(r.resize?'':"")+"
          "],u,i('
          ')),n},s.pt.creat=function(){var e=this,t=e.config,a=e.index,s=t.content,f="object"==typeof s,c=i("body");if(!t.id||!i("#"+t.id)[0]){switch("string"==typeof t.area&&(t.area="auto"===t.area?["",""]:[t.area,""]),t.shift&&(t.anim=t.shift),6==r.ie&&(t.fixed=!1),t.type){case 0:t.btn="btn"in t?t.btn:o.btn[0],r.closeAll("dialog");break;case 2:var s=t.content=f?t.content:[t.content||"http://layer.layui.com","auto"];t.content='';break;case 3:delete t.title,delete t.closeBtn,t.icon===-1&&0===t.icon,r.closeAll("loading");break;case 4:f||(t.content=[t.content,"body"]),t.follow=t.content[1],t.content=t.content[0]+'',delete t.title,t.tips="object"==typeof t.tips?t.tips:[t.tips,!0],t.tipsMore||r.closeAll("tips")}e.vessel(f,function(n,r,u){c.append(n[0]),f?function(){2==t.type||4==t.type?function(){i("body").append(n[1])}():function(){s.parents("."+l[0])[0]||(s.data("display",s.css("display")).show().addClass("layui-layer-wrap").wrap(n[1]),i("#"+l[0]+a).find("."+l[5]).before(r))}()}():c.append(n[1]),i(".layui-layer-move")[0]||c.append(o.moveElem=u),e.layero=i("#"+l[0]+a),t.scrollbar||l.html.css("overflow","hidden").attr("layer-full",a)}).auto(a),2==t.type&&6==r.ie&&e.layero.find("iframe").attr("src",s[0]),4==t.type?e.tips():e.offset(),t.fixed&&n.on("resize",function(){e.offset(),(/^\d+%$/.test(t.area[0])||/^\d+%$/.test(t.area[1]))&&e.auto(a),4==t.type&&e.tips()}),t.time<=0||setTimeout(function(){r.close(e.index)},t.time),e.move().callback(),l.anim[t.anim]&&e.layero.addClass(l.anim[t.anim]),t.isOutAnim&&e.layero.data("isOutAnim",!0)}},s.pt.auto=function(e){function t(e){e=s.find(e),e.height(f[1]-c-u-2*(0|parseFloat(e.css("padding-top"))))}var a=this,o=a.config,s=i("#"+l[0]+e);""===o.area[0]&&o.maxWidth>0&&(r.ie&&r.ie<8&&o.btn&&s.width(s.innerWidth()),s.outerWidth()>o.maxWidth&&s.width(o.maxWidth));var f=[s.innerWidth(),s.innerHeight()],c=s.find(l[1]).outerHeight()||0,u=s.find("."+l[6]).outerHeight()||0;switch(o.type){case 2:t("iframe");break;default:""===o.area[1]?o.fixed&&f[1]>=n.height()&&(f[1]=n.height(),t("."+l[5])):t("."+l[5])}return a},s.pt.offset=function(){var e=this,t=e.config,i=e.layero,a=[i.outerWidth(),i.outerHeight()],o="object"==typeof t.offset;e.offsetTop=(n.height()-a[1])/2,e.offsetLeft=(n.width()-a[0])/2,o?(e.offsetTop=t.offset[0],e.offsetLeft=t.offset[1]||e.offsetLeft):"auto"!==t.offset&&("t"===t.offset?e.offsetTop=0:"r"===t.offset?e.offsetLeft=n.width()-a[0]:"b"===t.offset?e.offsetTop=n.height()-a[1]:"l"===t.offset?e.offsetLeft=0:"lt"===t.offset?(e.offsetTop=0,e.offsetLeft=0):"lb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=0):"rt"===t.offset?(e.offsetTop=0,e.offsetLeft=n.width()-a[0]):"rb"===t.offset?(e.offsetTop=n.height()-a[1],e.offsetLeft=n.width()-a[0]):e.offsetTop=t.offset),t.fixed||(e.offsetTop=/%$/.test(e.offsetTop)?n.height()*parseFloat(e.offsetTop)/100:parseFloat(e.offsetTop),e.offsetLeft=/%$/.test(e.offsetLeft)?n.width()*parseFloat(e.offsetLeft)/100:parseFloat(e.offsetLeft),e.offsetTop+=n.scrollTop(),e.offsetLeft+=n.scrollLeft()),i.attr("minLeft")&&(e.offsetTop=n.height()-(i.find(l[1]).outerHeight()||0),e.offsetLeft=i.css("left")),i.css({top:e.offsetTop,left:e.offsetLeft})},s.pt.tips=function(){var e=this,t=e.config,a=e.layero,o=[a.outerWidth(),a.outerHeight()],r=i(t.follow);r[0]||(r=i("body"));var s={width:r.outerWidth(),height:r.outerHeight(),top:r.offset().top,left:r.offset().left},f=a.find(".layui-layer-TipsG"),c=t.tips[0];t.tips[1]||f.remove(),s.autoLeft=function(){s.left+o[0]-n.width()>0?(s.tipLeft=s.left+s.width-o[0],f.css({right:12,left:"auto"})):s.tipLeft=s.left},s.where=[function(){s.autoLeft(),s.tipTop=s.top-o[1]-10,f.removeClass("layui-layer-TipsB").addClass("layui-layer-TipsT").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left+s.width+10,s.tipTop=s.top,f.removeClass("layui-layer-TipsL").addClass("layui-layer-TipsR").css("border-bottom-color",t.tips[1])},function(){s.autoLeft(),s.tipTop=s.top+s.height+10,f.removeClass("layui-layer-TipsT").addClass("layui-layer-TipsB").css("border-right-color",t.tips[1])},function(){s.tipLeft=s.left-o[0]-10,s.tipTop=s.top,f.removeClass("layui-layer-TipsR").addClass("layui-layer-TipsL").css("border-bottom-color",t.tips[1])}],s.where[c-1](),1===c?s.top-(n.scrollTop()+o[1]+16)<0&&s.where[2]():2===c?n.width()-(s.left+s.width+o[0]+16)>0||s.where[3]():3===c?s.top-n.scrollTop()+s.height+o[1]+16-n.height()>0&&s.where[0]():4===c&&o[0]+16-s.left>0&&s.where[1](),a.find("."+l[5]).css({"background-color":t.tips[1],"padding-right":t.closeBtn?"30px":""}),a.css({left:s.tipLeft-(t.fixed?n.scrollLeft():0),top:s.tipTop-(t.fixed?n.scrollTop():0)})},s.pt.move=function(){var e=this,t=e.config,a=i(document),s=e.layero,l=s.find(t.move),f=s.find(".layui-layer-resize"),c={};return t.move&&l.css("cursor","move"),l.on("mousedown",function(e){e.preventDefault(),t.move&&(c.moveStart=!0,c.offset=[e.clientX-parseFloat(s.css("left")),e.clientY-parseFloat(s.css("top"))],o.moveElem.css("cursor","move").show())}),f.on("mousedown",function(e){e.preventDefault(),c.resizeStart=!0,c.offset=[e.clientX,e.clientY],c.area=[s.outerWidth(),s.outerHeight()],o.moveElem.css("cursor","se-resize").show()}),a.on("mousemove",function(i){if(c.moveStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1],l="fixed"===s.css("position");if(i.preventDefault(),c.stX=l?0:n.scrollLeft(),c.stY=l?0:n.scrollTop(),!t.moveOut){var f=n.width()-s.outerWidth()+c.stX,u=n.height()-s.outerHeight()+c.stY;af&&(a=f),ou&&(o=u)}s.css({left:a,top:o})}if(t.resize&&c.resizeStart){var a=i.clientX-c.offset[0],o=i.clientY-c.offset[1];i.preventDefault(),r.style(e.index,{width:c.area[0]+a,height:c.area[1]+o}),c.isResize=!0,t.resizing&&t.resizing(s)}}).on("mouseup",function(e){c.moveStart&&(delete c.moveStart,o.moveElem.hide(),t.moveEnd&&t.moveEnd(s)),c.resizeStart&&(delete c.resizeStart,o.moveElem.hide())}),e},s.pt.callback=function(){function e(){var e=a.cancel&&a.cancel(t.index,n);e===!1||r.close(t.index)}var t=this,n=t.layero,a=t.config;t.openLayer(),a.success&&(2==a.type?n.find("iframe").on("load",function(){a.success(n,t.index)}):a.success(n,t.index)),6==r.ie&&t.IE6(n),n.find("."+l[6]).children("a").on("click",function(){var e=i(this).index();if(0===e)a.yes?a.yes(t.index,n):a.btn1?a.btn1(t.index,n):r.close(t.index);else{var o=a["btn"+(e+1)]&&a["btn"+(e+1)](t.index,n);o===!1||r.close(t.index)}}),n.find("."+l[7]).on("click",e),a.shadeClose&&i("#layui-layer-shade"+t.index).on("click",function(){r.close(t.index)}),n.find(".layui-layer-min").on("click",function(){var e=a.min&&a.min(n);e===!1||r.min(t.index,a)}),n.find(".layui-layer-max").on("click",function(){i(this).hasClass("layui-layer-maxmin")?(r.restore(t.index),a.restore&&a.restore(n)):(r.full(t.index,a),setTimeout(function(){a.full&&a.full(n)},100))}),a.end&&(o.end[t.index]=a.end)},o.reselect=function(){i.each(i("select"),function(e,t){var n=i(this);n.parents("."+l[0])[0]||1==n.attr("layer")&&i("."+l[0]).length<1&&n.removeAttr("layer").show(),n=null})},s.pt.IE6=function(e){i("select").each(function(e,t){var n=i(this);n.parents("."+l[0])[0]||"none"===n.css("display")||n.attr({layer:"1"}).hide(),n=null})},s.pt.openLayer=function(){var e=this;r.zIndex=e.config.zIndex,r.setTop=function(e){var t=function(){r.zIndex++,e.css("z-index",r.zIndex+1)};return r.zIndex=parseInt(e[0].style.zIndex),e.on("mousedown",t),r.zIndex}},o.record=function(e){var t=[e.width(),e.height(),e.position().top,e.position().left+parseFloat(e.css("margin-left"))];e.find(".layui-layer-max").addClass("layui-layer-maxmin"),e.attr({area:t})},o.rescollbar=function(e){l.html.attr("layer-full")==e&&(l.html[0].style.removeProperty?l.html[0].style.removeProperty("overflow"):l.html[0].style.removeAttribute("overflow"),l.html.removeAttr("layer-full"))},e.layer=r,r.getChildFrame=function(e,t){return t=t||i("."+l[4]).attr("times"),i("#"+l[0]+t).find("iframe").contents().find(e)},r.getFrameIndex=function(e){return i("#"+e).parents("."+l[4]).attr("times")},r.iframeAuto=function(e){if(e){var t=r.getChildFrame("html",e).outerHeight(),n=i("#"+l[0]+e),a=n.find(l[1]).outerHeight()||0,o=n.find("."+l[6]).outerHeight()||0;n.css({height:t+a+o}),n.find("iframe").css({height:t})}},r.iframeSrc=function(e,t){i("#"+l[0]+e).find("iframe").attr("src",t)},r.style=function(e,t,n){var a=i("#"+l[0]+e),r=a.find(".layui-layer-content"),s=a.attr("type"),f=a.find(l[1]).outerHeight()||0,c=a.find("."+l[6]).outerHeight()||0;a.attr("minLeft");s!==o.type[3]&&s!==o.type[4]&&(n||(parseFloat(t.width)<=260&&(t.width=260),parseFloat(t.height)-f-c<=64&&(t.height=64+f+c)),a.css(t),c=a.find("."+l[6]).outerHeight(),s===o.type[2]?a.find("iframe").css({height:parseFloat(t.height)-f-c}):r.css({height:parseFloat(t.height)-f-c-parseFloat(r.css("padding-top"))-parseFloat(r.css("padding-bottom"))}))},r.min=function(e,t){var a=i("#"+l[0]+e),s=a.find(l[1]).outerHeight()||0,f=a.attr("minLeft")||181*o.minIndex+"px",c=a.css("position");o.record(a),o.minLeft[0]&&(f=o.minLeft[0],o.minLeft.shift()),a.attr("position",c),r.style(e,{width:180,height:s,left:f,top:n.height()-s,position:"fixed",overflow:"hidden"},!0),a.find(".layui-layer-min").hide(),"page"===a.attr("type")&&a.find(l[4]).hide(),o.rescollbar(e),a.attr("minLeft")||o.minIndex++,a.attr("minLeft",f)},r.restore=function(e){var t=i("#"+l[0]+e),n=t.attr("area").split(",");t.attr("type");r.style(e,{width:parseFloat(n[0]),height:parseFloat(n[1]),top:parseFloat(n[2]),left:parseFloat(n[3]),position:t.attr("position"),overflow:"visible"},!0),t.find(".layui-layer-max").removeClass("layui-layer-maxmin"),t.find(".layui-layer-min").show(),"page"===t.attr("type")&&t.find(l[4]).show(),o.rescollbar(e)},r.full=function(e){var t,a=i("#"+l[0]+e);o.record(a),l.html.attr("layer-full")||l.html.css("overflow","hidden").attr("layer-full",e),clearTimeout(t),t=setTimeout(function(){var t="fixed"===a.css("position");r.style(e,{top:t?0:n.scrollTop(),left:t?0:n.scrollLeft(),width:n.width(),height:n.height()},!0),a.find(".layui-layer-min").hide()},100)},r.title=function(e,t){var n=i("#"+l[0]+(t||r.index)).find(l[1]);n.html(e)},r.close=function(e){var t=i("#"+l[0]+e),n=t.attr("type"),a="layer-anim-close";if(t[0]){var s="layui-layer-wrap",f=function(){if(n===o.type[1]&&"object"===t.attr("conType")){t.children(":not(."+l[5]+")").remove();for(var a=t.find("."+s),r=0;r<2;r++)a.unwrap();a.css("display",a.data("display")).removeClass(s)}else{if(n===o.type[2])try{var f=i("#"+l[4]+e)[0];f.contentWindow.document.write(""),f.contentWindow.close(),t.find("."+l[5])[0].removeChild(f)}catch(c){}t[0].innerHTML="",t.remove()}"function"==typeof o.end[e]&&o.end[e](),delete o.end[e]};t.data("isOutAnim")&&t.addClass(a),i("#layui-layer-moves, #layui-layer-shade"+e).remove(),6==r.ie&&o.reselect(),o.rescollbar(e),t.attr("minLeft")&&(o.minIndex--,o.minLeft.push(t.attr("minLeft"))),r.ie&&r.ie<10||!t.data("isOutAnim")?f():setTimeout(function(){f()},200)}},r.closeAll=function(e){i.each(i("."+l[0]),function(){var t=i(this),n=e?t.attr("type")===e:1;n&&r.close(t.attr("times")),n=null})};var f=r.cache||{},c=function(e){return f.skin?" "+f.skin+" "+f.skin+"-"+e:""};r.prompt=function(e,t){var a="";if(e=e||{},"function"==typeof e&&(t=e),e.area){var o=e.area;a='style="width: '+o[0]+"; height: "+o[1]+';"',delete e.area}var s,l=2==e.formType?'":function(){return''}(),f=e.success;return delete e.success,r.open(i.extend({type:1,btn:["确定","取消"],content:l,skin:"layui-layer-prompt"+c("prompt"),maxWidth:n.width(),success:function(e){s=e.find(".layui-layer-input"),s.focus(),"function"==typeof f&&f(e)},resize:!1,yes:function(i){var n=s.val();""===n?s.focus():n.length>(e.maxlength||500)?r.tips("最多输入"+(e.maxlength||500)+"个字数",s,{tips:1}):t&&t(n,i,s)}},e))},r.tab=function(e){e=e||{};var t=e.tab||{},n=e.success;return delete e.success,r.open(i.extend({type:1,skin:"layui-layer-tab"+c("tab"),resize:!1,title:function(){var e=t.length,i=1,n="";if(e>0)for(n=''+t[0].title+"";i"+t[i].title+"";return n}(),content:'
            '+function(){var e=t.length,i=1,n="";if(e>0)for(n='
          • '+(t[0].content||"no content")+"
          • ";i'+(t[i].content||"no content")+"";return n}()+"
          ",success:function(t){var a=t.find(".layui-layer-title").children(),o=t.find(".layui-layer-tabmain").children();a.on("mousedown",function(t){t.stopPropagation?t.stopPropagation():t.cancelBubble=!0;var n=i(this),a=n.index();n.addClass("layui-layer-tabnow").siblings().removeClass("layui-layer-tabnow"),o.eq(a).show().siblings().hide(),"function"==typeof e.change&&e.change(a)}),"function"==typeof n&&n(t)}},e))},r.photos=function(t,n,a){function o(e,t,i){var n=new Image;return n.src=e,n.complete?t(n):(n.onload=function(){n.onload=null,t(n)},void(n.onerror=function(e){n.onerror=null,i(e)}))}var s={};if(t=t||{},t.photos){var l=t.photos.constructor===Object,f=l?t.photos:{},u=f.data||[],d=f.start||0;s.imgIndex=(0|d)+1,t.img=t.img||"img";var y=t.success;if(delete t.success,l){if(0===u.length)return r.msg("没有图片")}else{var p=i(t.photos),h=function(){u=[],p.find(t.img).each(function(e){var t=i(this);t.attr("layer-index",e),u.push({alt:t.attr("alt"),pid:t.attr("layer-pid"),src:t.attr("layer-src")||t.attr("src"),thumb:t.attr("src")})})};if(h(),0===u.length)return;if(n||p.on("click",t.img,function(){var e=i(this),n=e.attr("layer-index");r.photos(i.extend(t,{photos:{start:n,data:u,tab:t.tab},full:t.full}),!0),h()}),!n)return}s.imgprev=function(e){s.imgIndex--,s.imgIndex<1&&(s.imgIndex=u.length),s.tabimg(e)},s.imgnext=function(e,t){s.imgIndex++,s.imgIndex>u.length&&(s.imgIndex=1,t)||s.tabimg(e)},s.keyup=function(e){if(!s.end){var t=e.keyCode;e.preventDefault(),37===t?s.imgprev(!0):39===t?s.imgnext(!0):27===t&&r.close(s.index)}},s.tabimg=function(e){if(!(u.length<=1))return f.start=s.imgIndex-1,r.close(s.index),r.photos(t,!0,e)},s.event=function(){s.bigimg.hover(function(){s.imgsee.show()},function(){s.imgsee.hide()}),s.bigimg.find(".layui-layer-imgprev").on("click",function(e){e.preventDefault(),s.imgprev()}),s.bigimg.find(".layui-layer-imgnext").on("click",function(e){e.preventDefault(),s.imgnext()}),i(document).on("keyup",s.keyup)},s.loadi=r.load(1,{shade:!("shade"in t)&&.9,scrollbar:!1}),o(u[d].src,function(n){r.close(s.loadi),s.index=r.open(i.extend({type:1,id:"layui-layer-photos",area:function(){var a=[n.width,n.height],o=[i(e).width()-100,i(e).height()-100];if(!t.full&&(a[0]>o[0]||a[1]>o[1])){var r=[a[0]/o[0],a[1]/o[1]];r[0]>r[1]?(a[0]=a[0]/r[0],a[1]=a[1]/r[0]):r[0]'+(u[d].alt||
          '+(u.length>1?'':"")+'
          '+(u[d].alt||"")+""+s.imgIndex+"/"+u.length+"
          ",success:function(e,i){s.bigimg=e.find(".layui-layer-phimg"),s.imgsee=e.find(".layui-layer-imguide,.layui-layer-imgbar"),s.event(e),t.tab&&t.tab(u[d],e),"function"==typeof y&&y(e)},end:function(){s.end=!0,i(document).off("keyup",s.keyup)}},t))},function(){r.close(s.loadi),r.msg("当前图片地址异常
          是否继续查看下一张?",{time:3e4,btn:["下一张","不看了"],yes:function(){u.length>1&&s.imgnext(!0,!0)}})})}},o.run=function(t){i=t,n=i(e),l.html=i("html"),r.open=function(e){var t=new s(e);return t.index}},e.layui&&layui.define?(r.ready(),layui.define("jquery",function(t){r.path=layui.cache.dir,o.run(layui.jquery),e.layer=r,t("layer",r)})):"function"==typeof define&&define.amd?define(["jquery"],function(){return o.run(e.jQuery),r}):function(){o.run(e.jQuery),r.ready()}()}(window); \ No newline at end of file diff --git a/build/lay/modules/laypage.js b/build/lay/modules/laypage.js deleted file mode 100644 index ed2ffa3fd..000000000 --- a/build/lay/modules/laypage.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define(function(a){"use strict";function t(a){new p(a)}var e=document,r="getElementById",n="getElementsByTagName",s=0,p=function(a){var t=this,e=t.config=a||{};e.item=s++,t.render(!0)};p.on=function(a,t,e){return a.attachEvent?a.attachEvent("on"+t,function(){e.call(a,window.even)}):a.addEventListener(t,e,!1),p},p.prototype.type=function(){var a=this.config;if("object"==typeof a.cont)return void 0===a.cont.length?2:3},p.prototype.view=function(){var a=this,t=a.config,e=[],r={};if(t.pages=0|t.pages,t.curr=0|t.curr||1,t.groups="groups"in t?0|t.groups:5,t.first="first"in t?t.first:"首页",t.last="last"in t?t.last:"末页",t.prev="prev"in t?t.prev:"上一页",t.next="next"in t?t.next:"下一页",t.pages<=1)return"";for(t.groups>t.pages&&(t.groups=t.pages),r.index=Math.ceil((t.curr+(t.groups>1&&t.groups!==t.pages?1:0))/(0===t.groups?1:t.groups)),t.curr>1&&t.prev&&e.push(''+t.prev+""),r.index>1&&t.first&&0!==t.groups&&e.push(''+t.first+""),r.poor=Math.floor((t.groups-1)/2),r.start=r.index>1?t.curr-r.poor:1,r.end=r.index>1?function(){var a=t.curr+(t.groups-r.poor-1);return a>t.pages?t.pages:a}():t.groups,r.end-r.start"+r.start+""):e.push(''+r.start+"");return t.pages>t.groups&&r.end'+t.last+""),r.flow=!t.prev&&0===t.groups,(t.curr!==t.pages&&t.next||r.flow)&&e.push(function(){return r.flow&&t.curr===t.pages?''+t.next+"":''+t.next+""}()),'
          '+e.join("")+function(){return t.skip?'到第 ':""}()+"
          "},p.prototype.jump=function(a){if(a){for(var t=this,e=t.config,r=a.children,s=a[n]("button")[0],i=a[n]("input")[0],u=0,o=r.length;u/g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var n="Laytpl Error:";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e}},c=n.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=c("^"+r.open+"#",""),l=c(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(c(r.open+"#"),r.open+"# ").replace(c(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(/(?="|')/g,"\\").replace(n.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(n.query(1),function(e){var n='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(c(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),n='"+_escape_('),n+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,n.escape)}catch(u){return delete o.cache,n.error(u,p)}},t.pt.render=function(e,r){var c,t=this;return e?(c=t.cache?t.cache(e,n.escape):t.parse(t.tpl,e),r?void r(c):c):n.error("no data")};var o=function(e){return"string"!=typeof e?n.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var n in e)r[n]=e[n]},o.v="1.2.0",e("laytpl",o)}); \ No newline at end of file diff --git a/build/lay/modules/mobile.js b/build/lay/modules/mobile.js deleted file mode 100644 index e943c59d8..000000000 --- a/build/lay/modules/mobile.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define(function(i){i("layui.mobile",layui.v)});layui.define(function(e){"use strict";var r={open:"{{",close:"}}"},n={exp:function(e){return new RegExp(e,"g")},query:function(e,n,t){var o=["#([\\s\\S])+?","([^{#}])*?"][e||0];return c((n||"")+r.open+o+r.close+(t||""))},escape:function(e){return String(e||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""")},error:function(e,r){var n="Laytpl Error:";return"object"==typeof console&&console.error(n+e+"\n"+(r||"")),n+e}},c=n.exp,t=function(e){this.tpl=e};t.pt=t.prototype,window.errors=0,t.pt.parse=function(e,t){var o=this,p=e,a=c("^"+r.open+"#",""),l=c(r.close+"$","");e=e.replace(/\s+|\r|\t|\n/g," ").replace(c(r.open+"#"),r.open+"# ").replace(c(r.close+"}"),"} "+r.close).replace(/\\/g,"\\\\").replace(/(?="|')/g,"\\").replace(n.query(),function(e){return e=e.replace(a,"").replace(l,""),'";'+e.replace(/\\/g,"")+';view+="'}).replace(n.query(1),function(e){var n='"+(';return e.replace(/\s/g,"")===r.open+r.close?"":(e=e.replace(c(r.open+"|"+r.close),""),/^=/.test(e)&&(e=e.replace(/^=/,""),n='"+_escape_('),n+e.replace(/\\/g,"")+')+"')}),e='"use strict";var view = "'+e+'";return view;';try{return o.cache=e=new Function("d, _escape_",e),e(t,n.escape)}catch(u){return delete o.cache,n.error(u,p)}},t.pt.render=function(e,r){var c,t=this;return e?(c=t.cache?t.cache(e,n.escape):t.parse(t.tpl,e),r?void r(c):c):n.error("no data")};var o=function(e){return"string"!=typeof e?n.error("Template not found"):new t(e)};o.config=function(e){e=e||{};for(var n in e)r[n]=e[n]},o.v="1.2.0",e("laytpl",o)});layui.define(function(e){"use strict";var t=(window,document),i="querySelectorAll",n="getElementsByClassName",a=function(e){return t[i](e)},s={type:0,shade:!0,shadeClose:!0,fixed:!0,anim:"scale"},l={extend:function(e){var t=JSON.parse(JSON.stringify(s));for(var i in e)t[i]=e[i];return t},timer:{},end:{}};l.touch=function(e,t){e.addEventListener("click",function(e){t.call(this,e)},!1)};var o=0,r=["layui-m-layer"],d=function(e){var t=this;t.config=l.extend(e),t.view()};d.prototype.view=function(){var e=this,i=e.config,s=t.createElement("div");e.id=s.id=r[0]+o,s.setAttribute("class",r[0]+" "+r[0]+(i.type||0)),s.setAttribute("index",o);var l=function(){var e="object"==typeof i.title;return i.title?'

          '+(e?i.title[0]:i.title)+"

          ":""}(),d=function(){"string"==typeof i.btn&&(i.btn=[i.btn]);var e,t=(i.btn||[]).length;return 0!==t&&i.btn?(e=''+i.btn[0]+"",2===t&&(e=''+i.btn[1]+""+e),'
          '+e+"
          "):""}();if(i.fixed||(i.top=i.hasOwnProperty("top")?i.top:100,i.style=i.style||"",i.style+=" top:"+(t.body.scrollTop+i.top)+"px"),2===i.type&&(i.content='

          '+(i.content||"")+"

          "),i.skin&&(i.anim="up"),"msg"===i.skin&&(i.shade=!1),s.innerHTML=(i.shade?"
          ':"")+'
          "+l+'
          '+i.content+"
          "+d+"
          ",!i.type||2===i.type){var y=t[n](r[0]+i.type),u=y.length;u>=1&&c.close(y[0].getAttribute("index"))}document.body.appendChild(s);var m=e.elem=a("#"+e.id)[0];i.success&&i.success(m),e.index=o++,e.action(i,m)},d.prototype.action=function(e,t){var i=this;e.time&&(l.timer[i.index]=setTimeout(function(){c.close(i.index)},1e3*e.time));var a=function(){var t=this.getAttribute("type");0==t?(e.no&&e.no(),c.close(i.index)):e.yes?e.yes(i.index):c.close(i.index)};if(e.btn)for(var s=t[n]("layui-m-layerbtn")[0].children,o=s.length,r=0;r0&&e-1 in t)}function s(t){return A.call(t,function(t){return null!=t})}function u(t){return t.length>0?T.fn.concat.apply([],t):t}function c(t){return t.replace(/::/g,"/").replace(/([A-Z]+)([A-Z][a-z])/g,"$1_$2").replace(/([a-z\d])([A-Z])/g,"$1_$2").replace(/_/g,"-").toLowerCase()}function l(t){return t in F?F[t]:F[t]=new RegExp("(^|\\s)"+t+"(\\s|$)")}function f(t,e){return"number"!=typeof e||k[c(t)]?e:e+"px"}function h(t){var e,n;return $[t]||(e=L.createElement(t),L.body.appendChild(e),n=getComputedStyle(e,"").getPropertyValue("display"),e.parentNode.removeChild(e),"none"==n&&(n="block"),$[t]=n),$[t]}function p(t){return"children"in t?D.call(t.children):T.map(t.childNodes,function(t){if(1==t.nodeType)return t})}function d(t,e){var n,r=t?t.length:0;for(n=0;n]*>/,R=/^<(\w+)\s*\/?>(?:<\/\1>|)$/,z=/<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/gi,Z=/^(?:body|html)$/i,q=/([A-Z])/g,H=["val","css","html","text","data","width","height","offset"],I=["after","prepend","before","append"],V=L.createElement("table"),_=L.createElement("tr"),B={tr:L.createElement("tbody"),tbody:V,thead:V,tfoot:V,td:_,th:_,"*":L.createElement("div")},U=/complete|loaded|interactive/,X=/^[\w-]*$/,J={},W=J.toString,Y={},G=L.createElement("div"),K={tabindex:"tabIndex",readonly:"readOnly","for":"htmlFor","class":"className",maxlength:"maxLength",cellspacing:"cellSpacing",cellpadding:"cellPadding",rowspan:"rowSpan",colspan:"colSpan",usemap:"useMap",frameborder:"frameBorder",contenteditable:"contentEditable"},Q=Array.isArray||function(t){return t instanceof Array};return Y.matches=function(t,e){if(!e||!t||1!==t.nodeType)return!1;var n=t.matches||t.webkitMatchesSelector||t.mozMatchesSelector||t.oMatchesSelector||t.matchesSelector;if(n)return n.call(t,e);var r,i=t.parentNode,o=!i;return o&&(i=G).appendChild(t),r=~Y.qsa(i,e).indexOf(t),o&&G.removeChild(t),r},C=function(t){return t.replace(/-+(.)?/g,function(t,e){return e?e.toUpperCase():""})},N=function(t){return A.call(t,function(e,n){return t.indexOf(e)==n})},Y.fragment=function(t,e,n){var r,i,a;return R.test(t)&&(r=T(L.createElement(RegExp.$1))),r||(t.replace&&(t=t.replace(z,"<$1>")),e===E&&(e=M.test(t)&&RegExp.$1),e in B||(e="*"),a=B[e],a.innerHTML=""+t,r=T.each(D.call(a.childNodes),function(){a.removeChild(this)})),o(n)&&(i=T(r),T.each(n,function(t,e){H.indexOf(t)>-1?i[t](e):i.attr(t,e)})),r},Y.Z=function(t,e){return new d(t,e)},Y.isZ=function(t){return t instanceof Y.Z},Y.init=function(t,n){var r;if(!t)return Y.Z();if("string"==typeof t)if(t=t.trim(),"<"==t[0]&&M.test(t))r=Y.fragment(t,RegExp.$1,n),t=null;else{if(n!==E)return T(n).find(t);r=Y.qsa(L,t)}else{if(e(t))return T(L).ready(t);if(Y.isZ(t))return t;if(Q(t))r=s(t);else if(i(t))r=[t],t=null;else if(M.test(t))r=Y.fragment(t.trim(),RegExp.$1,n),t=null;else{if(n!==E)return T(n).find(t);r=Y.qsa(L,t)}}return Y.Z(r,t)},T=function(t,e){return Y.init(t,e)},T.extend=function(t){var e,n=D.call(arguments,1);return"boolean"==typeof t&&(e=t,t=n.shift()),n.forEach(function(n){m(t,n,e)}),t},Y.qsa=function(t,e){var n,r="#"==e[0],i=!r&&"."==e[0],o=r||i?e.slice(1):e,a=X.test(o);return t.getElementById&&a&&r?(n=t.getElementById(o))?[n]:[]:1!==t.nodeType&&9!==t.nodeType&&11!==t.nodeType?[]:D.call(a&&!r&&t.getElementsByClassName?i?t.getElementsByClassName(o):t.getElementsByTagName(e):t.querySelectorAll(e))},T.contains=L.documentElement.contains?function(t,e){return t!==e&&t.contains(e)}:function(t,e){for(;e&&(e=e.parentNode);)if(e===t)return!0;return!1},T.type=t,T.isFunction=e,T.isWindow=n,T.isArray=Q,T.isPlainObject=o,T.isEmptyObject=function(t){var e;for(e in t)return!1;return!0},T.isNumeric=function(t){var e=Number(t),n=typeof t;return null!=t&&"boolean"!=n&&("string"!=n||t.length)&&!isNaN(e)&&isFinite(e)||!1},T.inArray=function(t,e,n){return O.indexOf.call(e,t,n)},T.camelCase=C,T.trim=function(t){return null==t?"":String.prototype.trim.call(t)},T.uuid=0,T.support={},T.expr={},T.noop=function(){},T.map=function(t,e){var n,r,i,o=[];if(a(t))for(r=0;r=0?t:t+this.length]},toArray:function(){return this.get()},size:function(){return this.length},remove:function(){return this.each(function(){null!=this.parentNode&&this.parentNode.removeChild(this)})},each:function(t){return O.every.call(this,function(e,n){return t.call(e,n,e)!==!1}),this},filter:function(t){return e(t)?this.not(this.not(t)):T(A.call(this,function(e){return Y.matches(e,t)}))},add:function(t,e){return T(N(this.concat(T(t,e))))},is:function(t){return this.length>0&&Y.matches(this[0],t)},not:function(t){var n=[];if(e(t)&&t.call!==E)this.each(function(e){t.call(this,e)||n.push(this)});else{var r="string"==typeof t?this.filter(t):a(t)&&e(t.item)?D.call(t):T(t);this.forEach(function(t){r.indexOf(t)<0&&n.push(t)})}return T(n)},has:function(t){return this.filter(function(){return i(t)?T.contains(this,t):T(this).find(t).size()})},eq:function(t){return t===-1?this.slice(t):this.slice(t,+t+1)},first:function(){var t=this[0];return t&&!i(t)?t:T(t)},last:function(){var t=this[this.length-1];return t&&!i(t)?t:T(t)},find:function(t){var e,n=this;return e=t?"object"==typeof t?T(t).filter(function(){var t=this;return O.some.call(n,function(e){return T.contains(e,t)})}):1==this.length?T(Y.qsa(this[0],t)):this.map(function(){return Y.qsa(this,t)}):T()},closest:function(t,e){var n=[],i="object"==typeof t&&T(t);return this.each(function(o,a){for(;a&&!(i?i.indexOf(a)>=0:Y.matches(a,t));)a=a!==e&&!r(a)&&a.parentNode;a&&n.indexOf(a)<0&&n.push(a)}),T(n)},parents:function(t){for(var e=[],n=this;n.length>0;)n=T.map(n,function(t){if((t=t.parentNode)&&!r(t)&&e.indexOf(t)<0)return e.push(t),t});return v(e,t)},parent:function(t){return v(N(this.pluck("parentNode")),t)},children:function(t){return v(this.map(function(){return p(this)}),t)},contents:function(){return this.map(function(){return this.contentDocument||D.call(this.childNodes)})},siblings:function(t){return v(this.map(function(t,e){return A.call(p(e.parentNode),function(t){return t!==e})}),t)},empty:function(){return this.each(function(){this.innerHTML=""})},pluck:function(t){return T.map(this,function(e){return e[t]})},show:function(){return this.each(function(){"none"==this.style.display&&(this.style.display=""),"none"==getComputedStyle(this,"").getPropertyValue("display")&&(this.style.display=h(this.nodeName))})},replaceWith:function(t){return this.before(t).remove()},wrap:function(t){var n=e(t);if(this[0]&&!n)var r=T(t).get(0),i=r.parentNode||this.length>1;return this.each(function(e){T(this).wrapAll(n?t.call(this,e):i?r.cloneNode(!0):r)})},wrapAll:function(t){if(this[0]){T(this[0]).before(t=T(t));for(var e;(e=t.children()).length;)t=e.first();T(t).append(this)}return this},wrapInner:function(t){var n=e(t);return this.each(function(e){var r=T(this),i=r.contents(),o=n?t.call(this,e):t;i.length?i.wrapAll(o):r.append(o)})},unwrap:function(){return this.parent().each(function(){T(this).replaceWith(T(this).children())}),this},clone:function(){return this.map(function(){return this.cloneNode(!0)})},hide:function(){return this.css("display","none")},toggle:function(t){return this.each(function(){var e=T(this);(t===E?"none"==e.css("display"):t)?e.show():e.hide()})},prev:function(t){return T(this.pluck("previousElementSibling")).filter(t||"*")},next:function(t){return T(this.pluck("nextElementSibling")).filter(t||"*")},html:function(t){return 0 in arguments?this.each(function(e){var n=this.innerHTML;T(this).empty().append(g(this,t,e,n))}):0 in this?this[0].innerHTML:null},text:function(t){return 0 in arguments?this.each(function(e){var n=g(this,t,e,this.textContent);this.textContent=null==n?"":""+n}):0 in this?this.pluck("textContent").join(""):null},attr:function(t,e){var n;return"string"!=typeof t||1 in arguments?this.each(function(n){if(1===this.nodeType)if(i(t))for(j in t)y(this,j,t[j]);else y(this,t,g(this,e,n,this.getAttribute(t)))}):0 in this&&1==this[0].nodeType&&null!=(n=this[0].getAttribute(t))?n:E},removeAttr:function(t){return this.each(function(){1===this.nodeType&&t.split(" ").forEach(function(t){y(this,t)},this)})},prop:function(t,e){return t=K[t]||t,1 in arguments?this.each(function(n){this[t]=g(this,e,n,this[t])}):this[0]&&this[0][t]},removeProp:function(t){return t=K[t]||t,this.each(function(){delete this[t]})},data:function(t,e){var n="data-"+t.replace(q,"-$1").toLowerCase(),r=1 in arguments?this.attr(n,e):this.attr(n);return null!==r?b(r):E},val:function(t){return 0 in arguments?(null==t&&(t=""),this.each(function(e){this.value=g(this,t,e,this.value)})):this[0]&&(this[0].multiple?T(this[0]).find("option").filter(function(){return this.selected}).pluck("value"):this[0].value)},offset:function(t){if(t)return this.each(function(e){var n=T(this),r=g(this,t,e,n.offset()),i=n.offsetParent().offset(),o={top:r.top-i.top,left:r.left-i.left};"static"==n.css("position")&&(o.position="relative"),n.css(o)});if(!this.length)return null;if(L.documentElement!==this[0]&&!T.contains(L.documentElement,this[0]))return{top:0,left:0};var e=this[0].getBoundingClientRect();return{left:e.left+window.pageXOffset,top:e.top+window.pageYOffset,width:Math.round(e.width),height:Math.round(e.height)}},css:function(e,n){if(arguments.length<2){var r=this[0];if("string"==typeof e){if(!r)return;return r.style[C(e)]||getComputedStyle(r,"").getPropertyValue(e)}if(Q(e)){if(!r)return;var i={},o=getComputedStyle(r,"");return T.each(e,function(t,e){i[e]=r.style[C(e)]||o.getPropertyValue(e)}),i}}var a="";if("string"==t(e))n||0===n?a=c(e)+":"+f(e,n):this.each(function(){this.style.removeProperty(c(e))});else for(j in e)e[j]||0===e[j]?a+=c(j)+":"+f(j,e[j])+";":this.each(function(){this.style.removeProperty(c(j))});return this.each(function(){this.style.cssText+=";"+a})},index:function(t){return t?this.indexOf(T(t)[0]):this.parent().children().indexOf(this[0])},hasClass:function(t){return!!t&&O.some.call(this,function(t){return this.test(x(t))},l(t))},addClass:function(t){return t?this.each(function(e){if("className"in this){S=[];var n=x(this),r=g(this,t,e,n);r.split(/\s+/g).forEach(function(t){T(this).hasClass(t)||S.push(t)},this),S.length&&x(this,n+(n?" ":"")+S.join(" "))}}):this},removeClass:function(t){return this.each(function(e){if("className"in this){if(t===E)return x(this,"");S=x(this),g(this,t,e,S).split(/\s+/g).forEach(function(t){S=S.replace(l(t)," ")}),x(this,S.trim())}})},toggleClass:function(t,e){return t?this.each(function(n){var r=T(this),i=g(this,t,n,x(this));i.split(/\s+/g).forEach(function(t){(e===E?!r.hasClass(t):e)?r.addClass(t):r.removeClass(t)})}):this},scrollTop:function(t){if(this.length){var e="scrollTop"in this[0];return t===E?e?this[0].scrollTop:this[0].pageYOffset:this.each(e?function(){this.scrollTop=t}:function(){this.scrollTo(this.scrollX,t)})}},scrollLeft:function(t){if(this.length){var e="scrollLeft"in this[0];return t===E?e?this[0].scrollLeft:this[0].pageXOffset:this.each(e?function(){this.scrollLeft=t}:function(){this.scrollTo(t,this.scrollY)})}},position:function(){if(this.length){var t=this[0],e=this.offsetParent(),n=this.offset(),r=Z.test(e[0].nodeName)?{top:0,left:0}:e.offset();return n.top-=parseFloat(T(t).css("margin-top"))||0,n.left-=parseFloat(T(t).css("margin-left"))||0,r.top+=parseFloat(T(e[0]).css("border-top-width"))||0,r.left+=parseFloat(T(e[0]).css("border-left-width"))||0,{top:n.top-r.top,left:n.left-r.left}}},offsetParent:function(){return this.map(function(){for(var t=this.offsetParent||L.body;t&&!Z.test(t.nodeName)&&"static"==T(t).css("position");)t=t.offsetParent;return t})}},T.fn.detach=T.fn.remove,["width","height"].forEach(function(t){var e=t.replace(/./,function(t){return t[0].toUpperCase()});T.fn[t]=function(i){var o,a=this[0];return i===E?n(a)?a["inner"+e]:r(a)?a.documentElement["scroll"+e]:(o=this.offset())&&o[t]:this.each(function(e){a=T(this),a.css(t,g(this,i,e,a[t]()))})}}),I.forEach(function(e,n){var r=n%2;T.fn[e]=function(){var e,i,o=T.map(arguments,function(n){var r=[];return e=t(n),"array"==e?(n.forEach(function(t){return t.nodeType!==E?r.push(t):T.zepto.isZ(t)?r=r.concat(t.get()):void(r=r.concat(Y.fragment(t)))}),r):"object"==e||null==n?n:Y.fragment(n)}),a=this.length>1;return o.length<1?this:this.each(function(t,e){i=r?e:e.parentNode,e=0==n?e.nextSibling:1==n?e.firstChild:2==n?e:null;var s=T.contains(L.documentElement,i);o.forEach(function(t){if(a)t=t.cloneNode(!0);else if(!i)return T(t).remove();i.insertBefore(t,e),s&&w(t,function(t){if(!(null==t.nodeName||"SCRIPT"!==t.nodeName.toUpperCase()||t.type&&"text/javascript"!==t.type||t.src)){var e=t.ownerDocument?t.ownerDocument.defaultView:window;e.eval.call(e,t.innerHTML)}})})})},T.fn[r?e+"To":"insert"+(n?"Before":"After")]=function(t){return T(t)[e](this),this}}),Y.Z.prototype=d.prototype=T.fn,Y.uniq=N,Y.deserializeValue=b,T.zepto=Y,T}();!function(t){function e(t){return t._zid||(t._zid=h++)}function n(t,n,o,a){if(n=r(n),n.ns)var s=i(n.ns);return(v[e(t)]||[]).filter(function(t){return t&&(!n.e||t.e==n.e)&&(!n.ns||s.test(t.ns))&&(!o||e(t.fn)===e(o))&&(!a||t.sel==a)})}function r(t){var e=(""+t).split(".");return{e:e[0],ns:e.slice(1).sort().join(" ")}}function i(t){return new RegExp("(?:^| )"+t.replace(" "," .* ?")+"(?: |$)")}function o(t,e){return t.del&&!y&&t.e in x||!!e}function a(t){return b[t]||y&&x[t]||t}function s(n,i,s,u,l,h,p){var d=e(n),m=v[d]||(v[d]=[]);i.split(/\s/).forEach(function(e){if("ready"==e)return t(document).ready(s);var i=r(e);i.fn=s,i.sel=l,i.e in b&&(s=function(e){var n=e.relatedTarget;if(!n||n!==this&&!t.contains(this,n))return i.fn.apply(this,arguments)}),i.del=h;var d=h||s;i.proxy=function(t){if(t=c(t),!t.isImmediatePropagationStopped()){t.data=u;var e=d.apply(n,t._args==f?[t]:[t].concat(t._args));return e===!1&&(t.preventDefault(),t.stopPropagation()),e}},i.i=m.length,m.push(i),"addEventListener"in n&&n.addEventListener(a(i.e),i.proxy,o(i,p))})}function u(t,r,i,s,u){var c=e(t);(r||"").split(/\s/).forEach(function(e){n(t,e,i,s).forEach(function(e){delete v[c][e.i],"removeEventListener"in t&&t.removeEventListener(a(e.e),e.proxy,o(e,u))})})}function c(e,n){return!n&&e.isDefaultPrevented||(n||(n=e),t.each(T,function(t,r){var i=n[t];e[t]=function(){return this[r]=w,i&&i.apply(n,arguments)},e[r]=E}),e.timeStamp||(e.timeStamp=Date.now()),(n.defaultPrevented!==f?n.defaultPrevented:"returnValue"in n?n.returnValue===!1:n.getPreventDefault&&n.getPreventDefault())&&(e.isDefaultPrevented=w)),e}function l(t){var e,n={originalEvent:t};for(e in t)j.test(e)||t[e]===f||(n[e]=t[e]);return c(n,t)}var f,h=1,p=Array.prototype.slice,d=t.isFunction,m=function(t){return"string"==typeof t},v={},g={},y="onfocusin"in window,x={focus:"focusin",blur:"focusout"},b={mouseenter:"mouseover",mouseleave:"mouseout"};g.click=g.mousedown=g.mouseup=g.mousemove="MouseEvents",t.event={add:s,remove:u},t.proxy=function(n,r){var i=2 in arguments&&p.call(arguments,2);if(d(n)){var o=function(){return n.apply(r,i?i.concat(p.call(arguments)):arguments)};return o._zid=e(n),o}if(m(r))return i?(i.unshift(n[r],n),t.proxy.apply(null,i)):t.proxy(n[r],n);throw new TypeError("expected function")},t.fn.bind=function(t,e,n){return this.on(t,e,n)},t.fn.unbind=function(t,e){return this.off(t,e)},t.fn.one=function(t,e,n,r){return this.on(t,e,n,r,1)};var w=function(){return!0},E=function(){return!1},j=/^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/,T={preventDefault:"isDefaultPrevented",stopImmediatePropagation:"isImmediatePropagationStopped",stopPropagation:"isPropagationStopped"};t.fn.delegate=function(t,e,n){return this.on(e,t,n)},t.fn.undelegate=function(t,e,n){return this.off(e,t,n)},t.fn.live=function(e,n){return t(document.body).delegate(this.selector,e,n),this},t.fn.die=function(e,n){return t(document.body).undelegate(this.selector,e,n),this},t.fn.on=function(e,n,r,i,o){var a,c,h=this;return e&&!m(e)?(t.each(e,function(t,e){h.on(t,n,r,e,o)}),h):(m(n)||d(i)||i===!1||(i=r,r=n,n=f),i!==f&&r!==!1||(i=r,r=f),i===!1&&(i=E),h.each(function(f,h){o&&(a=function(t){return u(h,t.type,i),i.apply(this,arguments)}),n&&(c=function(e){var r,o=t(e.target).closest(n,h).get(0);if(o&&o!==h)return r=t.extend(l(e),{currentTarget:o,liveFired:h}),(a||i).apply(o,[r].concat(p.call(arguments,1)))}),s(h,e,i,r,n,c||a)}))},t.fn.off=function(e,n,r){var i=this;return e&&!m(e)?(t.each(e,function(t,e){i.off(t,n,e)}),i):(m(n)||d(r)||r===!1||(r=n,n=f),r===!1&&(r=E),i.each(function(){u(this,e,r,n)}))},t.fn.trigger=function(e,n){return e=m(e)||t.isPlainObject(e)?t.Event(e):c(e),e._args=n,this.each(function(){e.type in x&&"function"==typeof this[e.type]?this[e.type]():"dispatchEvent"in this?this.dispatchEvent(e):t(this).triggerHandler(e,n)})},t.fn.triggerHandler=function(e,r){var i,o;return this.each(function(a,s){i=l(m(e)?t.Event(e):e),i._args=r,i.target=s,t.each(n(s,e.type||e),function(t,e){if(o=e.proxy(i),i.isImmediatePropagationStopped())return!1})}),o},"focusin focusout focus blur load resize scroll unload click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select keydown keypress keyup error".split(" ").forEach(function(e){t.fn[e]=function(t){return 0 in arguments?this.bind(e,t):this.trigger(e)}}),t.Event=function(t,e){m(t)||(e=t,t=e.type);var n=document.createEvent(g[t]||"Events"),r=!0;if(e)for(var i in e)"bubbles"==i?r=!!e[i]:n[i]=e[i];return n.initEvent(t,r,!0),c(n)}}(e),function(t){function e(e,n,r){var i=t.Event(n);return t(e).trigger(i,r),!i.isDefaultPrevented()}function n(t,n,r,i){if(t.global)return e(n||x,r,i)}function r(e){e.global&&0===t.active++&&n(e,null,"ajaxStart")}function i(e){e.global&&!--t.active&&n(e,null,"ajaxStop")}function o(t,e){var r=e.context;return e.beforeSend.call(r,t,e)!==!1&&n(e,r,"ajaxBeforeSend",[t,e])!==!1&&void n(e,r,"ajaxSend",[t,e])}function a(t,e,r,i){var o=r.context,a="success";r.success.call(o,t,a,e),i&&i.resolveWith(o,[t,a,e]),n(r,o,"ajaxSuccess",[e,r,t]),u(a,e,r)}function s(t,e,r,i,o){var a=i.context;i.error.call(a,r,e,t),o&&o.rejectWith(a,[r,e,t]),n(i,a,"ajaxError",[r,i,t||e]),u(e,r,i)}function u(t,e,r){var o=r.context;r.complete.call(o,e,t),n(r,o,"ajaxComplete",[e,r]),i(r)}function c(t,e,n){if(n.dataFilter==l)return t;var r=n.context;return n.dataFilter.call(r,t,e)}function l(){}function f(t){return t&&(t=t.split(";",2)[0]),t&&(t==T?"html":t==j?"json":w.test(t)?"script":E.test(t)&&"xml")||"text"}function h(t,e){return""==e?t:(t+"&"+e).replace(/[&?]{1,2}/,"?")}function p(e){e.processData&&e.data&&"string"!=t.type(e.data)&&(e.data=t.param(e.data,e.traditional)),!e.data||e.type&&"GET"!=e.type.toUpperCase()&&"jsonp"!=e.dataType||(e.url=h(e.url,e.data),e.data=void 0)}function d(e,n,r,i){return t.isFunction(n)&&(i=r,r=n,n=void 0),t.isFunction(r)||(i=r,r=void 0),{url:e,data:n,success:r,dataType:i}}function m(e,n,r,i){var o,a=t.isArray(n),s=t.isPlainObject(n);t.each(n,function(n,u){o=t.type(u),i&&(n=r?i:i+"["+(s||"object"==o||"array"==o?n:"")+"]"),!i&&a?e.add(u.name,u.value):"array"==o||!r&&"object"==o?m(e,u,r,n):e.add(n,u)})}var v,g,y=+new Date,x=window.document,b=/)<[^<]*)*<\/script>/gi,w=/^(?:text|application)\/javascript/i,E=/^(?:text|application)\/xml/i,j="application/json",T="text/html",S=/^\s*$/,C=x.createElement("a");C.href=window.location.href,t.active=0,t.ajaxJSONP=function(e,n){if(!("type"in e))return t.ajax(e);var r,i,u=e.jsonpCallback,c=(t.isFunction(u)?u():u)||"Zepto"+y++,l=x.createElement("script"),f=window[c],h=function(e){t(l).triggerHandler("error",e||"abort")},p={abort:h};return n&&n.promise(p),t(l).on("load error",function(o,u){clearTimeout(i),t(l).off().remove(),"error"!=o.type&&r?a(r[0],p,e,n):s(null,u||"error",p,e,n),window[c]=f,r&&t.isFunction(f)&&f(r[0]),f=r=void 0}),o(p,e)===!1?(h("abort"),p):(window[c]=function(){r=arguments},l.src=e.url.replace(/\?(.+)=\?/,"?$1="+c),x.head.appendChild(l),e.timeout>0&&(i=setTimeout(function(){h("timeout")},e.timeout)),p)},t.ajaxSettings={type:"GET",beforeSend:l,success:l,error:l,complete:l,context:null,global:!0,xhr:function(){return new window.XMLHttpRequest},accepts:{script:"text/javascript, application/javascript, application/x-javascript",json:j,xml:"application/xml, text/xml",html:T,text:"text/plain"},crossDomain:!1,timeout:0,processData:!0,cache:!0,dataFilter:l},t.ajax=function(e){var n,i,u=t.extend({},e||{}),d=t.Deferred&&t.Deferred();for(v in t.ajaxSettings)void 0===u[v]&&(u[v]=t.ajaxSettings[v]);r(u),u.crossDomain||(n=x.createElement("a"),n.href=u.url,n.href=n.href,u.crossDomain=C.protocol+"//"+C.host!=n.protocol+"//"+n.host),u.url||(u.url=window.location.toString()),(i=u.url.indexOf("#"))>-1&&(u.url=u.url.slice(0,i)),p(u);var m=u.dataType,y=/\?.+=\?/.test(u.url);if(y&&(m="jsonp"),u.cache!==!1&&(e&&e.cache===!0||"script"!=m&&"jsonp"!=m)||(u.url=h(u.url,"_="+Date.now())),"jsonp"==m)return y||(u.url=h(u.url,u.jsonp?u.jsonp+"=?":u.jsonp===!1?"":"callback=?")),t.ajaxJSONP(u,d);var b,w=u.accepts[m],E={},j=function(t,e){E[t.toLowerCase()]=[t,e]},T=/^([\w-]+:)\/\//.test(u.url)?RegExp.$1:window.location.protocol,N=u.xhr(),O=N.setRequestHeader;if(d&&d.promise(N),u.crossDomain||j("X-Requested-With","XMLHttpRequest"),j("Accept",w||"*/*"),(w=u.mimeType||w)&&(w.indexOf(",")>-1&&(w=w.split(",",2)[0]),N.overrideMimeType&&N.overrideMimeType(w)),(u.contentType||u.contentType!==!1&&u.data&&"GET"!=u.type.toUpperCase())&&j("Content-Type",u.contentType||"application/x-www-form-urlencoded"),u.headers)for(g in u.headers)j(g,u.headers[g]);if(N.setRequestHeader=j,N.onreadystatechange=function(){if(4==N.readyState){N.onreadystatechange=l,clearTimeout(b);var e,n=!1;if(N.status>=200&&N.status<300||304==N.status||0==N.status&&"file:"==T){if(m=m||f(u.mimeType||N.getResponseHeader("content-type")),"arraybuffer"==N.responseType||"blob"==N.responseType)e=N.response;else{e=N.responseText;try{e=c(e,m,u),"script"==m?(0,eval)(e):"xml"==m?e=N.responseXML:"json"==m&&(e=S.test(e)?null:t.parseJSON(e))}catch(r){n=r}if(n)return s(n,"parsererror",N,u,d)}a(e,N,u,d)}else s(N.statusText||null,N.status?"error":"abort",N,u,d)}},o(N,u)===!1)return N.abort(),s(null,"abort",N,u,d),N;var P=!("async"in u)||u.async;if(N.open(u.type,u.url,P,u.username,u.password),u.xhrFields)for(g in u.xhrFields)N[g]=u.xhrFields[g];for(g in E)O.apply(N,E[g]);return u.timeout>0&&(b=setTimeout(function(){N.onreadystatechange=l,N.abort(),s(null,"timeout",N,u,d)},u.timeout)),N.send(u.data?u.data:null),N},t.get=function(){return t.ajax(d.apply(null,arguments))},t.post=function(){var e=d.apply(null,arguments);return e.type="POST",t.ajax(e)},t.getJSON=function(){var e=d.apply(null,arguments);return e.dataType="json",t.ajax(e)},t.fn.load=function(e,n,r){if(!this.length)return this;var i,o=this,a=e.split(/\s/),s=d(e,n,r),u=s.success;return a.length>1&&(s.url=a[0],i=a[1]),s.success=function(e){o.html(i?t("
          ").html(e.replace(b,"")).find(i):e),u&&u.apply(o,arguments)},t.ajax(s),this};var N=encodeURIComponent;t.param=function(e,n){var r=[];return r.add=function(e,n){t.isFunction(n)&&(n=n()),null==n&&(n=""),this.push(N(e)+"="+N(n))},m(r,e,n),r.join("&").replace(/%20/g,"+")}}(e),function(t){t.fn.serializeArray=function(){var e,n,r=[],i=function(t){return t.forEach?t.forEach(i):void r.push({name:e,value:t})};return this[0]&&t.each(this[0].elements,function(r,o){n=o.type,e=o.name,e&&"fieldset"!=o.nodeName.toLowerCase()&&!o.disabled&&"submit"!=n&&"reset"!=n&&"button"!=n&&"file"!=n&&("radio"!=n&&"checkbox"!=n||o.checked)&&i(t(o).val())}),r},t.fn.serialize=function(){var t=[];return this.serializeArray().forEach(function(e){t.push(encodeURIComponent(e.name)+"="+encodeURIComponent(e.value))}),t.join("&")},t.fn.submit=function(e){if(0 in arguments)this.bind("submit",e);else if(this.length){var n=t.Event("submit");this.eq(0).trigger(n),n.isDefaultPrevented()||this.get(0).submit()}return this}}(e),function(){try{getComputedStyle(void 0)}catch(t){var e=getComputedStyle;window.getComputedStyle=function(t,n){try{return e(t,n)}catch(r){return null}}}}(),t("zepto",e)});layui.define(["layer-mobile","zepto"],function(e){"use strict";var t=layui.zepto,a=layui["layer-mobile"],i=(layui.device(),"layui-upload-enter"),n="layui-upload-iframe",r={icon:2,shift:6},o={file:"文件",video:"视频",audio:"音频"};a.msg=function(e){return a.open({content:e||"",skin:"msg",time:2})};var s=function(e){this.options=e};s.prototype.init=function(){var e=this,a=e.options,r=t("body"),s=t(a.elem||".layui-upload-file"),u=t('');return t("#"+n)[0]||r.append(u),s.each(function(r,s){s=t(s);var u='
          ',l=s.attr("lay-type")||a.type;a.unwrap||(u='
          '+u+''+(s.attr("lay-title")||a.title||"上传"+(o[l]||"图片"))+"
          "),u=t(u),a.unwrap||u.on("dragover",function(e){e.preventDefault(),t(this).addClass(i)}).on("dragleave",function(){t(this).removeClass(i)}).on("drop",function(){t(this).removeClass(i)}),s.parent("form").attr("target")===n&&(a.unwrap?s.unwrap():(s.parent().next().remove(),s.unwrap().unwrap())),s.wrap(u),s.off("change").on("change",function(){e.action(this,l)})})},s.prototype.action=function(e,i){var o=this,s=o.options,u=e.value,l=t(e),p=l.attr("lay-ext")||s.ext||"";if(u){switch(i){case"file":if(p&&!RegExp("\\w\\.("+p+")$","i").test(escape(u)))return a.msg("不支持该文件格式",r),e.value="";break;case"video":if(!RegExp("\\w\\.("+(p||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(u)))return a.msg("不支持该视频格式",r),e.value="";break;case"audio":if(!RegExp("\\w\\.("+(p||"mp3|wav|mid")+")$","i").test(escape(u)))return a.msg("不支持该音频格式",r),e.value="";break;default:if(!RegExp("\\w\\.("+(p||"jpg|png|gif|bmp|jpeg")+")$","i").test(escape(u)))return a.msg("不支持该图片格式",r),e.value=""}s.before&&s.before(e),l.parent().submit();var c=t("#"+n),f=setInterval(function(){var t;try{t=c.contents().find("body").text()}catch(i){a.msg("上传接口存在跨域",r),clearInterval(f)}if(t){clearInterval(f),c.contents().find("body").html("");try{t=JSON.parse(t)}catch(i){return t={},a.msg("请对上传接口返回JSON字符",r)}"function"==typeof s.success&&s.success(t,e)}},30);e.value=""}},e("upload-mobile",function(e){var t=new s(e=e||{});t.init()})});layui.define(["laytpl","upload-mobile","layer-mobile","zepto"],function(i){var e="2.0.0",a=layui.zepto,t=layui.laytpl,n=layui["layer-mobile"],l=layui["upload-mobile"],s=layui.device(),o="layui-show",c="layim-this",d=20,r={},u=function(){this.v=e,m(a("body"),"*[layim-event]",function(i){var e=a(this),t=e.attr("layim-event");U[t]?U[t].call(this,e,i):""})},m=function(i,e,t){var n,l="function"==typeof e,s=function(i){var e=a(this);e.data("lock")||(n||t.call(this,i),n=!1,e.data("lock","true"),setTimeout(function(){e.removeAttr("data-lock")},e.data("locktime")||0))};return l&&(t=e),i="string"==typeof i?a(i):i,y?void(l?i.on("touchmove",function(){n=!0}).on("touchend",s):i.on("touchmove",e,function(){n=!0}).on("touchend",e,s)):void(l?i.on("click",s):i.on("click",e,s))},y=/Android|iPhone|SymbianOS|Windows Phone|iPad|iPod/.test(navigator.userAgent);n.popBottom=function(i){n.close(n.popBottom.index),n.popBottom.index=n.open(a.extend({type:1,content:i.content||"",shade:!1,className:"layim-layer"},i))},u.prototype.config=function(i){i=i||{},i=a.extend({title:"我的IM",isgroup:0,isNewFriend:!0,voice:"default.mp3",chatTitleColor:"#36373C"},i),k(i)},u.prototype.on=function(i,e){return"function"==typeof e&&(r[i]?r[i].push(e):r[i]=[e]),this},u.prototype.chat=function(i){if(window.JSON&&window.JSON.parse)return L(i,-1),this},u.prototype.panel=function(i){return N(i)},u.prototype.cache=function(){return C},u.prototype.getMessage=function(i){return M(i),this},u.prototype.addList=function(i){return O(i),this},u.prototype.removeList=function(i){return Y(i),this},u.prototype.setFriendStatus=function(i,e){var t=a(".layim-friend"+i);t["online"===e?"removeClass":"addClass"]("layim-list-gray")},u.prototype.setChatStatus=function(i){var e=T(),a=e.elem.find(".layim-chat-status");return a.html(i),this},u.prototype.showNew=function(i,e){_(i,e)},u.prototype.content=function(i){return layui.data.content(i)};var p=function(i){var e={friend:"该分组下暂无好友",group:"暂无群组",history:"暂无任何消息"};return i=i||{},"history"===i.type&&(i.item=i.item||"d.sortHistory"),["{{# var length = 0; layui.each("+i.item+", function(i, data){ length++; }}",'
        • {{ data.username||data.groupname||data.name||"佚名" }}

          {{ data.remark||data.sign||"" }}

          new
        • ',"{{# }); if(length === 0){ }}",'
        • '+(e[i.type]||"暂无数据")+"
        • ","{{# } }}"].join("")},f=function(i,e,a){return['
          ','
          ',"

          ",a?'':"",'{{ d.title || d.base.title }}',"

          ","
          ",'
          ',i,"
          ","
          "].join("")},h=['
          ','
          ','
            ','
              ',p({type:"history"}),"
            ","
          ","
          ",'
          ','
            ',"{{# if(d.base.isNewFriend){ }}",'
          • 新的朋友
          • ',"{{# } if(d.base.isgroup){ }}",'
          • 群聊
          • ',"{{# } }}","
          ",'
            ','{{# layui.each(d.friend, function(index, item){ var spread = d.local["spread"+index]; }}',"
          • ",'
            {{# if(spread === "true"){ }}{{# } else { }}{{# } }}{{ item.groupname||"未命名分组"+index }}( {{ (item.list||[]).length }})
            ','
              ',p({type:"friend",item:"item.list",index:"index"}),"
            ","
          • ","{{# }); if(d.friend.length === 0){ }}",'
            • 暂无联系人
            ',"{{# } }}","
          ","
          ",'
          ','
            ',"{{# layui.each(d.base.moreList, function(index, item){ }}",'
          • ','{{item.iconUnicode||""}}{{item.title}}',"
          • ","{{# }); if(!d.base.copyright){ }}",'
          • 关于
          • ',"{{# } }}","
          ","
          ","
          ",'
            ','
          • 消息
          • ','
          • 联系人
          • ','
          • 更多
          • ',"
          "].join(""),v=['
          ','
          ',"
            ","
            ",'","
            "].join(""),g=function(i){return i<10?"0"+(0|i):i};layui.data.date=function(i){var e=new Date(i||new Date);return g(e.getMonth()+1)+"-"+g(e.getDate())+" "+g(e.getHours())+":"+g(e.getMinutes())},layui.data.content=function(i){var e=function(i){return new RegExp("\\n*\\["+(i||"")+"(pre|div|p|table|thead|th|tbody|tr|td|ul|li|ol|li|dl|dt|dd|h2|h3|h4|h5)([\\s\\S]*?)\\]\\n*","g")};return i=(i||"").replace(/&(?!#?[a-zA-Z0-9]+;)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,""").replace(/@(\S+)(\s+?|$)/g,'@$1$2').replace(/face\[([^\s\[\]]+?)\]/g,function(i){var e=i.replace(/^face/g,"");return''+e+''}).replace(/img\[([^\s]+?)\]/g,function(i){return''}).replace(/file\([\s\S]+?\)\[[\s\S]*?\]/g,function(i){var e=(i.match(/file\(([\s\S]+?)\)\[/)||[])[1],a=(i.match(/\)\[([\s\S]*?)\]/)||[])[1];return e?''+(a||e)+"":i}).replace(/audio\[([^\s]+?)\]/g,function(i){return'

            音频消息

            '}).replace(/video\[([^\s]+?)\]/g,function(i){return'
            '}).replace(/a\([\s\S]+?\)\[[\s\S]*?\]/g,function(i){var e=(i.match(/a\(([\s\S]+?)\)\[/)||[])[1],a=(i.match(/\)\[([\s\S]*?)\]/)||[])[1];return e?''+(a||e)+"":i}).replace(e(),"<$1 $2>").replace(e("/"),"").replace(/\n/g,"
            ")};var b,x,w=['
          • ','
            ','{{ d.username||"佚名" }}',"
            ",'
            {{ layui.data.content(d.content||" ") }}
            ',"
          • "].join(""),C={message:{},chat:[]},k=function(i){var e=i.init||{};return mine=e.mine||{},local=layui.data("layim-mobile")[mine.id]||{},obj={base:i,local:local,mine:mine,history:local.history||[]},create=function(e){var n=e.mine||{},l=layui.data("layim-mobile")[n.id]||{},s={base:i,local:l,mine:n,friend:e.friend||[],group:e.group||[],history:l.history||[]};s.sortHistory=j(s.history,"historyTime"),C=a.extend(C,s),S(t(f(h)).render(s)),layui.each(r.ready,function(i,e){e&&e(s)})},C=a.extend(C,obj),i.brief?layui.each(r.ready,function(i,e){e&&e(obj)}):void create(e)},S=function(i){return n.open({type:1,shade:!1,shadeClose:!1,anim:-1,content:i,success:function(i){b=a(i),A(b.find(".layui-layim"))}})},N=function(i,e){i=i||{};var l={base:C.base,local:C.local,title:i.title||"",data:i.data};return n.open({type:1,shade:!1,shadeClose:!1,anim:-1,content:t(f(i.tpl,e!==-1,!0)).render(l),success:function(e){var t=a(e);t.prev().find(".layim-panel").addClass("layui-m-anim-lout"),i.success&&i.success(e),i.isChat||A(t.find(".layim-content"))},end:i.end})},L=function(i,e,t){return i=i||{},i.id?(n.close(L.index),L.index=N({tpl:v,data:i,title:i.name,isChat:!0,success:function(e){x=a(e),B(),$(),delete C.message[i.type+i.id],_("Msg");var t=T(),n=t.elem.find(".layim-chat-main");layui.each(r.chatChange,function(i,e){e&&e(t)}),A(n),t.textarea.on("focus",function(){setTimeout(function(){n.scrollTop(n[0].scrollHeight+1e3)},500)})},end:function(){x=null,q.time=0}},e)):n.msg("非法用户")},A=function(i){s.ios&&i.on("touchmove",function(e){var a=i.scrollTop();a<=0&&(i.scrollTop(1),e.preventDefault(e)),this.scrollHeight-a-i.height()<=0&&(i.scrollTop(i.scrollTop()-1),e.preventDefault(e))})},T=function(){if(!x)return{};var i=x.find(".layim-chat"),e=JSON.parse(decodeURIComponent(i.find(".layim-chat-tool").data("json")));return{elem:i,data:e,textarea:i.find("input")}},j=function(i,e,a){var t=[],n=function(i,a){var t=i[e],n=a[e];return nt?1:0};return layui.each(i,function(i,e){t.push(e)}),t.sort(n),a&&t.reverse(),t},H=function(i){var e=layui.data("layim-mobile")[C.mine.id]||{},a={},n=e.history||{};n[i.type+i.id];if(b){var l=b.find(".layim-list-history");i.historyTime=(new Date).getTime(),i.sign=i.content,n[i.type+i.id]=i,e.history=n,layui.data("layim-mobile",{key:C.mine.id,value:e});var s=l.find(".layim-"+i.type+i.id),c=(C.message[i.type+i.id]||[]).length,d=function(){s=l.find(".layim-"+i.type+i.id),s.find("p").html(i.content),c>0&&s.find(".layim-msg-status").html(c).addClass(o)};if(s.length>0)d(),l.prepend(s.clone()),s.remove();else{a[i.type+i.id]=i;var r=t(p({type:"history",item:"d.data"})).render({data:a});l.prepend(r),d(),l.find(".layim-null").remove()}_("Msg")}},_=function(i,e){if(!e){var e;layui.each(C.message,function(){return e=!0,!1})}a("#LAY_layimNew"+i)[e?"addClass":"removeClass"](o)},q=function(){var i={username:C.mine?C.mine.username:"访客",avatar:C.mine?C.mine.avatar:layui.cache.dir+"css/pc/layim/skin/logo.jpg",id:C.mine?C.mine.id:null,mine:!0},e=T(),a=e.elem.find(".layim-chat-main ul"),l=e.data,s=C.base.maxLength||3e3,o=(new Date).getTime(),c=e.textarea;if(i.content=c.val(),""!==i.content){if(i.content.length>s)return n.msg("内容最长不能超过"+s+"个字符");o-(q.time||0)>6e4&&(a.append('
          • '+layui.data.date()+"
          • "),q.time=o),a.append(t(w).render(i));var d={mine:i,to:l},u={username:d.mine.username,avatar:d.mine.avatar,id:l.id,type:l.type,content:d.mine.content,timestamp:o,mine:!0};F(u),layui.each(r.sendMessage,function(i,e){e&&e(d)}),l.content=i.content,H(l),J(),c.val(""),c.next().addClass("layui-disabled")}},D=function(){var i=document.createElement("audio");i.src=layui.cache.dir+"css/modules/layim/voice/"+C.base.voice,i.play()},I={},M=function(i){i=i||{};var e={},a=T(),n=a.data||{},l=n.id==i.id&&n.type==i.type;if(i.timestamp=i.timestamp||(new Date).getTime(),i.system||F(i),I=JSON.parse(JSON.stringify(i)),C.base.voice&&D(),!x&&i.content||!l){if(C.message[i.type+i.id])C.message[i.type+i.id].push(i);else if(C.message[i.type+i.id]=[i],"friend"===i.type){var s;layui.each(C.friend,function(e,a){if(layui.each(a.list,function(e,a){if(a.id==i.id)return a.type="friend",a.name=a.username,C.chat.push(a),s=!0}),s)return!0}),s||(i.name=i.username,i.temporary=!0,C.chat.push(i))}else if("group"===i.type){var o;layui.each(C.group,function(e,a){if(a.id==i.id)return a.type="group",a.name=a.groupname,C.chat.push(a),o=!0}),o||(i.name=i.groupname,C.chat.push(i))}else i.name=i.name||i.username||i.groupname,C.chat.push(i);"group"===i.type&&layui.each(C.group,function(a,t){if(t.id==i.id)return e.avatar=t.avatar,!0}),!i.system}if(H(i),x&&l){var c=x.find(".layim-chat"),d=c.find(".layim-chat-main ul");i.system?d.append('
          • '+i.content+"
          • "):""!==i.content.replace(/\s/g,"")&&(i.timestamp-(q.time||0)>6e4&&(d.append('
          • '+layui.data.date(i.timestamp)+"
          • "),q.time=i.timestamp),d.append(t(w).render(i))),J()}},F=function(i){var e=layui.data("layim-mobile")[C.mine.id]||{},a=e.chatlog||{};a[i.type+i.id]?(a[i.type+i.id].push(i),a[i.type+i.id].length>d&&a[i.type+i.id].shift()):a[i.type+i.id]=[i],e.chatlog=a,layui.data("layim-mobile",{key:C.mine.id,value:e})},$=function(){var i=layui.data("layim-mobile")[C.mine.id]||{},e=T(),a=i.chatlog||{},n=e.elem.find(".layim-chat-main ul");layui.each(a[e.data.type+e.data.id],function(i,e){(new Date).getTime()>e.timestamp&&e.timestamp-(q.time||0)>6e4&&(n.append('
          • '+layui.data.date(e.timestamp)+"
          • "),q.time=e.timestamp),n.append(t(w).render(e))}),J()},O=function(i){var e,a={},l=b.find(".layim-list-"+i.type);if(C[i.type])if("friend"===i.type)layui.each(C.friend,function(t,l){if(i.groupid==l.id)return layui.each(C.friend[t].list,function(a,t){if(t.id==i.id)return e=!0}),e?n.msg("好友 ["+(i.username||"")+"] 已经存在列表中",{anim:6}):(C.friend[t].list=C.friend[t].list||[],a[C.friend[t].list.length]=i,i.groupIndex=t,C.friend[t].list.push(i),!0)});else if("group"===i.type){if(layui.each(C.group,function(a,t){if(t.id==i.id)return e=!0}),e)return n.msg("您已是 ["+(i.groupname||"")+"] 的群成员",{anim:6});a[C.group.length]=i,C.group.push(i)}if(!e){var s=t(p({type:i.type,item:"d.data",index:"friend"===i.type?"data.groupIndex":null})).render({data:a});if("friend"===i.type){var o=l.children("li").eq(i.groupIndex);o.find(".layui-layim-list").append(s),o.find(".layim-count").html(C.friend[i.groupIndex].list.length),o.find(".layim-null")[0]&&o.find(".layim-null").remove()}else"group"===i.type&&(l.append(s),l.find(".layim-null")[0]&&l.find(".layim-null").remove())}},Y=function(i){var e=b.find(".layim-list-"+i.type);C[i.type]&&("friend"===i.type?layui.each(C.friend,function(a,t){layui.each(t.list,function(t,n){if(i.id==n.id){var l=e.children("li").eq(a);l.find(".layui-layim-list").children("li");return l.find(".layui-layim-list").children("li").eq(t).remove(),C.friend[a].list.splice(t,1),l.find(".layim-count").html(C.friend[a].list.length),0===C.friend[a].list.length&&l.find(".layui-layim-list").html('
          • 该分组下已无好友了
          • '),!0}})}):"group"===i.type&&layui.each(C.group,function(a,t){if(i.id==t.id)return e.children("li").eq(a).remove(),C.group.splice(a,1),0===C.group.length&&e.html('
          • 暂无群组
          • '),!0}))},J=function(){var i=T(),e=i.elem.find(".layim-chat-main"),a=e.find("ul"),t=a.children(".layim-chat-li");if(t.length>=d){var n=t.eq(0);n.prev().remove(),a.prev().hasClass("layim-chat-system")||a.before('
            查看更多记录
            '),n.remove()}e.scrollTop(e[0].scrollHeight+1e3)},B=function(){var i=T(),e=i.textarea,a=e.next();e.off("keyup").on("keyup",function(i){var t=i.keyCode;13===t&&(i.preventDefault(),q()),a[""===e.val()?"addClass":"removeClass"]("layui-disabled")})},E=function(){var i=["[微笑]","[嘻嘻]","[哈哈]","[可爱]","[可怜]","[挖鼻]","[吃惊]","[害羞]","[挤眼]","[闭嘴]","[鄙视]","[爱你]","[泪]","[偷笑]","[亲亲]","[生病]","[太开心]","[白眼]","[右哼哼]","[左哼哼]","[嘘]","[衰]","[委屈]","[吐]","[哈欠]","[抱抱]","[怒]","[疑问]","[馋嘴]","[拜拜]","[思考]","[汗]","[困]","[睡]","[钱]","[失望]","[酷]","[色]","[哼]","[鼓掌]","[晕]","[悲伤]","[抓狂]","[黑线]","[阴险]","[怒骂]","[互粉]","[心]","[伤心]","[猪头]","[熊猫]","[兔子]","[ok]","[耶]","[good]","[NO]","[赞]","[来]","[弱]","[草泥马]","[神马]","[囧]","[浮云]","[给力]","[围观]","[威武]","[奥特曼]","[礼物]","[钟]","[话筒]","[蜡烛]","[蛋糕]"],e={};return layui.each(i,function(i,a){e[a]=layui.cache.dir+"images/face/"+i+".gif"}),e}(),P=layui.stope,R=function(i,e,a){var t,n=i.value;a||i.focus(),document.selection?(t=document.selection.createRange(),document.selection.empty(),t.text=e):(t=[n.substring(0,i.selectionStart),e,n.substr(i.selectionEnd)],a||i.focus(),i.value=t.join(""))},U={chat:function(i){var e=layui.data("layim-mobile")[C.mine.id]||{},t=i.data("type"),n=i.data("index"),l=i.attr("data-list")||i.index(),s={};"friend"===t?s=C[t][n].list[l]:"group"===t?s=C[t][l]:"history"===t&&(s=(e.history||{})[n]||{}),s.name=s.name||s.username||s.groupname,"history"!==t&&(s.type=t),L(s,!0),a(".layim-"+s.type+s.id).find(".layim-msg-status").removeClass(o)},spread:function(i){var e=i.attr("lay-type"),a="true"===e?"false":"true",t=layui.data("layim-mobile")[C.mine.id]||{};i.next()["true"===e?"removeClass":"addClass"](o),t["spread"+i.parent().index()]=a,layui.data("layim-mobile",{key:C.mine.id,value:t}),i.attr("lay-type",a),i.find(".layui-icon").html("true"===a?"":"")},tab:function(i){var e=i.index(),a=".layim-tab-content";i.addClass(c).siblings().removeClass(c),b.find(a).eq(e).addClass(o).siblings(a).removeClass(o)},back:function(i){var e=i.parents(".layui-m-layer").eq(0),a=e.attr("index"),t=".layim-panel";setTimeout(function(){n.close(a)},300),i.parents(t).eq(0).removeClass("layui-m-anim-left").addClass("layui-m-anim-rout"),e.prev().find(t).eq(0).removeClass("layui-m-anim-lout").addClass("layui-m-anim-right"),layui.each(r.back,function(i,e){setTimeout(function(){e&&e()},200)})},send:function(){q()},face:function(i,e){var t="",l=T(),s=l.textarea;layui.each(E,function(i,e){t+='
          • '}),t='
              '+t+"
            ",n.popBottom({content:t,success:function(i){var e=a(i).find(".layui-layim-face").children("li");m(e,function(){return R(s[0],"face"+this.title+" ",!0),s.next()[""===s.val()?"addClass":"removeClass"]("layui-disabled"),!1})}});var o=a(document);y?o.off("touchend",U.faceHide).on("touchend",U.faceHide):o.off("click",U.faceHide).on("click",U.faceHide),P(e)},faceHide:function(){n.close(n.popBottom.index),a(document).off("touchend",U.faceHide).off("click",U.faceHide)},image:function(i){var e=i.data("type")||"images",a={images:"uploadImage",file:"uploadFile"},t=T(),s=C.base[a[e]]||{};l({url:s.url||"",method:s.type,elem:i.find("input")[0],unwrap:!0,type:e,success:function(i){0==i.code?(i.data=i.data||{},"images"===e?R(t.textarea[0],"img["+(i.data.src||"")+"]"):"file"===e&&R(t.textarea[0],"file("+(i.data.src||"")+")["+(i.data.name||"下载文件")+"]"),q()):n.msg(i.msg||"上传失败")}})},extend:function(i){var e=i.attr("lay-filter"),a=T();layui.each(r["tool("+e+")"],function(e,t){t&&t.call(i,function(i){R(a.textarea[0],i)},q,a)})},newFriend:function(){layui.each(r.newFriend,function(i,e){e&&e()})},group:function(){N({title:"群聊",tpl:'
            尚未开放,请先采用私聊
            ',data:{}})},playAudio:function(i){var e=U.playAudio.audio,a=e||document.createElement("audio"),t=function(){a.pause(),i.removeAttr("status"),i.find("i").html("")};return a.play?void(i.attr("status")?t():(e||(a.src=i.data("src")),a.play(),i.attr("status","pause"),U.playAudio.audio=a,i.find("i").html(""),a.onended=function(){t()},a.onerror=function(){n.msg("播放音频源异常")})):n.msg("您的浏览器不支持audio")},playVideo:function(i){var e=i.data("src"),a=document.createElement("video");return a.play?(n.close(U.playVideo.index),void(U.playVideo.index=n.open({type:1,style:"width: 100%; height: 50%;",content:'
            '}))):n.msg("您的浏览器不支持video")},chatLog:function(i){var e=T();layui.each(r.chatlog,function(i,a){a&&a(e.data,e.elem.find(".layim-chat-main>ul"))})},moreList:function(i){var e=i.attr("lay-filter");layui.each(r.moreList,function(i,a){a&&a({alias:e})})},about:function(){n.open({content:'

            LayIM属于付费产品,欢迎通过官网获得授权,促进良性发展!

            当前版本:layim mobile v'+e+'

            版权所有:layim.layui.com

            ',className:"layim-about"})}};i("layim-mobile",new u)}).addcss("modules/layim/mobile/layim.css?v=2.00","skinlayim-mobilecss");layui["layui.mobile"]||layui.config({base:layui.cache.dir+"lay/modules/mobile/"}).extend({"layer-mobile":"layer-mobile",zepto:"zepto","upload-mobile":"upload-mobile","layim-mobile":"layim-mobile"}),layui.define(["layer-mobile","zepto","layim-mobile"],function(l){l("mobile",{layer:layui["layer-mobile"],layim:layui["layim-mobile"]})}); \ No newline at end of file diff --git a/build/lay/modules/tree.js b/build/lay/modules/tree.js deleted file mode 100644 index 221c0629c..000000000 --- a/build/lay/modules/tree.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("jquery",function(e){"use strict";var o=layui.jquery,a=layui.hint(),r="layui-tree-enter",i=function(e){this.options=e},t={arrow:["",""],checkbox:["",""],radio:["",""],branch:["",""],leaf:""};i.prototype.init=function(e){var o=this;e.addClass("layui-box layui-tree"),o.options.skin&&e.addClass("layui-tree-skin-"+o.options.skin),o.tree(e),o.on(e)},i.prototype.tree=function(e,a){var r=this,i=r.options,n=a||i.nodes;layui.each(n,function(a,n){var l=n.children&&n.children.length>0,c=o('
              '),s=o(["
            • ",function(){return l?''+(n.spread?t.arrow[1]:t.arrow[0])+"":""}(),function(){return i.check?''+("checkbox"===i.check?t.checkbox[0]:"radio"===i.check?t.radio[0]:"")+"":""}(),function(){return'"+(''+(l?n.spread?t.branch[1]:t.branch[0]:t.leaf)+"")+(""+(n.name||"未命名")+"")}(),"
            • "].join(""));l&&(s.append(c),r.tree(c,n.children)),e.append(s),"function"==typeof i.click&&r.click(s,n),r.spread(s,n),i.drag&&r.drag(s,n)})},i.prototype.click=function(e,o){var a=this,r=a.options;e.children("a").on("click",function(e){layui.stope(e),r.click(o)})},i.prototype.spread=function(e,o){var a=this,r=(a.options,e.children(".layui-tree-spread")),i=e.children("ul"),n=e.children("a"),l=function(){e.data("spread")?(e.data("spread",null),i.removeClass("layui-show"),r.html(t.arrow[0]),n.find(".layui-icon").html(t.branch[0])):(e.data("spread",!0),i.addClass("layui-show"),r.html(t.arrow[1]),n.find(".layui-icon").html(t.branch[1]))};i[0]&&(r.on("click",l),n.on("dblclick",l))},i.prototype.on=function(e){var a=this,i=a.options,t="layui-tree-drag";e.find("i").on("selectstart",function(e){return!1}),i.drag&&o(document).on("mousemove",function(e){var r=a.move;if(r.from){var i=(r.to,o('
              '));e.preventDefault(),o("."+t)[0]||o("body").append(i);var n=o("."+t)[0]?o("."+t):i;n.addClass("layui-show").html(r.from.elem.children("a").html()),n.css({left:e.pageX+10,top:e.pageY+10})}}).on("mouseup",function(){var e=a.move;e.from&&(e.from.elem.children("a").removeClass(r),e.to&&e.to.elem.children("a").removeClass(r),a.move={},o("."+t).remove())})},i.prototype.move={},i.prototype.drag=function(e,a){var i=this,t=(i.options,e.children("a")),n=function(){var t=o(this),n=i.move;n.from&&(n.to={item:a,elem:e},t.addClass(r))};t.on("mousedown",function(){var o=i.move;o.from={item:a,elem:e}}),t.on("mouseenter",n).on("mousemove",n).on("mouseleave",function(){var e=o(this),a=i.move;a.from&&(delete a.to,e.removeClass(r))})},e("tree",function(e){var r=new i(e=e||{}),t=o(e.elem);return t[0]?void r.init(t):a.error("layui.tree 没有找到"+e.elem+"元素")})}); \ No newline at end of file diff --git a/build/lay/modules/upload.js b/build/lay/modules/upload.js deleted file mode 100644 index d5b78f943..000000000 --- a/build/lay/modules/upload.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("layer",function(e){"use strict";var a=layui.jquery,t=layui.layer,i=(layui.device(),"layui-upload-enter"),n="layui-upload-iframe",r={icon:2,shift:6},o={file:"文件",video:"视频",audio:"音频"},s=function(e){this.options=e};s.prototype.init=function(){var e=this,t=e.options,r=a("body"),s=a(t.elem||".layui-upload-file"),u=a('');return a("#"+n)[0]||r.append(u),s.each(function(r,s){s=a(s);var u='
              ',l=s.attr("lay-type")||t.type;t.unwrap||(u='
              '+u+''+(s.attr("lay-title")||t.title||"上传"+(o[l]||"图片"))+"
              "),u=a(u),t.unwrap||u.on("dragover",function(e){e.preventDefault(),a(this).addClass(i)}).on("dragleave",function(){a(this).removeClass(i)}).on("drop",function(){a(this).removeClass(i)}),s.parent("form").attr("target")===n&&(t.unwrap?s.unwrap():(s.parent().next().remove(),s.unwrap().unwrap())),s.wrap(u),s.off("change").on("change",function(){e.action(this,l)})})},s.prototype.action=function(e,i){var o=this,s=o.options,u=e.value,l=a(e),p=l.attr("lay-ext")||s.ext||"";if(u){switch(i){case"file":if(p&&!RegExp("\\w\\.("+p+")$","i").test(escape(u)))return t.msg("不支持该文件格式",r),e.value="";break;case"video":if(!RegExp("\\w\\.("+(p||"avi|mp4|wma|rmvb|rm|flash|3gp|flv")+")$","i").test(escape(u)))return t.msg("不支持该视频格式",r),e.value="";break;case"audio":if(!RegExp("\\w\\.("+(p||"mp3|wav|mid")+")$","i").test(escape(u)))return t.msg("不支持该音频格式",r),e.value="";break;default:if(!RegExp("\\w\\.("+(p||"jpg|png|gif|bmp|jpeg")+")$","i").test(escape(u)))return t.msg("不支持该图片格式",r),e.value=""}s.before&&s.before(e),l.parent().submit();var c=a("#"+n),f=setInterval(function(){var a;try{a=c.contents().find("body").text()}catch(i){t.msg("上传接口存在跨域",r),clearInterval(f)}if(a){clearInterval(f),c.contents().find("body").html("");try{a=JSON.parse(a)}catch(i){return a={},t.msg("请对上传接口返回JSON字符",r)}"function"==typeof s.success&&s.success(a,e)}},30);e.value=""}},e("upload",function(e){var a=new s(e=e||{});a.init()})}); \ No newline at end of file diff --git a/build/lay/modules/util.js b/build/lay/modules/util.js deleted file mode 100644 index 2f6938f4e..000000000 --- a/build/lay/modules/util.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;layui.define("jquery",function(l){"use strict";var o=layui.jquery,i={fixbar:function(l){l=l||{},l.bgcolor=l.bgcolor?"background-color:"+l.bgcolor:"";var i,a,c="layui-fixbar-top",t=[l.bar1===!0?"":l.bar1,l.bar2===!0?"":l.bar2,""],r=o(['
                ',l.bar1?'
              • '+t[0]+"
              • ":"",l.bar2?'
              • '+t[1]+"
              • ":"",'
              • '+t[2]+"
              • ","
              "].join("")),e=r.find("."+c),s=function(){var i=o(document).scrollTop();i>=(l.showHeight||200)?a||(e.show(),a=1):a&&(e.hide(),a=0)};o(".layui-fixbar")[0]||("object"==typeof l.css&&r.css(l.css),o("body").append(r),s(),r.find("li").on("click",function(){var i=o(this),a=i.attr("lay-type");"top"===a&&o("html,body").animate({scrollTop:0},200),l.click&&l.click.call(this,a)}),o(document).on("scroll",function(){i&&clearTimeout(i),i=setTimeout(function(){s()},100)}))}};l("util",i)}); \ No newline at end of file diff --git a/build/layui.js b/build/layui.js deleted file mode 100644 index 7abfe7bb1..000000000 --- a/build/layui.js +++ /dev/null @@ -1,2 +0,0 @@ -/** layui-v1.0.9_rls MIT License By http://www.layui.com */ - ;!function(e){"use strict";var t=function(){this.v="1.0.9_rls"};t.fn=t.prototype;var n=document,o=t.fn.cache={},i=function(){var e=n.scripts,t=e[e.length-1].src;return t.substring(0,t.lastIndexOf("/")+1)}(),r=function(t){e.console&&console.error&&console.error("Layui hint: "+t)},a="undefined"!=typeof opera&&"[object Opera]"===opera.toString(),l={layer:"modules/layer",laydate:"modules/laydate",laypage:"modules/laypage",laytpl:"modules/laytpl",layim:"modules/layim",layedit:"modules/layedit",form:"modules/form",upload:"modules/upload",tree:"modules/tree",table:"modules/table",element:"modules/element",util:"modules/util",flow:"modules/flow",carousel:"modules/carousel",code:"modules/code",jquery:"modules/jquery",mobile:"modules/mobile","layui.all":"dest/layui.all"};o.modules={},o.status={},o.timeout=10,o.event={},t.fn.define=function(e,t){var n=this,i="function"==typeof e,r=function(){return"function"==typeof t&&t(function(e,t){layui[e]=t,o.status[e]=!0}),this};return i&&(t=e,e=[]),layui["layui.all"]||!layui["layui.all"]&&layui["layui.mobile"]?r.call(n):(n.use(e,r),n)},t.fn.use=function(e,t,u){function s(e,t){var n="PLaySTATION 3"===navigator.platform?/^complete$/:/^(complete|loaded)$/;("load"===e.type||n.test((e.currentTarget||e.srcElement).readyState))&&(o.modules[m]=t,y.removeChild(v),function i(){return++p>1e3*o.timeout/4?r(m+" is not a valid module"):void(o.status[m]?c():setTimeout(i,4))}())}function c(){u.push(layui[m]),e.length>1?f.use(e.slice(1),t,u):"function"==typeof t&&t.apply(layui,u)}var f=this,d=o.dir=o.dir?o.dir:i,y=n.getElementsByTagName("head")[0];e="string"==typeof e?[e]:e,window.jQuery&&jQuery.fn.on&&(f.each(e,function(t,n){"jquery"===n&&e.splice(t,1)}),layui.jquery=jQuery);var m=e[0],p=0;if(u=u||[],o.host=o.host||(d.match(/\/\/([\s\S]+?)\//)||["//"+location.host+"/"])[0],0===e.length||layui["layui.all"]&&l[m]||!layui["layui.all"]&&layui["layui.mobile"]&&l[m])return c(),f;var v=n.createElement("script"),h=(l[m]?d+"lay/":o.base||"")+(f.modules[m]||m)+".js";return v.async=!0,v.charset="utf-8",v.src=h+function(){var e=o.version===!0?o.v||(new Date).getTime():o.version||"";return e?"?v="+e:""}(),o.modules[m]?!function g(){return++p>1e3*o.timeout/4?r(m+" is not a valid module"):void("string"==typeof o.modules[m]&&o.status[m]?c():setTimeout(g,4))}():(y.appendChild(v),!v.attachEvent||v.attachEvent.toString&&v.attachEvent.toString().indexOf("[native code")<0||a?v.addEventListener("load",function(e){s(e,h)},!1):v.attachEvent("onreadystatechange",function(e){s(e,h)})),o.modules[m]=h,f},t.fn.getStyle=function(t,n){var o=t.currentStyle?t.currentStyle:e.getComputedStyle(t,null);return o[o.getPropertyValue?"getPropertyValue":"getAttribute"](n)},t.fn.link=function(e,t,i){var a=this,l=n.createElement("link"),u=n.getElementsByTagName("head")[0];"string"==typeof t&&(i=t);var s=(i||e).replace(/\.|\//g,""),c=l.id="layuicss-"+s,f=0;return l.rel="stylesheet",l.href=e+(o.debug?"?v="+(new Date).getTime():""),l.media="all",n.getElementById(c)||u.appendChild(l),"function"!=typeof t?a:(function d(){return++f>1e3*o.timeout/100?r(e+" timeout"):void(1989===parseInt(a.getStyle(n.getElementById(c),"width"))?function(){t()}():setTimeout(d,100))}(),a)},t.fn.addcss=function(e,t,n){return layui.link(o.dir+"css/"+e,t,n)},t.fn.img=function(e,t,n){var o=new Image;return o.src=e,o.complete?t(o):(o.onload=function(){o.onload=null,t(o)},void(o.onerror=function(e){o.onerror=null,n(e)}))},t.fn.config=function(e){e=e||{};for(var t in e)o[t]=e[t];return this},t.fn.modules=function(){var e={};for(var t in l)e[t]=l[t];return e}(),t.fn.extend=function(e){var t=this;e=e||{};for(var n in e)t[n]||t.modules[n]?r("模块名 "+n+" 已被占用"):t.modules[n]=e[n];return t},t.fn.router=function(e){var t=this,e=e||location.hash,n={path:[],search:{},hash:(e.match(/[^#](#.*$)/)||[])[1]||""};return/^#\//.test(e)?(e=e.replace(/^#\//,"").replace(/([^#])(#.*$)/,"$1").split("/")||[],t.each(e,function(e,t){/^\w+=/.test(t)?function(){t=t.split("="),n.search[t[0]]=t[1]}():n.path.push(t)}),n):n},t.fn.data=function(t,n){if(t=t||"layui",e.JSON&&e.JSON.parse){if(null===n)return delete localStorage[t];n="object"==typeof n?n:{key:n};try{var o=JSON.parse(localStorage[t])}catch(i){var o={}}return n.value&&(o[n.key]=n.value),n.remove&&delete o[n.key],localStorage[t]=JSON.stringify(o),n.key?o[n.key]:o}},t.fn.device=function(t){var n=navigator.userAgent.toLowerCase(),o=function(e){var t=new RegExp(e+"/([^\\s\\_\\-]+)");return e=(n.match(t)||[])[1],e||!1},i={os:function(){return/windows/.test(n)?"windows":/linux/.test(n)?"linux":/mac/.test(n)?"mac":/iphone|ipod|ipad|ios/.test(n)?"ios":void 0}(),ie:function(){return!!(e.ActiveXObject||"ActiveXObject"in e)&&((n.match(/msie\s(\d+)/)||[])[1]||"11")}(),weixin:o("micromessenger")};return t&&!i[t]&&(i[t]=o(t)),i.android=/android/.test(n),i.ios="ios"===i.os,i},t.fn.hint=function(){return{error:r}},t.fn.each=function(e,t){var n,o=this;if("function"!=typeof t)return o;if(e=e||[],e.constructor===Object){for(n in e)if(t.call(e[n],n,e[n]))break}else for(n=0;n' + separator + ''); + }); + othis.css('visibility', 'visible'); + }); + } +}); + +export { component as breadcrumb }; diff --git a/dist/components/carousel.js b/dist/components/carousel.js new file mode 100644 index 000000000..45adfa8fb --- /dev/null +++ b/dist/components/carousel.js @@ -0,0 +1,318 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * carousel + * 轮播 + */ + + +// 创建组件 +var component = component$1({ + name: 'carousel', + // 默认配置 + config: { + width: '600px', + height: '280px', + full: false, + // 是否全屏 + arrow: 'hover', + // 切换箭头默认显示状态:hover/always/none + indicator: 'inside', + // 指示器位置:inside/outside/none + autoplay: true, + // 是否自动切换 + interval: 3000, + // 自动切换的时间间隔,不能低于 800ms + anim: '', + // 动画类型:default/updown/fade + trigger: 'click', + // 指示器的触发方式:click/hover + index: 0 // 初始开始的索引 + }, + CONST: { + ELEM: 'layui-carousel', + ELEM_ITEM: '>*[carousel-item]>*', + ELEM_LEFT: 'layui-carousel-left', + ELEM_RIGHT: 'layui-carousel-right', + ELEM_PREV: 'layui-carousel-prev', + ELEM_NEXT: 'layui-carousel-next', + ELEM_ARROW: 'layui-carousel-arrow', + ELEM_IND: 'layui-carousel-ind' + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + that.elemItem = options.elem.find(CONST.ELEM_ITEM); + if (options.index < 0) { + options.index = 0; + } + if (options.index >= that.elemItem.length) { + options.index = that.elemItem.length - 1; + } + if (options.interval < 800) { + options.interval = 800; + } + + // 是否全屏模式 + if (options.full) { + options.elem.css({ + position: 'fixed', + width: '100%', + height: '100%', + zIndex: 9999 + }); + } else { + options.elem.css({ + width: options.width, + height: options.height + }); + } + options.elem.attr('lay-anim', options.anim); + + // 初始焦点状态 + that.elemItem.eq(options.index).addClass(CONST.CLASS_THIS); + + // 指示器、箭头等动作 + that.indicator(); + that.arrow(); + that.autoplay(); + }, + // 扩展实例方法 + extendsInstance: function () { + var that = this; + + // 确保与文档描述一致 + return { + elemInd: that.elemInd, + elemItem: that.elemItem, + timer: that.timer, + goto: function (index) { + that.goto(index); + } + }; + } +}); +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 获取上一个等待条目的索引 +Class.prototype.prevIndex = function () { + var that = this; + var options = that.config; + var prevIndex = options.index - 1; + if (prevIndex < 0) { + prevIndex = that.elemItem.length - 1; + } + return prevIndex; +}; + +// 获取下一个等待条目的索引 +Class.prototype.nextIndex = function () { + var that = this; + var options = that.config; + var nextIndex = options.index + 1; + if (nextIndex >= that.elemItem.length) { + nextIndex = 0; + } + return nextIndex; +}; + +// 索引递增 +Class.prototype.addIndex = function (num) { + var that = this; + var options = that.config; + num = num || 1; + options.index = options.index + num; + + // index 不能超过轮播总数量 + if (options.index >= that.elemItem.length) { + options.index = 0; + } +}; + +// 索引递减 +Class.prototype.subIndex = function (num) { + var that = this; + var options = that.config; + num = num || 1; + options.index = options.index - num; + + // index 不能超过轮播总数量 + if (options.index < 0) { + options.index = that.elemItem.length - 1; + } +}; + +// 自动轮播 +Class.prototype.autoplay = function () { + var that = this; + var options = that.config; + var itemsCount = that.elemItem.length; + if (!options.autoplay) return; + clearInterval(that.timer); + if (itemsCount > 1) { + that.timer = setInterval(function () { + that.slide(); + }, options.interval); + } +}; + +// 箭头 +Class.prototype.arrow = function () { + var that = this; + var options = that.config; + var itemsCount = that.elemItem.length; + + // 模板 + var tplArrow = $(['', ''].join('')); + + // 预设基础属性 + options.elem.attr('lay-arrow', options.arrow); + + // 避免重复插入 + if (options.elem.find('.' + CONST.ELEM_ARROW)[0]) { + options.elem.find('.' + CONST.ELEM_ARROW).remove(); + } + itemsCount > 1 ? options.elem.append(tplArrow) : tplArrow.remove(); + + // 事件 + tplArrow.on('click', function () { + var othis = $(this); + var type = othis.attr('lay-type'); + that.slide(type); + }); +}; + +// 跳转到特定下标 +Class.prototype.goto = function (index) { + var that = this; + var options = that.config; + if (index > options.index) { + that.slide('add', index - options.index); + } else if (index < options.index) { + that.slide('sub', options.index - index); + } +}; + +// 指示器 +Class.prototype.indicator = function () { + var that = this; + var options = that.config; + var itemsCount = that.elemItem.length; + + // 模板 + var tplInd = that.elemInd = $(['
                ', function () { + var li = []; + layui.each(that.elemItem, function (index) { + li.push(''); + }); + return li.join(''); + }(), '
              '].join('')); + + // 预设基础属性 + options.elem.attr('lay-indicator', options.indicator); + + // 避免重复插入 + if (options.elem.find('.' + CONST.ELEM_IND)[0]) { + options.elem.find('.' + CONST.ELEM_IND).remove(); + } + itemsCount > 1 ? options.elem.append(tplInd) : tplInd.remove(); + if (options.anim === 'updown') { + tplInd.css('margin-top', -(tplInd.height() / 2)); + } + + // 事件 + tplInd.find('li').on(options.trigger === 'hover' ? 'mouseover' : options.trigger, function () { + that.goto($(this).index()); + }); +}; + +// 滑动切换 +Class.prototype.slide = function (type, num) { + var that = this; + var elemItem = that.elemItem; + var itemsCount = elemItem.length; + var options = that.config; + var thisIndex = options.index; + var filter = options.elem.attr('lay-filter'); + if (that.haveSlide || itemsCount <= 1) return; + + // 滑动方向 + if (type === 'sub') { + that.subIndex(num); + elemItem.eq(options.index).addClass(CONST.ELEM_PREV); + setTimeout(function () { + elemItem.eq(thisIndex).addClass(CONST.ELEM_RIGHT); + elemItem.eq(options.index).addClass(CONST.ELEM_RIGHT); + }, 50); + } else { + // 默认递增滑 + that.addIndex(num); + elemItem.eq(options.index).addClass(CONST.ELEM_NEXT); + setTimeout(function () { + elemItem.eq(thisIndex).addClass(CONST.ELEM_LEFT); + elemItem.eq(options.index).addClass(CONST.ELEM_LEFT); + }, 50); + } + + // 移除过渡类 + setTimeout(function () { + elemItem.removeClass(CONST.CLASS_THIS + ' ' + CONST.ELEM_PREV + ' ' + CONST.ELEM_NEXT + ' ' + CONST.ELEM_LEFT + ' ' + CONST.ELEM_RIGHT); + elemItem.eq(options.index).addClass(CONST.CLASS_THIS); + that.haveSlide = false; // 解锁 + }, 350); + + // 指示器焦点 + that.elemInd.find('li').eq(options.index).addClass(CONST.CLASS_THIS).siblings().removeClass(CONST.CLASS_THIS); + that.haveSlide = true; + + // 回调返回的参数 + var params = { + index: options.index, + prevIndex: thisIndex, + item: elemItem.eq(options.index) + }; + typeof options.change === 'function' && options.change(params); + layui.event.call(this, CONST.MOD_NAME, 'change(' + filter + ')', params); +}; + +// 事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + if (options.elem.data('haveEvents')) return; + + // 移入移出容器 + options.elem.on('mouseenter touchstart', function () { + if (that.config.autoplay === 'always') return; + clearInterval(that.timer); + }).on('mouseleave touchend', function () { + if (that.config.autoplay === 'always') return; + that.autoplay(); + }); + var touchEl = options.elem; + var isVertical = options.anim === 'updown'; + lay.touchSwipe(touchEl, { + onTouchEnd: function (e, state) { + var duration = Date.now() - state.timeStart; + var distance = isVertical ? state.distanceY : state.distanceX; + var speed = distance / duration; + var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(distance) > touchEl[isVertical ? 'height' : 'width']() / 3; + if (shouldSwipe) { + that.slide(distance > 0 ? '' : 'sub'); + } + } + }); + options.elem.data('haveEvents', true); +}; + +export { component as carousel }; diff --git a/dist/components/code.js b/dist/components/code.js new file mode 100644 index 000000000..896ce6727 --- /dev/null +++ b/dist/components/code.js @@ -0,0 +1,685 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { util } from './util.js'; +import { element as component } from './element.js'; +import { layer } from './layer.js'; +import { form } from './form.js'; +import { tabs as component$1 } from './tabs.js'; + +/** + * code + * Code 预览组件 + */ + + +// 常量 +var CONST = { + ELEM_TAB: 'layui-tab', + ELEM_HEADER: 'layui-code-header', + ELEM_FULL: 'layui-code-full', + ELEM_PREVIEW: 'layui-code-preview', + ELEM_ITEM: 'layui-code-item', + ELEM_SHOW: 'layui-show', + ELEM_LINE: 'layui-code-line', + ELEM_LINE_NUM: 'layui-code-line-number', + ELEM_LN_MODE: 'layui-code-ln-mode', + CDDE_DATA_CLASS: 'LayuiCodeDataClass', + LINE_RAW_WIDTH: 45 // 行号初始宽度,需与 css 保持一致 +}; + +// 默认参数项 +var config = { + elem: '', + // 元素选择器 + about: '', + // 代码栏右上角信息 + ln: true, + // 代码区域是否显示行号 + header: false, + // 是否显示代码栏头部区域 + encode: true, + // 是否对 code 进行编码(若开启预览,则强制开启) + copy: true, + // 是否开启代码区域复制功能图标 + // 默认文本 + text: { + code: util.escape(''), + preview: 'Preview' + }, + wordWrap: true, + // 是否自动换行 + lang: 'text', + // 指定语言类型 + highlighter: false, + // 是否开启语法高亮,'hljs','prism','shiki' + langMarker: false, + // 代码区域是否显示语言类型标记 + // 行高亮 + highlightLine: { + // 聚焦 + focus: { + range: '', + // 高亮范围,不可全局设置值 '1,3-5,8' + comment: false, + // 是否解析注释,性能敏感不可全局开启 [!code type:] + classActiveLine: 'layui-code-line-has-focus', + // 添加到高亮行上的类 + classActivePre: 'layui-code-has-focused-lines' // 有高亮行时向根元素添加的类 + }, + // 高亮 + hl: { + comment: false, + classActiveLine: 'layui-code-line-highlighted' + }, + // diff++ + '++': { + comment: false, + classActiveLine: 'layui-code-line-diff-add' + }, + // diff-- + '--': { + comment: false, + classActiveLine: 'layui-code-line-diff-remove' + } + } +}; + +// 去除尾部空格 +var trimEnd = function (str) { + return String(str).replace(/\s+$/, ''); +}; +// 保留首行缩进 +var trim = function (str) { + return trimEnd(str).replace(/^\n|\n$/, ''); +}; + +// '1,3-5,8' -> [1,3,4,5,8] +var parseHighlightedLines = function (rangeStr) { + if (typeof rangeStr !== 'string') return []; + var lines = $.map(rangeStr.split(','), function (v) { + var range = v.split('-'); + var start = parseInt(range[0], 10); + var end = parseInt(range[1], 10); + return start && end ? $.map(new Array(end - start + 1), function (_, index) { + return start + index; + }) : start ? start : undefined; + }); + return lines; +}; + +// 引用自 https://github.com/innocenzi/shiki-processor/blob/efa20624be415c866cc8e350d1ada886b6b5cd52/src/utils/create-range-processor.ts#L7 +// 添加了 HTML 注释支持,用来处理预览场景 +var highlightLineRegex = /(?:\/\/|\/\*{1,2}||-->)?/; +var preprocessHighlightLine = function (highlightLineOptions, codeLines) { + var hasHighlightLine = false; + var needParseComment = false; + var lineClassMap = Object.create(null); + var preClassMap = Object.create(null); + var updateLineClassMap = function (lineNumber, className) { + if (!lineClassMap[lineNumber]) { + lineClassMap[lineNumber] = [CONST.ELEM_LINE]; + } + lineClassMap[lineNumber].push(className); + }; + + // 收集高亮行 className + $.each(highlightLineOptions, function (type, opts) { + if (opts.range) { + var highlightLines = parseHighlightedLines(opts.range); + if (highlightLines.length > 0) { + hasHighlightLine = true; + if (opts.classActivePre) { + preClassMap[opts.classActivePre] = true; + } + $.each(highlightLines, function (i, lineNumber) { + updateLineClassMap(lineNumber, opts.classActiveLine); + }); + } + } + if (opts.comment) { + needParseComment = true; + } + }); + + // 解析行高亮注释并收集 className + if (needParseComment) { + $.each(codeLines, function (i, line) { + var match = line.match(highlightLineRegex); + if (match && match[1] && lay.hasOwn(highlightLineOptions, match[1])) { + var opts = highlightLineOptions[match[1]]; + hasHighlightLine = true; + if (opts.classActivePre) { + preClassMap[opts.classActivePre] = true; + } + // 高亮的行数 + var lines = parseInt(match[2], 10); + if (match[2] && lines && lines > 1) { + var startLine = i + 1; + var endLine = startLine + lines - 1; + var highlightLines = parseHighlightedLines(startLine + '-' + endLine); + if (highlightLines.length > 0) { + $.each(highlightLines, function (i, lineNumber) { + updateLineClassMap(lineNumber, opts.classActiveLine); + }); + } + } else { + updateLineClassMap(i + 1, opts.classActiveLine); + } + } + }); + } + return { + needParseComment: needParseComment, + hasHighlightLine: hasHighlightLine, + preClass: Object.keys(preClassMap).join(' '), + lineClassMap: lineClassMap + }; +}; + +// export api +function code(options, mode) { + options = $.extend(true, {}, config, options); + + // 返回对象 + var ret = { + config: options, + reload: function (opts) { + // 重载 + layui.code(this.updateOptions(opts)); + }, + updateOptions: function (opts) { + // 更新属性(选项) + opts = opts || {}; + delete opts.elem; + return $.extend(true, options, opts); + }, + reloadCode: function (opts) { + // 仅重载 code + layui.code(this.updateOptions(opts), 'reloadCode'); + } + }; + + // 若 elem 非唯一 + var elem = $(options.elem); + if (elem.length > 1) { + // 是否正向渲染 + layui.each(options.obverse ? elem : elem.get().reverse(), function () { + layui.code($.extend({}, options, { + elem: this + }), mode); + }); + return ret; + } + + // 目标元素是否存在 + var othis = options.elem = $(options.elem); + if (!othis[0]) return ret; + + // 合并属性上的参数,并兼容旧版本属性写法 lay-* + $.extend(true, options, lay.options(othis[0]), function (obj) { + var attrs = ['title', 'height', 'encode', 'skin', 'about']; + layui.each(attrs, function (i, attr) { + var value = othis.attr('lay-' + attr); + if (typeof value === 'string') { + obj[attr] = value; + } + }); + return obj; + }({})); + + // codeRender 需要关闭编码 + // 未使用 codeRender 时若开启了预览,则强制开启编码 + options.encode = (options.encode || options.preview) && !options.codeRender; + + // 获得初始 code + options.code = options.code || function () { + var arr = []; + var textarea = othis.children('textarea'); + + // 若内容放置在 textarea 中 + textarea.each(function () { + arr.push(trim(this.value)); + }); + + // 内容直接放置在元素外层 + if (arr.length === 0) { + arr.push(trim(othis.html())); + } + return arr.join(''); + }(); + + // 创建 code 行结构 + var createCode = function (html) { + // codeRender + if (typeof options.codeRender === 'function') { + html = options.codeRender(String(html), options); + } + + // code 行 + var lines = String(html).split(/\r?\n/g); + + // 预处理行高亮 + var highlightLineInfo = preprocessHighlightLine(options.highlightLine, lines); + + // 包裹 code 行结构 + html = $.map(lines, function (line, num) { + var lineClass = highlightLineInfo.hasHighlightLine && highlightLineInfo.lineClassMap[num + 1] ? highlightLineInfo.lineClassMap[num + 1].join(' ') : CONST.ELEM_LINE; + return ['
              ', options.ln ? ['
              ', util.digit(num + 1) + '.', '
              '].join('') : '', '
              ', (highlightLineInfo.needParseComment ? line.replace(highlightLineRegex, '') : line) || ' ', '
              ', '
              '].join(''); + }); + if (highlightLineInfo.preClass) { + othis.addClass(highlightLineInfo.preClass); + } + return { + lines: lines, + html: html + }; + }; + + // 原始 code + var rawCode = options.code; + + // 最终 code + var finalCode = function (code) { + return typeof options.codeParse === 'function' ? options.codeParse(code, options) : code; + }; + + // 仅重载 code + if (mode === 'reloadCode') { + return othis.children('.layui-code-wrap').html(createCode(finalCode(rawCode)).html), ret; + } + + // 自增索引 + var index = lay.autoIncrementer('code'); + othis.attr('lay-code-index', index); + + // 初始化 className + var hasDataClass = CONST.CDDE_DATA_CLASS in othis.data(); + if (hasDataClass) { + othis.attr('class', othis.data(CONST.CDDE_DATA_CLASS) || ''); + } + + // 记录初始 className + if (!hasDataClass) { + othis.data(CONST.CDDE_DATA_CLASS, othis.attr('class')); + } + + // 工具栏 + var tools = { + copy: { + className: 'file-b', + title: [i18n.$t('code.copy')], + event: function () { + var code = util.unescape(finalCode(options.code)); + var hasOnCopy = typeof options.onCopy === 'function'; + + // 写入剪切板 + lay.clipboard.writeText({ + text: code, + done: function () { + if (hasOnCopy) { + var ret = options.onCopy(code, true); + if (ret === false) return; + } + layer.msg(i18n.$t('code.copied'), { + icon: 1 + }); + }, + error: function () { + if (hasOnCopy) { + var ret = options.onCopy(code, false); + if (ret === false) return; + } + layer.msg(i18n.$t('code.copyError'), { + icon: 2 + }); + } + }); + } + } + }; + + // 移除包裹结构 + (function fn() { + var elemViewHas = othis.parent('.' + CONST.ELEM_PREVIEW); + var elemTabHas = elemViewHas.children('.' + CONST.ELEM_TAB); + var elemPreviewViewHas = elemViewHas.children('.' + CONST.ELEM_ITEM + '-preview'); + + // 移除旧结构 + elemTabHas.remove(); // 移除 tab + elemPreviewViewHas.remove(); // 移除预览区域 + if (elemViewHas[0]) othis.unwrap(); // 移除外层容器 + + return fn; + })(); + + // 是否开启预览 + if (options.preview) { + var FILTER_VALUE = 'LAY-CODE-DF-' + index; + var layout = options.layout || ['code', 'preview']; + var isIframePreview = options.preview === 'iframe'; + + // 追加 Tab 组件 + var elemView = $('
              '); + var elemTabView = $('
              '); + var elemHeaderView = $('
              '); + var elemPreviewView = $('
              '); + var elemToolbar = $('
              '); + if (options.id) elemView.attr('id', options.id); + elemView.addClass(options.className); + elemTabView.attr('lay-filter', FILTER_VALUE); + + // 标签头 + layui.each(layout, function (i, v) { + var li = $('
            • '); + if (i === 0) li.addClass('layui-this'); + li.html(options.text[v]); + elemHeaderView.append(li); + }); + + // 工具栏 + $.extend(tools, { + full: { + className: 'screen-full', + title: [i18n.$t('code.maximize'), i18n.$t('code.restore')], + event: function (obj) { + var el = obj.elem; + var elemView = el.closest('.' + CONST.ELEM_PREVIEW); + var classNameFull = 'layui-icon-' + this.className; + var classNameRestore = 'layui-icon-screen-restore'; + var title = this.title; + var htmlElem = $('html,body'); + var ELEM_SCROLLBAR_HIDE = 'layui-scrollbar-hide'; + if (el.hasClass(classNameFull)) { + elemView.addClass(CONST.ELEM_FULL); + el.removeClass(classNameFull).addClass(classNameRestore); + el.attr('title', title[1]); + htmlElem.addClass(ELEM_SCROLLBAR_HIDE); + } else { + elemView.removeClass(CONST.ELEM_FULL); + el.removeClass(classNameRestore).addClass(classNameFull); + el.attr('title', title[0]); + htmlElem.removeClass(ELEM_SCROLLBAR_HIDE); + } + } + }, + window: { + className: 'release', + title: [i18n.$t('code.preview')], + event: function () { + util.openWin({ + content: finalCode(options.code) + }); + } + } + }); + + // copy + if (options.copy) { + if (layui.type(options.tools) === 'array') { + // 若 copy 未存在于 tools 中,则追加到最前 + if (options.tools.indexOf('copy') === -1) { + options.tools.unshift('copy'); + } + } else { + options.tools = ['copy']; + } + } + + // 工具栏事件 + elemToolbar.on('click', '>i', function () { + var oi = $(this); + var type = oi.data('type'); + var parameters = { + elem: oi, + type: type, + options: options, + // 当前属性选项 + rawCode: options.code, + // 原始 code + finalCode: util.unescape(finalCode(options.code)) // 最终 code + }; + + // 内部 tools event + tools[type] && typeof tools[type].event === 'function' && tools[type].event(parameters); + + // 外部 tools event + typeof options.toolsEvent === 'function' && options.toolsEvent(parameters); + }); + + // 增加工具栏 + if (options.addTools && options.tools) { + options.tools = [].concat(options.tools, options.addTools); + } + + // 渲染工具栏 + layui.each(options.tools, function (i, v) { + var viso = typeof v === 'object'; // 若为 object 值,则可自定义更多属性 + var tool = viso ? v : tools[v] || { + className: v, + title: [v] + }; + var className = tool.className || tool.type; + var title = tool.title || ['']; + var type = viso ? tool.type || className : v; + if (!type) return; + + // 若非内置 tool,则合并到 tools 中 + if (!tools[type]) { + var obj = {}; + obj[type] = tool; + $.extend(tools, obj); + } + elemToolbar.append(''); + }); + othis.addClass(CONST.ELEM_ITEM).wrap(elemView); // 包裹外层容器 + elemTabView.append(elemHeaderView); // 追加标签头 + options.tools && elemTabView.append(elemToolbar); // 追加工具栏 + othis.before(elemTabView); // 追加标签结构 + + // 追加预览 + if (isIframePreview) { + elemPreviewView.html(''); + } + + // 执行预览 + var runPreview = function (thisItemBody) { + var iframe = thisItemBody.children('iframe')[0]; + + // 是否 iframe 方式预览 + if (isIframePreview && iframe) { + iframe.srcdoc = finalCode(options.code); + } else { + thisItemBody.html(options.code); + } + + // 当前实例预览完毕后的回调 + setTimeout(function () { + typeof options.done === 'function' && options.done({ + container: thisItemBody, + options: options, + render: function () { + form.render(thisItemBody.find('.layui-form')); + component.render(); + component$1.render({ + elem: ['.' + CONST.ELEM_PREVIEW, '.layui-tabs'].join(' ') + }); + } + }); + }, 3); + }; + if (layout[0] === 'preview') { + elemPreviewView.addClass(CONST.ELEM_SHOW); + othis.before(elemPreviewView); + runPreview(elemPreviewView); + } else { + othis.addClass(CONST.ELEM_SHOW).after(elemPreviewView); + } + + // 内容项初始化样式 + options.previewStyle = [options.style, options.previewStyle].join(''); + elemPreviewView.attr('style', options.previewStyle); + + // tab change + component.on('tab(' + FILTER_VALUE + ')', function (data) { + var $this = $(this); + var thisElem = $(data.elem).closest('.' + CONST.ELEM_PREVIEW); + var elemItemBody = thisElem.find('.' + CONST.ELEM_ITEM); + var thisItemBody = elemItemBody.eq(data.index); + elemItemBody.removeClass(CONST.ELEM_SHOW); + thisItemBody.addClass(CONST.ELEM_SHOW); + if ($this.attr('lay-id') === 'preview') { + runPreview(thisItemBody); + } + setCodeLayout(); + }); + } + + // 创建 code 容器 + var codeElem = $(''); // 此处的闭合标签是为了兼容 IE8 + + // 添加主容器 className + othis.addClass(function (arr) { + if (!options.wordWrap) arr.push('layui-code-nowrap'); + return arr.join(' '); + }(['layui-code-view layui-border-box'])); + + // code 主题风格 + var theme = options.theme || options.skin; + if (theme) { + othis.removeClass('layui-code-theme-dark layui-code-theme-light'); + othis.addClass('layui-code-theme-' + theme); + } + + // 添加高亮必要的 className + if (options.highlighter) { + othis.addClass([options.highlighter, 'language-' + options.lang, 'layui-code-hl'].join(' ')); + } + + // 获取 code 行结构 + var createCodeRst = createCode(options.encode ? util.escape(finalCode(rawCode)) : rawCode // 是否编码 + ); + var lines = createCodeRst.lines; + + // 插入 code + othis.html(codeElem.html(createCodeRst.html)); + + // 插入行号边栏 + if (options.ln) { + othis.append('
              '); + } + + // 兼容旧版本 height 属性 + if (options.height) { + codeElem.css('max-height', options.height); + } + + // code 区域样式 + options.codeStyle = [options.style, options.codeStyle].join(''); + if (options.codeStyle) { + codeElem.attr('style', function (i, val) { + return (val || '') + options.codeStyle; + }); + } + + // 动态设置样式 + var cssRules = [{ + selector: '>.layui-code-wrap>.layui-code-line{}', + setValue: function (item, value) { + item.style['padding-left'] = value + 'px'; + } + }, { + selector: '>.layui-code-wrap>.layui-code-line>.layui-code-line-number{}', + setValue: function (item, value) { + item.style.width = value + 'px'; + } + }, { + selector: '>.layui-code-ln-side{}', + setValue: function (item, value) { + item.style.width = value + 'px'; + } + }]; + + // 生成初始 style 元素 + var styleElem = lay.style({ + target: othis[0], + id: 'DF-code-' + index, + text: $.map($.map(cssRules, function (val) { + return val.selector; + }), function (val) { + return ['.layui-code-view[lay-code-index="' + index + '"]', val].join(' '); + }).join('') + }); + + // 动态设置 code 布局 + var setCodeLayout = function fn() { + if (options.ln) { + var multiLine = Math.floor(lines.length / 100); + var lineElem = codeElem.children('.' + CONST.ELEM_LINE); + var width = lineElem.last().children('.' + CONST.ELEM_LINE_NUM).outerWidth(); + othis.addClass(CONST.ELEM_LN_MODE); + + // 若超出 100 行 + if (multiLine && width > CONST.LINE_RAW_WIDTH) { + lay.getStyleRules(styleElem, function (item, i) { + try { + cssRules[i].setValue(item, width); + } catch { + // ignore + } + }); + } + } + return fn; + }(); + + // 创建 code header + if (options.header) { + var headerElem = $('
              '); + headerElem.html(options.title || options.text.code); + othis.prepend(headerElem); + } + + // 创建 code 区域固定条 + var elemFixbar = $('
              '); + + // 若开启复制,且未开启预览,则单独生成复制图标 + if (options.copy && !options.preview) { + var copyElem = $(['', '', ''].join('')); + + // 点击复制 + copyElem.on('click', function () { + tools.copy.event(); + }); + elemFixbar.append(copyElem); + } + + // 创建 language marker + if (options.langMarker) { + elemFixbar.append('' + options.lang + ''); + } + + // 创建 about 自定义内容 + if (options.about) { + elemFixbar.append(options.about); + } + + // 生成 code fixbar + othis.append(elemFixbar); + + // code 渲染完毕后的回调 + if (!options.preview) { + setTimeout(function () { + typeof options.done === 'function' && options.done({}); + }, 3); + } + + // 所有实例渲染完毕后的回调 + if (options.elem.length === index + 1) { + typeof options.allDone === 'function' && options.allDone(); + } + return ret; +} + +export { code }; diff --git a/dist/components/collapse.js b/dist/components/collapse.js new file mode 100644 index 000000000..b30520d70 --- /dev/null +++ b/dist/components/collapse.js @@ -0,0 +1,101 @@ +import { layui } from '../core/layui.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * collapse + * 折叠面板组件 + */ + +var SUPER_MOD_NAME = 'element'; // 所属的超级模块名,确保向下兼容 + +// 创建组件 +var component = component$1({ + name: 'collapse', + // 组件名 + + // 默认配置 + config: { + elem: '.layui-collapse' + }, + render: function () { + var that = this; + var options = that.config; + options.elem.each(function () { + var elemItem = $(this).find('.layui-colla-item'); + elemItem.each(function () { + var othis = $(this); + var elemTitle = othis.find('.layui-colla-title'); + var elemCont = othis.find('.layui-colla-content'); + var isNone = elemCont.css('display') === 'none'; + var clickEventName = 'click.lay_collapse_click'; + + // 初始状态 + elemTitle.find('.layui-colla-icon').remove(); + elemTitle.append(''); + othis[isNone ? 'removeClass' : 'addClass'](CONST.CLASS_SHOW); + + // 兼容旧版( < 2.11.3) + if (elemCont.hasClass(CONST.CLASS_SHOW)) { + elemCont.removeClass(CONST.CLASS_SHOW); + } + + // 点击标题 + elemTitle.off(clickEventName, event.titleClick).on(clickEventName, event.titleClick); + }); + }); + } +}); + +// 基础事件体 +var event = { + // 点击面板标题项 + titleClick: function () { + var othis = $(this); + var wrapper = othis.closest('.layui-collapse'); + var filter = wrapper.attr('lay-filter'); + var ANIM_MS = 200; // 动画过渡毫秒数 + var CLASS_ITEM = '.layui-colla-item'; + var CLASS_CONTENT = '.layui-colla-content'; + var thisItemElem = othis.parent(CLASS_ITEM); + var thisContentElem = othis.siblings(CLASS_CONTENT); + var isNone = thisContentElem.css('display') === 'none'; + var isAccordion = typeof wrapper.attr('lay-accordion') === 'string'; + + // 动画执行完成后的操作 + var complete = function () { + $(this).css('display', ''); // 剔除动画生成的 style display,以适配外部样式的状态重置 + }; + + // 是否正处于动画中的状态 + if (thisContentElem.is(':animated')) return; + + // 展开或收缩 + if (isNone) { + // 先执行 slideDown 动画,再标注展开状态样式,避免元素 `block` 状态导致动画无效 + thisContentElem.slideDown(ANIM_MS, complete); + thisItemElem.addClass(CONST.CLASS_SHOW); + } else { + // 先取消展开状态样式,再将元素临时显示,避免 `none` 状态导致 slideUp 动画无效 + thisItemElem.removeClass(CONST.CLASS_SHOW); + thisContentElem.show().slideUp(ANIM_MS, complete); + } + + // 是否开启手风琴 + if (isAccordion) { + var itemSiblings = thisItemElem.siblings('.' + CONST.CLASS_SHOW); + itemSiblings.removeClass(CONST.CLASS_SHOW); + itemSiblings.children(CLASS_CONTENT).show().slideUp(ANIM_MS, complete); + } + + // 事件 + layui.event.call(this, SUPER_MOD_NAME, 'collapse(' + filter + ')', { + title: othis, + content: thisContentElem, + show: isNone + }); + } +}; +var CONST = component.CONST; + +export { component as collapse }; diff --git a/dist/components/colorpicker.js b/dist/components/colorpicker.js new file mode 100644 index 000000000..0cf36cfd7 --- /dev/null +++ b/dist/components/colorpicker.js @@ -0,0 +1,721 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * colorpicker + * 颜色选择组件 + */ + +var device = layui.device(); +var clickOrMousedown = device.mobile ? 'click' : 'mousedown'; + +// 创建组件 +var component = component$1({ + name: 'colorpicker', + // 默认配置 + config: { + color: '', + // 默认颜色,默认没有 + size: null, + // 选择器大小 + alpha: false, + // 是否开启透明度 + format: 'hex', + // 颜色显示/输入格式,可选 rgb,hex + predefine: false, + // 预定义颜色是否开启 + colors: [ + // 默认预定义颜色列表 + '#16baaa', '#16b777', '#1E9FFF', '#FF5722', '#FFB800', '#01AAED', '#999', '#c00', '#ff8c00', '#ffd700', '#90ee90', '#00ced1', '#1e90ff', '#c71585', '#393D49', 'rgb(0, 186, 189)', 'rgb(255, 120, 0)', 'rgb(250, 212, 0)', 'rgba(0,0,0,.5)', 'rgba(255, 69, 0, 0.68)', 'rgba(144, 240, 144, 0.5)', 'rgba(31, 147, 255, 0.73)'] + }, + CONST: { + ELEM: 'layui-colorpicker', + ELEM_MAIN: '.layui-colorpicker-main', + ICON_PICKER_DOWN: 'layui-icon-down', + ICON_PICKER_CLOSE: 'layui-icon-close', + PICKER_TRIG_SPAN: 'layui-colorpicker-trigger-span', + PICKER_TRIG_I: 'layui-colorpicker-trigger-i', + PICKER_SIDE: 'layui-colorpicker-side', + PICKER_SIDE_SLIDER: 'layui-colorpicker-side-slider', + PICKER_BASIS: 'layui-colorpicker-basis', + PICKER_ALPHA_BG: 'layui-colorpicker-alpha-bgcolor', + PICKER_ALPHA_SLIDER: 'layui-colorpicker-alpha-slider', + PICKER_BASIS_CUR: 'layui-colorpicker-basis-cursor', + PICKER_INPUT: 'layui-colorpicker-main-input' + }, + // 初始化之前 + beforeInit: function () { + var that = this; + that.stopClickOutsideEvent = $.noop; + that.stopResizeEvent = $.noop; + CONST.PICKER_OPENED = CONST.MOD_ID + '-opened'; + }, + // 渲染之前 + beforeRender: function () { + var that = this; + var options = that.config; + options.target = $('body'); // 后续考虑开放 target 元素 + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 颜色选择框对象 + var elemColorBox = $(['
              ', '', '', '', '', '', '
              '].join('')); + + // 初始化颜色选择框尺寸 + var elem = options.elem; + options.size && elemColorBox.addClass('layui-colorpicker-' + options.size); + + // 插入颜色选择框 + elem.addClass('layui-inline').html(that.elemColorBox = elemColorBox); + + // 获取背景色值 + that.color = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN)[0].style.background; + } +}); + +// RGB 转 HSB +var RGBToHSB = function (rgb) { + var hsb = { + h: 0, + s: 0, + b: 0 + }; + var min = Math.min(rgb.r, rgb.g, rgb.b); + var max = Math.max(rgb.r, rgb.g, rgb.b); + var delta = max - min; + hsb.b = max; + hsb.s = max !== 0 ? 255 * delta / max : 0; + if (hsb.s !== 0) { + if (rgb.r == max) { + // 因 rgb 中返回的数字为 string 类型 + hsb.h = (rgb.g - rgb.b) / delta; + } else if (rgb.g == max) { + hsb.h = 2 + (rgb.b - rgb.r) / delta; + } else { + hsb.h = 4 + (rgb.r - rgb.g) / delta; + } + } else { + hsb.h = -1; + } + if (max === min) { + hsb.h = 0; + } + hsb.h *= 60; + if (hsb.h < 0) { + hsb.h += 360; + } + hsb.s *= 100 / 255; + hsb.b *= 100 / 255; + return hsb; +}; + +// HEX 转 HSB +var HEXToHSB = function (hex) { + hex = hex.indexOf('#') > -1 ? hex.substring(1) : hex; + if (hex.length === 3) { + var num = hex.split(''); + hex = num[0] + num[0] + num[1] + num[1] + num[2] + num[2]; + } + hex = parseInt(hex, 16); + var rgb = { + r: hex >> 16, + g: (hex & 0x00ff00) >> 8, + b: hex & 0x0000ff + }; + return RGBToHSB(rgb); +}; + +// HSB 转 RGB +var HSBToRGB = function (hsb) { + var rgb = {}; + var h = hsb.h; + var s = hsb.s * 255 / 100; + var b = hsb.b * 255 / 100; + if (s === 0) { + rgb.r = rgb.g = rgb.b = b; + } else { + var t1 = b; + var t2 = (255 - s) * b / 255; + var t3 = (t1 - t2) * (h % 60) / 60; + if (h === 360) h = 0; + if (h < 60) { + rgb.r = t1; + rgb.b = t2; + rgb.g = t2 + t3; + } else if (h < 120) { + rgb.g = t1; + rgb.b = t2; + rgb.r = t1 - t3; + } else if (h < 180) { + rgb.g = t1; + rgb.r = t2; + rgb.b = t2 + t3; + } else if (h < 240) { + rgb.b = t1; + rgb.r = t2; + rgb.g = t1 - t3; + } else if (h < 300) { + rgb.b = t1; + rgb.g = t2; + rgb.r = t2 + t3; + } else if (h < 360) { + rgb.r = t1; + rgb.g = t2; + rgb.b = t1 - t3; + } else { + rgb.r = 0; + rgb.g = 0; + rgb.b = 0; + } + } + return { + r: Math.round(rgb.r), + g: Math.round(rgb.g), + b: Math.round(rgb.b) + }; +}; + +// HSB 转 HEX +var HSBToHEX = function (hsb) { + var rgb = HSBToRGB(hsb); + var hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)]; + $.each(hex, function (nr, val) { + if (val.length === 1) { + hex[nr] = '0' + val; + } + }); + return hex.join(''); +}; + +// 转化成所需 rgb 格式 +var RGBSTo = function (rgbs) { + var regexp = /[0-9]{1,3}/g; + var re = rgbs.match(regexp) || []; + return { + r: re[0], + g: re[1], + b: re[2] + }; +}; +var $win = $(window); +// var $doc = $(document); + +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 渲染颜色选择器 +Class.prototype.renderPicker = function () { + var that = this; + var options = that.config; + + // 颜色选择器对象 + var elemPicker = that.elemPicker = $(['
              ', + //颜色面板 + '
              ', '
              ', '
              ', '
              ', '
              ', '
              ', '
              ', '
              ', '
              ', '
              ', + //透明度条块 + '
              ', '
              ', '
              ', '
              ', '
              ', + //预设颜色列表 + function () { + if (options.predefine) { + var list = ['
              ']; + layui.each(options.colors, function (i, v) { + list.push(['
              ', '
              ', '
              '].join('')); + }); + list.push('
              '); + return list.join(''); + } else { + return ''; + } + }(), + //底部表单元素区域 + '
              ', '
              ', '', '
              ', '
              ', '', '', '', '
              '].join('')); + that.removePicker(options.id); // 若已存在则先移除 + options.target.append(elemPicker); + options.elem.data(CONST.PICKER_OPENED, true); // 面板已打开的标记 + + that.position(); + that.pickerEvents(); + that.onClickOutside(); + that.autoUpdatePosition(); +}; + +// 颜色选择器移除 +Class.prototype.removePicker = function (index) { + var that = this; + var options = that.config; + var elem = $('#layui-colorpicker' + (index || that.index)); + that.stopClickOutsideEvent(); + that.stopResizeEvent(); + if (elem[0]) { + elem.remove(); + options.elem.removeData(CONST.PICKER_OPENED); + + // 面板关闭后的回调 + typeof options.close === 'function' && options.close(that.color); + } + return that; +}; + +// 面板定位 +Class.prototype.position = function () { + var that = this; + var options = that.config; + lay.position(that.bindElem || that.elemColorBox[0], that.elemPicker[0], { + position: options.position, + align: 'center' + }); + return that; +}; + +// 颜色选择器赋值 +Class.prototype.val = function () { + var that = this, + // options = that.config, + elemColorBox = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN), + elemPickerInput = that.elemPicker.find('.' + CONST.PICKER_INPUT), + e = elemColorBox[0], + bgcolor = e.style.backgroundColor; + + // 判断是否有背景颜色 + if (bgcolor) { + // 转化成 hsb 格式 + var hsb = RGBToHSB(RGBSTo(bgcolor)); + var type = elemColorBox.attr('lay-type'); + + // 同步滑块的位置及颜色选择器的选择 + that.select(hsb.h, hsb.s, hsb.b); + + // 若格式要求为rgb + if (type === 'torgb') { + elemPickerInput.find('input').val(bgcolor); + } else if (type === 'rgba') { + // 若格式要求为 rgba + var rgb = RGBSTo(bgcolor); + + // 若开启透明度而没有设置,则给默认值 + if ((bgcolor.match(/[0-9]{1,3}/g) || []).length === 3) { + elemPickerInput.find('input').val('rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', 1)'); + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', 280); + } else { + elemPickerInput.find('input').val(bgcolor); + var left = bgcolor.slice(bgcolor.lastIndexOf(',') + 1, bgcolor.length - 1) * 280; + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', left); + } + + // 设置 span 背景色 + that.elemPicker.find('.' + CONST.PICKER_ALPHA_BG)[0].style.background = 'linear-gradient(to right, rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', 0), rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + '))'; + } else { + elemPickerInput.find('input').val('#' + HSBToHEX(hsb)); + } + } else { + // 若没有背景颜色则默认到最初始的状态 + that.select(0, 100, 100); + elemPickerInput.find('input').val(''); + that.elemPicker.find('.' + CONST.PICKER_ALPHA_BG)[0].style.background = ''; + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', 280); + } +}; + +// 颜色选择器滑动 / 点击 +Class.prototype.side = function () { + var that = this, + options = that.config, + span = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN), + type = span.attr('lay-type'), + side = that.elemPicker.find('.' + CONST.PICKER_SIDE), + slider = that.elemPicker.find('.' + CONST.PICKER_SIDE_SLIDER), + basis = that.elemPicker.find('.' + CONST.PICKER_BASIS), + choose = that.elemPicker.find('.' + CONST.PICKER_BASIS_CUR), + alphacolor = that.elemPicker.find('.' + CONST.PICKER_ALPHA_BG), + alphaslider = that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER), + _h = slider[0].offsetTop / 180 * 360, + _b = 100 - choose[0].offsetTop / 180 * 100, + _s = choose[0].offsetLeft / 260 * 100, + _a = Math.round(alphaslider[0].offsetLeft / 280 * 100) / 100, + i = that.elemColorBox.find('.' + CONST.PICKER_TRIG_I), + pre = that.elemPicker.find('.layui-colorpicker-pre').children('div'), + change = function (x, y, z, a) { + that.select(x, y, z); + var rgb = HSBToRGB({ + h: x, + s: y, + b: z + }); + var color = HSBToHEX({ + h: x, + s: y, + b: z + }); + var elemInput = that.elemPicker.find('.' + CONST.PICKER_INPUT).find('input'); + i.addClass(CONST.ICON_PICKER_DOWN).removeClass(CONST.ICON_PICKER_CLOSE); + span[0].style.background = 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'; + if (type === 'torgb') { + elemInput.val('rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'); + } else if (type === 'rgba') { + var left = a * 280; + alphaslider.css('left', left); + elemInput.val('rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + a + ')'); + span[0].style.background = 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + a + ')'; + alphacolor[0].style.background = 'linear-gradient(to right, rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', 0), rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + '))'; + } else { + elemInput.val('#' + color); + } + + //回调更改的颜色 + options.change && options.change($.trim(that.elemPicker.find('.' + CONST.PICKER_INPUT).find('input').val())); + }, + //拖拽元素 + elemMove = $(['
              '].join('')), + createMoveElem = function (call) { + $('#LAY-colorpicker-moving')[0] || $('body').append(elemMove); + elemMove.on('mousemove', call); + elemMove.on('mouseup', function () { + elemMove.remove(); + }).on('mouseleave', function () { + elemMove.remove(); + }); + }; + // 移动端滑动模拟事件中 + // 1. 不触发游标上绑定的事件,以提高性能,使滑动更流畅 + // 2. 游标上的事件需要冒泡到颜色拾取区域,用来模拟拖动游标的效果 + var needTrigger = true; + var needStopPropagation = true; + + //右侧主色选择 + slider.on('mousedown', function (e, triggerEvent) { + var oldtop = this.offsetTop; + var oldy = e.clientY === undefined ? triggerEvent.clientY : e.clientY; + var move = function (e) { + var top = oldtop + (e.clientY - oldy), + maxh = side[0].offsetHeight; + if (top < 0) top = 0; + if (top > maxh) top = maxh; + var h = top / 180 * 360; + _h = h; + change(h, _s, _b, _a); + e.preventDefault(); + }; + needStopPropagation && layui.stope(e); + createMoveElem(move); + e.preventDefault(); + }); + side.on('mousedown', function (e) { + var top = e.clientY - $(this).offset().top + $win.scrollTop(); + if (top < 0) top = 0; + if (top > this.offsetHeight) top = this.offsetHeight; + var h = top / 180 * 360; + _h = h; + change(h, _s, _b, _a); + e.preventDefault(); + needTrigger && slider.trigger('mousedown', e); + }); + + //中间小圆点颜色选择 + choose.on('mousedown', function (e, triggerEvent) { + var oldtop = this.offsetTop; + var oldleft = this.offsetLeft; + var oldy = e.clientY === undefined ? triggerEvent.clientY : e.clientY; + var oldx = e.clientX === undefined ? triggerEvent.clientX : e.clientX; + var move = function (e) { + var top = oldtop + (e.clientY - oldy), + left = oldleft + (e.clientX - oldx), + maxh = basis[0].offsetHeight, + maxw = basis[0].offsetWidth; + if (top < 0) top = 0; + if (top > maxh) top = maxh; + if (left < 0) left = 0; + if (left > maxw) left = maxw; + var s = left / 260 * 100, + b = 100 - top / 180 * 100; + _b = b; + _s = s; + change(_h, s, b, _a); + e.preventDefault(); + }; + needStopPropagation && layui.stope(e); + createMoveElem(move); + e.preventDefault(); + }); + basis.on('mousedown', function (e) { + var top = e.clientY - $(this).offset().top + $win.scrollTop(), + left = e.clientX - $(this).offset().left + $win.scrollLeft(); + if (top < 0) top = 0; + if (top > this.offsetHeight) top = this.offsetHeight; + if (left < 0) left = 0; + if (left > this.offsetWidth) left = this.offsetWidth; + var s = left / 260 * 100, + b = 100 - top / 180 * 100; + _b = b; + _s = s; + change(_h, s, b, _a); + layui.stope(e); + e.preventDefault(); + needTrigger && choose.trigger('mousedown', e); + }); + + //底部透明度选择 + alphaslider.on('mousedown', function (e, triggerEvent) { + var oldleft = this.offsetLeft; + var oldx = e.clientX === undefined ? triggerEvent.clientX : e.clientX; + var move = function (e) { + var left = oldleft + (e.clientX - oldx), + maxw = alphacolor[0].offsetWidth; + if (left < 0) left = 0; + if (left > maxw) left = maxw; + var a = Math.round(left / 280 * 100) / 100; + _a = a; + change(_h, _s, _b, a); + e.preventDefault(); + }; + needStopPropagation && layui.stope(e); + createMoveElem(move); + e.preventDefault(); + }); + alphacolor.on('mousedown', function (e) { + var left = e.clientX - $(this).offset().left; + if (left < 0) left = 0; + if (left > this.offsetWidth) left = this.offsetWidth; + var a = Math.round(left / 280 * 100) / 100; + _a = a; + change(_h, _s, _b, a); + e.preventDefault(); + needTrigger && alphaslider.trigger('mousedown', e); + }); + + // 预定义颜色选择 + pre.each(function () { + $(this).on('click', function () { + $(this).parent('.layui-colorpicker-pre').addClass('selected').siblings().removeClass('selected'); + var color = this.style.backgroundColor, + hsb = RGBToHSB(RGBSTo(color)), + a = color.slice(color.lastIndexOf(',') + 1, color.length - 1); + // var left; + _h = hsb.h; + _s = hsb.s; + _b = hsb.b; + if ((color.match(/[0-9]{1,3}/g) || []).length === 3) a = 1; + _a = a; + // left = a * 280; + change(hsb.h, hsb.s, hsb.b, a); + }); + }); + if (!lay.touchEventsSupported()) return; + // 触摸事件模拟 + layui.each([{ + elem: side, + eventType: 'mousedown' + }, { + elem: alphacolor, + eventType: 'mousedown' + }, { + elem: basis, + eventType: 'mousedown' + }], function (i, obj) { + lay.touchSwipe(obj.elem, { + onTouchStart: function () { + needTrigger = false; + needStopPropagation = false; + }, + onTouchMove: function (e) { + touchHandler(e, obj.eventType); + }, + onTouchEnd: function () { + elemMove.remove(); + needTrigger = true; + needStopPropagation = true; + } + }); + }); + function touchHandler(event, eventType) { + var pointer = event.touches[0]; + var simulatedEvent = document.createEvent('MouseEvent'); + simulatedEvent.initMouseEvent(eventType, true, true, window, 1, pointer.screenX, pointer.screenY, pointer.clientX, pointer.clientY, false, false, false, false, 0, null); + pointer.target.dispatchEvent(simulatedEvent); + } +}; + +// 颜色选择器hsb转换 +Class.prototype.select = function (h, s, b) { + var that = this; + // var options = that.config; + var hex = HSBToHEX({ + h: h, + s: 100, + b: 100 + }); + // var color = HSBToHEX({ h: h, s: s, b: b }); + var sidetop = h / 360 * 180; + var top = 180 - b / 100 * 180; + var left = s / 100 * 260; + var basisElem = that.elemPicker.find('.' + CONST.PICKER_BASIS)[0]; + that.elemPicker.find('.' + CONST.PICKER_SIDE_SLIDER).css('top', sidetop); //滑块的top + basisElem.style.background = '#' + hex; //颜色选择器的背景 + + //选择器的top left + that.elemPicker.find('.' + CONST.PICKER_BASIS_CUR).css({ + top: top / basisElem.offsetHeight * 100 + '%', + left: left / basisElem.offsetWidth * 100 + '%' + }); + + // if(type === 'change') return; + + // 选中的颜色 + // that.elemPicker.find('.' + CONST.PICKER_INPUT).find('input').val('#'+ color); +}; +Class.prototype.pickerEvents = function () { + var that = this; + var options = that.config; + var elemColorBoxSpan = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN); //颜色盒子 + var elemPickerInput = that.elemPicker.find('.' + CONST.PICKER_INPUT + ' input'); //颜色选择器表单 + + var pickerEvents = { + // 清空 + clear: function () { + elemColorBoxSpan[0].style.background = ''; + that.elemColorBox.find('.' + CONST.PICKER_TRIG_I).removeClass(CONST.ICON_PICKER_DOWN).addClass(CONST.ICON_PICKER_CLOSE); + that.color = ''; + options.done && options.done(''); + that.removePicker(); + }, + //确认 + confirm: function (othis, change) { + var value = $.trim(elemPickerInput.val()), + colorValue, + hsb; + if (value.indexOf(',') > -1) { + hsb = RGBToHSB(RGBSTo(value)); + that.select(hsb.h, hsb.s, hsb.b); + elemColorBoxSpan[0].style.background = colorValue = '#' + HSBToHEX(hsb); + if ((value.match(/[0-9]{1,3}/g) || []).length > 3 && elemColorBoxSpan.attr('lay-type') === 'rgba') { + var left = value.slice(value.lastIndexOf(',') + 1, value.length - 1) * 280; + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', left); + elemColorBoxSpan[0].style.background = value; + colorValue = value; + } + } else { + hsb = HEXToHSB(value); + elemColorBoxSpan[0].style.background = colorValue = '#' + HSBToHEX(hsb); + that.elemColorBox.find('.' + CONST.PICKER_TRIG_I).removeClass(CONST.ICON_PICKER_CLOSE).addClass(CONST.ICON_PICKER_DOWN); + } + if (change === 'change') { + that.select(hsb.h, hsb.s, hsb.b, change); + options.change && options.change(colorValue); + return; + } + that.color = value; + options.done && options.done(value); + that.removePicker(); + } + }; + + // 选择器面板点击事件 + that.elemPicker.on('click', '*[colorpicker-events]', function () { + var othis = $(this), + attrEvent = othis.attr('colorpicker-events'); + pickerEvents[attrEvent] && pickerEvents[attrEvent].call(this, othis); + }); + + // 输入框事件 + elemPickerInput.on('keyup', function (e) { + var othis = $(this); + pickerEvents.confirm.call(this, othis, e.keyCode === 13 ? null : 'change'); + }); +}; + +// 事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 弹出颜色选择器 + that.elemColorBox.on('click', function () { + // 主面板是否已打开 + var opened = options.elem.data(CONST.PICKER_OPENED); + + // 根据主面板状态,自动切换打开与关闭 + if (opened) { + that.removePicker(); + } else { + that.renderPicker(); + that.val(); + that.side(); + } + }); +}; + +/** + * 点击面板外部时的事件 + */ +Class.prototype.onClickOutside = function () { + var that = this; + var options = that.config; + that.stopClickOutsideEvent(); + var stop = lay.onClickOutside(that.elemPicker[0], function () { + var elemColorBoxSpan = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN); + if (that.color) { + var hsb = RGBToHSB(RGBSTo(that.color)); + that.select(hsb.h, hsb.s, hsb.b); + } else { + that.elemColorBox.find('.' + CONST.PICKER_TRIG_I).removeClass(CONST.ICON_PICKER_DOWN).addClass(CONST.ICON_PICKER_CLOSE); + } + elemColorBoxSpan[0].style.background = that.color || ''; + + // 取消选择的回调 + typeof options.cancel === 'function' && options.cancel(that.color); + + // 移除面板 + that.removePicker(); + }, { + ignore: [options.elem[0]], + event: clickOrMousedown, + capture: false + }); + that.stopClickOutsideEvent = function () { + stop(); + that.stopClickOutsideEvent = $.noop; + }; +}; + +/** + * 窗口大小变化时自动更新位置 + */ +Class.prototype.autoUpdatePosition = function () { + var that = this; + // var options = that.config; + var RESIZE_EVENT_NAME = 'resize.lay_colorpicker_resize'; + that.stopResizeEvent(); + var windowResizeHandler = function () { + that.position(); + }; + $win.on(RESIZE_EVENT_NAME, windowResizeHandler); + that.stopResizeEvent = function () { + $win.off(RESIZE_EVENT_NAME, windowResizeHandler); + that.stopResizeEvent = $.noop; + }; +}; + +export { component as colorpicker }; diff --git a/dist/components/dropdown.js b/dist/components/dropdown.js new file mode 100644 index 000000000..2896fb417 --- /dev/null +++ b/dist/components/dropdown.js @@ -0,0 +1,692 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { laytpl } from '../core/laytpl.js'; +import { util } from './util.js'; + +/** + * dropdown + * 下拉菜单组件 + */ + +var device = layui.device(); +var clickOrMousedown = device.mobile ? 'touchstart' : 'mousedown'; + +// 模块名 +var MOD_NAME = 'dropdown'; +var MOD_INDEX = 'layui_' + MOD_NAME + '_index'; // 模块索引名 +var MOD_INDEX_OPENED = MOD_INDEX + '_opened'; +var MOD_ID = 'lay-' + MOD_NAME + '-id'; +var resizeObserver = lay.createSharedResizeObserver(MOD_NAME); + +// 外部接口 +var dropdown = { + config: { + customName: { + // 自定义 data 字段名 + id: 'id', + title: 'title', + children: 'child' + } + }, + // 设置全局项 + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + // 事件 + on: function (events, callback) { + return layui.onevent.call(this, MOD_NAME, events, callback); + } +}; + +// 操作当前实例 +var thisModule = function () { + var that = this; + var options = that.config; + var id = options.id; + return { + config: options, + // 重置实例 + reload: function (options) { + that.reload.call(that, options); + }, + reloadData: function (options) { + dropdown.reloadData(id, options); + }, + close: function () { + that.remove(); + }, + open: function () { + that.render(); + } + }; +}; + +// 字符常量 +var STR_ELEM = 'layui-dropdown'; +// var STR_HIDE = 'layui-hide'; +var STR_DISABLED = 'layui-disabled'; +// var STR_NONE = 'layui-none'; +var STR_ITEM_UP = 'layui-menu-item-up'; +var STR_ITEM_DOWN = 'layui-menu-item-down'; +var STR_MENU_TITLE = 'layui-menu-body-title'; +var STR_ITEM_GROUP = 'layui-menu-item-group'; +var STR_ITEM_PARENT = 'layui-menu-item-parent'; +var STR_ITEM_DIV = 'layui-menu-item-divider'; +var STR_ITEM_CHECKED = 'layui-menu-item-checked'; +var STR_ITEM_CHECKED2 = 'layui-menu-item-checked2'; +var STR_MENU_PANEL = 'layui-menu-body-panel'; +var STR_MENU_PANEL_L = 'layui-menu-body-panel-left'; +var STR_ELEM_SHADE = 'layui-dropdown-shade'; +var STR_GROUP_TITLE = '.' + STR_ITEM_GROUP + '>.' + STR_MENU_TITLE; + +// 构造器 +var Class = function (options) { + var that = this; + that.index = dropdown.index = lay.autoIncrementer('dropdown'); + that.config = $.extend({}, that.config, dropdown.config, options); + that.stopClickOutsideEvent = $.noop; + that.stopResizeEvent = $.noop; + that.init(); +}; + +// 默认配置 +Class.prototype.config = { + trigger: 'click', + // 事件类型 + content: '', + // 自定义菜单内容 + className: '', + // 自定义样式类名 + style: '', + // 设置面板 style 属性 + show: false, + // 是否初始即显示菜单面板 + isAllowSpread: true, + // 是否允许菜单组展开收缩 + isSpreadItem: true, + // 是否初始展开子菜单 + data: [], + // 菜单数据结构 + delay: [200, 300], + // 延时显示或隐藏的毫秒数,若为 number 类型,则表示显示和隐藏的延迟时间相同,trigger 为 hover 时才生效 + shade: 0, + // 遮罩 + accordion: false, + // 手风琴效果,仅菜单组生效。基础菜单需要在容器上追加 'lay-accordion' 属性。 + closeOnClick: true // 面板打开后,再次点击目标元素时是否关闭面板。行为取决于所使用的触发事件类型 +}; + +// 重载实例 +Class.prototype.reload = function (options, type) { + var that = this; + that.config = $.extend({}, that.config, options); + that.init(true, type); +}; + +// 初始化准备 +Class.prototype.init = function (rerender, type) { + var that = this; + var options = that.config; + + // 若 elem 非唯一 + var elem = $(options.elem); + if (elem.length > 1) { + layui.each(elem, function () { + dropdown.render($.extend({}, options, { + elem: this + })); + }); + return that; + } + + // 合并 lay-options 属性上的配置信息 + $.extend(options, lay.options(elem[0])); + + // 若重复执行 render,则视为 reload 处理 + if (!rerender && elem.attr(MOD_ID)) { + var newThat = thisModule.getThis(elem.attr(MOD_ID)); + if (!newThat) return; + return newThat.reload(options, type); + } + options.elem = $(options.elem); + options.target = $('body'); // 后续考虑开放 target 元素 + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + options.id = 'id' in options ? options.id : elem.attr('id') || that.index; + thisModule.that[options.id] = that; // 记录当前实例对象 + elem.attr(MOD_ID, options.id); // 目标元素已渲染过的标记 + + // 初始化自定义字段名 + options.customName = $.extend({}, dropdown.config.customName, options.customName); + + // 若传入 hover,则解析为 mouseenter + if (options.trigger === 'hover') { + options.trigger = 'mouseenter'; + } + + // 初始即显示或者面板弹出之后执行了刷新数据 + if (options.show || type === 'reloadData' && that.mainElem && options.target.find(that.mainElem.get(0)).length) that.render(type); + + // 若面板已经打开,则无需再绑定目标元素事件,避免 render 重复执行 + if (!elem.data(MOD_INDEX_OPENED)) { + that.events(); // 事件 + } +}; + +// 渲染 +Class.prototype.render = function (type) { + var that = this; + var options = that.config; + var customName = options.customName; + + // 默认菜单内容 + var getDefaultView = function () { + var elemUl = $('
                '); + if (options.data.length > 0) { + eachItemView(elemUl, options.data); + } else { + elemUl.html('
              • ' + i18n.$t('dropdown.noData') + '
              • '); + } + return elemUl; + }; + + // 遍历菜单项 + var eachItemView = function (views, data) { + // var views = []; + + layui.each(data, function (index, item) { + // 是否存在子级 + var isChild = item[customName.children] && item[customName.children].length > 0; + var isSpreadItem = 'isSpreadItem' in item ? item.isSpreadItem : options.isSpreadItem; + var title = function (title) { + var templet = item.templet || options.templet; + if (templet) { + title = typeof templet === 'function' ? templet(item) : laytpl(templet).render(item); + } + return title; + }(util.escape(item[customName.title])); + + // 初始类型 + var type = function () { + if (isChild) { + item.type = item.type || 'parent'; + } + if (item.type) { + return { + group: 'group', + parent: 'parent', + '-': '-' + }[item.type] || 'parent'; + } + return ''; + }(); + if (type !== '-' && !item[customName.title] && !item[customName.id] && !isChild) return; + + //列表元素 + var viewLi = $(['', + //标题区 + function () { + //是否超文本 + var viewText = 'href' in item ? '' + title + '' : title; + + //是否存在子级 + if (isChild) { + return '
                ' + viewText + function () { + if (type === 'parent') { + return ''; + } else if (type === 'group' && options.isAllowSpread) { + return ''; + } else { + return ''; + } + }() + '
                '; + } + return '
                ' + viewText + '
                '; + }(), ''].join('')); + viewLi.data('item', item); + + //子级区 + if (isChild) { + var elemPanel = $('
                '); + var elemUl = $('
                  '); + if (type === 'parent') { + elemPanel.append(eachItemView(elemUl, item[customName.children])); + viewLi.append(elemPanel); + } else { + viewLi.append(eachItemView(elemUl, item[customName.children])); + } + } + views.append(viewLi); + }); + return views; + }; + + // 主模板 + var TPL_MAIN = ['
                  ', '
                  '].join(''); + + // 重载或插入面板内容 + var mainElem; + var content = options.content || getDefaultView(); + var mainElemExisted = thisModule.findMainElem(options.id); + if (type === 'reloadData' && mainElemExisted.length) { + // 是否仅重载数据 + mainElem = that.mainElem = mainElemExisted; + mainElemExisted.html(content); + } else { + // 常规渲染 + mainElem = that.mainElem = $(TPL_MAIN); + mainElem.append(content); + + // 初始化某些属性 + mainElem.addClass(options.className); + mainElem.attr('style', options.style); + + // 辞旧迎新 + that.remove(options.id); + options.target.append(mainElem); + options.elem.data(MOD_INDEX_OPENED, true); // 面板已打开的标记 + + // 遮罩 + var shade = options.shade ? '
                  ' : ''; + var shadeElem = $(shade); + // 处理移动端点击穿透问题 + if (clickOrMousedown === 'touchstart') { + shadeElem.on(clickOrMousedown, function (e) { + e.preventDefault(); + }); + } + mainElem.before(shadeElem); + + // 如果是鼠标移入事件,则鼠标移出时自动关闭 + if (options.trigger === 'mouseenter') { + mainElem.on('mouseenter', function () { + clearTimeout(that.timer); + }).on('mouseleave', function () { + that.delayRemove(); + }); + } + } + that.position(); // 定位坐标 + + // 阻止全局事件 + mainElem.find('.layui-menu').on(clickOrMousedown, function (e) { + layui.stope(e); + }); + + // 触发菜单列表事件 + mainElem.find('.layui-menu li').on('click', function (e) { + var othis = $(this); + var data = othis.data('item') || {}; + var isChild = data[customName.children] && data[customName.children].length > 0; + var isClickAllScope = options.clickScope === 'all'; // 是否所有父子菜单均触发点击事件 + + if (data.disabled) return; // 菜单项禁用状态 + + // 普通菜单项点击后的回调及关闭面板 + if ((!isChild || isClickAllScope) && data.type !== '-') { + var ret = typeof options.click === 'function' ? options.click(data, othis, e) : null; + ret === false || isChild || that.remove(); + layui.stope(e); + } + }); + + // 触发菜单组展开收缩 + mainElem.find(STR_GROUP_TITLE).on('click', function () { + var othis = $(this); + var elemGroup = othis.parent(); + var data = elemGroup.data('item') || {}; + if (data.type === 'group' && options.isAllowSpread) { + thisModule.spread(elemGroup, options.accordion); + } + }); + that.onClickOutside(); + that.autoUpdatePosition(); + + // 组件打开完毕的事件 + typeof options.ready === 'function' && options.ready(mainElem, options.elem); +}; + +// 位置定位 +Class.prototype.position = function () { + var that = this; + var options = that.config; + lay.position(options.elem[0], that.mainElem[0], { + position: options.position, + e: that.e, + clickType: options.trigger === 'contextmenu' ? 'right' : null, + align: options.align || null + }); +}; + +// 移除面板 +Class.prototype.remove = function (id) { + id = id || this.config.id; + var that = thisModule.getThis(id); // 根据 id 查找对应的实例 + if (!that) return; + var options = that.config; + var mainElem = thisModule.findMainElem(id); + that.stopClickOutsideEvent(); + that.stopResizeEvent(); + + // 若存在已打开的面板元素,则移除 + if (mainElem[0]) { + mainElem.prev('.' + STR_ELEM_SHADE).remove(); // 先移除遮罩 + mainElem.remove(); + options.elem.removeData(MOD_INDEX_OPENED); + typeof options.close === 'function' && options.close(options.elem); + } +}; +Class.prototype.normalizedDelay = function () { + var that = this; + var options = that.config; + var delay = [].concat(options.delay); + return { + show: delay[0], + hide: delay[1] !== undefined ? delay[1] : delay[0] + }; +}; + +// 延迟移除面板 +Class.prototype.delayRemove = function () { + var that = this; + // var options = that.config; + clearTimeout(that.timer); + that.timer = setTimeout(function () { + that.remove(); + }, that.normalizedDelay().hide); +}; + +// 事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 是否鼠标移入时触发 + var isMouseEnter = options.trigger === 'mouseenter'; + var trigger = options.trigger + '.lay_dropdown_render'; + + // 始终先解除上一个触发元素的事件(如重载时改变 elem 的情况) + if (that.thisEventElem) that.thisEventElem.off(trigger); + that.thisEventElem = options.elem; + + // 触发元素事件 + options.elem.off(trigger).on(trigger, function (e) { + clearTimeout(that.timer); + that.e = e; + + // 主面板是否已打开 + var opened = options.elem.data(MOD_INDEX_OPENED); + + // 若为鼠标移入事件,则延迟触发 + if (isMouseEnter) { + if (!opened) { + that.timer = setTimeout(function () { + that.render(); + }, that.normalizedDelay().show); + } + } else { + // 若为 click 事件,则根据主面板状态,自动切换打开与关闭 + if (options.closeOnClick && opened && options.trigger === 'click') { + that.remove(); + } else { + that.render(); + } + } + e.preventDefault(); + }); + + // 如果是鼠标移入事件 + if (isMouseEnter) { + // 执行鼠标移出事件 + options.elem.on('mouseleave', function () { + that.delayRemove(); + }); + } +}; + +/** + * 点击面板外部时的事件 + */ +Class.prototype.onClickOutside = function () { + var that = this; + var options = that.config; + var isCtxMenu = options.trigger === 'contextmenu'; + var isTopElem = lay.isTopElem(options.elem[0]); + that.stopClickOutsideEvent(); + var stop = lay.onClickOutside(that.mainElem[0], function (e) { + // 点击面板外部时的事件 + if (typeof options.onClickOutside === 'function') { + var shouldClose = options.onClickOutside(e); + if (shouldClose === false) return; + } + that.remove(); + }, { + ignore: isCtxMenu || isTopElem ? null : [options.elem[0]], + event: clickOrMousedown, + capture: false, + detectIframe: true + }); + that.stopClickOutsideEvent = function () { + stop(); + that.stopClickOutsideEvent = $.noop; + }; +}; + +/** + * 窗口大小变化时自动更新位置 + */ +Class.prototype.autoUpdatePosition = function () { + var that = this; + var options = that.config; + that.stopResizeEvent(); + var windowResizeHandler = function () { + if (that.mainElem && (!that.mainElem[0] || !that.mainElem.is(':visible'))) return; + if (options.trigger === 'contextmenu') { + that.remove(); + } else { + that.position(); + } + }; + $(window).on('resize.lay_dropdown_resize', windowResizeHandler); + var shouldObserveResize = resizeObserver && options.trigger !== 'contextmenu'; + var triggerEl = options.elem[0]; + var contentEl = that.mainElem[0]; + if (shouldObserveResize) { + resizeObserver.observe(triggerEl, $.proxy(that.position, that)); + resizeObserver.observe(contentEl, $.proxy(that.position, that)); + } + that.stopResizeEvent = function () { + $(window).off('resize.lay_dropdown_resize', windowResizeHandler); + if (shouldObserveResize) { + resizeObserver.unobserve(triggerEl); + resizeObserver.unobserve(contentEl); + } + that.stopResizeEvent = $.noop; + }; +}; + +// 记录所有实例 +thisModule.that = {}; // 记录所有实例对象 + +// 获取当前实例对象 +thisModule.getThis = function (id) { + if (id === undefined) { + throw new Error('ID argument required'); + } + return thisModule.that[id]; +}; + +// 根据 id 从页面查找组件主面板元素 +thisModule.findMainElem = function (id) { + return $('.' + STR_ELEM + '[' + MOD_ID + '="' + id + '"]'); +}; + +// 设置菜单组展开和收缩状态 +thisModule.spread = function (othis, isAccordion) { + var contentElem = othis.children('ul'); + var needSpread = othis.hasClass(STR_ITEM_UP); + var ANIM_MS = 200; + + // 动画执行完成后的操作 + var complete = function () { + $(this).css({ + display: '' + }); // 剔除临时 style,以适配外部样式的状态重置; + }; + + // 动画是否正在执行 + if (contentElem.is(':animated')) return; + + // 展开 + if (needSpread) { + othis.removeClass(STR_ITEM_UP).addClass(STR_ITEM_DOWN); + contentElem.hide().stop().slideDown(ANIM_MS, complete); + } else { + // 收缩 + contentElem.stop().slideUp(ANIM_MS, complete); + othis.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP); + } + + // 手风琴 + if (needSpread && isAccordion) { + var groupSibs = othis.siblings('.' + STR_ITEM_DOWN); + groupSibs.children('ul').stop().slideUp(ANIM_MS, complete); + groupSibs.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP); + } +}; + +// 全局事件 +(function () { + var _WIN = $(window); + var _DOC = $(document); + + // 基础菜单的静态元素事件 + var ELEM_LI = '.layui-menu:not(.layui-dropdown-menu) li'; + _DOC.on('click', ELEM_LI, function () { + var othis = $(this); + var parent = othis.parents('.layui-menu').eq(0); + var isChild = othis.hasClass(STR_ITEM_GROUP) || othis.hasClass(STR_ITEM_PARENT); + var filter = parent.attr('lay-filter') || parent.attr('id'); + var options = lay.options(this); + + // 非触发元素 + if (othis.hasClass(STR_ITEM_DIV)) return; + + // 非菜单组 + if (!isChild) { + // 选中 + parent.find('.' + STR_ITEM_CHECKED).removeClass(STR_ITEM_CHECKED); // 清除选中样式 + parent.find('.' + STR_ITEM_CHECKED2).removeClass(STR_ITEM_CHECKED2); // 清除父级菜单选中样式 + othis.addClass(STR_ITEM_CHECKED); //添加选中样式 + othis.parents('.' + STR_ITEM_PARENT).addClass(STR_ITEM_CHECKED2); // 添加父级菜单选中样式 + + options.title = options.title || $.trim(othis.children('.' + STR_MENU_TITLE).text()); + + // 触发事件 + layui.event.call(this, MOD_NAME, 'click(' + filter + ')', options); + } + }); + + // 基础菜单的展开收缩事件 + _DOC.on('click', ELEM_LI + STR_GROUP_TITLE, function () { + var othis = $(this); + var elemGroup = othis.parents('.' + STR_ITEM_GROUP + ':eq(0)'); + var options = lay.options(elemGroup[0]); + var isAccordion = typeof othis.parents('.layui-menu').eq(0).attr('lay-accordion') === 'string'; + if ('isAllowSpread' in options ? options.isAllowSpread : true) { + thisModule.spread(elemGroup, isAccordion); + } + }); + + // 判断子级菜单是否超出屏幕 + var ELEM_LI_PAR = '.layui-menu .' + STR_ITEM_PARENT; + _DOC.on('mouseenter', ELEM_LI_PAR, function () { + var othis = $(this); + var elemPanel = othis.find('.' + STR_MENU_PANEL); + if (!elemPanel[0]) return; + var rect = elemPanel[0].getBoundingClientRect(); + + // 是否超出右侧屏幕 + if (rect.right > _WIN.width()) { + elemPanel.addClass(STR_MENU_PANEL_L); + // 不允许超出左侧屏幕 + rect = elemPanel[0].getBoundingClientRect(); + if (rect.left < 0) { + elemPanel.removeClass(STR_MENU_PANEL_L); + } + } + + // 是否超出底部屏幕 + if (rect.bottom > _WIN.height()) { + elemPanel.eq(0).css('margin-top', -(rect.bottom - _WIN.height() + 5)); + } + }).on('mouseleave', ELEM_LI_PAR, function () { + var othis = $(this); + var elemPanel = othis.children('.' + STR_MENU_PANEL); + elemPanel.removeClass(STR_MENU_PANEL_L); + elemPanel.css('margin-top', 0); + }); +})(); + +// 关闭面板 +dropdown.close = function (id) { + var that = thisModule.getThis(id); + if (!that) return this; + that.remove(); + return thisModule.call(that); +}; + +// 打开面板 +dropdown.open = function (id) { + var that = thisModule.getThis(id); + if (!that) return this; + that.render(); + return thisModule.call(that); +}; + +// 重载实例 +dropdown.reload = function (id, options, type) { + var that = thisModule.getThis(id); + if (!that) return this; + that.reload(options, type); + return thisModule.call(that); +}; + +// 仅重载数据 +dropdown.reloadData = function () { + var args = $.extend([], arguments); + args[2] = 'reloadData'; + + // 重载时,与数据相关的参数 + var dataParams = new RegExp('^(' + ['data', 'templet', 'content'].join('|') + ')$'); + + // 过滤与数据无关的参数 + layui.each(args[1], function (key) { + if (!dataParams.test(key)) { + delete args[1][key]; + } + }); + return dropdown.reload.apply(null, args); +}; + +// 核心入口 +dropdown.render = function (options) { + var inst = new Class(options); + return thisModule.call(inst); +}; + +export { dropdown }; diff --git a/dist/components/element.js b/dist/components/element.js new file mode 100644 index 000000000..9e76db248 --- /dev/null +++ b/dist/components/element.js @@ -0,0 +1,82 @@ +import { layui } from '../core/layui.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; +import { tab as component$3 } from './tab.js'; +import { nav as component$6 } from './nav.js'; +import { breadcrumb as component$5 } from './breadcrumb.js'; +import { progress as component$2 } from './progress.js'; +import { collapse as component$4 } from './collapse.js'; + +/** + * element + * 常用元素操作 + */ + +const elements = { + tab: component$3, + nav: component$6, + breadcrumb: component$5, + progress: component$2, + collapse: component$4 +}; + +// 创建组件 +const component = component$1({ + name: 'element', + // 模块名 + + CONST: { + MOD_NAME: 'element' + } +}); + +// const CONST = component.CONST; + +// 保留原接口,确保向下兼容 +$.extend(component, { + render(type, filter) { + const elemFilter = function () { + if (typeof filter === 'string' && filter) { + return '[lay-filter="' + filter + '"]'; + } + return ''; + }(); + const components = { + tab: '.layui-tab' + elemFilter, + nav: '.layui-nav' + elemFilter, + breadcrumb: '.layui-breadcrumb' + elemFilter, + progress: '.layui-progress' + elemFilter, + collapse: '.layui-collapse' + elemFilter + }; + + // 仅允许渲染指定组件 + if (type && !components[type]) return; + + // 若 filter 为 jQuery 对象 + if (type && typeof filter === 'object' && filter instanceof $) { + return elements[type].render({ + elem: filter + }); + } + return components[type] ? elements[type].render({ + elem: components[type] + }) : layui.each(components, function (componentName) { + elements[componentName].render({ + elem: components[componentName] + }); + }); + }, + tabAdd: component$3.tabAdd, + tabDelete: component$3.tabDelete, + tabChange: component$3.tabChange, + tab: component$3.tab, + progress: component$2.setValue +}); +component.init = component.render; + +// 自动渲染 +$(() => { + component.render(); +}); + +export { component as element }; diff --git a/dist/components/flow.js b/dist/components/flow.js new file mode 100644 index 000000000..b0294849a --- /dev/null +++ b/dist/components/flow.js @@ -0,0 +1,205 @@ +import { layui } from '../core/layui.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * flow + * 流加载组件 + */ + + +// 创建组件 +var component = component$1({ + name: 'flow', + CONST: { + ELEM_LOAD: '', + ELEM_MORE: 'layui-flow-more', + FLOW_SCROLL_EVENTS: 'scroll.lay_flow_scroll', + LAZYIMG_SCROLL_EVENTS: 'scroll.lay_flow_lazyimg_scroll' + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + var page = 0; + var locked; + var finished; + var elem = options.elem; + if (!elem[0]) return; + var scrollElem = $(options.scrollElem || document); // 滚动条所在元素 + var threshold = 'mb' in options ? options.mb : 50; // 临界距离 + var isAuto = 'isAuto' in options ? options.isAuto : true; // 否自动滚动加载 + var moreText = options.moreText || i18n.$t('flow.loadMore'); // 手动加载时,加载更多按钮文案 + var endText = options.end || i18n.$t('flow.noMore'); // “末页”显示文案 + var direction = options.direction || 'bottom'; + var isTop = direction === 'top'; + + // 滚动条所在元素是否为 document + var notDocument = options.scrollElem && options.scrollElem !== document; + + // 加载更多 + var ELEM_TEXT = '' + moreText + ''; + var $more = $(''); + elem.find('.' + CONST.ELEM_MORE).remove(); // 清除旧的「加载更多」元素 + elem[isTop ? 'prepend' : 'append']($more); + + // 加载下一个元素 + var next = function (content, status) { + var scrollHeightStart = notDocument ? scrollElem.prop('scrollHeight') : document.documentElement.scrollHeight; + var scrollTopStart = scrollElem.scrollTop(); + $more[isTop ? 'after' : 'before'](content); + status = status == 0 ? true : null; + status ? $more.html(endText) : $moreBtn.html(ELEM_TEXT); + finished = status; + locked = null; + + // 如果允许图片懒加载 + if (options.isLazyimg) { + component.lazyimg({ + elem: options.elem.find('img[lay-src]'), + scrollElem: options.scrollElem, + direction: options.direction, + id: options.id + }); + } + if (isTop) { + var scrollHeightEnd = notDocument ? scrollElem.prop('scrollHeight') : document.documentElement.scrollHeight; + if (page === 1) { + // 首次渲染后滑动到底部 + scrollElem.scrollTop(scrollHeightEnd); + } else if (page > 1) { + var nextElementHeight = scrollHeightEnd - scrollHeightStart; + scrollElem.scrollTop(scrollTopStart + nextElementHeight); + } + } + }; + var $moreBtn = $more.find('a'); + + // 触发请求 + var done = function fn() { + locked = true; + $moreBtn.html(CONST.ELEM_LOAD); + typeof options.done === 'function' && options.done(++page, next); + return fn; + }(); + + // 不自动滚动加载 + $moreBtn.on('click', function () { + if (finished) return; + locked || done(); + }); + if (!isAuto) return that; + + // 滚动条滚动事件 + var timer; + var FLOW_SCROLL_EVENTS = CONST.FLOW_SCROLL_EVENTS + '_' + options.id; + scrollElem.off(FLOW_SCROLL_EVENTS).on(FLOW_SCROLL_EVENTS, function () { + var othis = $(this), + top = othis.scrollTop(); + if (timer) clearTimeout(timer); + + // 如果已经结束,或者元素处于隐藏状态,则不执行滚动加载 + if (finished || !elem.width()) return; + timer = setTimeout(function () { + // 计算滚动所在容器的可视高度 + var height = notDocument ? othis.height() : $(window).height(); + + // 计算滚动所在容器的实际高度 + var scrollHeight = notDocument ? othis.prop('scrollHeight') : document.documentElement.scrollHeight; + + // 临界点 + if (!isTop ? scrollHeight - top - height <= threshold : top <= threshold) { + locked || done(); + } + }, 100); + }); + } +}); +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +// 保留原接口,确保向下兼容 +$.extend(component, { + load: function (options) { + return component.render(options); + }, + // 图片懒加载 + lazyimg: function (options) { + options = options || {}; + var scrollElem = $(options.scrollElem || document); // 滚动条所在元素 + var elem = options.elem || 'img'; + var direction = options.direction || 'bottom'; + var isTop = direction === 'top'; + var index = 0; + + // 滚动条所在元素是否为 document + var notDocument = options.scrollElem && options.scrollElem !== document; + + // 显示图片 + var render = function fn(othis) { + var $elem = $(elem); + + // 计算滚动所在容器的可视高度 + var height = notDocument ? scrollElem.height() : $(window).height(); + var start = scrollElem.scrollTop(); + var end = start + height; + var show = function (item) { + var elemTop = notDocument ? function () { + return item.offset().top - scrollElem.offset().top + start; + }() : item.offset().top; + + /* 始终只加载在当前屏范围内的图片 */ + if ((isTop ? elemTop + item.height() : elemTop) >= start && elemTop <= end) { + if (item.attr('lay-src')) { + var src = item.attr('lay-src'); + layui.img(src, function () { + var next = $elem.eq(index); + item.attr('src', src).removeAttr('lay-src'); + + /* 当前图片加载就绪后,检测下一个图片是否在当前屏 */ + next[0] && fn(next); + index++; + }, function () { + item.removeAttr('lay-src'); + }); + } + } + }; + if (othis) { + show(othis); + } else { + // 计算未加载过的图片 + for (var i = 0; i < $elem.length; i++) { + var item = $elem.eq(i), + elemTop = notDocument ? function () { + return item.offset().top - scrollElem.offset().top + start; + }() : item.offset().top; + show(item); + index = i; + + // 如果图片的 top 坐标,超出了当前屏,则终止后续图片的遍历 + if (elemTop > end) break; + } + } + return fn; + }(); + + // 滚动事件 + var timer; + var id = options.id || ''; + var LAZYIMG_SCROLL_EVENTS = CONST.LAZYIMG_SCROLL_EVENTS + '_' + id; + scrollElem.off(LAZYIMG_SCROLL_EVENTS).on(LAZYIMG_SCROLL_EVENTS, function () { + if (timer) clearTimeout(timer); + timer = setTimeout(function () { + render(); + }, 50); + }); + return render; + } +}); + +export { component as flow }; diff --git a/dist/components/form.js b/dist/components/form.js new file mode 100644 index 000000000..ea6ceb8a2 --- /dev/null +++ b/dist/components/form.js @@ -0,0 +1,1461 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { util } from './util.js'; +import { layer } from './layer.js'; + +/** + * form 表单组件 + */ + +var hint = layui.hint(); +// var device = layui.device(); + +var MOD_NAME = 'form'; +var ELEM = '.layui-form'; +var THIS = 'layui-this'; +// var SHOW = 'layui-show'; +var HIDE = 'layui-hide'; +var DISABLED = 'layui-disabled'; +var OUT_OF_RANGE = 'layui-input-number-out-of-range'; +var BAD_INPUT = 'layui-input-number-invalid'; +var resizeObserver = lay.createSharedResizeObserver(MOD_NAME); + +// ie8 中可以获取到 input 元素的 'indeterminate' 属性描述符,但重新定义 getter/setter 无效,无报错 +// AppleWebKit/537.36 无法获取 input 元素任意属性的属性描述符(包括lookupGetter),但可以重新定义 getter/setter +var needCheckboxFallback = lay.ie && parseFloat(lay.ie) === 8 || typeof Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'checked') === 'undefined'; +var Form = function () { + this.config = { + // 内置的验证规则 + verify: { + required: function (value) { + if (!/[\S]+/.test(value) || value === undefined || value === null) { + return i18n.$t('form.validateMessages.required'); + } + }, + phone: function (value) { + var EXP = /^1\d{10}$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.phone'); + } + }, + email: function (value) { + var EXP = /^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.email'); + } + }, + url: function (value) { + var EXP = /^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.url'); + } + }, + number: function (value) { + if (value && isNaN(value)) { + return i18n.$t('form.validateMessages.number'); + } + }, + date: function (value) { + var EXP = /^(\d{4})[-/](\d{1}|0\d{1}|1[0-2])([-/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.date'); + } + }, + identity: function (value) { + var EXP = /(^\d{15}$)|(^\d{17}(x|X|\d)$)/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.identity'); + } + } + }, + autocomplete: null // 全局 autocomplete 状态。 null 表示不干预 + }; +}; + +// 全局设置 +Form.prototype.set = function (options) { + var that = this; + $.extend(true, that.config, options); + return that; +}; + +// 验证规则设定 +Form.prototype.verify = function (settings) { + var that = this; + $.extend(true, that.config.verify, settings); + return that; +}; + +// 获取指定表单对象 +Form.prototype.getFormElem = function (filter) { + return $(ELEM + function () { + return filter ? '[lay-filter="' + filter + '"]' : ''; + }()); +}; + +// 表单事件 +Form.prototype.on = function (events, callback) { + return layui.onevent.call(this, MOD_NAME, events, callback); +}; + +// 赋值/取值 +Form.prototype.val = function (filter, object) { + var that = this; + var formElem = that.getFormElem(filter); + + // 遍历 + formElem.each(function () { + var itemForm = $(this); + + // 赋值 + for (var key in object) { + if (!lay.hasOwn(object, key)) continue; + var type; + var value = object[key]; + var itemElem = itemForm.find('[name="' + key + '"]'); + + // 如果对应的表单不存在,则不执行 + if (!itemElem[0]) continue; + type = itemElem[0].type; + + // 如果为复选框 + if (type === 'checkbox') { + itemElem[0].checked = value; + } else if (type === 'radio') { + // 如果为单选框 + itemElem.each(function () { + this.checked = this.value == value + ''; + }); + } else { + // 其它类型的表单 + itemElem.val(value); + } + } + }); + form.render(null, filter); + + // 返回值 + return that.getValue(filter); +}; + +// 取值 +Form.prototype.getValue = function (filter, itemForm) { + itemForm = itemForm || this.getFormElem(filter); + var nameIndex = {}, + // 数组 name 索引 + field = {}, + fieldElem = itemForm.find('input,select,textarea'); // 获取所有表单域 + + layui.each(fieldElem, function (_, item) { + var othis = $(this), + init_name; // 初始 name + + item.name = (item.name || '').replace(/^\s*|\s*&/, ''); + if (!item.name) return; + + // 用于支持数组 name + if (/^.*\[\]$/.test(item.name)) { + var key = item.name.match(/^(.*)\[\]$/g)[0]; + nameIndex[key] = nameIndex[key] | 0; + init_name = item.name.replace(/^(.*)\[\]$/, '$1[' + nameIndex[key]++ + ']'); + } + if (/^(checkbox|radio)$/.test(item.type) && !item.checked) return; // 复选框和单选框未选中,不记录字段 + // select 多选用 jQuery 方式取值,未选中 option 时, + // jQuery v2.2.4 及以下版本返回 null,以上(3.x) 返回 []。 + // 统一规范化为 [],参考 https://github.com/jquery/jquery/issues/2562 + field[init_name || item.name] = this.tagName === 'SELECT' && typeof this.getAttribute('multiple') === 'string' ? othis.val() || [] : this.value; + }); + return field; +}; + +// 表单控件渲染 +Form.prototype.render = function (type, filter) { + var that = this; + var options = that.config; + var elemForm = $(ELEM + function () { + return filter ? '[lay-filter="' + filter + '"]' : ''; + }()); + var items = { + // 输入框 + input: function (elem) { + var inputs = elem || elemForm.find('input,textarea'); + + // 初始化全局的 autocomplete + options.autocomplete && inputs.attr('autocomplete', options.autocomplete); + var handleInputNumber = function (elem, eventType) { + var that = this; + var rawValue = elem.val(); + var value = Number(rawValue); + var step = Number(elem.attr('step')) || 1; // 加减的数字间隔 + var min = Number(elem.attr('min')); + var max = Number(elem.attr('max')); + var precision = Number(elem.attr('lay-precision')); + var noAction = eventType !== 'click' && rawValue === ''; // 初始渲染和失焦时空值不作处理 + var isInit = eventType === 'init'; + var isBadInput = isNaN(value); + var isStepStrictly = typeof elem.attr('lay-step-strictly') === 'string'; + elem.toggleClass(BAD_INPUT, isBadInput); + if (isBadInput) return; // 若非数字,则不作处理 + + if (eventType === 'click') { + // 兼容旧版行为,2.10 以前 readonly 不禁用控制按钮 + if (elem[0].type === 'text' && typeof elem.attr('readonly') === 'string') return; + var isDecrement = !!$(that).index(); // 0: icon-up, 1: icon-down + value = isDecrement ? value - step : value + step; + } + + // 获取小数点后位数 + var decimals = function (step) { + var decimals = (step.toString().match(/\.(\d+$)/) || [])[1] || ''; + return decimals.length; + }; + precision = precision >= 0 ? precision : Math.max(decimals(step), decimals(rawValue)); + + // 赋值 + if (!noAction) { + // 初始渲染时只处理数字精度 + if (!isInit) { + if (isStepStrictly) { + value = Math.round(value / step) * step; + } + if (value <= min) value = min; + if (value >= max) value = max; + } + // 若 `lay-precision` 为 0, 则表示只保留整数 + if (precision === 0) { + value = parseInt(value); + } else if (precision > 0) { + // 小数位精度 + value = value.toFixed(precision); + } + elem.val(value); + elem.attr('lay-input-mirror', elem.val()); + } + + // 超出范围的样式 + var outOfRange = value < min || value > max; + elem[outOfRange && !noAction ? 'addClass' : 'removeClass'](OUT_OF_RANGE); + if (isInit) return; + + // 更新按钮状态 + var controlBtn = { + increment: elem.next().find('.layui-icon-up'), + decrement: elem.next().find('.layui-icon-down') + }; + controlBtn.increment[value >= max && !noAction ? 'addClass' : 'removeClass'](DISABLED); + controlBtn.decrement[value <= min && !noAction ? 'addClass' : 'removeClass'](DISABLED); + }; + + // 初始化输入框动态点缀 + elemForm.find('input[lay-affix],textarea[lay-affix]').each(function () { + var othis = $(this); + var affix = othis.attr('lay-affix'); + var CLASS_WRAP = 'layui-input-wrap'; + var CLASS_SUFFIX = 'layui-input-suffix'; + var CLASS_AFFIX = 'layui-input-affix'; + var disabled = othis.is('[disabled]') || othis.is('[readonly]'); + + // 根据是否空值来显示或隐藏元素 + var showAffix = function (elem, value) { + elem = $(elem); + if (!elem[0]) return; + elem[$.trim(value) ? 'removeClass' : 'addClass'](HIDE); + }; + + // 渲染动态点缀内容 + var renderAffix = function (opts) { + opts = $.extend({}, affixOptions[affix] || { + value: affix + }, opts, lay.options(othis[0])); + var elemAffix = $('
                  '); + var value = layui.isArray(opts.value) ? opts.value : [opts.value]; + var elemIcon = $(function () { + var arr = []; + layui.each(value, function (i, item) { + arr.push(''); + }); + return arr.join(''); + }()); + elemAffix.append(elemIcon); // 插入图标元素 + + // 追加 className + if (opts.split) elemAffix.addClass('layui-input-split'); + if (opts.className) elemAffix.addClass(opts.className); + + // 移除旧的元素 + var hasElemAffix = othis.next('.' + CLASS_AFFIX); + if (hasElemAffix[0]) hasElemAffix.remove(); + + // 是否在规定的容器中 + if (!othis.parent().hasClass(CLASS_WRAP)) { + othis.wrap('
                  '); + } + + // 是否已经存在后缀元素 + var hasElemSuffix = othis.next('.' + CLASS_SUFFIX); + if (hasElemSuffix[0]) { + hasElemAffix = hasElemSuffix.find('.' + CLASS_AFFIX); + if (hasElemAffix[0]) hasElemAffix.remove(); + hasElemSuffix.prepend(elemAffix); + othis.css('padding-right', function () { + var paddingRight = othis.closest('.layui-input-group')[0] ? 0 : hasElemSuffix.outerWidth(); + return paddingRight + elemAffix.outerWidth(); + }); + } else { + elemAffix.addClass(CLASS_SUFFIX); + othis.after(elemAffix); + } + opts.show === 'auto' && showAffix(elemAffix, othis.val()); + typeof opts.init === 'function' && opts.init.call(this, othis, opts); + + // 输入事件 + othis.on('input propertychange', function () { + var value = this.value; + opts.show === 'auto' && showAffix(elemAffix, value); + }); + + // 失去焦点事件 + othis.on('blur', function () { + typeof opts.blur === 'function' && opts.blur.call(this, othis, opts); + }); + + // 点击动态后缀事件 + elemIcon.on('click', function () { + var inputFilter = othis.attr('lay-filter'); + if ($(this).hasClass(DISABLED)) return; + typeof opts.click === 'function' && opts.click.call(this, othis, opts); + + // 对外事件 + layui.event.call(this, MOD_NAME, 'input-affix(' + inputFilter + ')', { + elem: othis[0], + affix: affix, + options: opts + }); + }); + }; + + // 动态点缀配置项 + var affixOptions = { + eye: { + // 密码显隐 + value: 'eye-invisible', + click: function (elem) { + // 事件 + var SHOW_NAME = 'LAY_FORM_INPUT_AFFIX_SHOW'; + var isShow = elem.data(SHOW_NAME); + elem.attr('type', isShow ? 'password' : 'text').data(SHOW_NAME, !isShow); + renderAffix({ + value: isShow ? 'eye-invisible' : 'eye' + }); + } + }, + clear: { + // 内容清除 + value: 'clear', + click: function (elem) { + elem.val('').focus(); + showAffix($(this).parent(), null); + }, + show: 'auto', + // 根据输入框值是否存在来显示或隐藏点缀图标 + disabled: disabled // 跟随输入框禁用状态 + }, + number: { + // 数字输入框 + value: ['up', 'down'], + split: true, + className: 'layui-input-number', + disabled: othis.is('[disabled]'), + // 跟随输入框禁用状态 + init: function (elem) { + // 旧版浏览器不支持更改 input 元素的 type 属性,需要主动设置 text + if (elem.attr('type') === 'text' || elem[0].type === 'text') { + var ns = '.lay_input_number'; + var skipCheck = false; + var isComposition = false; + var isReadonly = typeof elem.attr('readonly') === 'string'; + var isMouseWheel = typeof elem.attr('lay-wheel') === 'string'; + var btnElem = elem.next('.layui-input-number').children('i'); + // 旧版浏览器不支持 beforeInput 事件,需要设置一个 attr 存储输入前的值 + elem.attr('lay-input-mirror', elem.val()); + elem.off(ns); + // 旧版浏览器不支持 event.inputType 属性,需要用 keydown 事件来判断是否跳过输入检查 + elem.on('keydown' + ns, function (e) { + skipCheck = false; + if (e.keyCode === 8 || e.keyCode === 46) { + // Backspace || Delete + skipCheck = true; + } + // Up & Down 键盘事件处理 + if (!isReadonly && btnElem.length === 2 && (e.keyCode === 38 || e.keyCode === 40)) { + e.preventDefault(); + btnElem.eq(e.keyCode === 38 ? 0 : 1).click(); + } + }); + elem.on('input' + ns + ' propertychange' + ns, function (e) { + if (isComposition || e.type === 'propertychange' && e.originalEvent.propertyName !== 'value') return; + if (skipCheck || canInputNumber(this.value)) { + elem.attr('lay-input-mirror', this.value); + } else { + // 恢复输入前的值 + this.value = elem.attr('lay-input-mirror'); + } + elem.toggleClass(BAD_INPUT, isNaN(Number(this.value))); + }); + elem.on('compositionstart' + ns, function () { + isComposition = true; + }); + elem.on('compositionend' + ns, function () { + isComposition = false; + elem.trigger('input'); + }); + // 响应鼠标滚轮或触摸板 + if (isMouseWheel) { + elem.on(['wheel', 'mousewheel', 'DOMMouseScroll'].join(ns + ' ') + ns, function (e) { + if (!btnElem.length) return; + if (!$(this).is(':focus')) return; + var direction = 0; + e.preventDefault(); + // IE9+,chrome 和 firefox 同时添加 'wheel' 和 'mousewheel' 事件时,只执行 'wheel' 事件 + if (e.type === 'wheel') { + e.deltaX = e.originalEvent.deltaX; + e.deltaY = e.originalEvent.deltaY; + direction = Math.abs(e.deltaX) >= Math.abs(e.deltaY) ? e.deltaX : e.deltaY; + } else if (e.type === 'mousewheel') { + direction = -e.originalEvent.wheelDelta; + } else if (e.type === 'DOMMouseScroll') { + direction = e.originalEvent.detail; + } + btnElem.eq(direction > 0 ? 1 : 0).click(); + }); + } + if (isReadonly) { + btnElem.addClass(DISABLED); + } + } + handleInputNumber.call(this, elem, 'init'); + }, + click: function (elem) { + handleInputNumber.call(this, elem, 'click'); + }, + blur: function (elem) { + handleInputNumber.call(this, elem, 'blur'); + } + } + }; + renderAffix(); + }); + }, + // 下拉选择框 + select: function (elem) { + var TIPS = i18n.$t('form.select.placeholder'); + var CLASS = 'layui-form-select'; + var TITLE = 'layui-select-title'; + var NONE = 'layui-select-none'; + var CREATE_OPTION = 'layui-select-create-option'; + var PANEL_WRAP = 'layui-select-panel-wrap'; + var PANEL_ELEM_DATA = 'layui-select-panel-elem-data'; + var selects = elem || elemForm.find('select'); + + // 各种事件 + var events = function (reElem, titleElem, disabled, isSearch, isCreatable, isAppendTo) { + var select = $(this); + var title = titleElem; + var input = title.find('input'); + var dl = reElem.find('dl'); + // var dds = dl.children('dd'); + var dts = dl.children('dt'); // select 分组dt元素 + var index = this.selectedIndex; // 当前选中的索引 + var initValue = ''; + var removeClickOutsideEvent; + if (disabled) return; + + /** + * 搜索项 + * @typedef searchOption + * @prop {boolean} [caseSensitive=false] 是否区分大小写 + * @prop {boolean} [fuzzy=false] 是否开启模糊匹配,开启后将会忽略模式出现在字符串中的位置。 + */ + /** @type {searchOption} */ + var laySearch = select.attr('lay-search') === 'cs' ? { + caseSensitive: true + } : lay.options(select, { + attr: 'lay-search' + }); + // 目前只支持 body + var appendTarget = select.attr('lay-append-to') || 'body'; + var appendPosition = select.attr('lay-append-position'); + + // #1449 + // IE10 和 11 中,带有占位符的 input 元素获得/失去焦点时,会触发 input 事件 + // 当鼠标按下时,根据 input 元素上的 __ieph 标识忽略 input 事件 + var needPlaceholderPatch = !!(lay.ie && (lay.ie === '10' || lay.ie === '11') && input.attr('placeholder')); + + // 展开下拉 + var showDown = function () { + if (isAppendTo) { + // 如果追加面板元素后出现滚动条,触发元素宽度可能会有变化,所以先追加面板元素 + reElem.appendTo(appendTarget).css({ + width: title.width() + 'px' + }); + var updatePosition = function () { + lay.position(title[0], reElem[0], { + position: appendPosition, + allowBottomOut: true, + offset: [0, 5] + }); + }; + updatePosition(); + $(window).on('resize.lay_select_resize', updatePosition); + if (resizeObserver) { + resizeObserver.observe(reElem[0], updatePosition); + } + } + var top = reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop(); + var dlHeight = dl.outerHeight(); + var dds = dl.children('dd'); + index = select[0].selectedIndex; // 获取最新的 selectedIndex + title.parent().addClass(CLASS + 'ed'); + dds.removeClass(HIDE); + dts.removeClass(HIDE); + + // 初始选中样式 + dds.removeClass(THIS); + index >= 0 && dds.eq(index).addClass(THIS); + + // 上下定位识别 + if (top + dlHeight > $win.height() && top >= dlHeight) { + reElem.addClass(CLASS + 'up'); + } + followScroll(); + if (needPlaceholderPatch) { + dl.off('mousedown.lay_select_ieph').on('mousedown.lay_select_ieph', function () { + input[0].__ieph = true; + setTimeout(function () { + input[0].__ieph = false; + }, 60); + }); + } + removeClickOutsideEvent = lay.onClickOutside(isAppendTo ? reElem[0] : dl[0], function () { + hideDown(); + initValue && input.val(initValue); + }, { + ignore: title, + detectIframe: true, + capture: false + }); + }; + + // 隐藏下拉 + var hideDown = function (choose) { + title.parent().removeClass(CLASS + 'ed ' + CLASS + 'up'); + input.blur(); + isCreatable && dl.children('.' + CREATE_OPTION).remove(); + if (typeof removeClickOutsideEvent === 'function') { + removeClickOutsideEvent(); + removeClickOutsideEvent = null; + } + if (isAppendTo) { + reElem.detach(); + $(window).off('resize.lay_select_resize'); + if (resizeObserver) { + resizeObserver.unobserve(reElem[0]); + } + } + if (choose) return; + notOption(input.val(), function (none) { + var selectedIndex = select[0].selectedIndex; + + // 未查询到相关值 + if (none) { + initValue = $(select[0].options[selectedIndex]).prop('text'); // 重新获得初始选中值 + + // 如果是第一项,且文本值等于 placeholder,则清空初始值 + if (selectedIndex === 0 && initValue === input.attr('placeholder')) { + initValue = ''; + } + + // 如果有选中值,则将输入框纠正为该值。否则清空输入框 + input.val(initValue || ''); + } + }); + }; + + // 定位下拉滚动条 + var followScroll = function () { + var thisDd = dl.children('dd.' + THIS); + if (!thisDd[0]) return; + var posTop = thisDd.position().top; + var dlHeight = dl.height(); + var ddHeight = thisDd.height(); + + // 若选中元素在滚动条不可见底部 + if (posTop > dlHeight) { + dl.scrollTop(posTop + dl.scrollTop() - dlHeight + ddHeight - 5); + } + + // 若选择元素在滚动条不可见顶部 + if (posTop < 0) { + dl.scrollTop(posTop + dl.scrollTop() - 5); + } + }; + + // 点击标题区域 + title.on('click', function () { + title.parent().hasClass(CLASS + 'ed') ? hideDown() : showDown(); + dl.find('.' + NONE).remove(); + }); + + // 点击箭头获取焦点 + title.find('.layui-edge').on('click', function () { + input.focus(); + }); + + // select 中 input 键盘事件 + input.on('keyup', function (e) { + // 键盘松开 + var keyCode = e.keyCode; + + // Tab键展开 + if (keyCode === 9) { + showDown(); + } + }).on('keydown', function (e) { + // 键盘按下 + var keyCode = e.keyCode; + + // Tab键隐藏 + if (keyCode === 9) { + hideDown(); + } + + // 标注 dd 的选中状态 + var setThisDd = function (prevNext) { + e.preventDefault(); + var allDisplayedElem = dl.children('dd:not(.' + HIDE + ',.' + DISABLED + ')'); + if (!allDisplayedElem.length) return; + var firstIndex = 0; + var lastIndex = allDisplayedElem.length - 1; + var selectedIndex = -1; + layui.each(allDisplayedElem, function (index, el) { + if ($(el).hasClass(THIS)) { + selectedIndex = index; + return true; + } + }); + var nextIndex = prevNext === 'prev' ? selectedIndex - 1 < firstIndex ? lastIndex : selectedIndex - 1 : selectedIndex + 1 > lastIndex ? firstIndex : selectedIndex + 1; + var selectedElem = allDisplayedElem.eq(nextIndex); + selectedElem.addClass(THIS).siblings().removeClass(THIS); // 标注样式 + followScroll(); // 定位滚动条 + }; + if (keyCode === 38) setThisDd('prev'); // Up 键 + if (keyCode === 40) setThisDd('next'); // Down 键 + + // Enter 键 + if (keyCode === 13) { + e.preventDefault(); + dl.children('dd.' + THIS).trigger('click'); + } + }).on('paste', function () { + showDown(); + }); + + // 检测值是否不属于 select 项 + var notOption = function (value, callback, origin) { + var num = 0; + var dds = dl.children('dd'); + var hasEquals = false; + var rawValue = value; + var fuzzyMatchRE; + if (!laySearch.caseSensitive) { + value = value.toLowerCase(); + } + if (laySearch.fuzzy) { + fuzzyMatchRE = fuzzyMatchRegExp(value, laySearch.caseSensitive); + } + layui.each(dds, function () { + var othis = $(this); + var text = othis.text(); + var isCreateOption = isCreatable && othis.hasClass(CREATE_OPTION); + + // 需要区分大小写 + if (isCreatable && !isCreateOption && text === rawValue) { + hasEquals = true; + } + + // 是否区分大小写 + if (!laySearch.caseSensitive) { + text = text.toLowerCase(); + } + + // 匹配 + var not = laySearch.fuzzy ? !fuzzyMatchRE.test(text) : text.indexOf(value) === -1; + if (value === '' || origin === 'blur' ? value !== text : not) num++; + origin === 'keyup' && othis[(isCreatable ? not && !isCreateOption : not) ? 'addClass' : 'removeClass'](HIDE); + }); + // 处理 select 分组元素 + origin === 'keyup' && layui.each(dts, function () { + var othis = $(this); + var thisDds = othis.nextUntil('dt').filter('dd'); // 当前分组下的dd元素 + if (isCreatable) thisDds = thisDds.not('.' + CREATE_OPTION); + var allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了 + othis[allHide ? 'addClass' : 'removeClass'](HIDE); + }); + var none = num === dds.length; + return callback(none, hasEquals), none; + }; + + // 搜索匹配 + var search = function (e) { + var value = this.value, + keyCode = e.keyCode; + if (keyCode === 9 || keyCode === 13 || keyCode === 37 || keyCode === 38 || keyCode === 39 || keyCode === 40) { + return false; + } + if (needPlaceholderPatch && e.target.__ieph) { + e.target.__ieph = false; + return false; + } + notOption(value, function (none, hasEquals) { + if (isCreatable) { + if (hasEquals) { + dl.children('.' + CREATE_OPTION).remove(); + } else { + var createOptionElem = dl.children('.' + CREATE_OPTION); + if (createOptionElem[0]) { + createOptionElem.attr('lay-value', value).text(value); + } else { + // 临时显示在顶部 + var ddElem = $('
                  ').addClass(CREATE_OPTION).attr('lay-value', value).text(value); + var firstOptionELem = dl.children().eq(0); + var hasTips = firstOptionELem.hasClass('layui-select-tips'); + firstOptionELem[hasTips ? 'after' : 'before'](ddElem); + } + } + } else { + if (none) { + dl.find('.' + NONE)[0] || dl.append('

                  ' + i18n.$t('form.select.noMatch') + '

                  '); + } else { + dl.find('.' + NONE).remove(); + } + } + }, 'keyup'); + + // 当搜索值清空时 + if (value === '') { + // 取消选中项 + select.val(''); + dl.find('.' + THIS).removeClass(THIS); + (select[0].options[0] || {}).value || dl.children('dd:eq(0)').addClass(THIS); + dl.find('.' + NONE).remove(); + isCreatable && dl.children('.' + CREATE_OPTION).remove(); + } + followScroll(); // 定位滚动条 + }; + if (isSearch) { + input.on('input propertychange', layui.debounce(search, 50)).on('blur', function () { + var selectedIndex = select[0].selectedIndex; + initValue = $(select[0].options[selectedIndex]).prop('text'); // 重新获得初始选中值 + + // 如果是第一项,且文本值等于 placeholder,则清空初始值 + if (selectedIndex === 0 && initValue === input.attr('placeholder')) { + initValue = ''; + } + setTimeout(function () { + notOption(input.val(), function () { + initValue || input.val(''); // none && !initValue + }, 'blur'); + }, 200); + }); + } + + // 选择 + dl.on('click', 'dd', function () { + var othis = $(this), + value = othis.attr('lay-value'); + var filter = select.attr('lay-filter'); // 获取过滤器 + + if (othis.hasClass(DISABLED)) return false; + + // 将新增的 option 元素添加到末尾 + if (isCreatable && othis.hasClass(CREATE_OPTION)) { + var optionElem = $('
                  '); + if (index === 0 && !item.value && tagName !== 'optgroup') { + dd.addClass('layui-select-tips'); + dd.text(item.text || TIPS); + arr.push(dd.prop('outerHTML')); + } else if (tagName === 'optgroup') { + var dt = $('
                  '); + dt.text(item.label); + arr.push(dt.prop('outerHTML')); + } else { + dd.attr('lay-value', item.value); + if (value === item.value) { + dd.addClass(THIS); + } + if (item.disabled) { + dd.addClass(DISABLED); + } + dd.text(item.text); + arr.push(dd.prop('outerHTML')); + } + }); + if (arr.length === 0) { + arr.push('
                  ' + i18n.$t('form.select.noData') + '
                  '); + } + return arr.join(''); + }(); + elem.html(content); + return elem; + }(); + + // 如果已经渲染,则 Rerender + if (hasRender[0]) { + if (isAppendTo) { + var panelWrapElem = hasRender.data(PANEL_ELEM_DATA); + panelWrapElem && panelWrapElem.remove(); + } + hasRender.remove(); + } + if (isAppendTo) { + selectWrapper.append(titleElem); + othis.after(selectWrapper); + var contentWrapElem = $('
                  ').append(contentElem); + selectWrapper.data(PANEL_ELEM_DATA, contentWrapElem); // 将面板元素对象记录在触发元素 data 中,重新渲染时需要清理旧面板元素 + events.call(this, contentWrapElem, titleElem, disabled, isSearch, isCreatable, isAppendTo); + } else { + selectWrapper.append(titleElem).append(contentElem); + othis.after(selectWrapper); + events.call(this, selectWrapper, titleElem, disabled, isSearch, isCreatable, isAppendTo); + } + }); + }, + // 复选框/开关 + checkbox: function (elem) { + var CLASS = { + checkbox: ['layui-form-checkbox', 'layui-form-checked', 'checkbox'], + switch: ['layui-form-switch', 'layui-form-onswitch', 'switch'], + SUBTRA: 'layui-icon-indeterminate', + ICON: 'layui-icon', + ICON_OK: 'layui-icon-ok' + }; + var clickEventName = 'click.lay_checkbox_click'; + var checks = elem || elemForm.find('input[type=checkbox]'); + // 风格 + /* var skins = { + primary: true, // 默认风格 + tag: true, // 标签风格 + switch: true, // 开关风格 + }; */ + // 事件 + var events = function (reElem, RE_CLASS) { + var check = $(this); + var skin = check.attr('lay-skin') || 'primary'; + var isSwitch = skin === 'switch'; + var isPrimary = skin === 'primary'; + + // 勾选 + // 通过重新赋值触发美化元素样式更新 + check.off(clickEventName).on(clickEventName, function () { + var filter = check.attr('lay-filter'); // 获取过滤器 + var checked = check[0].checked; + var indeterminate = check[0].indeterminate; + + // 禁用 + if (check[0].disabled) return; + + // 半选 + check[0].indeterminate = indeterminate; + + // 开关 + check[0].checked = checked; + + // 事件 + layui.event.call(check[0], MOD_NAME, RE_CLASS[2] + '(' + filter + ')', { + elem: check[0], + value: check[0].value, + othis: reElem + }); + }); + reElem.on('click', function () { + var hasLabel = check.closest('label').length; + if (!hasLabel) { + check.trigger('click'); + } + }); + that.syncAppearanceOnPropChanged(this, 'checked', function () { + if (isSwitch) { + var title = (reElem.next('*[lay-checkbox]')[0] ? reElem.next().html() : check.attr('title') || '').split('|'); + reElem.children('div').html(this.checked ? title[0] : title[1] || title[0]); + } + reElem.toggleClass(RE_CLASS[1], this.checked); + }); + if (isPrimary) { + that.syncAppearanceOnPropChanged(this, 'indeterminate', function () { + if (this.indeterminate) { + reElem.children('.' + CLASS.ICON).removeClass(CLASS.ICON_OK).addClass(CLASS.SUBTRA); + } else { + reElem.children('.' + CLASS.ICON).removeClass(CLASS.SUBTRA).addClass(CLASS.ICON_OK); + } + }); + } + }; + + // 遍历复选框 + checks.each(function (index, check) { + var othis = $(this); + var skin = othis.attr('lay-skin') || 'primary'; + var title = util.escape($.trim(check.title || function () { + // 向下兼容 lay-text 属性 + return check.title = othis.attr('lay-text') || ''; + }())); + var disabled = this.disabled; + + // if(!skins[skin]) skin = 'primary'; // 若非内置风格,则强制为默认风格 + var RE_CLASS = CLASS[skin] || CLASS.checkbox; + + // 替代元素 + var hasRender = othis.next('.' + RE_CLASS[0]); + hasRender[0] && hasRender.remove(); // 若已经渲染,则 Rerender + + // 若存在标题模板,则优先读取标题模板 + var titleTplAttrs = []; + if (othis.next('[lay-checkbox]')[0]) { + var titleTplElem = othis.next(); + title = titleTplElem.html() || ''; + if (titleTplElem[0].attributes.length > 1) { + layui.each(titleTplElem[0].attributes, function (i, attr) { + if (attr.name !== 'lay-checkbox') { + titleTplAttrs.push(attr.name + '="' + attr.value + '"'); + } + }); + } + } + titleTplAttrs = titleTplAttrs.join(' '); + + // 若为开关,则对 title 进行分隔解析 + title = skin === 'switch' ? title.split('|') : [title]; + if (othis.closest('[lay-ignore]').length) return othis.show(); + + // 处理 IE8 indeterminate 属性重新定义 get set 后无法设置值的问题 + if (needCheckboxFallback) { + toggleAttribute.call(check, 'lay-form-sync-checked', check.checked); + !check.checked && toggleAttribute.call(check, 'lay-form-sync-indeterminate', check.indeterminate); + } + + // 替代元素 + var reElem = $(['
                  ', function () { + // 不同风格的内容 + var type = { + // 复选框 + checkbox: [title[0] ? '
                  ' + title[0] + '
                  ' : skin === 'primary' ? '' : '
                  ', ''].join(''), + // 开关 + switch: '
                  ' + ((check.checked ? title[0] : title[1] || title[0]) || '') + '
                  ' + }; + return type[skin] || type['checkbox']; + }(), '
                  '].join('')); + othis.after(reElem); + events.call(this, reElem, RE_CLASS); + }); + }, + // 单选框 + radio: function (elem) { + var CLASS = 'layui-form-radio'; + var ICON = ['layui-icon-radio', 'layui-icon-circle']; + var radios = elem || elemForm.find('input[type=radio]'); + var clickEventName = 'click.lay_radio_click'; + + // 事件 + var events = function (reElem) { + var radio = $(this); + var ANIM = 'layui-anim-scaleSpring'; + radio.off(clickEventName).on(clickEventName, function () { + var filter = radio.attr('lay-filter'); // 获取过滤器 + + if (radio[0].disabled) return; + radio[0].checked = true; + layui.event.call(radio[0], MOD_NAME, 'radio(' + filter + ')', { + elem: radio[0], + value: radio[0].value, + othis: reElem + }); + }); + reElem.on('click', function () { + var hasLabel = radio.closest('label').length; + if (!hasLabel) { + radio.trigger('click'); + } + }); + that.syncAppearanceOnPropChanged(this, 'checked', function () { + var radioEl = this; + if (radioEl.checked) { + reElem.addClass(CLASS + 'ed'); + reElem.children('.layui-icon').addClass(ANIM + ' ' + ICON[0]); + var forms = radio.parents(ELEM); + var sameRadios = forms.find('input[name=' + radioEl.name.replace(/(\.|#|\[|\])/g, '\\$1') + ']'); // 找到相同name的兄弟 + layui.each(sameRadios, function () { + if (radioEl === this) return; + this.checked = false; + }); + } else { + reElem.removeClass(CLASS + 'ed'); + reElem.children('.layui-icon').removeClass(ANIM + ' ' + ICON[0]).addClass(ICON[1]); + } + }); + }; + + // 初始渲染 + radios.each(function (index, radio) { + var othis = $(this), + hasRender = othis.next('.' + CLASS); + var disabled = this.disabled; + var skin = othis.attr('lay-skin'); + if (othis.closest('[lay-ignore]').length) return othis.show(); + if (needCheckboxFallback) { + toggleAttribute.call(radio, 'lay-form-sync-checked', radio.checked); + } + hasRender[0] && hasRender.remove(); // 如果已经渲染,则Rerender + + var title = util.escape(radio.title || ''); + var titleTplAttrs = []; + if (othis.next('[lay-radio]')[0]) { + var titleTplElem = othis.next(); + title = titleTplElem.html() || ''; + if (titleTplElem[0].attributes.length > 1) { + layui.each(titleTplElem[0].attributes, function (i, attr) { + if (attr.name !== 'lay-radio') { + titleTplAttrs.push(attr.name + '="' + attr.value + '"'); + } + }); + } + } + titleTplAttrs = titleTplAttrs.join(' '); + + // 替代元素 + var reElem = $(['
                  ', '', '
                  ' + title + '
                  ', '
                  '].join('')); + othis.after(reElem); + events.call(this, reElem); + }); + } + }; + + // 执行所有渲染项 + var renderItem = function () { + layui.each(items, function (index, item) { + item(); + }); + }; + + // jquery 对象 + if (layui.type(type) === 'object') { + // 若对象为表单域容器 + if ($(type).is(ELEM)) { + elemForm = $(type); + renderItem(); + } else { + // 对象为表单项 + type.each(function (index, item) { + var elem = $(item); + if (!elem.closest(ELEM).length) { + return; // 若不在 layui-form 容器中直接跳过 + } + if (item.tagName === 'SELECT') { + items['select'](elem); + } else if (item.tagName === 'INPUT') { + var itemType = item.type; + if (itemType === 'checkbox' || itemType === 'radio') { + items[itemType](elem); + } else { + items['input'](elem); + } + } + }); + } + } else { + type ? items[type] ? items[type]() : hint.error('[form] "' + type + '" is an unsupported form element type') : renderItem(); + } + return that; +}; + +/** + * checkbox 和 radio 指定属性变化时自动更新 UI + * 只能用于 boolean 属性 + * @param {HTMLInputElement} elem - HTMLInput 元素 + * @param {'checked' | 'indeterminate'} propName - 属性名 + * @param {() => void} handler - 属性值改变时执行的回调 + * @see https://learn.microsoft.com/zh-cn/previous-versions//ff382725(v=vs.85)?redirectedfrom=MSDN + */ +Form.prototype.syncAppearanceOnPropChanged = function () { + // 处理 IE8 indeterminate 属性重新定义 get set 后无法设置值的问题 + // 此处性能敏感,不希望每次赋值取值时都判断是否需要 fallback + if (needCheckboxFallback) { + return function (elem, propName, handler) { + var originProps = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, propName); + Object.defineProperty(elem, propName, lay.extend({}, originProps, { + // 此处的 get 是为了兼容 IE<9 + get: function () { + return typeof this.getAttribute('lay-form-sync-' + propName) === 'string'; + }, + set: function (newValue) { + toggleAttribute.call(this, 'lay-form-sync-' + propName, newValue); + handler.call(this); + } + })); + }; + } + return function (elem, propName, handler) { + var originProps = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, propName); + Object.defineProperty(elem, propName, lay.extend({}, originProps, { + // 此处的 get 是为了兼容 IE<9 + get: function () { + return originProps.get.call(this); + }, + set: function (newValue) { + originProps.set.call(this, newValue); + handler.call(this); + } + })); + }; +}(); + +/** + * 主动触发验证 + * @param {(string|HTMLElement|JQuery)} elem - 要验证的区域表单元素 + * @return {boolean} 返回结果。若验证通过,返回 `true`, 否则返回 `false` + */ +Form.prototype.validate = function (elem) { + var that = this; + var intercept; // 拦截标识 + var options = that.config; // 获取全局配置项 + var verify = options.verify; // 验证规则 + var DANGER = 'layui-form-danger'; // 警示样式 + + elem = $(elem); + + // 节点不存在可视为 true + if (!elem[0]) return true; + + // 若节点不存在特定属性,则查找容器内有待验证的子节点 + if (elem.attr('lay-verify') === undefined) { + // 若校验的是一个不带验证规则的容器,校验内部的 lay-verify 节点 + if (that.validate(elem.find('*[lay-verify]')) === false) { + return false; + } + } + + // 开始校验 + layui.each(elem, function (_, item) { + var othis = $(this); + var verifyStr = othis.attr('lay-verify') || ''; + var vers = verifyStr.split('|'); + var verType = othis.attr('lay-vertype'); // 提示方式 + var value = othis.val(); + value = typeof value === 'string' ? $.trim(value) : value; + othis.removeClass(DANGER); // 移除警示样式 + + // 遍历元素绑定的验证规则 + layui.each(vers, function (_, thisVer) { + var verst; // 校验结果 + var errorText = ''; // 错误提示文本 + var rule = verify[thisVer]; // 获取校验规则 + + // 匹配验证规则 + if (rule) { + verst = typeof rule === 'function' ? errorText = rule(value, item) : !rule[0].test(value); // 兼容早期数组中的正则写法 + + // 是否属于美化替换后的表单元素 + var isForm2Elem = item.tagName.toLowerCase() === 'select' || /^(checkbox|radio)$/.test(item.type); + errorText = errorText || rule[1]; + + // 获取自定义必填项提示文本 + if (thisVer === 'required') { + errorText = othis.attr('lay-reqtext') || errorText; + } + + // 若命中校验规则 + if (verst) { + // 提示层风格 + if (verType === 'tips') { + layer.tips(errorText, function () { + if (!othis.closest('[lay-ignore]').length) { + if (isForm2Elem) { + return othis.next(); + } + } + return othis; + }(), { + tips: 1 + }); + } else if (verType === 'alert') { + layer.alert(errorText, { + title: i18n.$t('form.verifyErrorPromptTitle'), + shadeClose: true + }); + } + // 若返回的为字符或数字,则自动弹出默认提示框;否则由 verify 方法中处理提示 + else if (/\b(string|number)\b/.test(typeof errorText)) { + layer.msg(errorText, { + icon: 5, + shift: 6 + }); + } + setTimeout(function () { + (isForm2Elem ? othis.next().find('input') : item).focus(); + }, 7); + othis.addClass(DANGER); + return intercept = true; + } + } + }); + if (intercept) return intercept; + }); + return !intercept; +}; + +// 提交表单并校验 +var submit = Form.prototype.submit = function (filter, callback) { + var field = {}; // 字段集合 + var button = $(this); // 当前触发的按钮 + + // 表单域 lay-filter 属性值 + var layFilter = typeof filter === 'string' ? filter : button.attr('lay-filter'); + + // 当前所在表单域 + var elem = this.getFormElem ? this.getFormElem(layFilter) : button.parents(ELEM).eq(0); + + // 获取需要校验的元素 + var verifyElem = elem.find('*[lay-verify]'); + + // 开始校验 + if (!form.validate(verifyElem)) return false; + + // 获取当前表单值 + field = form.getValue(null, elem); + + // 返回的参数 + var params = { + elem: this.getFormElem ? window.event && window.event.target : this, + // 触发事件的对象 + form: this.getFormElem ? elem[0] : button.parents('form')[0], + // 当前所在的 form 元素,如果存在的话 + field: field // 当前表单数据 + }; + + // 回调 + typeof callback === 'function' && callback(params); + + // 事件 + return layui.event.call(this, MOD_NAME, 'submit(' + layFilter + ')', params); +}; +function fuzzyMatchRegExp(keyword, caseSensitive) { + var wordMap = {}; + var regexPattern = ['^']; + var escapeRegExp = function (str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + }; + if (!caseSensitive) keyword = keyword.toLowerCase(); + var i; + + // 统计关键字中各字符出现次数 + var wordArr = keyword.trim().split(''); + for (i = 0; i < wordArr.length; i++) { + var c = wordArr[i]; + wordMap[c] = (wordMap[c] || 0) + 1; + } + + // 构建正则表达式模式 + for (c in wordMap) { + regexPattern.push('(?=.*'); + for (i = 0; i < wordMap[c]; i++) { + regexPattern.push(escapeRegExp(c)); + if (i !== wordMap[c] - 1) { + regexPattern.push('.*'); // 在字符之间添加任意字符匹配 + } + } + regexPattern.push(')'); + } + regexPattern.push('.*'); + return new RegExp(regexPattern.join(''), !caseSensitive ? 'i' : undefined); +} + +// 引用自 https://github.com/msn0/mdn-polyfills/blob/master/src/Element.prototype.toggleAttribute/toggleattribute.js +function toggleAttribute(name, force) { + var forcePassed = arguments.length === 2; + var forceOn = !!force; + var forceOff = forcePassed && !force; + if (this.getAttribute(name) !== null) { + if (forceOn) return true; + this.removeAttribute(name); + return false; + } else { + if (forceOff) return false; + this.setAttribute(name, ''); + return true; + } +} + +// 修改自 https://github.com/Tencent/tdesign-common/blob/53786c58752401e648cc45918f2a4dbb9e8cecfa/js/input-number/number.ts#L209 +var specialCode = ['-', '.', 'e', 'E', '+']; +function canInputNumber(number) { + if (number === '') return true; + // 数字最前方不允许出现连续的两个 0 + if (number.slice(0, 2) === '00') return false; + // 不能出现空格 + if (number.match(/\s/g)) return false; + // 只能出现一个点(.) + var tempMatched = number.match(/\./g); + if (tempMatched && tempMatched.length > 1) return false; + // 只能出现一个e(e) + tempMatched = number.match(/e/g); + if (tempMatched && tempMatched.length > 1) return false; + // 只能出现一个负号(-)或 一个正号(+),并且在第一个位置;但允许 3e+10 这种形式 + var tempNumber = number.slice(1); + tempMatched = tempNumber.match(/(\+|-)/g); + if (tempMatched && (!/e(\+|-)/i.test(tempNumber) || tempMatched.length > 1)) return false; + // 允许输入数字字符 + var isNumber = !isNaN(Number(number)); + if (!isNumber && !(specialCode.indexOf(number.slice(-1)) !== -1)) return false; + if (/e/i.test(number) && (!/\de/i.test(number) || /e\./.test(number))) return false; + return true; +} +var form = new Form(); +var $dom = $(document); +var $win = $(window); + +// 初始自动完成渲染 +$(function () { + form.render(); +}); + +// 表单 reset 重置渲染 +$dom.on('reset', ELEM, function () { + var filter = $(this).attr('lay-filter'); + setTimeout(function () { + form.render(null, filter); + }, 50); +}); + +// 表单提交事件 +$dom.on('submit', ELEM, submit).on('click', '*[lay-submit]', submit); + +export { form }; diff --git a/dist/components/laydate.js b/dist/components/laydate.js new file mode 100644 index 000000000..5fd92f010 --- /dev/null +++ b/dist/components/laydate.js @@ -0,0 +1,2713 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; + +/** + * laydate + * 日期与时间组件 + */ + + +// 模块名 +var MOD_NAME = 'laydate'; +var MOD_ID = 'lay-' + MOD_NAME + '-id'; // 已渲染过的索引标记名 +var zhCN = 'zh-CN'; // 简体中文语言码 +var YearBeforeMonthLocale = ['eu-ES', 'ja-JP', 'km-KH', 'ko-KR', 'pt-BR', 'si-LK', 'ms-MY', 'ug-CN', 'zh-CN', 'zh-HK', 'zh-TW']; // 年份在前的语言 + +function addSpaceBetweenChars(str) { + if (typeof str !== 'string' || str.length <= 1) { + return str; + } + var result = ''; + for (var i = 0; i < str.length - 1; i++) { + var char = str[i]; + var nextChar = str[i + 1]; + result += char; + + // 判断当前字符和下一个字符的类型 + var isCharDigit = isDigit(char); + var isNextCharDigit = isDigit(nextChar); + + // 在数字和非数字(非空格)之间添加空格 + if (isCharDigit && !isNextCharDigit && nextChar !== ' ' || + // 数字 → 非数字(非空格) + char !== ' ' && !isCharDigit && isNextCharDigit // 非空格非数字 → 数字 + ) { + result += ' '; + } + } + result += str[str.length - 1]; // 添加最后一个字符 + return result; +} +function isDigit(char) { + var code = char.charCodeAt(0); + return code >= 48 && code <= 57; // '0' 到 '9' 的 ASCII 码范围 +} + +// 对象合并时,让数组覆盖,而非合并 +function overwriteArray(objValue, srcValue) { + // 数组覆盖而非合并 + if (Array.isArray(objValue) && Array.isArray(srcValue)) { + return srcValue; + } +} + +// 外部调用 +var laydate = { + config: { + weekStart: 0 // 默认周日一周的开始 + }, + // 全局配置项 + + // 设置全局项 + set: function (options) { + var that = this; + that.config = lay.extend({}, that.config, options, overwriteArray); + return that; + }, + // 主体 CSS 等待事件 + ready: function (callback) { + var cssname = 'laydate'; + var path = 'modules/laydate.css?v=' + laydate.v; + + // 打包版直接执行回调函数 + if (layui['layui.all']) { + typeof callback === 'function' && callback(); + } else { + layui.addcss(path, callback, cssname); + } + return this; + } +}; + +// 操作当前实例 +var thisModule = function () { + var that = this; + var options = that.config; + var id = options.id; + thisModule.that[id] = that; // 记录当前实例对象 + + return that.inst = { + // 提示框 + hint: function (content) { + that.hint.call(that, content); + }, + // 重载实例 + reload: function (options) { + that.reload.call(that, options); + }, + config: that.config + }; +}; + +// 字符常量 +var ELEM = '.layui-laydate'; +var THIS = 'layui-this'; +// var SHOW = 'layui-show'; +// var HIDE = 'layui-hide'; +var DISABLED = 'laydate-disabled'; +var LIMIT_YEAR = [100, 200000]; +var ELEM_STATIC = 'layui-laydate-static'; +var ELEM_LIST = 'layui-laydate-list'; +var ELEM_SELECTED = 'laydate-selected'; +var ELEM_HINT = 'layui-laydate-hint'; +var ELEM_DAY_NOW = 'laydate-day-now'; +var ELEM_PREV = 'laydate-day-prev'; +var ELEM_NEXT = 'laydate-day-next'; +var ELEM_FOOTER = 'layui-laydate-footer'; +var ELEM_SHORTCUT = 'layui-laydate-shortcut'; +var ELEM_NOW = '.laydate-btns-now'; +var ELEM_CONFIRM = '.laydate-btns-confirm'; +var ELEM_TIME_TEXT = 'laydate-time-text'; +var ELEM_TIME_BTN = 'laydate-btns-time'; +var ELEM_PREVIEW = 'layui-laydate-preview'; +var ELEM_MAIN = 'layui-laydate-main'; +var ELEM_SHADE = 'layui-laydate-shade'; + +// 组件构造器 +var Class = function (options) { + var that = this; + that.index = laydate.index = lay.autoIncrementer('laydate'); + that.config = lay.extend({}, that.config, laydate.config, options, overwriteArray); + + // 若 elem 非唯一,则拆分为多个实例 + var elem = lay(options.elem || that.config.elem); + if (elem.length > 1) { + lay.each(elem, function () { + laydate.render(lay.extend({}, that.config, { + elem: this + }), overwriteArray); + }); + return that; + } + + // 初始化属性 + options = lay.extend(that.config, lay.options(elem[0]), overwriteArray); // 继承节点上的属性 + + // 更新 i18n 消息对象 + that.i18nMessages = that.getI18nMessages(); + + // 处理日期面板顶部年月顺序 + // 这是一个变通的方法,因为 i18nMessages.monthBeforeYear 不存在 + if (typeof that.i18nMessages.monthBeforeYear !== 'boolean') { + if (!window.Intl) { + that.i18nMessages.monthBeforeYear = !(YearBeforeMonthLocale.indexOf(options.lang) > -1); + } else { + var formatter = new Intl.DateTimeFormat(options.lang, { + year: 'numeric', + month: 'short' + }); + var parts = formatter.formatToParts(new Date(1970, 0)); + var order = []; + parts.map(function (part) { + if (part.type === 'year' || part.type === 'month') { + order.push(part.type); + } + }); + that.i18nMessages.monthBeforeYear = order[0] === 'month'; + } + } + + // 若重复执行 render,则视为 reload 处理 + if (elem[0] && elem.attr(MOD_ID)) { + var newThat = thisModule.getThis(elem.attr(MOD_ID)); + if (!newThat) return; + return newThat.reload(options); + } + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + options.id = 'id' in options ? options.id : elem.attr('id') || that.index; + + // 自增索引 + options.index = that.index; + + // 初始化 + laydate.ready(function () { + that.init(); + }); +}; + +// 日期格式字符 +var dateType = 'yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s'; + +// 将日期格式字符转换为数组 +thisModule.formatArr = function (format) { + return (format || '').match(new RegExp(dateType + '|.', 'g')) || []; +}; + +/* + 组件操作 +*/ + +// 是否闰年 +Class.isLeapYear = function (year) { + return year % 4 === 0 && year % 100 !== 0 || year % 400 === 0; +}; + +// 默认配置 +Class.prototype.config = { + type: 'date', + // 控件类型,支持:year/month/date/time/datetime + range: false, + // 是否开启范围选择,即双控件 + format: 'yyyy-MM-dd', + // 默认日期格式 + value: null, + // 默认日期,支持传入new Date(),或者符合format参数设定的日期格式字符 + isInitValue: true, + // 用于控制是否自动向元素填充初始值(需配合 value 参数使用) + min: '1900-1-1', + // 有效最小日期,年月日必须用“-”分割,时分秒必须用“:”分割。注意:它并不是遵循 format 设定的格式。 + max: '2099-12-31', + // 有效最大日期,同上 + trigger: 'click', + // 呼出控件的事件 + show: false, + // 是否直接显示,如果设置 true,则默认直接显示控件 + showBottom: true, + // 是否显示底部栏 + isPreview: true, + // 是否显示值预览 + btns: ['clear', 'now', 'confirm'], + // 右下角显示的按钮,会按照数组顺序排列 + // 为实现 lang 选项就近生效,去除此处的默认值,$t 设置了英文回退值 + lang: '', + // 语言,只支持 cn/en,即中文和英文 + theme: 'default', + // 主题 + position: null, + // 控件定位方式定位, 默认absolute,支持:fixed/absolute/static + calendar: false, + // 是否开启公历重要节日,仅支持中文版 + mark: {}, + // 日期备注,如重要事件或活动标记 + holidays: null, + // 标注法定节假日或补假上班 + zIndex: null, + // 控件层叠顺序 + done: null, + // 控件选择完毕后的回调,点击清空/现在/确定也均会触发 + change: null, + // 日期时间改变后的回调 + autoConfirm: true, + // 是否自动确认(日期|年份|月份选择器非range下是否自动确认) + shade: 0 +}; +Class.prototype.getI18nMessages = function () { + var that = this; + var options = that.config; + var locale = i18n.config.locale; + + // 纠正旧版「简体中文」语言码 + if (options.lang === 'cn') { + options.lang = zhCN; + } else if (!options.lang) { + options.lang = i18n.config.locale; + } + locale = options.lang; + return { + months: i18n.$t('laydate.months', null, { + locale: locale, + default: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'] + }), + weeks: i18n.$t('laydate.weeks', null, { + locale: locale, + default: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] + }), + time: i18n.$t('laydate.time', null, { + locale: locale, + default: ['Hour', 'Minute', 'Second'] + }), + literal: { + year: i18n.$t('laydate.literal.year', null, { + locale: locale, + default: '' + }) + }, + monthBeforeYear: i18n.$t('laydate.monthBeforeYear', null, { + locale: locale, + default: null + }), + selectDate: i18n.$t('laydate.selectDate', null, { + locale: locale, + default: 'Select Date' + }), + selectTime: i18n.$t('laydate.selectTime', null, { + locale: locale, + default: 'Select Time' + }), + startTime: i18n.$t('laydate.startTime', null, { + locale: locale, + default: 'Start Time' + }), + endTime: i18n.$t('laydate.endTime', null, { + locale: locale, + default: 'End Time' + }), + tools: { + confirm: i18n.$t('laydate.tools.confirm', null, { + locale: locale, + default: 'Confirm' + }), + clear: i18n.$t('laydate.tools.clear', null, { + locale: locale, + default: 'Clear' + }), + now: i18n.$t('laydate.tools.now', null, { + locale: locale, + default: 'Now' + }), + reset: i18n.$t('laydate.tools.reset', null, { + locale: locale, + default: 'Reset' + }) + }, + rangeOrderPrompt: i18n.$t('laydate.rangeOrderPrompt', null, { + locale: locale, + default: 'End time cannot be less than start Time\nPlease re-select' + }), + invalidDatePrompt: i18n.$t('laydate.invalidDatePrompt', null, { + locale: locale, + default: 'Invalid date\n' + }), + formatErrorPrompt: function (format) { + return i18n.$t('laydate.formatErrorPrompt', { + format: format + }, { + locale: locale, + default: 'Date format is invalid\nMust follow the format:\n{format}\n' + }); + }, + autoResetPrompt: i18n.$t('laydate.autoResetPrompt', null, { + locale: locale, + default: 'It has been reset' + }), + preview: i18n.$t('laydate.preview', null, { + locale: locale, + default: 'The selected result' + }) + }; +}; + +// 仅简体中文生效,不做国际化 +Class.prototype.markerOfChineseFestivals = { + '0-1-1': '元旦', + '0-2-14': '情人', + '0-3-8': '妇女', + '0-3-12': '植树', + '0-4-1': '愚人', + '0-5-1': '劳动', + '0-5-4': '青年', + '0-6-1': '儿童', + '0-9-10': '教师', + '0-10-1': '国庆', + '0-12-25': '圣诞' +}; + +// 重载实例 +Class.prototype.reload = function (options) { + var that = this; + that.config = lay.extend({}, that.config, options, overwriteArray); + that.init(); +}; + +//初始准备 +Class.prototype.init = function () { + var that = this, + options = that.config, + isStatic = options.position === 'static', + format = { + year: 'yyyy', + month: 'yyyy-MM', + date: 'yyyy-MM-dd', + time: 'HH:mm:ss', + datetime: 'yyyy-MM-dd HH:mm:ss' + }; + options.elem = lay(options.elem); + options.eventElem = lay(options.eventElem); + if (!options.elem[0]) return; + layui.type(options.theme) !== 'array' && (options.theme = [options.theme]); + // 设置了全面版模式 + if (options.fullPanel) { + if (options.type !== 'datetime' || options.range) { + // 目前只支持datetime的全面版 + delete options.fullPanel; + } + } + + //日期范围分隔符 + that.rangeStr = options.range ? typeof options.range === 'string' ? options.range : '-' : ''; + + //日期范围的日历面板是否联动 + that.rangeLinked = !!(options.range && options.rangeLinked && (options.type === 'date' || options.type === 'datetime')); + + //切换日历联动方式 + that.autoCalendarModel = function () { + var state = that.rangeLinked; + that.rangeLinked = options.range && (options.type === 'date' || options.type === 'datetime') && (!that.startDate || !that.endDate || that.startDate && that.endDate && that.startDate.year === that.endDate.year && that.startDate.month === that.endDate.month); + lay(that.elem)[that.rangeLinked ? 'addClass' : 'removeClass']('layui-laydate-linkage'); + return that.rangeLinked != state; // 返回发生了变化 + }; + + //是否自动切换 + that.autoCalendarModel.auto = that.rangeLinked && options.rangeLinked === 'auto'; + + //若 range 参数为数组,则表示为开始日期和结束日期的 input 对象 + if (layui.type(options.range) === 'array') { + that.rangeElem = [lay(options.range[0]), lay(options.range[1])]; + } + + //若 type 设置非法,则初始化为 date 类型 + if (!format[options.type]) { + window.console && console.error && console.error("laydate type error:'" + options.type + "' is not supported"); + options.type = 'date'; + } + + //根据不同 type,初始化默认 format + if (options.format === format.date) { + options.format = format[options.type] || format.date; + } + + //将日期格式转化成数组 + that.format = thisModule.formatArr(options.format); + + // 设置了一周的开始是周几,此处做一个控制 + if (options.weekStart) { + if (!/^[0-6]$/.test(options.weekStart)) { + var lang = that.i18nMessages; + options.weekStart = lang.weeks.indexOf(options.weekStart); + if (options.weekStart === -1) options.weekStart = 0; + } + } + + //生成正则表达式 + that.EXP_IF = ''; + that.EXP_SPLIT = ''; + lay.each(that.format, function (i, item) { + var EXP = new RegExp(dateType).test(item) ? '\\d{' + function () { + if (new RegExp(dateType).test(that.format[i === 0 ? i + 1 : i - 1] || '')) { + if (/^yyyy|y$/.test(item)) return 4; + return item.length; + } + if (/^yyyy$/.test(item)) return '1,4'; + if (/^y$/.test(item)) return '1,308'; + return '1,2'; + }() + '}' : '\\' + item; + that.EXP_IF = that.EXP_IF + EXP; + that.EXP_SPLIT = that.EXP_SPLIT + '(' + EXP + ')'; + }); + //验证日期格式正则 + that.EXP_IF_ONE = new RegExp('^' + that.EXP_IF + '$'); //验证单个日期格式 + that.EXP_IF = new RegExp('^' + (options.range ? that.EXP_IF + '\\s\\' + that.rangeStr + '\\s' + that.EXP_IF : that.EXP_IF) + '$'); + that.EXP_SPLIT = new RegExp('^' + that.EXP_SPLIT + '$', ''); + + //如果不是 input|textarea 元素,则默认采用 click 事件 + if (!that.isInput(options.elem[0])) { + if (options.trigger === 'focus') { + options.trigger = 'click'; + } + } + + // 设置唯一 KEY + options.elem.attr('lay-key', that.index); + options.eventElem.attr('lay-key', that.index); + options.elem.attr(MOD_ID, options.id); // 渲染过的标记 + + //获取限制内日期 + lay.each(['min', 'max'], function (i, item) { + var ymd = []; + var hms = []; + if (typeof options[item] === 'number') { + //如果为数字 + var day = options[item], + tDate = new Date(), + time = that.newDate({ + //今天的最大毫秒数 + year: tDate.getFullYear(), + month: tDate.getMonth(), + date: tDate.getDate(), + hours: i ? 23 : 0, + minutes: i ? 59 : 0, + seconds: i ? 59 : 0 + }).getTime(), + STAMP = 86400000, + //代表一天的毫秒数 + thisDate = new Date(day ? day < STAMP ? time + day * STAMP : day //如果数字小于一天的毫秒数,则数字为天数,否则为毫秒数 + : time); + ymd = [thisDate.getFullYear(), thisDate.getMonth() + 1, thisDate.getDate()]; + hms = [thisDate.getHours(), thisDate.getMinutes(), thisDate.getSeconds()]; + } else if (typeof options[item] === 'string') { + ymd = (options[item].match(/\d+-\d+-\d+/) || [''])[0].split('-'); + hms = (options[item].match(/\d+:\d+:\d+/) || [''])[0].split(':'); + } else if (typeof options[item] === 'object') { + return options[item]; + } + options[item] = { + year: ymd[0] | 0 || new Date().getFullYear(), + month: ymd[1] ? (ymd[1] | 0) - 1 : new Date().getMonth(), + date: ymd[2] | 0 || new Date().getDate(), + hours: hms[0] | 0, + minutes: hms[1] | 0, + seconds: hms[2] | 0 + }; + }); + that.elemID = 'layui-laydate' + options.elem.attr('lay-key'); + if (options.show || isStatic) that.render(); + isStatic || that.events(); + + // 重定义 input 元素的 get set + if (typeof options.formatToDisplay === 'function') { + if (that.isInput(options.elem[0])) { + that.formatToDisplay(options.elem[0], options.formatToDisplay); + } else { + var rangeElem = that.rangeElem; + if (rangeElem) { + that.formatToDisplay(rangeElem[0][0], options.formatToDisplay); + that.formatToDisplay(rangeElem[1][0], options.formatToDisplay); + } + } + } + + //默认赋值 + if (options.value && options.isInitValue) { + if (layui.type(options.value) === 'date') { + that.setValue(that.parse(0, that.systemDate(options.value))); + } else { + that.setValue(options.value); + } + } +}; + +//控件主体渲染 +Class.prototype.render = function () { + var that = this, + options = that.config, + lang = that.i18nMessages, + isStatic = options.position === 'static', + //主面板 + elem = that.elem = lay.elem('div', { + id: that.elemID, + class: ['layui-laydate', options.range ? ' layui-laydate-range' : '', that.rangeLinked ? ' layui-laydate-linkage' : '', isStatic ? ' ' + ELEM_STATIC : '', options.fullPanel ? ' laydate-theme-fullpanel' : '', + // 全面版 + // ,options.theme && options.theme !== 'default' && !/^#/.test(options.theme) ? (' laydate-theme-' + options.theme) : '' + function () { + var themeStr = ''; + lay.each(options.theme, function (index, theme) { + if (theme !== 'default' && !/^#/.test(theme)) { + themeStr += ' laydate-theme-' + theme; + } + }); + return themeStr; + }()].join('') + }), + //主区域 + elemMain = that.elemMain = [], + elemHeader = that.elemHeader = [], + elemCont = that.elemCont = [], + elemTable = that.table = [], + //底部区域 + divFooter = that.footer = lay.elem('div', { + class: ELEM_FOOTER + }), + //快捷栏 + divShortcut = that.shortcut = lay.elem('ul', { + class: ELEM_SHORTCUT + }); + if (options.zIndex) elem.style.zIndex = options.zIndex; + + //单双日历区域 + lay.each(new Array(2), function (i) { + if (!options.range && i > 0) { + return true; + } + + //头部区域 + var divHeader = lay.elem('div', { + class: 'layui-laydate-header' + }), + //左右切换 + headerChild = [function () { + //上一年 + var elem = lay.elem('i', { + class: 'layui-icon laydate-icon laydate-prev-y' + }); + elem.innerHTML = ''; + return elem; + }(), function () { + //上一月 + var elem = lay.elem('i', { + class: 'layui-icon laydate-icon laydate-prev-m' + }); + elem.innerHTML = ''; + return elem; + }(), function () { + //年月选择 + var elem = lay.elem('div', { + class: 'laydate-set-ym' + }); + elem.appendChild(lay.elem('span')); + elem.appendChild(lay.elem('span')); + return elem; + }(), function () { + //下一月 + var elem = lay.elem('i', { + class: 'layui-icon laydate-icon laydate-next-m' + }); + elem.innerHTML = ''; + return elem; + }(), function () { + //下一年 + var elem = lay.elem('i', { + class: 'layui-icon laydate-icon laydate-next-y' + }); + elem.innerHTML = ''; + return elem; + }()], + //日历内容区域 + divContent = lay.elem('div', { + class: 'layui-laydate-content' + }), + table = lay.elem('table'), + thead = lay.elem('thead'), + theadTr = lay.elem('tr'); + + //生成年月选择 + lay.each(headerChild, function (i, item) { + divHeader.appendChild(item); + }); + + //生成表格 + thead.appendChild(theadTr); + lay.each(new Array(6), function (i) { + //表体 + var tr = table.insertRow(0); + lay.each(new Array(7), function (j) { + if (i === 0) { + var th = lay.elem('th'); + th.innerHTML = lang.weeks[(j + options.weekStart) % 7]; + theadTr.appendChild(th); + } + tr.insertCell(j); + }); + }); + table.insertBefore(thead, table.children[0]); //表头 + divContent.appendChild(table); + elemMain[i] = lay.elem('div', { + class: ELEM_MAIN + ' laydate-main-list-' + i + }); + elemMain[i].appendChild(divHeader); + elemMain[i].appendChild(divContent); + elemHeader.push(headerChild); + elemCont.push(divContent); + elemTable.push(table); + }); + + //生成底部栏 + lay(divFooter).html(function () { + var html = [], + btns = []; + if (options.type === 'datetime') { + html.push('' + lang.selectTime + ''); + } + if (!(!options.range && options.type === 'datetime') || options.fullPanel) { + html.push(''); + } + lay.each(options.btns, function (i, item) { + var title = lang.tools[item] || 'btn'; + if (options.range && item === 'now') return; + if (isStatic && item === 'clear') { + title = lang.tools.reset; + } + btns.push('' + title + ''); + }); + html.push(''); + return html.join(''); + }()); + + // 生成快捷键栏 + if (options.shortcuts) { + elem.appendChild(divShortcut); + lay(divShortcut).html(function () { + var shortcutBtns = []; + lay.each(options.shortcuts, function (i, item) { + shortcutBtns.push('
                • ' + item.text + '
                • '); + }); + return shortcutBtns.join(''); + }()).find('li').on('click', function () { + var btnSetting = options.shortcuts[this.dataset['index']] || {}; + var value = (typeof btnSetting.value === 'function' ? btnSetting.value() : btnSetting.value) || []; + if (!layui.isArray(value)) { + value = [value]; + } + var type = options.type; + lay.each(value, function (i, item) { + var dateTime = [options.dateTime, that.endDate][i]; + if (type === 'time' && layui.type(item) !== 'date') { + if (that.EXP_IF.test(item)) { + item = (item.match(that.EXP_SPLIT) || []).slice(1); + lay.extend(dateTime, { + hours: item[0] | 0, + minutes: item[2] | 0, + seconds: item[4] | 0 + }); + } + } else { + lay.extend(dateTime, that.systemDate(layui.type(item) === 'date' ? item : new Date(item))); + } + if (type === 'time' || type === 'datetime') { + that[['startTime', 'endTime'][i]] = { + hours: dateTime.hours, + minutes: dateTime.minutes, + seconds: dateTime.seconds + }; + } + if (i === 0) { + // 第一个值作为startDate + that.startDate = lay.extend({}, dateTime); + } else { + that.endState = true; + } + if (type === 'year' || type === 'month' || type === 'time') { + that.listYM[i] = [dateTime.year, dateTime.month + 1]; + } else if (i) { + that.autoCalendarModel.auto && that.autoCalendarModel(); + } + }); + that.checkDate('limit').calendar(null, null, 'init'); + var timeBtn = lay(that.footer).find('.' + ELEM_TIME_BTN).removeClass(DISABLED); + timeBtn && timeBtn.attr('lay-type') === 'date' && timeBtn[0].click(); + that.done(null, 'change'); + lay(this).addClass(THIS); + + // 自动确认 + if (options.position !== 'static') { + that.setValue(that.parse()).done().remove(); + } + /* + if (options.position !== 'static' && !options.range && options.autoConfirm) { + if (type === 'date') { + that.choose(lay(elem).find('td.layui-this')) + } else if (type === 'year' || type === 'month') { + if(lay(elemMain[0]).find('.' + ELEM_MAIN + ' li.' + THIS + ':not(.laydate-disabled)')[0]) { + that.setValue(that.parse()).done().remove(); + } + } + } + */ + }); + } + + //插入到主区域 + lay.each(elemMain, function (i, main) { + elem.appendChild(main); + }); + options.showBottom && elem.appendChild(divFooter); + + // 生成自定义主题 + var style = lay.elem('style'); + var styleText = []; + var colorTheme; + var isPrimaryColor = true; + lay.each(options.theme, function (index, theme) { + // 主色 + if (isPrimaryColor && /^#/.test(theme)) { + colorTheme = true; + isPrimaryColor = false; + styleText.push(['#{{id}} .layui-laydate-header{background-color:{{theme}};}', '#{{id}} li.layui-this,#{{id}} td.layui-this>div{background-color:{{theme}} !important;}', options.theme.indexOf('circle') !== -1 ? '' : '#{{id}} .layui-this{background-color:{{theme}} !important;}', '#{{id}} .laydate-day-now{color:{{theme}} !important;}', '#{{id}} .laydate-day-now:after{border-color:{{theme}} !important;}'].join('').replace(/{{id}}/g, that.elemID).replace(/{{theme}}/g, theme)); + return; + } + // 第二个自定义颜色作为辅色 + if (!isPrimaryColor && /^#/.test(theme)) { + styleText.push(['#{{id}} .laydate-selected>div{background-color:{{theme}} !important;}', '#{{id}} .laydate-selected:hover>div{background-color:{{theme}} !important;}'].join('').replace(/{{id}}/g, that.elemID).replace(/{{theme}}/g, theme)); + } + }); + //快捷栏样式 + if (options.shortcuts && options.range) { + styleText.push('#{{id}}.layui-laydate-range{width: 628px;}'.replace(/{{id}}/g, that.elemID)); + } + if (styleText.length) { + styleText = styleText.join(''); + if ('styleSheet' in style) { + style.setAttribute('type', 'text/css'); + style.styleSheet.cssText = styleText; + } else { + style.innerHTML = styleText; + } + colorTheme && lay(elem).addClass('laydate-theme-molv'); + elem.appendChild(style); + } + + //移除上一个控件 + that.remove(Class.thisElemDate); + + //记录当前执行的实例索引 + laydate.thisId = options.id; + + //如果是静态定位,则插入到指定的容器中,否则,插入到body + isStatic ? options.elem.append(elem) : (document.body.appendChild(elem), that.position()); //定位 + + var shade = options.shade ? '
                  ' : ''; + elem.insertAdjacentHTML('beforebegin', shade); + that.checkDate().calendar(null, 0, 'init'); //初始校验 + that.changeEvent(); //日期切换 + + Class.thisElemDate = that.elemID; + that.renderAdditional(); + typeof options.ready === 'function' && options.ready(lay.extend({}, options.dateTime, { + month: options.dateTime.month + 1 + })); + that.preview(); +}; + +//控件移除 +Class.prototype.remove = function (prev) { + var that = this, + options = that.config, + elem = lay('#' + (prev || that.elemID)); + if (!elem[0]) return that; + if (!elem.hasClass(ELEM_STATIC)) { + that.checkDate(function () { + elem.remove(); + //delete options.dateTime; + delete that.startDate; + delete that.endDate; + delete that.endState; + delete that.startTime; + delete that.endTime; + delete laydate.thisId; + typeof options.close === 'function' && options.close(that); + }); + } + lay('.' + ELEM_SHADE).remove(); + return that; +}; + +//定位算法 +Class.prototype.position = function () { + var that = this, + options = that.config; + lay.position(options.elem[0], that.elem, { + position: options.position + }); + return that; +}; + +// 提示 +Class.prototype.hint = function (opts) { + var that = this; + // var options = that.config; + var div = lay.elem('div', { + class: ELEM_HINT + }); + if (!that.elem) return; + + // 兼容旧版参数 + if (typeof opts === 'object') { + opts = opts || {}; + } else { + opts = { + content: opts + }; + } + div.innerHTML = opts.content || ''; + lay(that.elem).find('.' + ELEM_HINT).remove(); + that.elem.appendChild(div); + clearTimeout(that.hinTimer); + that.hinTimer = setTimeout(function () { + lay(that.elem).find('.' + ELEM_HINT).remove(); + }, 'ms' in opts ? opts.ms : 3000); +}; + +//获取递增/减后的年月 +Class.prototype.getAsYM = function (Y, M, type) { + type ? M-- : M++; + if (M < 0) { + M = 11; + Y--; + } + if (M > 11) { + M = 0; + Y++; + } + return [Y, M]; +}; + +//系统日期 +Class.prototype.systemDate = function (newDate) { + var thisDate = newDate || new Date(); + return { + year: thisDate.getFullYear(), + //年 + month: thisDate.getMonth(), + //月 + date: thisDate.getDate(), + //日 + hours: newDate ? newDate.getHours() : 0, + //时 + minutes: newDate ? newDate.getMinutes() : 0, + //分 + seconds: newDate ? newDate.getSeconds() : 0 //秒 + }; +}; + +//日期校验 +Class.prototype.checkDate = function (fn) { + var that = this, + // thisDate = new Date(), + options = that.config, + lang = that.i18nMessages, + dateTime = options.dateTime = options.dateTime || that.systemDate(), + thisMaxDate, + error, + elem = options.elem[0], + // valType = that.isInput(elem) ? 'val' : 'html', + value = function () { + //如果传入了开始和结束日期的 input 对象,则将其拼接为日期范围字符 + if (that.rangeElem) { + var vals = [that.rangeElem[0].val(), that.rangeElem[1].val()]; + if (vals[0] && vals[1]) { + return vals.join(' ' + that.rangeStr + ' '); + } + } + return that.isInput(elem) ? elem.value : options.position === 'static' ? '' : lay(elem).attr('lay-date'); + }(), + //校验日期有效数字 + checkValid = function (dateTime) { + if (!dateTime) { + return; + } + if (dateTime.year > LIMIT_YEAR[1]) dateTime.year = LIMIT_YEAR[1], error = true; //不能超过20万年 + if (dateTime.month > 11) dateTime.month = 11, error = true; + if (dateTime.seconds > 59) dateTime.seconds = 0, dateTime.minutes++, error = true; + if (dateTime.minutes > 59) dateTime.minutes = 0, dateTime.hours++, error = true; + if (dateTime.hours > 23) dateTime.hours = 0, error = true; + + //计算当前月的最后一天 + thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); + if (dateTime.date > thisMaxDate) dateTime.date = thisMaxDate, error = true; + }, + //获得初始化日期值 + initDate = function (dateTime, value, index) { + var startEnd = ['startTime', 'endTime']; + value = (value.match(that.EXP_SPLIT) || []).slice(1); + index = index || 0; + if (options.range) { + that[startEnd[index]] = that[startEnd[index]] || {}; + } + lay.each(that.format, function (i, item) { + var thisv = parseFloat(value[i]); + if (value[i].length < item.length) error = true; + if (/yyyy|y/.test(item)) { + //年 + if (thisv < LIMIT_YEAR[0]) thisv = LIMIT_YEAR[0], error = true; //年不能低于100年 + dateTime.year = thisv; + } else if (/MM|M/.test(item)) { + //月 + if (thisv < 1) thisv = 1, error = true; + dateTime.month = thisv - 1; + } else if (/dd|d/.test(item)) { + //日 + if (thisv < 1) thisv = 1, error = true; + dateTime.date = thisv; + } else if (/HH|H/.test(item)) { + //时 + if (thisv < 0) thisv = 0, error = true; + if (thisv > 23) thisv = 23, error = true; + dateTime.hours = thisv; + options.range && (that[startEnd[index]].hours = thisv); + } else if (/mm|m/.test(item)) { + //分 + if (thisv < 0) thisv = 0, error = true; + if (thisv > 59) thisv = 59, error = true; + dateTime.minutes = thisv; + options.range && (that[startEnd[index]].minutes = thisv); + } else if (/ss|s/.test(item)) { + //秒 + if (thisv < 0) thisv = 0, error = true; + if (thisv > 59) thisv = 59, error = true; + dateTime.seconds = thisv; + options.range && (that[startEnd[index]].seconds = thisv); + } + }); + checkValid(dateTime); + }; + if (fn === 'limit') { + if (options.range) { + checkValid(that.rangeLinked ? that.startDate : dateTime); // 校验开始时间 + that.endDate && checkValid(that.endDate); // 校验结束时间 + } else { + checkValid(dateTime); + } + return that; + } + value = value || options.value; + if (typeof value === 'string') { + value = value.replace(/\s+/g, ' ').replace(/^\s|\s$/g, ''); + } + + //如果开启范围,则计算结束日期 + var getEndDate = function () { + if (options.range) { + that.endDate = that.endDate || lay.extend({}, options.dateTime, function () { + var obj = {}, + dateTime = options.dateTime, + EYM = that.getAsYM(dateTime.year, dateTime.month); + + //初始右侧面板的年月 + if (options.type === 'year') { + obj.year = dateTime.year + 1; + } else if (options.type !== 'time') { + obj.year = EYM[0]; + obj.month = EYM[1]; + } + + //初始右侧面板的时间 + if (options.type === 'datetime' || options.type === 'time') { + obj.hours = 23; + obj.minutes = obj.seconds = 59; + } + return obj; + }()); + } + }; + getEndDate(); + if (typeof value === 'string' && value) { + if (that.EXP_IF.test(value)) { + //校验日期格式 + if (options.range) { + value = value.split(' ' + that.rangeStr + ' '); + lay.each([options.dateTime, that.endDate], function (i, item) { + initDate(item, value[i], i); + }); + } else { + initDate(dateTime, value); + } + } else { + //格式不合法 + that.hint(lang.formatErrorPrompt(options.range ? options.format + ' ' + that.rangeStr + ' ' + options.format : options.format) + lang.autoResetPrompt); + error = true; + } + } else if (value && layui.type(value) === 'date') { + //若值为日期对象 + options.dateTime = that.systemDate(value); + } else { + //重置开始日期 + options.dateTime = that.systemDate(); + delete that.startTime; + + //重置结束日期 + delete that.endDate; //删除原有的结束日期 + getEndDate(); //并重新获得新的结束日期 + delete that.endTime; + } + + //从日期范围表单中获取初始值 + (function () { + if (that.rangeElem) { + var vals = [that.rangeElem[0].val(), that.rangeElem[1].val()], + arrDate = [options.dateTime, that.endDate]; + lay.each(vals, function (_i, _v) { + if (that.EXP_IF_ONE.test(_v)) { + //校验日期格式 + initDate(arrDate[_i], _v, _i); + } + }); + } + })(); + + // 校验日期有效数字 + checkValid(dateTime); + if (options.range) checkValid(that.endDate); + + // 如果初始值格式错误,则纠正初始值 + if (error && value) { + that.setValue(options.range ? that.endDate ? that.parse() : '' : that.parse()); + } + + //如果当前日期不在设定的最大小日期区间,则自动纠正在可选区域 + //校验主面板是否在可选日期区间 + var minMaxError; + if (that.getDateTime(dateTime) > that.getDateTime(options.max)) { + //若超出最大日期 + dateTime = options.dateTime = lay.extend({}, options.max); + minMaxError = true; + } else if (that.getDateTime(dateTime) < that.getDateTime(options.min)) { + //若少于最小日期 + dateTime = options.dateTime = lay.extend({}, options.min); + minMaxError = true; + } + + //校验右侧面板是否在可选日期区间 + if (options.range) { + if (that.getDateTime(that.endDate) < that.getDateTime(options.min) || that.getDateTime(that.endDate) > that.getDateTime(options.max)) { + that.endDate = lay.extend({}, options.max); + minMaxError = true; + } + // 有时间范围的情况下初始化startTime和endTime + that.startTime = { + hours: options.dateTime.hours, + minutes: options.dateTime.minutes, + seconds: options.dateTime.seconds + }; + that.endTime = { + hours: that.endDate.hours, + minutes: that.endDate.minutes, + seconds: that.endDate.seconds + }; + // 如果是年月范围,将对应的日期统一成当月的1日进行比较,避免出现同一个月但是开始日期大于结束日期的情况 + if (options.type === 'month') { + options.dateTime.date = 1; + that.endDate.date = 1; + } + } + + // 初始值不在最大最小范围内 + if (minMaxError && value) { + that.setValue(that.parse()); + that.hint('value ' + lang.invalidDatePrompt + lang.autoResetPrompt); + } + + // 初始赋值 startDate,endState + that.startDate = that.startDate || value && lay.extend({}, options.dateTime); // 有默认值才初始化startDate + that.autoCalendarModel.auto && that.autoCalendarModel(); + that.endState = !options.range || !that.rangeLinked || !!(that.startDate && that.endDate); // 初始化选中范围状态 + + fn && fn(); + return that; +}; + +/** + * 渲染备注 + * @param {JQuery} tdElem td 元素 + * @param {[number, number, number]} YMD 年月日 + * @param {object | string} markers 备注信息 + */ +Class.prototype.markRender = function (tdElem, YMD, markers) { + var markText; + if (typeof markers === 'object') { + lay.each(markers || {}, function (key, title) { + var keys = key.split('-'); + if ((keys[0] == YMD[0] || keys[0] == 0) && ( + //每年的每月 + keys[1] == YMD[1] || keys[1] == 0) && + //每月的每日 + keys[2] == YMD[2]) { + //特定日 + markText = title || YMD[2]; + } + }); + } else if (typeof markers === 'string') { + markText = markers || YMD[2]; + } + markText && tdElem.find('div').html('' + markText + ''); +}; + +/** + * 公历重要日期与自定义备注 + * @param {JQuery} td + * @param {[number, number, number]} YMD + * @returns Class + */ +Class.prototype.mark = function (td, YMD) { + var that = this; + var options = that.config; + var render = function (markers) { + that.markRender(td, YMD, markers); + }; + + // chineseFestivals 仅简体中文生效 + if (options.calendar) { + if (options.lang === zhCN) { + render(that.markerOfChineseFestivals); + } + } + if (typeof options.mark === 'function') { + options.mark({ + year: YMD[0], + month: YMD[1], + date: YMD[2] + }, render); + } else if (typeof options.mark === 'object') { + render(options.mark); + } + return that; +}; + +/** + * 渲染法定节假日或补假上班标记 + * @param {JQuery} tdElem td 元素 + * @param {[number, number, number]} YMD 年月日 + * @param {[Array, Array] | string} markers 标记信息 + */ +Class.prototype.holidaysRender = function (tdElem, YMD, markers) { + var type = ['holidays', 'workdays']; + var isEquals = function (ymdStr1, ymdStr2) { + var ymd1 = ymdStr1.split('-'); + var ymd2 = ymdStr2.split('-'); + lay.each(ymd1, function (i, v) { + ymd1[i] = parseInt(v, 10); + }); + lay.each(ymd2, function (i, v) { + ymd2[i] = parseInt(v, 10); + }); + return ymd1.join('-') === ymd2.join('-'); + }; + var insertHtml = function (el, type, text) { + el.find('div').html(['', text, ''].join('')); + }; + if (layui.type(markers) === 'array') { + lay.each(markers, function (idx, item) { + lay.each(item, function (i, dayStr) { + if (isEquals(dayStr, tdElem.attr('lay-ymd'))) { + insertHtml(tdElem, type[idx], YMD[2]); + } + }); + }); + } else if (typeof markers === 'string') { + if (type.indexOf(markers) !== -1) { + insertHtml(tdElem, markers, YMD[2]); + } + } +}; + +/** + * 标注法定节假日或补假上班 + * @param {JQuery} td + * @param {[number, number, number]} YMD + * @returns Class + */ +Class.prototype.holidays = function (td, YMD) { + var that = this; + var options = that.config; + var render = function (markers) { + that.holidaysRender(td, YMD, markers); + }; + if (typeof options.holidays === 'function') { + options.holidays({ + year: YMD[0], + month: YMD[1], + date: YMD[2] + }, render); + } else if (layui.type(options.holidays) === 'array') { + render(options.holidays); + } + return that; +}; + +/** + * 自定义单元格 + * @param {HTMLElement|Array} el - 单元格元素 + * @param {{year:number, month:number, date:number}} dateObj - 当前单元格对应的日期信息 + * @param {'year' | 'month' | 'date'} panelMode - 面板模式 + * @returns + */ +Class.prototype.cellRender = function (el, dateObj, panelMode) { + var that = this; + var options = that.config; + if (typeof options.cellRender === 'function') { + var render = function (content) { + if (typeof content === 'string') { + lay(el).html(content); + } else if (typeof content === 'object') { + lay(el).html('').append(lay(content)[0]); + } + }; + options.cellRender(dateObj, render, { + originElem: el, + type: panelMode + }); + } + return that; +}; + +/** + * 给定年份的开始日期 + * @param {Date} date + */ +Class.prototype.startOfYear = function (date) { + var newDate = new Date(date); + newDate.setFullYear(newDate.getFullYear(), 0, 1); + newDate.setHours(0, 0, 0, 0); + return newDate; +}; + +/** + * 给定年份的结束日期 + * @param {Date} date + */ +Class.prototype.endOfYear = function (date) { + var newDate = new Date(date); + var year = newDate.getFullYear(); + newDate.setFullYear(year + 1, 0, 0); + newDate.setHours(23, 59, 59, 999); + return newDate; +}; + +/** + * 给定月份的开始日期 + * @param {Date} date + */ +Class.prototype.startOfMonth = function (date) { + var newDate = new Date(date); + newDate.setDate(1); + newDate.setHours(0, 0, 0, 0); + return newDate; +}; + +/** + * 给定月份的结束日期 + * @param {Date} date + */ +Class.prototype.endOfMonth = function (date) { + var newDate = new Date(date); + var month = newDate.getMonth(); + newDate.setFullYear(newDate.getFullYear(), month + 1, 0); + newDate.setHours(23, 59, 59, 999); + return newDate; +}; + +/** + * 将指定的天数添加到给定日期 + * @param {Date} date 要更改的日期 + * @param {number} amount 天数 + */ +Class.prototype.addDays = function (date, amount) { + var newDate = new Date(date); + if (!amount) return newDate; + newDate.setDate(newDate.getDate() + amount); + return newDate; +}; + +/** + * 不可选取的年或月。年或月中的所有日期都禁用时,才判定为不可选取。 + * @param {Date} date 要检测的年或月 + * @param {'year' | 'month'} type 面板类型 + * @param {'start' | 'end'} position 面板位置 + */ +Class.prototype.isDisabledYearOrMonth = function (date, type, position) { + var that = this; + var options = that.config; + var millisecondsInDay = 24 * 60 * 60 * 1000; + var startDay = type === 'year' ? that.startOfYear(date) : that.startOfMonth(date); + var endDay = type === 'year' ? that.endOfYear(date) : that.endOfMonth(date); + var numOfDays = Math.floor((endDay.getTime() - startDay.getTime()) / millisecondsInDay) + 1; + var disabledCount = 0; + for (var i = 0; i < numOfDays; i++) { + var day = that.addDays(startDay, i); + if (options.disabledDate.call(options, day, position)) { + disabledCount++; + } + } + return disabledCount === numOfDays; +}; + +/** + * @typedef limitOptions + * @prop {JQuery} [elem] - 检测的元素, 例如面板中年月日时分秒元素,“现在”,“确认” 按钮等 + * @prop {number} [index] - 元素集合中,当前检测元素的索引,years:0,month:0,date:0-41,hms:0 + * @prop {['hours', 'minutes', 'seconds'] | ['hours', 'minutes'] | ['hours']} [time] - 是否比较时分秒 + * @prop {'year'|'month'|string} [type] - 面板类型? + * @prop {0 | 1} [rangeType] - 面板索引, 0 表示 start, 1 表示 end + * @prop {Partial<{year:number,month: number,date:number,hours:number,minutes:number,seconds:number}>} [date] - 检测的日期时间对象 + * @prop {'date' | 'time' | 'datetime'} disabledType - 禁用类型,按钮应使用 datetime + */ +/** + * 不可选取的日期 + * @param {number} date 当前检测的日期的时间戳 + * @param {limitOptions} opts + * @returns {boolean} + */ +Class.prototype.isDisabledDate = function (date, opts) { + opts = opts || {}; + var that = this; + var options = that.config; + var position = options.range ? opts.rangeType === 0 ? 'start' : 'end' : 'start'; + if (!options.disabledDate) return false; + if (options.type === 'time') return false; + if (!(opts.disabledType === 'date' || opts.disabledType === 'datetime')) return false; + + // 不需要时分秒 + var normalizedDate = new Date(date); + normalizedDate.setHours(0, 0, 0, 0); + return opts.type === 'year' || opts.type === 'month' ? that.isDisabledYearOrMonth(normalizedDate, opts.type, position) : options.disabledDate.call(options, normalizedDate, position); +}; + +/** + * 不可选取的时间 + * @param {number} date 当前检测的日期的时间戳 + * @param {limitOptions} opts + * @returns {boolean} + */ +Class.prototype.isDisabledTime = function (date, opts) { + opts = opts || {}; + var that = this; + var options = that.config; + var position = options.range ? opts.rangeType === 0 ? 'start' : 'end' : 'start'; + if (!options.disabledTime) return false; + if (!(options.type === 'time' || options.type === 'datetime')) return false; + if (!(opts.disabledType === 'time' || opts.disabledType === 'datetime')) return false; + var isDisabledItem = function (compareVal, rangeFn, rangeFnParam) { + return function () { + return (typeof rangeFn === 'function' && rangeFn.apply(options, rangeFnParam) || []).indexOf(compareVal) !== -1; + }; + }; + var dateObj = that.systemDate(new Date(date)); + var disabledTime = options.disabledTime.call(options, that.newDate(dateObj), position) || {}; + + // 面板中的时分秒 HTML 元素需要分别检测是否禁用 + // 按钮检测任意一项是否禁用即可 + return opts.disabledType === 'datetime' ? isDisabledItem(dateObj.hours, disabledTime.hours)() || isDisabledItem(dateObj.minutes, disabledTime.minutes, [dateObj.hours])() || isDisabledItem(dateObj.seconds, disabledTime.seconds, [dateObj.hours, dateObj.minutes])() : [isDisabledItem(dateObj.hours, disabledTime.hours), isDisabledItem(dateObj.minutes, disabledTime.minutes, [dateObj.hours]), isDisabledItem(dateObj.seconds, disabledTime.seconds, [dateObj.hours, dateObj.minutes])][opts.time.length - 1](); +}; + +/** + * 不可选取的日期时间 + * @param {number} timestamp 当前检测的日期的时间戳 + * @param {limitOptions} opts + * @returns + */ +Class.prototype.isDisabledDateTime = function (timestamp, opts) { + opts = opts || {}; + var that = this; + // var options = that.config; + + return that.isDisabledDate(timestamp, opts) || that.isDisabledTime(timestamp, opts); +}; + +/** + * 无效日期范围的标记 + * @param {limitOptions} opts + * + */ +Class.prototype.limit = function (opts) { + opts = opts || {}; + var that = this; + var options = that.config; + var timestamp = {}; + var dateTime = opts.index > (opts.time ? 0 : 41) ? that.endDate : options.dateTime; + var isOut; + lay.each({ + now: lay.extend({}, dateTime, opts.date || {}), + min: options.min, + max: options.max + }, function (key, item) { + timestamp[key] = that.newDate(lay.extend({ + year: item.year, + month: opts.type === 'year' ? 0 : item.month, + // 年份的时候只比较年 + date: opts.type === 'year' || opts.type === 'month' ? 1 : item.date // 年月只比较年月不与最大最小比日期 + }, function () { + var hms = {}; + lay.each(opts.time, function (i, keys) { + hms[keys] = item[keys]; + }); + return hms; + }())).getTime(); //time:是否比较时分秒 + }); + isOut = timestamp.now < timestamp.min || timestamp.now > timestamp.max || that.isDisabledDateTime(timestamp.now, opts); + opts.elem && opts.elem[isOut ? 'addClass' : 'removeClass'](DISABLED); + return isOut; +}; + +//当前日期对象 +Class.prototype.thisDateTime = function (index) { + var that = this, + options = that.config; + return index ? that.endDate : options.dateTime; +}; + +//日历表 +Class.prototype.calendar = function (value, index, type) { + index = index ? 1 : 0; + var that = this, + options = that.config, + dateTime = value || that.thisDateTime(index), + thisDate = new Date(), + startWeek, + prevMaxDate, + thisMaxDate, + lang = that.i18nMessages, + isAlone = options.type !== 'date' && options.type !== 'datetime', + tds = lay(that.table[index]).find('td'), + elemYM = lay(that.elemHeader[index][2]).find('span'); + if (dateTime.year < LIMIT_YEAR[0]) dateTime.year = LIMIT_YEAR[0], that.hint(lang.invalidDatePrompt); + if (dateTime.year > LIMIT_YEAR[1]) dateTime.year = LIMIT_YEAR[1], that.hint(lang.invalidDatePrompt); + + //记录初始值 + if (!that.firstDate) { + that.firstDate = lay.extend({}, dateTime); + } + + //计算当前月第一天的星期 + thisDate.setFullYear(dateTime.year, dateTime.month, 1); + startWeek = (thisDate.getDay() + (7 - options.weekStart)) % 7; + prevMaxDate = laydate.getEndDate(dateTime.month || 12, dateTime.year); //计算上个月的最后一天 + thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); //计算当前月的最后一天 + + //赋值日 + lay.each(tds, function (index_, item) { + var YMD = [dateTime.year, dateTime.month], + st; + item = lay(item); + item.removeAttr('class'); + if (index_ < startWeek) { + st = prevMaxDate - startWeek + index_; + item.addClass('laydate-day-prev'); + YMD = that.getAsYM(dateTime.year, dateTime.month, 'sub'); + } else if (index_ >= startWeek && index_ < thisMaxDate + startWeek) { + st = index_ - startWeek; + if (!that.rangeLinked) { + st + 1 === dateTime.date && item.addClass(THIS); + } + } else { + st = index_ - thisMaxDate - startWeek; + item.addClass('laydate-day-next'); + YMD = that.getAsYM(dateTime.year, dateTime.month); + } + YMD[1]++; + YMD[2] = st + 1; + item.attr('lay-ymd', YMD.join('-')).html('
                  ' + YMD[2] + '
                  '); + that.mark(item, YMD).holidays(item, YMD).limit({ + elem: item, + date: { + year: YMD[0], + month: YMD[1] - 1, + date: YMD[2] + }, + index: index_, + rangeType: index, + disabledType: 'date' // 日面板,检测当前日期是否禁用 + }); + that.cellRender(item, { + year: YMD[0], + month: YMD[1], + date: YMD[2] + }, 'date'); + }); + + //同步头部年月 + lay(elemYM[0]).attr('lay-ym', dateTime.year + '-' + (dateTime.month + 1)); + lay(elemYM[1]).attr('lay-ym', dateTime.year + '-' + (dateTime.month + 1)); + if (!that.panelYM) that.panelYM = {}; + that.panelYM[index] = { + year: dateTime.year, + month: dateTime.month + }; + var normalizedYearStr = addSpaceBetweenChars(dateTime.year + lang.literal.year); + var normalizedMonthStr = addSpaceBetweenChars(lang.months[dateTime.month]); + if (!lang.monthBeforeYear) { + lay(elemYM[0]).attr('lay-type', 'year').html(normalizedYearStr); + lay(elemYM[1]).attr('lay-type', 'month').html(normalizedMonthStr); + } else { + lay(elemYM[0]).attr('lay-type', 'month').html(normalizedMonthStr); + lay(elemYM[1]).attr('lay-type', 'year').html(normalizedYearStr); + } + + //初始默认选择器 + if (isAlone) { + //年、月等独立选择器 + if (options.range) { + if (value || type !== 'init') { + // 判断是否需要显示年月时间列表 + that.listYM = [[(that.startDate || options.dateTime).year, (that.startDate || options.dateTime).month + 1], [that.endDate.year, that.endDate.month + 1]]; + that.list(options.type, 0).list(options.type, 1); + + //同步按钮可点状态 + options.type === 'time' ? that.setBtnStatus(true, lay.extend({}, that.systemDate(), that.startTime), lay.extend({}, that.systemDate(), that.endTime)) : that.setBtnStatus(true); + } + } else { + that.listYM = [[dateTime.year, dateTime.month + 1]]; + that.list(options.type, 0); + } + } + + //初始赋值双日历 + if (options.range && type === 'init') { + //执行渲染第二个日历 + if (that.rangeLinked) { + var EYM = that.getAsYM(dateTime.year, dateTime.month, index ? 'sub' : null); + that.calendar(lay.extend({}, dateTime, { + year: EYM[0], + month: EYM[1] + }), 1 - index); // 渲染另外一个 + } else { + that.calendar(null, 1 - index); + } + } + + // 通过检测当前有效日期,来设定底部按钮状态 + if (!options.range) { + var timeParams = ['hours', 'minutes', 'seconds']; + + // 现在按钮 + that.limit({ + elem: lay(that.footer).find(ELEM_NOW), + date: that.systemDate(/^(datetime|time)$/.test(options.type) ? new Date() : null), + index: 0, + time: timeParams, + disabledType: 'datetime' // 按钮,检测日期和时间 + }); + // 确认按钮 + that.limit({ + elem: lay(that.footer).find(ELEM_CONFIRM), + index: 0, + time: timeParams, + disabledType: 'datetime' // 按钮,检测日期和时间 + }); + } + + //同步按钮可点状态 + that.setBtnStatus(); + + // 重置快捷栏选中状态 + lay(that.shortcut).find('li.' + THIS).removeClass(THIS); + + //标记选择范围 + if (options.range && !isAlone && type !== 'init') that.stampRange(); + return that; +}; + +//生成年月时分秒列表 +Class.prototype.list = function (type, index) { + var that = this, + options = that.config, + dateTime = that.rangeLinked ? options.dateTime : [options.dateTime, that.endDate][index], + lang = that.i18nMessages, + isAlone = options.range && options.type !== 'date' && options.type !== 'datetime', + //独立范围选择器 + ul = lay.elem('ul', { + class: ELEM_LIST + ' ' + { + year: 'laydate-year-list', + month: 'laydate-month-list', + time: 'laydate-time-list' + }[type] + }), + elemHeader = that.elemHeader[index], + elemYM = lay(elemHeader[2]).find('span'), + elemCont = that.elemCont[index || 0], + haveList = lay(elemCont).find('.' + ELEM_LIST)[0], + isMonthBeforeYear = lang.monthBeforeYear, + text = lang.literal.year, + listYM = that.listYM[index] || {}, + hms = ['hours', 'minutes', 'seconds'], + startEnd = ['startTime', 'endTime'][index]; + if (listYM[0] < 1) listYM[0] = 1; + + //生成年列表 + if (type === 'year') { + var yearNum, + startY = yearNum = listYM[0] - 7; + if (startY < 1) startY = yearNum = 1; + lay.each(new Array(15), function () { + var li = lay.elem('li', { + 'lay-ym': yearNum + }), + ymd = { + year: yearNum, + month: 0, + date: 1 + }; + yearNum == listYM[0] && lay(li).addClass(THIS); + li.innerHTML = yearNum + text; + ul.appendChild(li); + + /* + if(yearNum < that.firstDate.year){ + ymd.month = options.min.month; + ymd.date = options.min.date; + } else if(yearNum >= that.firstDate.year){ + ymd.month = options.max.month; + ymd.date = options.max.date; + } + */ + + that.limit({ + elem: lay(li), + date: ymd, + index: index, + type: type, + rangeType: index, + disabledType: 'date' // 年面板,检测当前年份中的所有日期是否禁用 + }); + that.cellRender(li, { + year: yearNum, + month: 1, + date: 1 + }, 'year'); + yearNum++; + }); + lay(elemYM[!isMonthBeforeYear ? 0 : 1]).attr('lay-ym', yearNum - 8 + '-' + listYM[1]).html(startY + text + ' - ' + (yearNum - 1 + text)); + } + + //生成月列表 + else if (type === 'month') { + lay.each(new Array(12), function (i) { + var li = lay.elem('li', { + 'lay-ym': i + }), + ymd = { + year: listYM[0], + month: i, + date: 1 + }; + i + 1 == listYM[1] && lay(li).addClass(THIS); + li.innerHTML = lang.months[i]; + ul.appendChild(li); + + /* + if(listYM[0] < that.firstDate.year){ + ymd.date = options.min.date; + } else if(listYM[0] >= that.firstDate.year){ + ymd.date = options.max.date; + } + */ + + that.limit({ + elem: lay(li), + date: ymd, + index: index, + type: type, + rangeType: index, + disabledType: 'date' // 月面板,检测当前月份中的所有日期是否禁用 + }); + that.cellRender(li, { + year: listYM[0], + month: i + 1, + date: 1 + }, 'month'); + }); + lay(elemYM[!isMonthBeforeYear ? 0 : 1]).attr('lay-ym', listYM[0] + '-' + listYM[1]).html(listYM[0] + text); + } + + //生成时间列表 + else if (type === 'time') { + //检测时分秒状态是否在有效日期时间范围内 + var setTimeStatus = function () { + lay(ul).find('ol').each(function (i, ol) { + lay(ol).find('li').each(function (ii, li) { + that.limit({ + elem: lay(li), + date: [{ + hours: ii + }, { + hours: that[startEnd].hours, + minutes: ii + }, { + hours: that[startEnd].hours, + minutes: that[startEnd].minutes, + seconds: ii + }][i], + index: index, + rangeType: index, + disabledType: 'time', + // 时间面板,分别检测时分秒列表是否禁用 + time: [['hours'], ['hours', 'minutes'], ['hours', 'minutes', 'seconds']][i] + }); + }); + }); + if (!options.range) { + that.limit({ + elem: lay(that.footer).find(ELEM_CONFIRM), + date: that[startEnd], + index: 0, + time: ['hours', 'minutes', 'seconds'], + disabledType: 'datetime' // 确认按钮,检测时分秒列表任意一项是否禁用 + }); + } + }; + var setTimeListVisibility = function () { + var showHour = options.format.indexOf('H') !== -1; + var showMinute = options.format.indexOf('m') !== -1; + var showSecond = options.format.indexOf('s') !== -1; + var liElem = ul.children; + var hideCount = 0; + lay.each([showHour, showMinute, showSecond], function (i, isShow) { + if (!isShow) { + liElem[i].className += ' layui-hide'; + hideCount++; + } + }); + ul.className += ' laydate-time-list-hide-' + hideCount; + }; + + //初始化时间对象 + if (options.range) { + if (!that[startEnd]) { + that[startEnd] = startEnd === 'startTime' ? dateTime : that.endDate; + } + } else { + that[startEnd] = dateTime; + } + + //生成时分秒 + lay.each([24, 60, 60], function (i, item) { + var li = lay.elem('li'), + childUL = ['

                  ' + lang.time[i] + '

                    ']; + lay.each(new Array(item), function (ii) { + childUL.push('' + lay.digit(ii, 2) + ''); + }); + li.innerHTML = childUL.join('') + '
                  '; + ul.appendChild(li); + }); + setTimeStatus(); + setTimeListVisibility(); + } + + //插入容器 + if (haveList) elemCont.removeChild(haveList); + elemCont.appendChild(ul); + + //年月面板 - 选择事件 + if (type === 'year' || type === 'month') { + //显示切换箭头 + lay(that.elemMain[index]).addClass('laydate-ym-show'); + + //选中 + lay(ul).find('li').on('click', function () { + var ym = lay(this).attr('lay-ym') | 0; + if (lay(this).hasClass(DISABLED)) return; + if (that.rangeLinked) { + lay.extend(dateTime, { + year: type === 'year' ? ym : listYM[0], + month: type === 'year' ? listYM[1] - 1 : ym + }); + } else { + dateTime[type] = ym; + } + + //当为年选择器或者年月选择器 + var isYearOrMonth = ['year', 'month'].indexOf(options.type) !== -1; + var isChangeMonth = type === 'year' && ['date', 'datetime'].indexOf(options.type) !== -1; + if (isYearOrMonth || isChangeMonth) { + lay(ul).find('.' + THIS).removeClass(THIS); + lay(this).addClass(THIS); + + //如果为年月选择器,点击了年列表,则切换到月选择器 + if (options.type === 'month' && type === 'year' || isChangeMonth) { + that.listYM[index][0] = ym; + isAlone && ((index ? that.endDate : dateTime).year = ym); + that.list('month', index); + } + } else { + that.checkDate('limit').calendar(dateTime, index, 'init'); // 重新渲染一下两个面板 + that.closeList(); + } + if (!options.range) { + that.limit({ + type: type, + elem: lay(that.footer).find(ELEM_CONFIRM), + date: dateTime, + disabledType: 'datetime' // 按钮,检测日期和时间 + }); + } + that.setBtnStatus(); //同步按钮可点状态 + + //若为月选择器,只有当选择月份时才自动关闭; + //若为年选择器,选择年份即自动关闭 + //且在范围未开启时 + if (!options.range && options.autoConfirm) { + if (options.type === 'month' && type === 'month' || options.type === 'year' && type === 'year') { + that.setValue(that.parse()).done().remove(); + } + } + that.autoCalendarModel.auto && !that.rangeLinked ? that.choose(lay(elemCont).find('td.layui-this'), index) : that.endState && that.done(null, 'change'); + lay(that.footer).find('.' + ELEM_TIME_BTN).removeClass(DISABLED); + }); + } else { + //时间选择面板 - 选择事件 + var span = lay.elem('span', { + class: ELEM_TIME_TEXT + }), + //滚动条定位 + scroll = function () { + lay(ul).find('ol').each(function (i) { + var ol = this, + li = lay(ol).find('li'); + ol.scrollTop = 30 * (that[startEnd][hms[i]] - 2); + if (ol.scrollTop <= 0) { + li.each(function (ii) { + if (!lay(this).hasClass(DISABLED)) { + ol.scrollTop = 30 * (ii - 2); + return true; + } + }); + } + }); + }, + haveSpan = lay(elemHeader[2]).find('.' + ELEM_TIME_TEXT); + scroll(); + span.innerHTML = options.range ? [lang.startTime, lang.endTime][index] : lang.selectTime; + lay(that.elemMain[index]).addClass('laydate-time-show'); + if (haveSpan[0]) haveSpan.remove(); + elemHeader[2].appendChild(span); + var olElem = lay(ul).find('ol'); + olElem.each(function (i) { + var ol = this; + //选择时分秒 + lay(ol).find('li').on('click', function () { + var value = this.innerHTML | 0; + if (lay(this).hasClass(DISABLED)) return; + if (options.range) { + that[startEnd][hms[i]] = value; + } else { + dateTime[hms[i]] = value; + } + lay(ol).find('.' + THIS).removeClass(THIS); + lay(this).addClass(THIS); + setTimeStatus(); + scroll(); + (that.endDate || options.type === 'time' || options.type === 'datetime') && that.done(null, 'change'); + + //同步按钮可点状态 + that.setBtnStatus(); + }); + }); + if (layui.device().mobile) { + olElem.css({ + overflowY: 'auto', + touchAction: 'pan-y' + }); + } + } + return that; +}; + +//记录列表切换后的年月 +Class.prototype.listYM = []; + +//关闭列表 +Class.prototype.closeList = function () { + var that = this; + // var options = that.config; + + lay.each(that.elemCont, function (index) { + lay(this).find('.' + ELEM_LIST).remove(); + lay(that.elemMain[index]).removeClass('laydate-ym-show laydate-time-show'); + }); + lay(that.elem).find('.' + ELEM_TIME_TEXT).remove(); +}; + +//检测结束日期是否超出开始日期 +Class.prototype.setBtnStatus = function (tips, start, end) { + var that = this, + options = that.config, + lang = that.i18nMessages, + isOut, + elemBtn = lay(that.footer).find(ELEM_CONFIRM), + timeParams = options.type === 'datetime' || options.type === 'time' ? ['hours', 'minutes', 'seconds'] : undefined; + if (options.range) { + start = start || (that.rangeLinked ? that.startDate : options.dateTime); + end = end || that.endDate; + isOut = !that.endState || that.newDate(start).getTime() > that.newDate(end).getTime(); + + //如果不在有效日期内,直接禁用按钮,否则比较开始和结束日期 + that.limit({ + date: start, + disabledType: 'datetime', + // 按钮,检测日期和时间 + time: timeParams, + rangeType: 0 + }) || that.limit({ + date: end, + disabledType: 'datetime', + // 按钮,检测日期和时间 + time: timeParams, + rangeType: 1 + }) ? elemBtn.addClass(DISABLED) : elemBtn[isOut ? 'addClass' : 'removeClass'](DISABLED); + + // 是否异常提示 + if (tips && isOut) { + that.hint(lang.rangeOrderPrompt); + } + } +}; + +// 转义为规定格式的日期字符 +Class.prototype.parse = function (state, date) { + var that = this; + var options = that.config; + var startDate = that.rangeLinked ? that.startDate : options.dateTime; + var dateTime = date || (state == 'end' ? lay.extend({}, that.endDate, that.endTime) : options.range ? lay.extend({}, startDate || options.dateTime, that.startTime) : options.dateTime); + var format = laydate.parse(dateTime, that.format, 1); + + // 返回日期范围字符 + if (options.range && state === undefined) { + return format + ' ' + that.rangeStr + ' ' + that.parse('end'); + } + return format; +}; + +//创建指定日期时间对象 +Class.prototype.newDate = function (dateTime) { + dateTime = dateTime || {}; + return new Date(dateTime.year || 1, dateTime.month || 0, dateTime.date || 1, dateTime.hours || 0, dateTime.minutes || 0, dateTime.seconds || 0); +}; + +// 获得指定日期时间对象的毫秒数 +Class.prototype.getDateTime = function (obj) { + return this.newDate(obj).getTime(); +}; + +/** + * 格式化输入框显示值 + * @param {HTMLInputElement} elem HTML input 元素 + * @param {(value: string) => string} displayValueCallback + */ +Class.prototype.formatToDisplay = function (elem, displayValueCallback) { + var that = this; + var props = Object.getOwnPropertyDescriptor(HTMLInputElement.prototype, 'value'); + Object.defineProperty(elem, 'value', lay.extend({}, props, { + get: function () { + return this.getAttribute('lay-date'); + }, + set: function (value) { + props.set.call(this, displayValueCallback.call(that, value)); + this.setAttribute('lay-date', value); + } + })); +}; + +//赋值 +Class.prototype.setValue = function (value) { + var that = this, + options = that.config, + elem = options.elem[0]; + + //静态展现则不作默认赋值 + if (options.position === 'static') return that; + value = value || ''; + + //绑定的元素是否为 input + if (that.isInput(elem)) { + lay(elem).val(value); + } else { + //如果 range 传入了开始和结束的 input 对象,则分别对其赋值 + var rangeElem = that.rangeElem; + if (rangeElem) { + if (layui.type(value) !== 'array') { + value = value.split(' ' + that.rangeStr + ' '); + } + rangeElem[0].val(value[0] || ''); + rangeElem[1].val(value[1] || ''); + } else { + if (lay(elem).find('*').length === 0) { + var displayValue = typeof options.formatToDisplay === 'function' ? options.formatToDisplay(value) : value; + lay(elem).html(displayValue); + } + lay(elem).attr('lay-date', value); + } + } + return that; +}; + +//预览 +Class.prototype.preview = function () { + var that = this, + options = that.config; + if (!options.isPreview) return; + var elemPreview = lay(that.elem).find('.' + ELEM_PREVIEW), + value = options.range ? (that.rangeLinked ? that.endState : that.endDate) ? that.parse() : '' : that.parse(); + + // 显示预览 + elemPreview.html(value); + + // 预览颜色渐变 + var oldValue = elemPreview.html(); + if (oldValue) { + var color = layui.type(options.theme) === 'array' ? options.theme[0] : options.theme; + elemPreview.css({ + color: /^#/.test(String(color)) ? color : '#16b777' + }); + setTimeout(function () { + elemPreview.css({ + color: '#777' + }); + }, 300); + } +}; + +// 附加的渲染处理,在 ready 和 change 的时候调用 +Class.prototype.renderAdditional = function () { + var that = this; + var options = that.config; + + // 处理全面板 + if (options.fullPanel) { + that.list('time', 0); + } +}; + +// 标记范围内的日期 +Class.prototype.stampRange = function () { + var that = this, + options = that.config, + startTime = that.rangeLinked ? that.startDate : options.dateTime, + endTime, + tds = lay(that.elem).find('td'); + if (options.range && !that.endState) lay(that.footer).find(ELEM_CONFIRM).addClass(DISABLED); + // if(!that.endState) return; + + startTime = startTime && that.newDate({ + year: startTime.year, + month: startTime.month, + date: startTime.date + }).getTime(); + endTime = that.endState && that.endDate && that.newDate({ + year: that.endDate.year, + month: that.endDate.month, + date: that.endDate.date + }).getTime(); + + // if(startTime > endTime) return that.hint(TIPS_OUT); + + lay.each(tds, function (i, item) { + var ymd = lay(item).attr('lay-ymd').split('-'); + var thisTime = that.newDate({ + year: ymd[0], + month: ymd[1] - 1, + date: ymd[2] + }).getTime(); + + // 标记当天 + if (options.rangeLinked && !that.startDate) { + if (thisTime === that.newDate(that.systemDate()).getTime()) { + lay(item).addClass(lay(item).hasClass(ELEM_PREV) || lay(item).hasClass(ELEM_NEXT) ? '' : ELEM_DAY_NOW); + } + } + + /* + * 标注区间 + */ + + lay(item).removeClass(ELEM_SELECTED + ' ' + THIS); + if (thisTime === startTime || thisTime === endTime) { + (that.rangeLinked || !that.rangeLinked && (i < 42 ? thisTime === startTime : thisTime === endTime)) && lay(item).addClass(lay(item).hasClass(ELEM_PREV) || lay(item).hasClass(ELEM_NEXT) ? ELEM_SELECTED : THIS); + } + if (thisTime > startTime && thisTime < endTime) { + lay(item).addClass(ELEM_SELECTED); + } + }); +}; + +// 执行 done/change 回调 +Class.prototype.done = function (param, type) { + var that = this; + var options = that.config; + var start = lay.extend({}, lay.extend(that.rangeLinked ? that.startDate : options.dateTime, that.startTime)); + var end = lay.extend({}, lay.extend(that.endDate, that.endTime)); + lay.each([start, end], function (i, item) { + if (!('month' in item)) return; + lay.extend(item, { + month: item.month + 1 + }); + }); + that.preview(); + param = param || [that.parse(), start, end]; + type === 'change' && that.renderAdditional(); + typeof options[type || 'done'] === 'function' && options[type || 'done'].apply(options, param); + return that; +}; + +/** + * 判断日期是否存在面板,用于处理日期范围选择的一些边缘情况 + * @param {object} datetime 日期时间对象 + * @param {number} index - 面板索引 + * @returns + */ +Class.prototype.checkPanelDate = function (datetime, index) { + var that = this; + var options = that.config; + // 年月范围选择不需要处理 + if (options.type !== 'date' && options.type !== 'datetime') return; + var startPanel = index === 0; + var month = datetime.month + 1; // 点击的日期所在月份 + var panelMonth = that.panelYM[index].month + 1; // 当前面板头部月份 + + // 边缘日期的处理 + var firstRenderIndex = that.endState ? + // 二次点击(一般为结束日期)任意一侧面板时: + // 1. 左侧面板中,点击的月份属于下一个月时,应渲染右侧面板而不是左侧面板; + // 2. 左侧面板中,点击的月份属于上一个月时,应将两个面板都重新渲染(等效点击 prevMonth); + // 3. 右侧面板同理。 + function () { + return startPanel && month > panelMonth || !startPanel && month < panelMonth ? 1 - index : index; + }() : + // 初次点击(一般为开始日期)任意一侧面板时: + // 1. 让该面板自行切换,以保持日期的「选中状态」在该侧; + // 2. 另一侧面板则根据点击的面板进行响应式切换,以保持左右面板始终为连续月份。 + index; + + // 为简化实现,只要点击的月份不等于当前面板顶部显示的月份时,就重新渲染两侧面板 + return { + needFullRender: month !== panelMonth, + index: firstRenderIndex + }; +}; + +//选择日期 +Class.prototype.choose = function (td, index) { + if (td.hasClass(DISABLED)) return; + var that = this, + options = that.config, + panelIndex = index; // 记录点击的是哪一个面板的 + + if (that.rangeLinked) { + if (that.endState || !that.startDate) { + // 重新选择或者第一次选择 + index = 0; + that.endState = false; + } else { + index = 1; + that.endState = true; + } + } + var dateTime = that.thisDateTime(index), + // tds = lay(that.elem).find('td'), + YMD = td.attr('lay-ymd').split('-'); + YMD = { + year: YMD[0] | 0, + month: (YMD[1] | 0) - 1, + date: YMD[2] | 0 + }; + lay.extend(dateTime, YMD); //同步 dateTime + + //范围选择 + if (options.range) { + //补充时分秒 + lay.each(['startTime', 'endTime'], function (i, item) { + that[item] = that[item] || { + hours: i ? 23 : 0, + minutes: i ? 59 : 0, + seconds: i ? 59 : 0 + }; + if (index === i) { + // 判断选择之后的是否在范围内,超出则需要调整时分秒 + if (that.getDateTime(lay.extend({}, dateTime, that[item])) < that.getDateTime(options.min)) { + that[item] = { + hours: options.min.hours, + minutes: options.min.minutes, + seconds: options.min.seconds + }; + lay.extend(dateTime, that[item]); + } else if (that.getDateTime(lay.extend({}, dateTime, that[item])) > that.getDateTime(options.max)) { + that[item] = { + hours: options.max.hours, + minutes: options.max.minutes, + seconds: options.max.seconds + }; + lay.extend(dateTime, that[item]); + } + } + }); + if (!index) { + that.startDate = lay.extend({}, dateTime); // 同步startDate + } + // 校验另外一个日期是否在有效的范围内 + // 此处为范围选择的日期面板点击选中处理,所以 disabledType 为 date + if (that.endState && !that.limit({ + date: that.rangeLinked ? that.startDate : that.thisDateTime(1 - index), + disabledType: 'date' + })) { + // 根据选择之后判断是否需要切换模式 + var isChange; + if (that.endState && that.autoCalendarModel.auto) { + isChange = that.autoCalendarModel(); + } + // 判断是否反选 + var needSwapDate = (isChange || that.rangeLinked && that.endState) && that.newDate(that.startDate) > that.newDate(that.endDate); + if (needSwapDate) { + var isSameDate = that.startDate.year === that.endDate.year && that.startDate.month === that.endDate.month && that.startDate.date === that.endDate.date; + var startDate; + // 如果是同一天并且出现了反选证明是时分秒出现开始时间大于结束时间的现象 + if (isSameDate) { + startDate = that.startTime; + that.startTime = that.endTime; + that.endTime = startDate; + } + // 当出现反向选择时(即“后点击”的日期比“先点击”的日期小),重新提取区间 + startDate = that.startDate; + that.startDate = lay.extend({}, that.endDate, that.startTime); + options.dateTime = lay.extend({}, that.startDate); + that.endDate = lay.extend({}, startDate, that.endTime); + } + isChange && (options.dateTime = lay.extend({}, that.startDate)); + } + if (that.rangeLinked) { + // 处理日期范围选择的一些边缘情况 + var checkState = that.checkPanelDate(dateTime, panelIndex); + var dateTimeTemp = lay.extend({}, dateTime); + var renderMode = isChange || checkState && checkState.needFullRender ? 'init' : null; + var panelIdx = checkState ? checkState.index : panelIndex; + that.calendar(dateTimeTemp, panelIdx, renderMode); + } else { + that.calendar(null, index, isChange ? 'init' : null); + } + that.endState && that.done(null, 'change'); + } else if (options.position === 'static') { + //直接嵌套的选中 + that.calendar().done().done(null, 'change'); //同时执行 done 和 change 回调 + } else if (options.type === 'date') { + options.autoConfirm ? that.setValue(that.parse()).done().remove() : that.calendar().done(null, 'change'); + } else if (options.type === 'datetime') { + that.calendar().done(null, 'change'); + } +}; + +//底部按钮 +Class.prototype.tool = function (btn, type) { + var that = this, + options = that.config, + lang = that.i18nMessages, + dateTime = options.dateTime, + isStatic = options.position === 'static', + active = { + //选择时间 + datetime: function () { + if (lay(btn).hasClass(DISABLED)) return; + that.list('time', 0); + options.range && that.list('time', 1); + lay(btn).attr('lay-type', 'date').html(that.i18nMessages.selectDate); + }, + //选择日期 + date: function () { + that.closeList(); + lay(btn).attr('lay-type', 'datetime').html(that.i18nMessages.selectTime); + }, + //清空、重置 + clear: function () { + isStatic && (lay.extend(dateTime, that.firstDate), that.calendar()); + options.range && (delete options.dateTime, delete that.endDate, delete that.startTime, delete that.endTime); + that.setValue(''); + that.done(null, 'onClear').done(['', {}, {}]).remove(); + }, + // 现在 + now: function () { + var thisDate = new Date(); + + // 当前系统时间未在 min/max 范围内,则不可点击 + if (lay(btn).hasClass(DISABLED)) { + return that.hint(lang.tools.now + ', ' + lang.invalidDatePrompt); + } + lay.extend(dateTime, that.systemDate(), { + hours: thisDate.getHours(), + minutes: thisDate.getMinutes(), + seconds: thisDate.getSeconds() + }); + that.setValue(that.parse()); + isStatic && that.calendar(); + that.done(null, 'onNow').done().remove(); + }, + //确定 + confirm: function () { + if (options.range) { + if (lay(btn).hasClass(DISABLED)) { + var isTimeout = options.type === 'time' ? that.startTime && that.endTime && that.newDate(that.startTime) > that.newDate(that.endTime) : that.startDate && that.endDate && that.newDate(lay.extend({}, that.startDate, that.startTime || {})) > that.newDate(lay.extend({}, that.endDate, that.endTime || {})); + return that.hint(isTimeout ? lang.rangeOrderPrompt : lang.invalidDatePrompt); + } + } else { + if (lay(btn).hasClass(DISABLED)) return that.hint(lang.invalidDatePrompt); + } + that.setValue(that.parse()); + that.done(null, 'onConfirm').done().remove(); + } + }; + active[type] && active[type](); +}; + +//统一切换处理 +Class.prototype.change = function (index) { + var that = this, + options = that.config, + dateTime = that.thisDateTime(index), + isAlone = options.range && (options.type === 'year' || options.type === 'month'), + elemCont = that.elemCont[index || 0], + listYM = that.listYM[index], + addSubYear = function (type) { + var isYear = lay(elemCont).find('.laydate-year-list')[0], + isMonth = lay(elemCont).find('.laydate-month-list')[0]; + + //切换年列表 + if (isYear) { + listYM[0] = type ? listYM[0] - 15 : listYM[0] + 15; + that.list('year', index); + } + if (isMonth) { + //切换月面板中的年 + type ? listYM[0]-- : listYM[0]++; + that.list('month', index); + } + if (isYear || isMonth) { + lay.extend(dateTime, { + year: listYM[0] + }); + if (isAlone) dateTime.year = listYM[0]; + options.range || that.done(null, 'change'); + options.range || that.limit({ + elem: lay(that.footer).find(ELEM_CONFIRM), + date: { + year: listYM[0], + month: isYear ? 0 : listYM[1] - 1 + }, + disabledType: 'datetime' // 按钮,检测日期和时间 + }); + } + that.setBtnStatus(); + return isYear || isMonth; + }; + return { + prevYear: function () { + if (addSubYear('sub')) return; + if (that.rangeLinked) { + options.dateTime.year--; + that.checkDate('limit').calendar(null, null, 'init'); + } else { + dateTime.year--; + that.checkDate('limit').calendar(null, index); + // 面板自动切换的模式下重新判定是否发生模式转换等细节处理 + that.autoCalendarModel.auto ? that.choose(lay(elemCont).find('td.layui-this'), index) : that.done(null, 'change'); + } + }, + prevMonth: function () { + var YM; + // rangeLinked 模式非实时选择日期,不需要同步 options.dateTime,应根据面板显示日期切换 + if (that.rangeLinked) { + var panelYM = that.panelYM[0]; + var dateTimeTemp; + YM = that.getAsYM(panelYM.year, panelYM.month, 'sub'); + dateTimeTemp = lay.extend({}, options.dateTime, that.panelYM[0], { + year: YM[0], + month: YM[1] + }); + that.checkDate('limit').calendar(dateTimeTemp, null, 'init'); + } else { + YM = that.getAsYM(dateTime.year, dateTime.month, 'sub'); + lay.extend(dateTime, { + year: YM[0], + month: YM[1] + }); + that.checkDate('limit').calendar(null, null, 'init'); + that.autoCalendarModel.auto ? that.choose(lay(elemCont).find('td.layui-this'), index) : that.done(null, 'change'); + } + }, + nextMonth: function () { + var YM; + if (that.rangeLinked) { + var panelYM = that.panelYM[0]; + YM = that.getAsYM(panelYM.year, panelYM.month); + var dateTimeTemp = lay.extend({}, options.dateTime, that.panelYM[0], { + year: YM[0], + month: YM[1] + }); + that.checkDate('limit').calendar(dateTimeTemp, null, 'init'); + } else { + YM = that.getAsYM(dateTime.year, dateTime.month); + lay.extend(dateTime, { + year: YM[0], + month: YM[1] + }); + that.checkDate('limit').calendar(null, null, 'init'); + that.autoCalendarModel.auto ? that.choose(lay(elemCont).find('td.layui-this'), index) : that.done(null, 'change'); + } + }, + nextYear: function () { + if (addSubYear()) return; + if (that.rangeLinked) { + options.dateTime.year++; + that.checkDate('limit').calendar(null, 0, 'init'); + } else { + dateTime.year++; + that.checkDate('limit').calendar(null, index); + that.autoCalendarModel.auto ? that.choose(lay(elemCont).find('td.layui-this'), index) : that.done(null, 'change'); + } + } + }; +}; + +// 日期切换事件 +Class.prototype.changeEvent = function () { + var that = this; + // var options = that.config; + + //日期选择事件 + lay(that.elem).on('click', function (e) { + lay.stope(e); + }).on('mousedown', function (e) { + lay.stope(e); + }); + + //年月切换 + lay.each(that.elemHeader, function (i, header) { + //上一年 + lay(header[0]).on('click', function () { + that.change(i).prevYear(); + }); + + //上一月 + lay(header[1]).on('click', function () { + that.change(i).prevMonth(); + }); + + //选择年月 + lay(header[2]).find('span').on('click', function () { + var othis = lay(this), + layYM = othis.attr('lay-ym'), + layType = othis.attr('lay-type'); + if (!layYM) return; + layYM = layYM.split('-'); + that.listYM[i] = [layYM[0] | 0, layYM[1] | 0]; + that.list(layType, i); + lay(that.footer).find('.' + ELEM_TIME_BTN).addClass(DISABLED); + }); + + //下一月 + lay(header[3]).on('click', function () { + that.change(i).nextMonth(); + }); + + //下一年 + lay(header[4]).on('click', function () { + that.change(i).nextYear(); + }); + }); + + //点击日期 + lay.each(that.table, function (i, table) { + var tds = lay(table).find('td'); + tds.on('click', function () { + that.choose(lay(this), i); + }); + }); + + //点击底部按钮 + lay(that.footer).find('span').on('click', function () { + var type = lay(this).attr('lay-type'); + that.tool(this, type); + }); +}; + +//是否输入框 +Class.prototype.isInput = function (elem) { + return /input|textarea/.test(elem.tagName.toLocaleLowerCase()) || /INPUT|TEXTAREA/.test(elem.tagName); +}; + +//绑定的元素事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + if (!options.elem[0] || options.elem[0].eventHandler) return; + var showEvent = function () { + // 已经打开的面板避免重新渲染 + if (laydate.thisId === options.id) return; + that.render(); + }; + + //绑定呼出控件事件 + options.elem.on(options.trigger, showEvent); + options.elem[0].eventHandler = true; + options.eventElem.on(options.trigger, showEvent); + + // 元素解绑 + that.unbind = function () { + that.remove(); + options.elem.off(options.trigger, showEvent); + options.elem.removeAttr('lay-key'); + options.elem.removeAttr(MOD_ID); + options.elem[0].eventHandler = false; + options.eventElem.off(options.trigger, showEvent); + options.eventElem.removeAttr('lay-key'); + delete thisModule.that[options.id]; + }; +}; + +// 绑定关闭控件事件 +lay(document).on('mousedown', function (e) { + if (!laydate.thisId) return; + var that = thisModule.getThis(laydate.thisId); + if (!that) return; + var options = that.config; + if (e.target === options.elem[0] || e.target === options.eventElem[0] || e.target === lay(options.closeStop)[0] || options.elem[0] && options.elem[0].contains(e.target)) return; + that.remove(); +}).on('keydown', function (e) { + if (!laydate.thisId) return; + var that = thisModule.getThis(laydate.thisId); + if (!that) return; + + // 回车触发确认 + if (that.config.position === 'static') return; + if (e.keyCode === 13) { + if (lay('#' + that.elemID)[0] && that.elemID === Class.thisElemDate) { + e.preventDefault(); + lay(that.footer).find(ELEM_CONFIRM)[0].click(); + } + } +}); + +//自适应定位 +lay(window).on('resize', function () { + if (!laydate.thisId) return; + var that = thisModule.getThis(laydate.thisId); + if (!that) return; + if (!that.elem || !lay(ELEM)[0]) { + return false; + } + that.position(); +}); + +// 记录所有实例 +thisModule.that = {}; //记录所有实例对象 + +// 获取当前实例对象 +thisModule.getThis = function (id) { + var that = thisModule.that[id]; + if (!that) { + layui.hint().error(id ? MOD_NAME + " instance with ID '" + id + "' not found" : 'ID argument required'); + } + return that; +}; + +// 渲染 - 核心接口 +laydate.render = function (options) { + var inst = new Class(options); + return thisModule.call(inst); +}; + +// 重载 +laydate.reload = function (id, options) { + var that = thisModule.getThis(id); + if (!that) return; + return that.reload(options); +}; + +// 获取对应 ID 的实例 +laydate.getInst = function (id) { + var that = thisModule.getThis(id); + if (that) { + return that.inst; + } +}; + +// 面板提示 +laydate.hint = function (id, opts) { + var that = thisModule.getThis(id); + if (!that) return; + return that.hint(opts); +}; + +// 解绑实例 +laydate.unbind = function (id) { + var that = thisModule.getThis(id); + if (!that) return; + return that.unbind(); +}; + +// 关闭日期面板 +laydate.close = function (id) { + var that = thisModule.getThis(id || laydate.thisId); + if (!that) return; + return that.remove(); +}; + +// 将指定对象转化为日期值 +laydate.parse = function (dateTime, format, one) { + dateTime = dateTime || {}; + + //如果 format 是字符型,则转换为数组格式 + if (typeof format === 'string') { + format = thisModule.formatArr(format); + } + format = (format || []).concat(); + + //转义为规定格式 + lay.each(format, function (i, item) { + if (/yyyy|y/.test(item)) { + //年 + format[i] = lay.digit(dateTime.year, item.length); + } else if (/MM|M/.test(item)) { + //月 + format[i] = lay.digit(dateTime.month + (one || 0), item.length); + } else if (/dd|d/.test(item)) { + //日 + format[i] = lay.digit(dateTime.date, item.length); + } else if (/HH|H/.test(item)) { + //时 + format[i] = lay.digit(dateTime.hours, item.length); + } else if (/mm|m/.test(item)) { + //分 + format[i] = lay.digit(dateTime.minutes, item.length); + } else if (/ss|s/.test(item)) { + //秒 + format[i] = lay.digit(dateTime.seconds, item.length); + } + }); + return format.join(''); +}; + +// 得到某月的最后一天 +laydate.getEndDate = function (month, year) { + var thisDate = new Date(); + //设置日期为下个月的第一天 + thisDate.setFullYear(year || thisDate.getFullYear(), month || thisDate.getMonth() + 1, 1); + //减去一天,得到当前月最后一天 + return new Date(thisDate.getTime() - 1000 * 60 * 60 * 24).getDate(); +}; + +export { laydate }; diff --git a/dist/components/layer.js b/dist/components/layer.js new file mode 100644 index 000000000..e37e44be6 --- /dev/null +++ b/dist/components/layer.js @@ -0,0 +1,1701 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; + +/** + * layer + * 通用 Web 弹出层组件 + */ + +var win; +var ready = { + config: { + removeFocus: true + }, + end: {}, + beforeEnd: {}, + events: { + resize: {} + }, + minStackIndex: 0, + minStackArr: [], + // 五种原始层模式 + type: ['dialog', 'page', 'iframe', 'loading', 'tips'], + // 获取节点的 style 属性值 + getStyle: function (node, name) { + var style = node.currentStyle ? node.currentStyle : window.getComputedStyle(node, null); + return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name); + } +}; + +// 默认内置方法。 +var layer = { + ie: function () { + // ie 版本 + var agent = navigator.userAgent.toLowerCase(); + return !!window.ActiveXObject || 'ActiveXObject' in window ? (agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识 + : false; + }(), + config: function (options) { + options = options || {}; + layer.cache = ready.config = $.extend({}, ready.config, options); + typeof options.extend === 'string' && (options.extend = [options.extend]); + return this; + }, + // 主体 CSS 等待事件(已弃用) + ready: function (callback) { + typeof callback === 'function' && callback(); + return this; + }, + // 各种快捷引用 + alert: function (content, options, yes) { + var type = typeof options === 'function'; + if (type) yes = options; + return layer.open($.extend({ + content: content, + yes: yes + }, type ? {} : options)); + }, + confirm: function (content, options, yes, cancel) { + var type = typeof options === 'function'; + if (type) { + cancel = yes; + yes = options; + } + return layer.open($.extend({ + content: content, + btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')], + yes: yes, + btn2: cancel + }, type ? {} : options)); + }, + msg: function (content, options, end) { + // 最常用提示层 + var type = typeof options === 'function', + rskin = ready.config.skin; + var skin = (rskin ? rskin + ' ' + rskin + '-msg' : '') || 'layui-layer-msg'; + var anim = doms.anim.length - 1; + if (type) end = options; + return layer.open($.extend({ + content: content, + time: 3000, + shade: false, + skin: skin, + title: false, + closeBtn: false, + btn: false, + resize: false, + end: end, + removeFocus: false + }, type && !ready.config.skin ? { + skin: skin + ' layui-layer-hui', + anim: anim + } : function () { + options = options || {}; + if (options.icon === -1 || options.icon === undefined && !ready.config.skin) { + options.skin = skin + ' ' + (options.skin || 'layui-layer-hui'); + } + return options; + }())); + }, + load: function (icon, options) { + return layer.open($.extend({ + type: 3, + icon: icon || 0, + resize: false, + shade: 0.01, + removeFocus: false + }, options)); + }, + tips: function (content, follow, options) { + return layer.open($.extend({ + type: 4, + content: [content, follow], + closeBtn: false, + time: 3000, + shade: false, + resize: false, + fixed: false, + maxWidth: 260, + removeFocus: false + }, options)); + } +}; +var Class = function (setings) { + var that = this, + creat = function () { + that.creat(); + }; + // TODO 临时的同步方案 + ready.config.title = i18n.$t('layer.defaultTitle'); + that.index = layer.index = lay.autoIncrementer('layer'); + that.config.maxWidth = $(win).width() - 15 * 2; // 初始最大宽度:当前屏幕宽,左右留 15px 边距 + that.config = $.extend({}, that.config, ready.config, setings); + document.body ? creat() : setTimeout(function () { + creat(); + }, 30); +}; +Class.pt = Class.prototype; + +// 缓存常用字符 +var doms = ['layui-layer', '.layui-layer-title', '.layui-layer-main', '.layui-layer-dialog', 'layui-layer-iframe', 'layui-layer-content', 'layui-layer-btn', 'layui-layer-close']; + +// 内置动画类 +doms.anim = { + // 旧版动画 + 0: 'layer-anim-00', + 1: 'layer-anim-01', + 2: 'layer-anim-02', + 3: 'layer-anim-03', + 4: 'layer-anim-04', + 5: 'layer-anim-05', + 6: 'layer-anim-06', + // 滑出方向 + slideDown: 'layer-anim-slide-down', + slideLeft: 'layer-anim-slide-left', + slideUp: 'layer-anim-slide-up', + slideRight: 'layer-anim-slide-right' +}; +doms.SHADE = 'layui-layer-shade'; +doms.MOVE = 'layui-layer-move'; +var SHADE_KEY = 'LAYUI-LAYER-SHADE-KEY'; +var RECORD_HEIGHT_KEY = 'LAYUI_LAYER_CONTENT_RECORD_HEIGHT'; + +// 默认配置 +Class.pt.config = { + type: 0, + shade: 0.3, + fixed: true, + move: doms[1], + title: i18n.$t('layer.defaultTitle'), + offset: 'auto', + area: 'auto', + closeBtn: 1, + icon: -1, + time: 0, + // 0 表示不自动关闭 + zIndex: 19891014, + maxWidth: 360, + anim: 0, + isOutAnim: true, + // 退出动画 + minStack: true, + // 最小化堆叠 + moveType: 1, + resize: true, + scrollbar: true, + // 是否允许浏览器滚动条 + tips: 2 +}; + +// 容器 +Class.pt.vessel = function (conType, callback) { + var that = this, + times = that.index, + config = that.config; + var zIndex = config.zIndex + times, + titype = typeof config.title === 'object'; + var ismax = config.maxmin && (config.type === 1 || config.type === 2); + var titleHTML = config.title ? '
                  ' + (titype ? config.title[0] : config.title) + '
                  ' : ''; + config.zIndex = zIndex; + callback([ + // 遮罩 + config.shade ? '
                  ' : '', + // 主体 + '
                  ' + (conType && config.type != 2 ? '' : titleHTML) + + // 内容区 + '' + + // 表情或图标 + function () { + var face = ['layui-icon-tips', 'layui-icon-success', 'layui-icon-error', 'layui-icon-question', 'layui-icon-lock', 'layui-icon-face-cry', 'layui-icon-face-smile']; + var additFaceClass; + + // 动画类 + var animClass = 'layui-anim layui-anim-rotate layui-anim-loop'; + + // 信息框表情 + if (config.type == 0 && config.icon !== -1) { + // 加载(加载图标) + if (config.icon == 16) { + additFaceClass = 'layui-icon layui-icon-loading ' + animClass; + } + return ''; + } + + // 加载层图标 + if (config.type == 3) { + var type = ['layui-icon-loading', 'layui-icon-loading-1']; + // 风格 2 + if (config.icon == 2) { + return '
                  '; + } + return ''; + } + return ''; + }() + (config.type == 1 && conType ? '' : config.content || '') + '
                  ' + + // 右上角按钮 + '
                  ' + function () { + var arr = []; + + // 最小化、最大化 + if (ismax) { + arr.push(''); + arr.push(''); + } + + // 关闭按钮 + if (config.closeBtn) { + arr.push(''); + } + return arr.join(''); + }() + '
                  ' + ( + // 底部按钮 + config.btn ? function () { + var button = ''; + typeof config.btn === 'string' && (config.btn = [config.btn]); + for (var i = 0, len = config.btn.length; i < len; i++) { + button += '' + config.btn[i] + ''; + } + return '
                  ' + button + '
                  '; + }() : '') + (config.resize ? '' : '') + '
                  '], titleHTML, $('
                  ')); + return that; +}; + +// 创建骨架 +Class.pt.creat = function () { + var that = this; + var config = that.config; + var times = that.index; + var content = config.content; + var conType = typeof content === 'object'; + var body = $('body'); + var setAnim = function (layero) { + // anim 兼容旧版 shift + if (config.shift) { + config.anim = config.shift; + } + + // 为兼容 jQuery3.0 的 css 动画影响元素尺寸计算 + if (doms.anim[config.anim]) { + var animClass = 'layer-anim ' + doms.anim[config.anim]; + layero.addClass(animClass).one('webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', function () { + $(this).removeClass(animClass); + }); + } + }; + + // 若 id 对应的弹层已经存在,则不重新创建 + if (config.id && $('.' + doms[0]).find('#' + config.id)[0]) { + return function () { + var layero = $('#' + config.id).closest('.' + doms[0]); + var index = layero.attr('times'); + var options = layero.data('config'); + var elemShade = $('#' + doms.SHADE + index); + var maxminStatus = layero.data('maxminStatus') || {}; + // 若弹层为最小化状态,则点击目标元素时,自动还原 + if (maxminStatus === 'min') { + layer.restore(index); + } else if (options.hideOnClose) { + elemShade.show(); + layero.show(); + setAnim(layero); + setTimeout(function () { + elemShade.css({ + opacity: elemShade.data(SHADE_KEY) + }); + }, 10); + } + }(); + } + + // 是否移除活动元素的焦点 + if (config.removeFocus && document.activeElement) { + document.activeElement.blur(); // 将原始的聚焦节点失焦 + } + + // 初始化 area 属性 + if (typeof config.area === 'string') { + config.area = config.area === 'auto' ? ['', ''] : [config.area, '']; + } + switch (config.type) { + case 0: + config.btn = 'btn' in config ? config.btn : i18n.$t('layer.confirm'); + layer.closeAll('dialog'); + break; + case 2: + content = config.content = conType ? config.content : [config.content || '', 'auto']; + config.content = ''; + break; + case 3: + delete config.title; + delete config.closeBtn; + config.icon === -1 && config.icon === 0; + layer.closeAll('loading'); + break; + case 4: + conType || (config.content = [config.content, 'body']); + config.follow = config.content[1]; + config.content = config.content[0] + ''; + delete config.title; + config.tips = typeof config.tips === 'object' ? config.tips : [config.tips, true]; + config.tipsMore || layer.closeAll('tips'); + break; + } + + // 建立容器 + that.vessel(conType, function (html, titleHTML, moveElem) { + body.append(html[0]); + conType ? function () { + config.type == 2 || config.type == 4 ? function () { + $('body').append(html[1]); + }() : function () { + if (!content.parents('.' + doms[0])[0]) { + content.data('display', content.css('display')).show().addClass('layui-layer-wrap').wrap(html[1]); + $('#' + doms[0] + times).find('.' + doms[5]).before(titleHTML); + } + }(); + }() : body.append(html[1]); + $('#' + doms.MOVE)[0] || body.append(ready.moveElem = moveElem); + that.layero = $('#' + doms[0] + times); + that.shadeo = $('#' + doms.SHADE + times); + config.scrollbar || ready.setScrollbar(times); + }).auto(times); + + // 遮罩 + that.shadeo.css({ + 'background-color': config.shade[1] || '#000', + opacity: config.shade[0] || config.shade, + transition: config.shade[2] || '' + }); + that.shadeo.data(SHADE_KEY, config.shade[0] || config.shade); + + // 坐标自适应浏览器窗口尺寸 + config.type == 4 ? that.tips() : function () { + that.offset(); + // 首次弹出时,若 css 尚未加载,则等待 css 加载完毕后,重新设定尺寸 + parseInt(ready.getStyle(document.getElementById(doms.MOVE), 'z-index')) || function () { + that.layero.css('visibility', 'hidden'); + layer.ready(function () { + that.offset(); + that.layero.css('visibility', 'visible'); + }); + }(); + }(); + + // 若是固定定位,则跟随 resize 事件来自适应坐标 + if (config.fixed) { + if (!ready.events.resize[that.index]) { + ready.events.resize[that.index] = function () { + that.resize(); + }; + // 此处 resize 事件不会一直叠加,当关闭弹层时会移除该事件 + win.on('resize', ready.events.resize[that.index]); + } + } + + // 记录配置信息 + that.layero.data('config', config); + + // 自动关闭 + config.time <= 0 || setTimeout(function () { + layer.close(that.index); + }, config.time); + that.move().callback(); + setAnim(that.layero); +}; + +// 当前实例的 resize 事件 +Class.pt.resize = function () { + var that = this; + var config = that.config; + that.offset(); + (/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) && that.auto(that.index); + config.type == 4 && that.tips(); +}; + +// 自适应 +Class.pt.auto = function (index) { + var that = this, + config = that.config, + layero = $('#' + doms[0] + index); + if ((config.area[0] === '' || config.area[0] === 'auto') && config.maxWidth > 0) { + layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth); + } + var area = [layero.innerWidth(), layero.innerHeight()]; + var titHeight = layero.find(doms[1]).outerHeight() || 0; + var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + var setHeight = function (elem) { + elem = layero.find(elem); + elem.height(area[1] - titHeight - btnHeight - 2 * (parseFloat(elem.css('padding-top')) | 0)); + }; + switch (config.type) { + case 2: + setHeight('iframe'); + break; + default: + if (config.area[1] === '' || config.area[1] === 'auto') { + if (config.maxHeight > 0 && layero.outerHeight() > config.maxHeight) { + area[1] = config.maxHeight; + setHeight('.' + doms[5]); + } else if (config.fixed && area[1] >= win.height()) { + area[1] = win.height(); + setHeight('.' + doms[5]); + } + } else { + setHeight('.' + doms[5]); + } + break; + } + return that; +}; + +// 计算坐标 +Class.pt.offset = function () { + var that = this, + config = that.config, + layero = that.layero; + var coords = ready.updatePosition(layero, config); + that.offsetTop = coords.offsetTop; + that.offsetLeft = coords.offsetLeft; +}; + +// Tips +Class.pt.tips = function () { + var that = this, + config = that.config, + layero = that.layero; + var layArea = [layero.outerWidth(), layero.outerHeight()], + follow = $(config.follow); + if (!follow[0]) follow = $('body'); + var goal = { + width: follow.outerWidth(), + height: follow.outerHeight(), + top: follow.offset().top, + left: follow.offset().left + }, + tipsG = layero.find('.layui-layer-TipsG'); + var guide = config.tips[0]; + config.tips[1] || tipsG.remove(); + goal.autoLeft = function () { + if (goal.left + layArea[0] - win.width() > 0) { + goal.tipLeft = goal.left + goal.width - layArea[0]; + tipsG.css({ + right: 12, + left: 'auto' + }); + } else { + goal.tipLeft = goal.left - (goal.width * 0.75 < 21 ? 21 - goal.width * 0.5 : 0); + goal.tipLeft = Math.max(goal.tipLeft, 0); + } + }; + + // 辨别 tips 的方位 + // 21 为箭头大小 8*2 + 箭头相对父元素的top偏移 5 + goal.where = [function () { + // 上 + goal.autoLeft(); + goal.tipTop = goal.top - layArea[1] - 10; + tipsG.removeClass('layui-layer-TipsB').addClass('layui-layer-TipsT').css('border-right-color', config.tips[1]); + }, function () { + // 右 + goal.tipLeft = goal.left + goal.width + 10; + goal.tipTop = goal.top - (goal.height * 0.75 < 21 ? 21 - goal.height * 0.5 : 0); + goal.tipTop = Math.max(goal.tipTop, 0); + tipsG.removeClass('layui-layer-TipsL').addClass('layui-layer-TipsR').css('border-bottom-color', config.tips[1]); + }, function () { + // 下 + goal.autoLeft(); + goal.tipTop = goal.top + goal.height + 10; + tipsG.removeClass('layui-layer-TipsT').addClass('layui-layer-TipsB').css('border-right-color', config.tips[1]); + }, function () { + // 左 + goal.tipLeft = goal.left - layArea[0] - 10; + goal.tipTop = goal.top - (goal.height * 0.75 < 21 ? 21 - goal.height * 0.5 : 0); + goal.tipTop = Math.max(goal.tipTop, 0); + tipsG.removeClass('layui-layer-TipsR').addClass('layui-layer-TipsL').css('border-bottom-color', config.tips[1]); + }]; + goal.where[guide - 1](); + + /* 8*2为小三角形占据的空间 */ + if (guide === 1) { + goal.top - (win.scrollTop() + layArea[1] + 8 * 2) < 0 && goal.where[2](); + } else if (guide === 2) { + win.width() - (goal.left + goal.width + layArea[0] + 8 * 2) > 0 || goal.where[3](); + } else if (guide === 3) { + goal.top - win.scrollTop() + goal.height + layArea[1] + 8 * 2 - win.height() > 0 && goal.where[0](); + } else if (guide === 4) { + layArea[0] + 8 * 2 - goal.left > 0 && goal.where[1](); + } + layero.find('.' + doms[5]).css({ + 'background-color': config.tips[1], + 'padding-right': config.closeBtn ? '30px' : '' + }); + layero.css({ + left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0), + top: goal.tipTop - (config.fixed ? win.scrollTop() : 0) + }); +}; + +// 拖拽层 +Class.pt.move = function () { + var that = this; + var config = that.config; + var _DOC = $(document); + var layero = that.layero; + var DATA_NAME = ['LAY_MOVE_DICT', 'LAY_RESIZE_DICT']; + var moveElem = layero.find(config.move); + var resizeElem = layero.find('.layui-layer-resize'); + + // 给指定元素添加拖动光标 + if (config.move) moveElem.css('cursor', 'move'); + + // 按下拖动元素 + moveElem.on('mousedown', function (e) { + if (e.button) { + return; + } // 不是左键不处理 + var othis = $(this); + var dict = {}; + if (config.move) { + dict.layero = layero; + dict.config = config; + dict.offset = [e.clientX - parseFloat(layero.css('left')), e.clientY - parseFloat(layero.css('top'))]; + othis.data(DATA_NAME[0], dict); + ready.eventMoveElem = othis; + ready.moveElem.css('cursor', 'move').show(); + } + e.preventDefault(); + }); + + // 按下右下角拉伸 + resizeElem.on('mousedown', function (e) { + var othis = $(this); + var dict = {}; + if (config.resize) { + dict.layero = layero; + dict.config = config; + dict.offset = [e.clientX, e.clientY]; + dict.index = that.index; + dict.area = [layero.outerWidth(), layero.outerHeight()]; + othis.data(DATA_NAME[1], dict); + ready.eventResizeElem = othis; + ready.moveElem.css('cursor', 'se-resize').show(); + } + e.preventDefault(); + }); + + // 拖动元素,避免多次调用实例造成事件叠加 + if (ready.docEvent) return that; + _DOC.on('mousemove', function (e) { + var dict, config, X, Y; + + // 拖拽移动 + if (ready.eventMoveElem) { + dict = ready.eventMoveElem.data(DATA_NAME[0]) || {}; + config = dict.config; + X = e.clientX - dict.offset[0]; + Y = e.clientY - dict.offset[1]; + var layero = dict.layero; + var fixed = layero.css('position') === 'fixed'; + e.preventDefault(); + dict.stX = fixed ? 0 : win.scrollLeft(); + dict.stY = fixed ? 0 : win.scrollTop(); + + // 控制元素不被拖出窗口外 + if (!config.moveOut) { + var setRig = win.width() - layero.outerWidth() + dict.stX; + var setBot = win.height() - layero.outerHeight() + dict.stY; + X < dict.stX && (X = dict.stX); + X > setRig && (X = setRig); + Y < dict.stY && (Y = dict.stY); + Y > setBot && (Y = setBot); + } + + // 拖动时跟随鼠标位置 + layero.css({ + left: X, + top: Y + }); + } + + // Resize + if (ready.eventResizeElem) { + dict = ready.eventResizeElem.data(DATA_NAME[1]) || {}; + config = dict.config; + X = e.clientX - dict.offset[0]; + Y = e.clientY - dict.offset[1]; + e.preventDefault(); + + // 拉伸宽高 + layer.style(dict.index, { + width: dict.area[0] + X, + height: dict.area[1] + Y + }); + config.resizing && config.resizing(dict.layero); + } + }).on('mouseup', function () { + if (ready.eventMoveElem) { + var dict = ready.eventMoveElem.data(DATA_NAME[0]) || {}; + var config = dict.config; + ready.eventMoveElem.removeData(DATA_NAME[0]); + delete ready.eventMoveElem; + ready.moveElem.hide(); + config.moveEnd && config.moveEnd(dict.layero); + } + if (ready.eventResizeElem) { + ready.eventResizeElem.removeData(DATA_NAME[1]); + delete ready.eventResizeElem; + ready.moveElem.hide(); + } + }); + ready.docEvent = true; // 已给 document 执行全局事件 + return that; +}; +Class.pt.btnLoading = function (btnElem, isLoading) { + if (isLoading) { + var loadingTpl = ''; + if (btnElem.find('.layui-layer-btn-loading-icon')[0]) return; + btnElem.addClass('layui-layer-btn-is-loading').attr({ + disabled: '' + }).prepend(loadingTpl); + } else { + btnElem.removeClass('layui-layer-btn-is-loading').removeAttr('disabled').find('.layui-layer-btn-loading-icon').remove(); + } +}; +Class.pt.callback = function () { + var that = this, + layero = that.layero, + config = that.config; + that.openLayer(); + if (config.success) { + if (config.type == 2) { + layero.find('iframe').on('load', function () { + config.success(layero, that.index, that); + }); + } else { + config.success(layero, that.index, that); + } + } + + // 按钮 + layero.find('.' + doms[6]).children('a').on('click', function () { + var btnElem = $(this); + var index = btnElem.index(); + if (btnElem.attr('disabled')) return; + + // 若为异步按钮 + if (config.btnAsync) { + var btnCallback = index === 0 ? config.yes || config['btn1'] : config['btn' + (index + 1)]; + that.loading = function (isLoading) { + that.btnLoading(btnElem, isLoading); + }; + if (btnCallback) { + ready.promiseLikeResolve(btnCallback.call(config, that.index, layero, that)).then(function (result) { + if (result !== false) { + layer.close(that.index); + } + }, function (reason) { + reason !== undefined && window.console && window.console.error('layer error hint: ' + reason); + }); + } else { + layer.close(that.index); + } + } else { + // 普通按钮 + if (index === 0) { + if (config.yes) { + config.yes(that.index, layero, that); + } else if (config['btn1']) { + config['btn1'](that.index, layero, that); + } else { + layer.close(that.index); + } + } else { + var close = config['btn' + (index + 1)] && config['btn' + (index + 1)](that.index, layero, that); + close === false || layer.close(that.index); + } + } + }); + + // 取消 + function cancel() { + var close = config.cancel && config.cancel(that.index, layero, that); + close === false || layer.close(that.index); + } + + // 右上角关闭回调 + layero.find('.' + doms[7]).on('click', cancel); + + // 点遮罩关闭 + if (config.shadeClose) { + that.shadeo.on('click', function () { + layer.close(that.index); + }); + } + + // 最小化 + layero.find('.layui-layer-min').on('click', function () { + var min = config.min && config.min(layero, that.index, that); + min === false || layer.min(that.index, config); + }); + + // 全屏/还原 + layero.find('.layui-layer-max').on('click', function () { + if ($(this).hasClass('layui-layer-maxmin')) { + layer.restore(that.index); + config.restore && config.restore(layero, that.index, that); + } else { + layer.full(that.index, config); + setTimeout(function () { + config.full && config.full(layero, that.index, that); + }, 100); + } + }); + config.end && (ready.end[that.index] = config.end); + config.beforeEnd && (ready.beforeEnd[that.index] = $.proxy(config.beforeEnd, config, layero, that.index, that)); +}; + +// 需依赖原型的对外方法 +Class.pt.openLayer = function () { + var that = this; + + // 置顶当前窗口 + layer.zIndex = that.config.zIndex; + layer.setTop = function (layero) { + var setZindex = function () { + layer.zIndex++; + layero.css('z-index', layer.zIndex + 1); + }; + layer.zIndex = parseInt(layero[0].style.zIndex); + layero.on('mousedown', setZindex); + return layer.zIndex; + }; +}; + +// 记录宽高坐标,用于还原 +ready.record = function (layero) { + if (!layero[0]) return window.console && console.error('index error'); + var type = layero.attr('type'); + var contentElem = layero.find('.layui-layer-content'); + var contentRecordHeightElem = type === ready.type[2] ? contentElem.children('iframe') : contentElem; + var area = [layero[0].style.width || ready.getStyle(layero[0], 'width'), layero[0].style.height || ready.getStyle(layero[0], 'height'), layero.position().top, layero.position().left + parseFloat(layero.css('margin-left'))]; + layero.find('.layui-layer-max').addClass('layui-layer-maxmin'); + layero.attr({ + area: area + }); + contentElem.data(RECORD_HEIGHT_KEY, ready.getStyle(contentRecordHeightElem[0], 'height')); +}; + +// 设置页面滚动条 +ready.setScrollbar = function () { + doms.html.css('overflow', 'hidden'); +}; + +// 恢复页面滚动条 +ready.restScrollbar = function (index) { + if (!doms.html.css('overflow')) return; + + // 关闭和大小化, layer-full 处理 + var targetEl = $('.' + doms[0]).filter(function () { + var layero = $(this); + var options = layero.data('config') || {}; + return options.scrollbar === false && layero.data('maxminStatus') !== 'min' && layero.attr('times') !== String(index); + }); + if (targetEl.length === 0) { + doms.html.css('overflow', ''); + } +}; + +// 类似 Promise.resolve +ready.promiseLikeResolve = function (value) { + var deferred = $.Deferred(); + if (value && typeof value.then === 'function') { + value.then(deferred.resolve, deferred.reject); + } else { + deferred.resolve(value); + } + return deferred.promise(); +}; +ready.updatePosition = function (layero, config) { + var area = [layero.outerWidth(), layero.outerHeight()]; + var coords = { + offsetTop: (win.height() - area[1]) / 2, + offsetLeft: (win.width() - area[0]) / 2 + }; + if (typeof config.offset === 'object') { + coords.offsetTop = config.offset[0]; + coords.offsetLeft = config.offset[1] || coords.offsetLeft; + } else if (config.offset !== 'auto') { + if (config.offset === 't') { + // 上 + coords.offsetTop = 0; + } else if (config.offset === 'r') { + // 右 + coords.offsetLeft = win.width() - area[0]; + } else if (config.offset === 'b') { + // 下 + coords.offsetTop = win.height() - area[1]; + } else if (config.offset === 'l') { + // 左 + coords.offsetLeft = 0; + } else if (config.offset === 'lt') { + // 左上 + coords.offsetTop = 0; + coords.offsetLeft = 0; + } else if (config.offset === 'lb') { + // 左下 + coords.offsetTop = win.height() - area[1]; + coords.offsetLeft = 0; + } else if (config.offset === 'rt') { + // 右上 + coords.offsetTop = 0; + coords.offsetLeft = win.width() - area[0]; + } else if (config.offset === 'rb') { + // 右下 + coords.offsetTop = win.height() - area[1]; + coords.offsetLeft = win.width() - area[0]; + } else { + coords.offsetTop = config.offset; + } + } + if (!config.fixed) { + coords.offsetTop = /%$/.test(coords.offsetTop) ? win.height() * parseFloat(coords.offsetTop) / 100 : parseFloat(coords.offsetTop); + coords.offsetLeft = /%$/.test(coords.offsetLeft) ? win.width() * parseFloat(coords.offsetLeft) / 100 : parseFloat(coords.offsetLeft); + coords.offsetTop += win.scrollTop(); + coords.offsetLeft += win.scrollLeft(); + } + + // 最小化窗口时的自适应 + if (layero.data('maxminStatus') === 'min') { + coords.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0); + coords.offsetLeft = layero.css('left'); + } + + // 设置坐标 + layero.css({ + top: coords.offsetTop, + left: coords.offsetLeft + }); + return coords; +}; + +/** + * 外部方法 + */ + +// 获取子 iframe 的 DOM +layer.getChildFrame = function (selector, index) { + index = index || $('.' + doms[4]).attr('times'); + return $('#' + doms[0] + index).find('iframe').contents().find(selector); +}; + +// 得到当前 iframe 层的索引,子 iframe 时使用 +layer.getFrameIndex = function (name) { + if (!name) return; + return $('#' + name).parents('.' + doms[4]).attr('times'); +}; + +// iframe 层自适应宽高 +layer.iframeAuto = function (index) { + if (!index) return; + var layero = $('#' + doms[0] + index); + var options = layero.data('config'); + var iframeHeight = layer.getChildFrame('html', index).outerHeight(); + var titleHeight = layero.find(doms[1]).outerHeight() || 0; + var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + var maxHeight = 'maxHeight' in options ? options.maxHeight : win.height(); + if (maxHeight) { + iframeHeight = Math.min(iframeHeight, maxHeight - titleHeight - btnHeight); + } + layero.css({ + height: iframeHeight + titleHeight + btnHeight + }); + layero.find('iframe').css({ + height: iframeHeight + }); + ready.updatePosition(layero, options); +}; + +// 重置 iframe url +layer.iframeSrc = function (index, url) { + $('#' + doms[0] + index).find('iframe').attr('src', url); +}; + +// 设定层的样式 +layer.style = function (index, options, limit) { + var layero = $('#' + doms[0] + index); + var contentElem = layero.find('.layui-layer-content'); + var type = layero.attr('type'); + var titHeight = layero.find(doms[1]).outerHeight() || 0; + var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + // var minLeft = layero.attr('minLeft'); + + // loading 和 tips 层不允许更改 + if (type === ready.type[3] || type === ready.type[4]) { + return; + } + if (!limit) { + if (parseFloat(options.width) <= 260) { + options.width = 260; + } + if (parseFloat(options.height) - titHeight - btnHeight <= 64) { + options.height = 64 + titHeight + btnHeight; + } + } + layero.css(options); + btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + if (type === ready.type[2]) { + layero.find('iframe').css({ + height: (typeof options.height === 'number' ? options.height : layero.height()) - titHeight - btnHeight + }); + } else { + contentElem.css({ + height: (typeof options.height === 'number' ? options.height : layero.height()) - titHeight - btnHeight - parseFloat(contentElem.css('padding-top')) - parseFloat(contentElem.css('padding-bottom')) + }); + } +}; + +// 最小化 +layer.min = function (index, options) { + var layero = $('#' + doms[0] + index); + var maxminStatus = layero.data('maxminStatus'); + if (maxminStatus === 'min') return; // 当前的状态是否已经是最小化 + if (maxminStatus === 'max') layer.restore(index); // 若当前为最大化,则先还原后再最小化 + + layero.data('maxminStatus', 'min'); + options = options || layero.data('config') || {}; + var shadeo = $('#' + doms.SHADE + index); + var elemMin = layero.find('.layui-layer-min'); + var titHeight = layero.find(doms[1]).outerHeight() || 0; + var minLeft = layero.attr('minLeft'); // 最小化时的横坐标 + var hasMinLeft = typeof minLeft === 'string'; // 是否已经赋值过最小化坐标 + var left = hasMinLeft ? minLeft : 181 * ready.minStackIndex + 'px'; + var position = layero.css('position'); + var minWidth = 180; // 最小化时的宽度 + var settings = { + width: minWidth, + height: titHeight, + position: 'fixed', + overflow: 'hidden' + }; + ready.record(layero); // 记录当前尺寸、坐标,用于还原 + + // 简易最小化补位 + if (ready.minStackArr.length > 0) { + left = ready.minStackArr[0]; + ready.minStackArr.shift(); + } + + // left 是否超出边界 + if (parseFloat(left) + minWidth > win.width()) { + left = win.width() - minWidth - function () { + ready.minStackArr.edgeIndex = ready.minStackArr.edgeIndex || 0; + return ready.minStackArr.edgeIndex += 3; + }(); + if (left < 0) left = 0; + } + + // 是否堆叠在左下角 + if (options.minStack) { + settings.left = left; + settings.top = win.height() - titHeight; + hasMinLeft || ready.minStackIndex++; // 若未赋值过最小化坐标,则最小化操作索引自增 + layero.attr('minLeft', left); + } + layero.attr('position', position); + layer.style(index, settings, true); + elemMin.hide(); + layero.attr('type') === 'page' && layero.find(doms[4]).hide(); + ready.restScrollbar(index); + + // 隐藏遮罩 + shadeo.hide(); +}; + +// 还原 +layer.restore = function (index) { + var layero = $('#' + doms[0] + index); + var shadeo = $('#' + doms.SHADE + index); + var contentElem = layero.find('.layui-layer-content'); + var area = layero.attr('area').split(','); + var type = layero.attr('type'); + var options = layero.data('config') || {}; + var contentRecordHeight = contentElem.data(RECORD_HEIGHT_KEY); + layero.removeData('maxminStatus'); // 移除最大最小状态 + + // 恢复原来尺寸 + layer.style(index, { + width: area[0], + // 数值或百分比 + height: area[1], + top: parseFloat(area[2]), + left: parseFloat(area[3]), + position: layero.attr('position'), + overflow: 'visible' + }, true); + layero.find('.layui-layer-max').removeClass('layui-layer-maxmin'); + layero.find('.layui-layer-min').show(); + type === 'page' && layero.find(doms[4]).show(); + + // 恢复页面滚动条弹层打开时的状态 + options.scrollbar ? ready.restScrollbar(index) : ready.setScrollbar(index); + + // #1604 + if (contentRecordHeight !== undefined) { + contentElem.removeData(RECORD_HEIGHT_KEY); + var contentRecordHeightElem = type === ready.type[2] ? contentElem.children('iframe') : contentElem; + contentRecordHeightElem.css({ + height: contentRecordHeight + }); + } + + // 恢复遮罩 + shadeo.show(); + // ready.events.resize[index](); // ? +}; + +// 全屏(最大化) +layer.full = function (index) { + var layero = $('#' + doms[0] + index); + var maxminStatus = layero.data('maxminStatus'); + if (maxminStatus === 'max') return; // 检查当前的状态是否已经是最大化 + if (maxminStatus === 'min') layer.restore(index); // 若当前为最小化,则先还原后再最大化 + + layero.data('maxminStatus', 'max'); + ready.record(layero); // 记录当前尺寸、坐标 + + ready.setScrollbar(index); + setTimeout(function () { + var isfix = layero.css('position') === 'fixed'; + layer.style(index, { + top: isfix ? 0 : win.scrollTop(), + left: isfix ? 0 : win.scrollLeft(), + width: '100%', + height: '100%' + }, true); + layero.find('.layui-layer-min').hide(); + }, 100); +}; + +// 改变 title +layer.title = function (name, index) { + var title = $('#' + doms[0] + (index || layer.index)).find(doms[1]); + title.html(name); +}; + +// 关闭 layer 总方法 +layer.close = function (index, callback) { + var layero = function () { + var closest = $('.' + doms[0]).children('#' + index).closest('.' + doms[0]); + return closest[0] ? (index = closest.attr('times'), closest) : $('#' + doms[0] + index); + }(); + var type = layero.attr('type'); + var options = layero.data('config') || {}; + var hideOnClose = options.id && options.hideOnClose; // 是否关闭时移除弹层容器 + + if (!layero[0]) return; + var executor = function () { + // 关闭动画 + var closeAnim = { + slideDown: 'layer-anim-slide-down-out', + slideLeft: 'layer-anim-slide-left-out', + slideUp: 'layer-anim-slide-up-out', + slideRight: 'layer-anim-slide-right-out' + }[options.anim] || 'layer-anim-close'; + + // 移除主容器 + var remove = function () { + var WRAP = 'layui-layer-wrap'; + + // 是否关闭时隐藏弹层容器 + if (hideOnClose) { + layero.removeClass('layer-anim ' + closeAnim); + return layero.hide(); + } + + // 是否为页面捕获层 + if (type === ready.type[1] && layero.attr('conType') === 'object') { + layero.children(':not(.' + doms[5] + ')').remove(); + var wrap = layero.find('.' + WRAP); + for (var i = 0; i < 2; i++) { + wrap.unwrap(); + } + wrap.css('display', wrap.data('display')).removeClass(WRAP); + } else { + // 低版本 IE 回收 iframe + if (type === ready.type[2]) { + try { + var iframe = $('#' + doms[4] + index)[0]; + iframe.contentWindow.document.write(''); + iframe.contentWindow.close(); + layero.find('.' + doms[5])[0].removeChild(iframe); + } catch { + // ignore + } + } + layero[0].innerHTML = ''; + layero.remove(); + } + typeof ready.end[index] === 'function' && ready.end[index](); + delete ready.end[index]; + typeof callback === 'function' && callback(); + + // 移除 reisze 事件 + if (ready.events.resize[index]) { + win.off('resize', ready.events.resize[index]); + delete ready.events.resize[index]; + } + }; + // 移除遮罩 + var shadeo = $('#' + doms.SHADE + index); + if (layer.ie && layer.ie < 10 || !options.isOutAnim) { + shadeo[hideOnClose ? 'hide' : 'remove'](); + } else { + shadeo.css({ + opacity: 0 + }); + setTimeout(function () { + shadeo[hideOnClose ? 'hide' : 'remove'](); + }, 350); + } + + // 是否允许关闭动画 + if (options.isOutAnim) { + layero.addClass('layer-anim ' + closeAnim); + } + ready.restScrollbar(index); + + // 记住被关闭层的最小化堆叠坐标 + if (typeof layero.attr('minLeft') === 'string') { + ready.minStackIndex--; + ready.minStackArr.push(layero.attr('minLeft')); + } + if (layer.ie && layer.ie < 10 || !options.isOutAnim) { + remove(); + } else { + setTimeout(function () { + remove(); + }, 200); + } + }; + if (!hideOnClose && typeof ready.beforeEnd[index] === 'function') { + ready.promiseLikeResolve(ready.beforeEnd[index]()).then(function (result) { + if (result !== false) { + delete ready.beforeEnd[index]; + executor(); + } + }, function (reason) { + reason !== undefined && window.console && window.console.error('layer error hint: ' + reason); + }); + } else { + delete ready.beforeEnd[index]; + executor(); + } +}; + +// 关闭所有层 +layer.closeAll = function (type, callback) { + if (typeof type === 'function') { + callback = type; + type = null; + } + var domsElem = $('.' + doms[0]); + $.each(domsElem, function (_index) { + var othis = $(this); + var is = type ? othis.attr('type') === type : 1; + is && layer.close(othis.attr('times'), _index === domsElem.length - 1 ? callback : null); + is = null; + }); + if (domsElem.length === 0) typeof callback === 'function' && callback(); +}; + +// 根据弹层类型关闭最近打开的层 +layer.closeLast = function (type, callback) { + var layerIndexList = []; + var isArrayType = $.isArray(type); + $(typeof type === 'string' ? '.layui-layer-' + type : '.layui-layer').each(function (i, el) { + var layero = $(el); + var shouldSkip = isArrayType && type.indexOf(layero.attr('type')) === -1 || layero.css('display') === 'none'; + if (shouldSkip) return true; + layerIndexList.push(Number(layero.attr('times'))); + }); + if (layerIndexList.length > 0) { + var layerIndexMax = Math.max.apply(null, layerIndexList); + layer.close(layerIndexMax, callback); + } +}; + +/* + * 拓展模块,layui 开始合并在一起 + */ + +var cache = layer.cache || {}; +var skin = function (type) { + return cache.skin ? ' ' + cache.skin + ' ' + cache.skin + '-' + type : ''; +}; + +// 仿系统 prompt +layer.prompt = function (options, yes) { + var style = ''; + var placeholder = ''; + options = options || {}; + + // 兼容旧版参数 + var legacyTypeMap = { + 0: 'text', + 1: 'password', + 2: 'textarea' + }; + if (options.formType in legacyTypeMap) { + options.formType = legacyTypeMap[options.formType]; + } + if (typeof options === 'function') yes = options; + if (options.area) { + var area = options.area; + style = 'style="width: ' + area[0] + '; height: ' + area[1] + ';"'; + delete options.area; + } + if (options.placeholder) { + placeholder = ' placeholder="' + options.placeholder + '"'; + } + var prompt; + var content = options.formType == 'textarea' ? '' : function () { + return ''; + }(); + var success = options.success; + delete options.success; + return layer.open($.extend({ + type: 1, + btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')], + content: content, + skin: 'layui-layer-prompt' + skin('prompt'), + maxWidth: win.width(), + success: function (layero) { + prompt = layero.find('.layui-layer-input'); + prompt.val(options.value || '').focus(); + typeof success === 'function' && success(layero); + }, + resize: false, + yes: function (index) { + var value = prompt.val(); + if (value.length > (options.maxlength || 500)) { + layer.tips(i18n.$t('layer.prompt.InputLengthPrompt', { + length: options.maxlength || 500 + }), prompt, { + tips: 1 + }); + } else { + yes && yes(value, index, prompt); + } + } + }, options)); +}; + +// tab 层 +layer.tab = function (options) { + options = options || {}; + var tab = options.tab || {}; + var THIS = 'layui-this'; + var success = options.success; + delete options.success; + return layer.open($.extend({ + type: 1, + skin: 'layui-layer-tab' + skin('tab'), + resize: false, + title: function () { + var len = tab.length, + ii = 1, + str = ''; + if (len > 0) { + str = '' + tab[0].title + ''; + for (; ii < len; ii++) { + str += '' + tab[ii].title + ''; + } + } + return str; + }(), + content: '
                    ' + function () { + var len = tab.length, + ii = 1, + str = ''; + if (len > 0) { + str = '
                  • ' + (tab[0].content || 'no content') + '
                  • '; + for (; ii < len; ii++) { + str += '
                  • ' + (tab[ii].content || 'no content') + '
                  • '; + } + } + return str; + }() + '
                  ', + success: function (layero) { + var btn = layero.find('.layui-layer-title').children(); + var main = layero.find('.layui-layer-tabmain').children(); + btn.on('mousedown', function (e) { + e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; + var othis = $(this), + index = othis.index(); + othis.addClass(THIS).siblings().removeClass(THIS); + main.eq(index).show().siblings().hide(); + typeof options.change === 'function' && options.change(index); + }); + typeof success === 'function' && success(layero); + } + }, options)); +}; + +// 图片层 +layer.photos = function (options, loop, key) { + var dict = {}; + + // 默认属性 + options = $.extend(true, { + toolbar: true, + footer: true + }, options); + if (!options.photos) return; + + // 若 photos 并非选择器或 jQuery 对象,则为普通 object + var isObject = !(typeof options.photos === 'string' || options.photos instanceof $); + var photos = isObject ? options.photos : {}; + var data = photos.data || []; + var start = photos.start || 0; + var success = options.success; + dict.imgIndex = (start | 0) + 1; + options.img = options.img || 'img'; + delete options.success; + + // 若 options.photos 不是一个对象 + if (!isObject) { + // 页面直接获取 + var parent = $(options.photos), + pushData = function () { + data = []; + parent.find(options.img).each(function (index) { + var othis = $(this); + othis.attr('layer-index', index); + data.push({ + alt: othis.attr('alt'), + pid: othis.attr('layer-pid'), + src: othis.attr('lay-src') || othis.attr('layer-src') || othis.attr('src'), + thumb: othis.attr('src') + }); + }); + }; + pushData(); + loop || parent.on('click', options.img, function () { + pushData(); + var othis = $(this), + index = othis.attr('layer-index'); + layer.photos($.extend(options, { + photos: { + start: index, + data: data, + tab: options.tab + }, + full: options.full + }), true); + }); + + // 不直接弹出 + if (!loop) return; + } else if (data.length === 0) { + return layer.msg(i18n.$t('layer.photos.noData')); + } + + // 上一张 + dict.imgprev = function (key) { + dict.imgIndex--; + if (dict.imgIndex < 1) { + dict.imgIndex = data.length; + } + dict.tabimg(key); + }; + + // 下一张 + dict.imgnext = function (key, errorMsg) { + dict.imgIndex++; + if (dict.imgIndex > data.length) { + dict.imgIndex = 1; + if (errorMsg) { + return; + } + } + dict.tabimg(key); + }; + + // 方向键 + dict.keyup = function (event) { + if (!dict.end) { + var code = event.keyCode; + event.preventDefault(); + if (code === 37) { + dict.imgprev(true); + } else if (code === 39) { + dict.imgnext(true); + } else if (code === 27) { + layer.close(dict.index); + } + } + }; + + // 切换 + dict.tabimg = function (key) { + if (data.length <= 1) return; + photos.start = dict.imgIndex - 1; + layer.close(dict.index); + return layer.photos(options, true, key); + }; + dict.isNumber = function (n) { + return typeof n === 'number' && !isNaN(n); + }; + dict.image = {}; + dict.getTransform = function (opts) { + var transforms = []; + var rotate = opts.rotate; + var scaleX = opts.scaleX; + var scale = opts.scale; + if (dict.isNumber(rotate) && rotate !== 0) { + transforms.push('rotate(' + rotate + 'deg)'); + } + if (dict.isNumber(scaleX) && scaleX !== 1) { + transforms.push('scaleX(' + scaleX + ')'); + } + if (dict.isNumber(scale)) { + transforms.push('scale(' + scale + ')'); + } + return transforms.length ? transforms.join(' ') : 'none'; + }; + + // 一些动作 + dict.event = function (layero, index, that) { + // 上一张 + dict.main.find('.layui-layer-photos-prev').on('click', function (event) { + event.preventDefault(); + dict.imgprev(true); + }); + + // 下一张 + dict.main.find('.layui-layer-photos-next').on('click', function (event) { + event.preventDefault(); + dict.imgnext(true); + }); + $(document).on('keyup', dict.keyup); + + // 头部工具栏事件 + layero.off('click').on('click', '*[toolbar-event]', function () { + var othis = $(this); + var event = othis.attr('toolbar-event'); + switch (event) { + case 'rotate': + dict.image.rotate = ((dict.image.rotate || 0) + Number(othis.attr('data-option'))) % 360; + dict.imgElem.css({ + transform: dict.getTransform(dict.image) + }); + break; + case 'scalex': + dict.image.scaleX = dict.image.scaleX === -1 ? 1 : -1; + dict.imgElem.css({ + transform: dict.getTransform(dict.image) + }); + break; + case 'zoom': + var ratio = Number(othis.attr('data-option')); + dict.image.scale = (dict.image.scale || 1) + ratio; + // 缩小状态最小值 + if (ratio < 0 && dict.image.scale < 0 - ratio) { + dict.image.scale = 0 - ratio; + } + dict.imgElem.css({ + transform: dict.getTransform(dict.image) + }); + break; + case 'reset': + dict.image.scaleX = 1; + dict.image.scale = 1; + dict.image.rotate = 0; + dict.imgElem.css({ + transform: 'none' + }); + break; + case 'close': + layer.close(index); + break; + } + that.offset(); + that.auto(index); + }); + + // 鼠标滚轮缩放图片事件 + dict.main.on('mousewheel DOMMouseScroll', function (e) { + var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail; + var zoomElem = dict.main.find('[toolbar-event="zoom"]'); + if (delta > 0) { + zoomElem.eq(0).trigger('click'); + } else { + zoomElem.eq(1).trigger('click'); + } + e.preventDefault(); + }); + + // 滑动切换图片事件 + var touchEndCallback = function (e, state) { + var duration = Date.now() - state.timeStart; + var speed = state.distanceX / duration; + var threshold = win.width() / 3; + var shouldSwipe = Math.abs(speed) > 0.25 || Math.abs(state.distanceX) > threshold; + if (!shouldSwipe) return; + if (state.direction === 'left') { + dict.imgnext(true); + } else if (state.direction === 'right') { + dict.imgprev(true); + } + }; + $.each([that.shadeo, dict.main], function (i, elem) { + lay.touchSwipe(elem, { + onTouchEnd: touchEndCallback + }); + }); + }; + + // 图片预加载 + function loadImage(url, callback, error) { + var img = new Image(); + img.src = url; + if (img.complete) { + return callback(img); + } + img.onload = function () { + img.onload = null; + callback(img); + }; + img.onerror = function (e) { + img.onerror = null; + error(e); + }; + } + dict.loadi = layer.load(1, { + shade: 'shade' in options ? false : [0.9, undefined, 'unset'], + scrollbar: false + }); + loadImage(data[start].src, function (img) { + layer.close(dict.loadi); + var alt = data[start].alt || ''; + + // 切换图片时不出现动画 + if (key) options.anim = -1; + + // 弹出图片层 + dict.index = layer.open($.extend({ + type: 1, + id: 'layui-layer-photos', + area: function () { + var imgarea = [img.width, img.height]; + var winarea = [$(window).width() - 100, $(window).height() - 100]; + + // 若实际图片的宽或者高比 屏幕大(那么进行缩放) + if (!options.full && (imgarea[0] > winarea[0] || imgarea[1] > winarea[1])) { + var wh = [imgarea[0] / winarea[0], imgarea[1] / winarea[1]]; // 取宽度缩放比例、高度缩放比例 + if (wh[0] > wh[1]) { + // 取缩放比例最大的进行缩放 + imgarea[0] = imgarea[0] / wh[0]; + imgarea[1] = imgarea[1] / wh[0]; + } else if (wh[0] < wh[1]) { + imgarea[0] = imgarea[0] / wh[1]; + imgarea[1] = imgarea[1] / wh[1]; + } + } + return [imgarea[0] + 'px', imgarea[1] + 'px']; + }(), + title: false, + shade: [0.9, undefined, 'unset'], + shadeClose: true, + closeBtn: false, + move: '.layer-layer-photos-main img', + moveType: 1, + scrollbar: false, + moveOut: true, + anim: 5, + isOutAnim: false, + skin: 'layui-layer-photos' + skin('photos'), + content: '
                  ' + '' + alt + '' + function () { + var arr = ['
                  ']; + + // 左右箭头翻页 + if (data.length > 1) { + arr.push(['
                  ', '', '', '
                  '].join('')); + } + + // 头部工具栏 + if (options.toolbar) { + arr.push(['
                  ', '', '', '', '', '', '', '
                  '].join('')); + } + + // 底部栏 + if (options.footer) { + arr.push([''].join('')); + } + arr.push('
                  '); + return arr.join(''); + }() + '
                  ', + success: function (layero, index, that) { + dict.main = layero.find('.layer-layer-photos-main'); + dict.footer = layero.find('.layui-layer-photos-footer'); + dict.imgElem = dict.main.children('img'); + dict.event(layero, index, that); + options.tab && options.tab(data[start], layero); + typeof success === 'function' && success(layero); + }, + end: function () { + dict.end = true; + $(document).off('keyup', dict.keyup); + } + }, options)); + }, function () { + layer.close(dict.loadi); + layer.msg('' + i18n.$t('layer.photos.urlError.prompt') + '', { + time: 30000, + btn: [i18n.$t('layer.photos.urlError.confirm'), i18n.$t('layer.photos.urlError.cancel')], + yes: function () { + data.length > 1 && dict.imgnext(true, true); + } + }); + }); +}; + +// 主入口 +ready.run = function (_$) { + var $ = _$; + win = $(window); + + // 移动端兼容性处理 + // https://gitee.com/layui/layui/issues/I81WGC + // https://github.com/jquery/jquery/issues/1729 + var agent = navigator.userAgent.toLowerCase(); + var isMobile = /android|iphone|ipod|ipad|ios/.test(agent); + var _win = $(window); + if (isMobile) { + $.each({ + Height: 'height', + Width: 'width' + }, function (propSuffix, funcName) { + var propName = 'inner' + propSuffix; + win[funcName] = function () { + return propName in window ? window[propName] : _win[funcName](); + }; + }); + } + doms.html = $('html'); + layer.open = function (deliver) { + var o = new Class(deliver); + return o.index; + }; +}; +layer.path = layui.cache.dir; +layer.ready(); +ready.run($); + +export { layer }; diff --git a/dist/components/laypage.js b/dist/components/laypage.js new file mode 100644 index 000000000..82a51aafb --- /dev/null +++ b/dist/components/laypage.js @@ -0,0 +1,290 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; + +/** + * laypage 分页组件 + */ + +var doc = document; +var id = 'getElementById'; +var tag = 'getElementsByTagName'; + +// 字符常量 +// var MOD_NAME = 'laypage'; +var DISABLED = 'layui-disabled'; + +// 构造器 +var Class = function (options) { + var that = this; + that.config = options || {}; + that.index = laypage.index = lay.autoIncrementer('laypage'); + that.render(true); +}; + +// 判断传入的容器类型 +Class.prototype.type = function () { + var config = this.config; + if (typeof config.elem === 'object') { + return config.elem.length === undefined ? 2 : 3; + } +}; + +// 分页视图 +Class.prototype.view = function () { + var that = this; + var config = that.config; + + // 连续页码个数 + var groups = config.groups = 'groups' in config ? Number(config.groups) || 0 : 5; + + // 排版 + config.layout = typeof config.layout === 'object' ? config.layout : ['prev', 'page', 'next']; + config.count = Number(config.count) || 0; // 数据总数 + config.curr = Number(config.curr) || 1; // 当前页 + + // 每页条数的选择项 + config.limits = typeof config.limits === 'object' ? config.limits : [10, 20, 30, 40, 50]; + + // 默认条数 + config.limit = Number(config.limit) || 10; + + // 总页数 + config.pages = Math.ceil(config.count / config.limit) || 1; + + // 当前页不能超过总页数 + if (config.curr > config.pages) { + config.curr = config.pages; + } else if (config.curr < 1) { + // 当前分页不能小于 1 + config.curr = 1; + } + + // 连续分页个数不能低于 0 且不能大于总页数 + if (groups < 0) { + groups = 1; + } else if (groups > config.pages) { + groups = config.pages; + } + config.prev = 'prev' in config ? config.prev : i18n.$t('laypage.prev'); // 上一页文本 + config.next = 'next' in config ? config.next : i18n.$t('laypage.next'); // 下一页文本 + + // 计算当前组 + var index = config.pages > groups ? Math.ceil((config.curr + (groups > 1 ? 1 : 0)) / (groups > 0 ? groups : 1)) : 1; + + // 视图片段 + var views = { + // 上一页 + prev: function () { + return config.prev ? '' + config.prev + '' : ''; + }(), + // 页码 + page: function () { + var pager = []; + + // 数据量为0时,不输出页码 + if (config.count < 1) { + return ''; + } + + // 首页 + if (index > 1 && config.first !== false && groups !== 0) { + pager.push('' + (config.first || 1) + ''); + } + + // 计算当前页码组的起始页 + var halve = Math.floor((groups - 1) / 2); // 页码数等分 + var start = index > 1 ? config.curr - halve : 1; + var end = index > 1 ? function () { + var max = config.curr + (groups - halve - 1); + return max > config.pages ? config.pages : max; + }() : groups; + + // 防止最后一组出现“不规定”的连续页码数 + if (end - start < groups - 1) { + start = end - groups + 1; + } + + // 输出左分割符 + if (config.first !== false && start > 2) { + pager.push('...'); + } + + // 输出连续页码 + for (; start <= end; start++) { + if (start === config.curr) { + // 当前页 + pager.push('' + start + ''); + } else { + pager.push('' + start + ''); + } + } + + // 输出输出右分隔符 & 末页 + if (config.pages > groups && config.pages > end && config.last !== false) { + if (end + 1 < config.pages) { + pager.push('...'); + } + if (groups !== 0) { + pager.push('' + (config.last || config.pages) + ''); + } + } + return pager.join(''); + }(), + // 下一页 + next: function () { + return config.next ? '' + config.next + '' : ''; + }(), + // 数据总数 + count: function () { + var countText = typeof config.countText === 'object' ? config.countText[0] + config.count + config.countText[1] : i18n.$t('laypage.total', { + total: config.count + }); + return '' + countText + ''; + }(), + // 每页条数 + limit: function () { + var elemArr = [''; + }(), + // 刷新当前页 + refresh: ['', '', ''].join(''), + // 跳页区域 + skip: function () { + var skipText = typeof config.skipText === 'object' ? config.skipText : [i18n.$t('laypage.goto'), i18n.$t('laypage.page'), i18n.$t('laypage.confirm')]; + return ['' + skipText[0], '', skipText[1] + '', ''].join(''); + }() + }; + return ['
                  ', function () { + var plate = []; + layui.each(config.layout, function (index, item) { + if (views[item]) { + plate.push(views[item]); + } + }); + return plate.join(''); + }(), '
                  '].join(''); +}; + +// 跳页的回调 +Class.prototype.jump = function (elem, isskip) { + if (!elem) return; + var that = this; + var config = that.config; + var childs = elem.children; + var btn = elem[tag]('button')[0]; + var input = elem[tag]('input')[0]; + var select = elem[tag]('select')[0]; + var skip = function () { + var curr = Number(input.value.replace(/\s|\D/g, '')); + if (curr) { + config.curr = curr; + that.render(); + } + }; + if (isskip) return skip(); + + // 页码 + for (var i = 0, len = childs.length; i < len; i++) { + if (childs[i].nodeName.toLowerCase() === 'a') { + laypage.on(childs[i], 'click', function () { + var curr = Number(this.getAttribute('data-page')); + if (curr < 1 || curr > config.pages) return; + config.curr = curr; + that.render(); + }); + } + } + + // 条数 + if (select) { + laypage.on(select, 'change', function () { + var value = this.value; + if (config.curr * value > config.count) { + config.curr = Math.ceil(config.count / value); + } + config.limit = value; + that.render(); + }); + } + + // 确定 + if (btn) { + laypage.on(btn, 'click', function () { + skip(); + }); + } +}; + +// 输入页数字控制 +Class.prototype.skip = function (elem) { + if (!elem) return; + var that = this; + var input = elem[tag]('input')[0]; + if (!input) return; + + // 键盘事件 + laypage.on(input, 'keyup', function (e) { + var value = this.value; + var keyCode = e.keyCode; + if (/^(37|38|39|40)$/.test(keyCode)) return; + if (/\D/.test(value)) { + this.value = value.replace(/\D/, ''); + } + if (keyCode === 13) { + that.jump(elem, true); + } + }); +}; + +// 渲染分页 +Class.prototype.render = function (load) { + var that = this; + var config = that.config; + var type = that.type(); + var view = that.view(); + if (type === 2) { + config.elem && (config.elem.innerHTML = view); + } else if (type === 3) { + config.elem.html(view); + } else { + if (doc[id](config.elem)) { + doc[id](config.elem).innerHTML = view; + } + } + config.jump && config.jump(config, load); + var elem = doc[id]('layui-laypage-' + that.index); + that.jump(elem); + if (config.hash && !load) { + location.hash = '!' + config.hash + '=' + config.curr; + } + that.skip(elem); +}; + +// 外部接口 +var laypage = { + // 分页渲染 + render: function (options) { + var o = new Class(options); + return o.index; + }, + on: function (elem, even, fn) { + elem.attachEvent ? elem.attachEvent('on' + even, function (e) { + // for ie + e.target = e.srcElement; + fn.call(elem, e); + }) : elem.addEventListener(even, fn, false); + return this; + } +}; + +export { laypage }; diff --git a/dist/components/nav.js b/dist/components/nav.js new file mode 100644 index 000000000..378999df3 --- /dev/null +++ b/dist/components/nav.js @@ -0,0 +1,232 @@ +import { layui } from '../core/layui.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * nav + * 导航菜单组件 + */ + +var device = layui.device(); +var SUPER_MOD_NAME = 'element'; // 所属的超级模块名,确保向下兼容 + +// 创建组件 +var component = component$1({ + name: 'nav', + // 组件名 + + // 默认配置 + config: { + elem: '.layui-nav' + }, + CONST: { + NAV_ELEM: '.layui-nav', + NAV_ITEM: 'layui-nav-item', + NAV_BAR: 'layui-nav-bar', + NAV_TREE: 'layui-nav-tree', + NAV_CHILD: 'layui-nav-child', + NAV_CHILD_C: 'layui-nav-child-c', + NAV_MORE: 'layui-nav-more', + NAV_DOWN: 'layui-icon-down', + NAV_ANIM: 'layui-anim layui-anim-upbit' + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + var TIME = 200; + var timer = {}; + var timerMore = {}; + var timeEnd = {}; + var NAV_TITLE = 'layui-nav-title'; + + // 滑块跟随 + var follow = function (bar, nav, index) { + var othis = $(this); + var child = othis.find('.' + CONST.NAV_CHILD); + + // 是否垂直导航菜单 + if (nav.hasClass(CONST.NAV_TREE)) { + // 无子菜单时跟随 + if (!child[0]) { + var thisA = othis.children('.' + NAV_TITLE); + bar.css({ + top: othis.offset().top - nav.offset().top + nav.scrollTop(), + height: (thisA[0] ? thisA : othis).outerHeight(), + opacity: 1 + }); + } + } else { + child.addClass(CONST.NAV_ANIM); + + // 若居中对齐 + if (child.hasClass(CONST.NAV_CHILD_C)) { + child.css({ + left: -(child.outerWidth() - othis.width()) / 2 + }); + } + + // 滑块定位 + if (child[0]) { + // 若有子菜单,则滑块消失 + bar.css({ + left: bar.position().left + bar.width() / 2, + width: 0, + opacity: 0 + }); + } else { + // bar 跟随 + bar.css({ + left: othis.position().left + parseFloat(othis.css('marginLeft')), + top: othis.position().top + othis.height() - bar.height() + }); + } + + // 渐显滑块并适配宽度 + timer[index] = setTimeout(function () { + bar.css({ + width: child[0] ? 0 : othis.width(), + opacity: child[0] ? 0 : 1 + }); + }, device.ie && device.ie < 10 ? 0 : TIME); + + // 显示子菜单 + clearTimeout(timeEnd[index]); + if (child.css('display') === 'block') { + clearTimeout(timerMore[index]); + } + timerMore[index] = setTimeout(function () { + child.addClass(CONST.CLASS_SHOW); + othis.find('.' + CONST.NAV_MORE).addClass(CONST.NAV_MORE + 'd'); + }, 300); + } + }; + + // 遍历导航 + options.elem.each(function (index) { + var othis = $(this); + var bar = $(''); + var itemElem = othis.find('.' + CONST.NAV_ITEM); + + // hover 滑动效果 + var hasBarElem = othis.find('.' + CONST.NAV_BAR); + if (hasBarElem[0]) hasBarElem.remove(); + othis.append(bar); + (othis.hasClass(CONST.NAV_TREE) ? itemElem.find('dd,>.' + CONST.NAV_TITLE) : itemElem).off('mouseenter.lay_nav').on('mouseenter.lay_nav', function () { + follow.call(this, bar, othis, index); + }).off('mouseleave.lay_nav').on('mouseleave.lay_nav', function () { + // 鼠标移出 + // 是否为垂直导航 + if (othis.hasClass(CONST.NAV_TREE)) { + bar.css({ + height: 0, + opacity: 0 + }); + } else { + // 隐藏子菜单 + clearTimeout(timerMore[index]); + timerMore[index] = setTimeout(function () { + othis.find('.' + CONST.NAV_CHILD).removeClass(CONST.CLASS_SHOW); + othis.find('.' + CONST.NAV_MORE).removeClass(CONST.NAV_MORE + 'd'); + }, 300); + } + }); + + // 鼠标离开当前菜单时 + othis.off('mouseleave.lay_nav').on('mouseleave.lay_nav', function () { + clearTimeout(timer[index]); + timeEnd[index] = setTimeout(function () { + if (!othis.hasClass(CONST.NAV_TREE)) { + bar.css({ + width: 0, + left: bar.position().left + bar.width() / 2, + opacity: 0 + }); + } + }, TIME); + }); + + // 展开子菜单 + itemElem.find('a').each(function () { + var thisA = $(this); + var child = thisA.siblings('.' + CONST.NAV_CHILD); + var clickEventName = 'click.lay_nav_click'; + + // 输出小箭头 + if (child[0] && !thisA.children('.' + CONST.NAV_MORE)[0]) { + thisA.append(''); + } + + // 点击菜单 + thisA.off(clickEventName, events.clickThis).on(clickEventName, events.clickThis); + }); + }); + } +}); +var events = { + // 点击当前菜单 - a 标签触发 + clickThis: function () { + var othis = $(this); + var parents = othis.closest(CONST.NAV_ELEM); + var filter = parents.attr('lay-filter'); + var parent = othis.parent(); + var child = othis.siblings('.' + CONST.NAV_CHILD); + var unselect = typeof parent.attr('lay-unselect') === 'string'; // 是否禁用选中 + + // 满足点击选中的条件 + if (!(othis.attr('href') !== 'javascript:;' && othis.attr('target') === '_blank') && !unselect) { + if (!child[0]) { + parents.find('.' + CONST.CLASS_THIS).removeClass(CONST.CLASS_THIS); + parent.addClass(CONST.CLASS_THIS); + } + } + + // 若为垂直菜单 + if (parents.hasClass(CONST.NAV_TREE)) { + var NAV_ITEMED = CONST.NAV_ITEM + 'ed'; // 用于标注展开状态 + var needExpand = !parent.hasClass(NAV_ITEMED); // 是否执行展开 + var ANIM_MS = 200; // 动画过渡毫秒数 + + // 动画执行完成后的操作 + var complete = function () { + $(this).css({ + display: '' // 剔除动画生成的 style display,以适配外部样式的状态重置 + }); + // 避免导航滑块错位 + parents.children('.' + CONST.NAV_BAR).css({ + opacity: 0 + }); + }; + + // 是否正处于动画中的状态 + if (child.is(':animated')) return; + + // 剔除可能存在的 CSS3 动画类 + child.removeClass(CONST.NAV_ANIM); + + // 若有子菜单,则对其执行展开或收缩 + if (child[0]) { + if (needExpand) { + // 先执行 slideDown 动画,再标注展开状态样式,避免元素 `block` 状态导致动画无效 + child.slideDown(ANIM_MS, complete); + parent.addClass(NAV_ITEMED); + } else { + // 先取消展开状态样式,再将元素临时显示,避免 `none` 状态导致 slideUp 动画无效 + parent.removeClass(NAV_ITEMED); + child.show().slideUp(ANIM_MS, complete); + } + + // 手风琴 --- 收缩兄弟展开项 + if (typeof parents.attr('lay-accordion') === 'string' || parents.attr('lay-shrink') === 'all') { + var parentSibs = parent.siblings('.' + NAV_ITEMED); + parentSibs.removeClass(NAV_ITEMED); + parentSibs.children('.' + CONST.NAV_CHILD).show().stop().slideUp(ANIM_MS, complete); + } + } + } + layui.event.call(this, SUPER_MOD_NAME, 'nav(' + filter + ')', othis); + } +}; +var CONST = component.CONST; + +export { component as nav }; diff --git a/dist/components/progress.js b/dist/components/progress.js new file mode 100644 index 000000000..df5eb230d --- /dev/null +++ b/dist/components/progress.js @@ -0,0 +1,58 @@ +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * progress + * 进度条组件 + */ + + +// 创建组件 +var component = component$1({ + name: 'progress', + // 组件名 + + // 默认配置 + config: { + elem: '.layui-progress' + }, + CONST: { + ELEM: 'layui-progress' + }, + render: function () { + var that = this; + var options = that.config; + options.elem.each(function () { + var othis = $(this); + var elemBar = othis.find('.layui-progress-bar'); + var percent = elemBar.attr('lay-percent'); + elemBar.css('width', function () { + return /^.+\/.+$/.test(percent) ? new Function('return ' + percent)() * 100 + '%' : percent; + }); + if (othis.attr('lay-showpercent')) { + setTimeout(function () { + elemBar.html('' + percent + ''); + }, 350); + } + }); + } +}); +var CONST = component.CONST; + +// 扩展组件接口 +$.extend(component, { + // 动态改变进度条 + setValue: function (filter, percent) { + var ELEM = 'layui-progress'; + var elem = $('.' + ELEM + '[lay-filter=' + filter + ']'); + var elemBar = elem.find('.' + ELEM + '-bar'); + var text = elemBar.find('.' + ELEM + '-text'); + elemBar.css('width', function () { + return /^.+\/.+$/.test(percent) ? new Function('return ' + percent)() * 100 + '%' : percent; + }).attr('lay-percent', percent); + text.text(percent); + return this; + } +}); + +export { component as progress }; diff --git a/dist/components/rate.js b/dist/components/rate.js new file mode 100644 index 000000000..f4e65aac3 --- /dev/null +++ b/dist/components/rate.js @@ -0,0 +1,220 @@ +import { lay } from '../core/lay.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * rate + * 评分组件 + */ + + +// 创建组件 +var component = component$1({ + name: 'rate', + // 默认配置 + config: { + length: 5, + // 评分的最大长度值 + value: 0, + // 评分的初始值 + half: false, + // 是否可以选择半星 + text: false, + // 是否显示评分对应的文本 + readonly: false, + // 是否只读 + theme: '' // 主题颜色 + }, + CONST: { + ELEM: 'layui-rate', + ICON_RATE: 'layui-icon-rate', + ICON_RATE_SOLID: 'layui-icon-rate-solid', + ICON_RATE_HALF: 'layui-icon-rate-half', + ICON_SOLID_HALF: 'layui-icon-rate-solid layui-icon-rate-half', + ICON_SOLID_RATE: 'layui-icon-rate-solid layui-icon-rate', + ICON_HALF_RATE: 'layui-icon-rate layui-icon-rate-half' + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 自定义主题 + var style = options.theme ? 'style="color: ' + options.theme + ';"' : ''; + + // 最大值不能大于总长度 + if (options.value > options.length) { + options.value = options.length; + } + + // 如果没有选择半星的属性,却给了小数的数值,统一向上或向下取整 + if (parseInt(options.value) !== options.value) { + if (!options.half) { + options.value = Math.ceil(options.value) - options.value < 0.5 ? Math.ceil(options.value) : Math.floor(options.value); + } + } + + // 组件模板 + var template = '
                    '; + for (var i = 1; i <= options.length; i++) { + var item = '
                  • '; + if (options.half && parseInt(options.value) !== options.value && i == Math.ceil(options.value)) { + template = template + '
                  • '; + } else { + template = template + item; + } + } + template += '
                  '; + if (options.text) { + template += '' + options.value + ''; + } + + // 开始插入替代元素 + var othis = options.elem; + var hasRender = othis.next('.' + CONST.ELEM); + + // 生成替代元素 + hasRender[0] && hasRender.remove(); // 如果已经渲染,则 Rerender + that.elemTemplate = $(template); + options.span = that.elemTemplate.next('span'); + options.setText && options.setText(options.value); + othis.html(that.elemTemplate); + othis.addClass('layui-inline'); + + // 若非只读,则添加触控事件 + if (!options.readonly) { + that.action(); + } + }, + // 扩展实例方法 + extendsInstance: function () { + var that = this; + var options = that.config; + return { + setvalue: function (value) { + options.value = value; + that.render(); + } + }; + } +}); +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// li 相关事件 +Class.prototype.action = function () { + var that = this; + var options = that.config; + var _ul = that.elemTemplate; + var wide = _ul.find('i').width(); + var liElems = _ul.children('li'); + liElems.each(function (index) { + var ind = index + 1; + var othis = $(this); + + // 点击 + othis.on('click', function (e) { + // 将当前点击li的索引值赋给 value + options.value = ind; + if (options.half) { + // 获取鼠标在 li 上的位置 + var x = e.pageX - $(this).offset().left; + if (x <= wide / 2) { + options.value = options.value - 0.5; + } + } + if (options.text) { + _ul.next('span').text(options.value); + } + options.choose && options.choose(options.value); + options.setText && options.setText(options.value); + }); + + // 移入 + othis.on('mousemove', function (e) { + _ul.find('i').each(function () { + $(this).addClass(CONST.ICON_RATE).removeClass(CONST.ICON_SOLID_HALF); + }); + _ul.find('i:lt(' + ind + ')').each(function () { + $(this).addClass(CONST.ICON_RATE_SOLID).removeClass(CONST.ICON_HALF_RATE); + }); + // 如果设置可选半星,那么判断鼠标相对 li 的位置 + if (options.half) { + var x = e.pageX - $(this).offset().left; + if (x <= wide / 2) { + othis.children('i').addClass(CONST.ICON_RATE_HALF).removeClass(CONST.ICON_RATE_SOLID); + } + } + }); + + // 移出 + othis.on('mouseleave', function () { + _ul.find('i').each(function () { + $(this).addClass(CONST.ICON_RATE).removeClass(CONST.ICON_SOLID_HALF); + }); + _ul.find('i:lt(' + Math.floor(options.value) + ')').each(function () { + $(this).addClass(CONST.ICON_RATE_SOLID).removeClass(CONST.ICON_HALF_RATE); + }); + // 如果设置可选半星,根据分数判断是否有半星 + if (options.half) { + if (parseInt(options.value) !== options.value) { + _ul.children('li:eq(' + Math.floor(options.value) + ')').children('i').addClass(CONST.ICON_RATE_HALF).removeClass(CONST.ICON_SOLID_RATE); + } + } + }); + }); + lay.touchSwipe(_ul, { + onTouchMove: function (e, state) { + if (Date.now() - state.timeStart <= 200) return; + var pageX = e.touches[0].pageX; + var rateElemWidth = _ul.width(); + var itemElemWidth = rateElemWidth / options.length; // 单颗星的宽度 + var offsetX = pageX - _ul.offset().left; + var num = offsetX / itemElemWidth; // 原始值 + var remainder = num % 1; + var integer = num - remainder; + + // 最终值 + var score = remainder <= 0.5 && options.half ? integer + 0.5 : Math.ceil(num); + if (score > options.length) score = options.length; + if (score < 0) score = 0; + liElems.each(function (index) { + var iconElem = $(this).children('i'); + var isActiveIcon = Math.ceil(score) - index === 1; + var needSelect = Math.ceil(score) > index; + var shouldHalfIcon = score - index === 0.5; + if (needSelect) { + // 设置选中样式 + iconElem.addClass(CONST.ICON_RATE_SOLID).removeClass(CONST.ICON_HALF_RATE); + if (options.half && shouldHalfIcon) { + iconElem.addClass(CONST.ICON_RATE_HALF).removeClass(CONST.ICON_RATE_SOLID); + } + } else { + // 恢复初始样式 + iconElem.addClass(CONST.ICON_RATE).removeClass(CONST.ICON_SOLID_HALF); + } + + // 设置缩放样式 + iconElem.toggleClass('layui-rate-hover', isActiveIcon); + }); + + // 更新最终值 + options.value = score; + if (options.text) _ul.next('span').text(options.value); + options.setText && options.setText(options.value); + }, + onTouchEnd: function (e, state) { + if (Date.now() - state.timeStart <= 200) return; + _ul.find('i').removeClass('layui-rate-hover'); + options.choose && options.choose(options.value); + options.setText && options.setText(options.value); + } + }); +}; + +export { component as rate }; diff --git a/dist/components/slider.js b/dist/components/slider.js new file mode 100644 index 000000000..a1690d2b1 --- /dev/null +++ b/dist/components/slider.js @@ -0,0 +1,454 @@ +import { lay } from '../core/lay.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * slider 滑块组件 + */ + +var component = component$1({ + name: 'slider', + config: { + type: 'default', + // 滑块类型,垂直:vertical + min: 0, + // 最小值 + max: 100, + // 最大值,默认100 + value: 0, + // 初始值,默认为0 + step: 1, + // 间隔值 + showstep: false, + // 间隔点开启 + tips: true, + // 文字提示,开启 + tipsAlways: false, + // 文字提示,始终开启 + input: false, + // 输入框,关闭 + range: false, + // 范围选择,与输入框不能同时开启,默认关闭 + height: 200, + // 配合 type:"vertical" 使用,默认200px + disabled: false, + // 滑块禁用,默认关闭 + theme: '#16baaa' // 主题颜色 + }, + CONST: { + ELEM_VIEW: 'layui-slider', + SLIDER_BAR: 'layui-slider-bar', + SLIDER_WRAP: 'layui-slider-wrap', + SLIDER_WRAP_BTN: 'layui-slider-wrap-btn', + SLIDER_TIPS: 'layui-slider-tips', + SLIDER_INPUT: 'layui-slider-input', + SLIDER_INPUT_TXT: 'layui-slider-input-txt', + SLIDER_INPUT_BTN: 'layui-slider-input-btn', + ELEM_HOVER: 'layui-slider-hover' + }, + render: function () { + var that = this; + var options = that.config; + var scale; + + //间隔值不能小于等于 0 + if (options.step <= 0) options.step = 1; + + //最大值不能小于最小值 + if (options.max < options.min) options.max = options.min + options.step; + + //判断是否开启双滑块 + if (options.range) { + options.value = typeof options.value == 'object' ? options.value : [options.min, options.value]; + var minValue = Math.min(options.value[0], options.value[1]), + maxValue = Math.max(options.value[0], options.value[1]); + options.value[0] = Math.max(minValue, options.min); + options.value[1] = Math.max(maxValue, options.min); + options.value[0] = Math.min(options.value[0], options.max); + options.value[1] = Math.min(options.value[1], options.max); + var scaleFir = (options.value[0] - options.min) / (options.max - options.min) * 100; + var scaleSec = (options.value[1] - options.min) / (options.max - options.min) * 100; + scale = scaleSec - scaleFir + '%'; + scaleFir = scaleFir + '%'; + scaleSec = scaleSec + '%'; + } else { + //如果初始值是一个数组,则获取数组的最小值 + if (typeof options.value == 'object') { + options.value = Math.min.apply(null, options.value); + } + + //初始值不能小于最小值且不能大于最大值 + if (options.value < options.min) options.value = options.min; + if (options.value > options.max) options.value = options.max; + scale = (options.value - options.min) / (options.max - options.min) * 100 + '%'; + } + + //如果禁用,颜色为统一的灰色 + var theme = options.disabled ? '#c2c2c2' : options.theme; + + //滑块 + var temp = '
                  ' + (options.tips ? '
                  ' : '') + '
                  ' + '
                  ' + (options.range ? '
                  ' : '') + '
                  '; + var othis = $(options.elem); + var hasRender = othis.next('.' + CONST.ELEM_VIEW); + //生成替代元素 + hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender + that.elemTemp = $(temp); + + //把数据缓存到滑块上 + if (options.range) { + that.elemTemp.find('.' + CONST.SLIDER_WRAP).eq(0).data('value', options.value[0]); + that.elemTemp.find('.' + CONST.SLIDER_WRAP).eq(1).data('value', options.value[1]); + } else { + that.elemTemp.find('.' + CONST.SLIDER_WRAP).data('value', options.value); + } + + //插入替代元素 + othis.html(that.elemTemp); + + //垂直滑块 + if (options.type === 'vertical') { + that.elemTemp.height(options.height + 'px'); + } + + //显示间断点 + if (options.showstep) { + var number = (options.max - options.min) / options.step, + item = ''; + for (var i = 1; i < number + 1; i++) { + var step = i * 100 / number; + if (step < 100) { + item += '
                  '; + } + } + that.elemTemp.append(item); + } + + //插入输入框 + if (options.input && !options.range) { + var elemInput = $('
                  '); + othis.css('position', 'relative'); + othis.append(elemInput); + othis.find('.' + CONST.SLIDER_INPUT_TXT).children('input').val(options.value); + if (options.type === 'vertical') { + elemInput.css({ + left: 0, + top: -48 + }); + } else { + that.elemTemp.css('margin-right', elemInput.outerWidth() + 15); + } + } + + //给未禁止的滑块滑动事件 + if (!options.disabled) { + that.slide(); + } else { + that.elemTemp.addClass(CONST.CLASS_DISABLED); + that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN).addClass(CONST.CLASS_DISABLED); + } + + /** + * @description 设置提示文本内容 + * @param {Element} sliderWrapBtnElem 提示文本节点元素 + */ + function setSliderTipsTxt(sliderWrapBtnElem) { + var value = sliderWrapBtnElem.parent().data('value'); + var tipsTxt = options.setTips ? options.setTips(value) : value; + that.elemTemp.find('.' + CONST.SLIDER_TIPS).html(tipsTxt); + } + + /** + * @description 计算提示文本元素的 position left + * @param {Element} sliderWrapBtnElem 提示文本节点元素 + */ + function calcSliderTipsLeft(sliderWrapBtnElem) { + var sliderWidth = options.type === 'vertical' ? options.height : that.elemTemp[0].offsetWidth; + var sliderWrap = that.elemTemp.find('.' + CONST.SLIDER_WRAP); + var tipsLeft = options.type === 'vertical' ? sliderWidth - sliderWrapBtnElem.parent()[0].offsetTop - sliderWrap.height() : sliderWrapBtnElem.parent()[0].offsetLeft; + var left = tipsLeft / sliderWidth * 100; + return left; + } + + /** + * @description 设置提示文本元素的 position left + * @param {number} left 要设置的 left 的大小 + */ + function setSliderTipsLeft(left) { + if (options.type === 'vertical') { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({ + bottom: left + '%', + 'margin-bottom': '20px', + display: 'inline-block' + }); + } else { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({ + left: left + '%', + display: 'inline-block' + }); + } + } + + //判断是否要始终显示提示文本 + if (options.tips) { + if (options.tipsAlways) { + var sliderWrapBtnElem = that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN); + setSliderTipsTxt(sliderWrapBtnElem); + var left = calcSliderTipsLeft(sliderWrapBtnElem); + setSliderTipsLeft(left); + } else { + //划过滑块显示数值 + var timer; + that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN).on('mouseover', function () { + setSliderTipsTxt($(this)); + var left = calcSliderTipsLeft($(this)); + clearTimeout(timer); + timer = setTimeout(function () { + setSliderTipsLeft(left); + }, 300); + }).on('mouseout', function () { + clearTimeout(timer); + if (!options.tipsAlways) { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css('display', 'none'); + } + }); + } + } + }, + extendsInstance: function () { + var that = this; + var options = that.config; + return { + setValue: function (value, index) { + value = value > options.max ? options.max : value; + value = value < options.min ? options.min : value; + options.value = value; + return that.slide('set', value, index || 0); + } + }; + } +}); +var CONST = component.CONST; +var Class = component.Class; + +// 数值精度 +Class.prototype.precision = function () { + var that = this; + var options = that.config; + var precisions = $.map([options.min, options.max, options.step], function (v) { + var decimalArr = String(v).split('.'); + return decimalArr[1] ? decimalArr[1].length : 0; + }); + return Math.max.apply(null, precisions); +}; + +//滑块滑动 +Class.prototype.slide = function (setValue, value, i) { + var that = this; + var options = that.config; + var sliderAct = that.elemTemp; + var sliderWidth = function () { + return options.type === 'vertical' ? options.height : sliderAct[0].offsetWidth; + }; + var sliderWrap = sliderAct.find('.' + CONST.SLIDER_WRAP); + var sliderTxt = sliderAct.next('.' + CONST.SLIDER_INPUT); + var inputValue = sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(); + var step = 100 / ((options.max - options.min) / options.step); + var precision = that.precision(); + var change = function (offsetValue, index, from) { + if (Math.ceil(offsetValue) * step > 100) { + offsetValue = Math.ceil(offsetValue) * step; + } else { + offsetValue = Math.round(offsetValue) * step; + } + offsetValue = offsetValue > 100 ? 100 : offsetValue; + offsetValue = offsetValue < 0 ? 0 : offsetValue; + sliderWrap.eq(index).css(options.type === 'vertical' ? 'bottom' : 'left', offsetValue + '%'); + var firLeft = valueTo(sliderWrap[0].offsetLeft); + var secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0; + if (options.type === 'vertical') { + sliderAct.find('.' + CONST.SLIDER_TIPS).css({ + bottom: offsetValue + '%', + 'margin-bottom': '20px' + }); + firLeft = valueTo(sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height()); + secLeft = options.range ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) : 0; + } else { + sliderAct.find('.' + CONST.SLIDER_TIPS).css('left', offsetValue + '%'); + } + firLeft = firLeft > 100 ? 100 : firLeft; + secLeft = secLeft > 100 ? 100 : secLeft; + var minLeft = Math.min(firLeft, secLeft), + wrapWidth = Math.abs(firLeft - secLeft); + if (options.type === 'vertical') { + sliderAct.find('.' + CONST.SLIDER_BAR).css({ + height: wrapWidth + '%', + bottom: minLeft + '%' + }); + } else { + sliderAct.find('.' + CONST.SLIDER_BAR).css({ + width: wrapWidth + '%', + left: minLeft + '%' + }); + } + var selfValue = options.min + (options.max - options.min) * offsetValue / 100; + selfValue = Number(parseFloat(selfValue).toFixed(precision)); + inputValue = selfValue; + sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(inputValue); + sliderWrap.eq(index).data('value', selfValue); + sliderAct.find('.' + CONST.SLIDER_TIPS).html(options.setTips ? options.setTips(selfValue) : selfValue); + + //如果开启范围选择,则返回数组值 + if (options.range) { + var arrValue = [sliderWrap.eq(0).data('value'), sliderWrap.eq(1).data('value')]; + if (arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值,则调换顺序 + } + that.value = options.range ? arrValue : selfValue; // 最新值 + options.change && options.change(that.value); // change 回调 + + // 值完成选中的事件 + if (from === 'done') options.done && options.done(that.value); + }; + var valueTo = function (value) { + var oldLeft = value / sliderWidth() * 100 / step; + var left = Math.round(oldLeft) * step; + if (value == sliderWidth()) { + left = Math.ceil(oldLeft) * step; + } + return left; + }; + + //拖拽元素 + var elemMove = $(['
                  sliderWidth()) left = sliderWidth(); + var reaLeft = left / sliderWidth() * 100 / step; + change(reaLeft, index); + othis.addClass(CONST.ELEM_HOVER); + sliderAct.find('.' + CONST.SLIDER_TIPS).show(); + e.preventDefault(); + }; + var up = function (delay) { + othis.removeClass(CONST.ELEM_HOVER); + if (!options.tipsAlways) { + setTimeout(function () { + sliderAct.find('.' + CONST.SLIDER_TIPS).hide(); + }, delay); + } + }; + createMoveElem(othis, move, up); + }); + }); + + // 点击滑块 + sliderAct.on('click', function (e) { + var main = $('.' + CONST.SLIDER_WRAP_BTN); + var othis = $(this); + if (!main.is(event.target) && main.has(event.target).length === 0 && main.length) { + var index; + var offset = options.type === 'vertical' ? sliderWidth() - e.clientY + othis.offset().top - $(window).scrollTop() : e.clientX - othis.offset().left - $(window).scrollLeft(); + if (offset < 0) offset = 0; + if (offset > sliderWidth()) offset = sliderWidth(); + var reaLeft = offset / sliderWidth() * 100 / step; + if (options.range) { + if (options.type === 'vertical') { + index = Math.abs(offset - parseInt($(sliderWrap[0]).css('bottom'))) > Math.abs(offset - parseInt($(sliderWrap[1]).css('bottom'))) ? 1 : 0; + } else { + index = Math.abs(offset - sliderWrap[0].offsetLeft) > Math.abs(offset - sliderWrap[1].offsetLeft) ? 1 : 0; + } + } else { + index = 0; + } + change(reaLeft, index, 'done'); + e.preventDefault(); + } + }); + + //点击加减输入框 + sliderTxt.children('.' + CONST.SLIDER_INPUT_BTN).children('i').each(function (index) { + $(this).on('click', function () { + inputValue = sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').val(); + if (index == 1) { + //减 + inputValue = inputValue - options.step < options.min ? options.min : Number(inputValue) - options.step; + } else { + inputValue = Number(inputValue) + options.step > options.max ? options.max : Number(inputValue) + options.step; + } + var inputScale = (inputValue - options.min) / (options.max - options.min) * 100 / step; + change(inputScale, 0, 'done'); + }); + }); + + //获取输入框值 + var getInputValue = function () { + var realValue = this.value; + realValue = isNaN(realValue) ? 0 : realValue; + realValue = realValue < options.min ? options.min : realValue; + realValue = realValue > options.max ? options.max : realValue; + this.value = realValue; + var inputScale = (realValue - options.min) / (options.max - options.min) * 100 / step; + change(inputScale, 0, 'done'); + }; + sliderTxt.children('.' + CONST.SLIDER_INPUT_TXT).children('input').on('keydown', function (e) { + if (e.keyCode === 13) { + e.preventDefault(); + getInputValue.call(this); + } + }).on('change', getInputValue); +}; + +export { component as slider }; diff --git a/dist/components/tab.js b/dist/components/tab.js new file mode 100644 index 000000000..00d42cfc4 --- /dev/null +++ b/dist/components/tab.js @@ -0,0 +1,271 @@ +import { layui } from '../core/layui.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * tab + * 选项卡组件(已被 tabs 平替,仅为兼容保留) + */ + +var SUPER_MOD_NAME = 'element'; // 所属的超级模块名,确保向下兼容 + +// 创建组件 +var component = component$1({ + name: 'tab', + // 组件名 + + // 默认配置 + config: { + elem: '.layui-tab' + }, + CONST: { + ELEM: 'layui-tab', + HEADER: 'layui-tab-title', + CLOSE: 'layui-tab-close', + MORE: 'layui-tab-more', + BAR: 'layui-tab-bar' + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + events.tabAuto(null, options.elem); + } +}); +var CONST = component.CONST; +var $win = $(window); +var $doc = $(document); + +// 基础事件 +var events = { + // Tab 点击 + tabClick: function (obj) { + obj = obj || {}; + var options = obj.options || {}; + var othis = obj.liElem || $(this); + var parents = options.headerElem ? othis.parent() : othis.parents('.layui-tab').eq(0); + var item = options.bodyElem ? $(options.bodyElem) : parents.children('.layui-tab-content').children('.layui-tab-item'); + var elemA = othis.find('a'); + var isJump = elemA.attr('href') !== 'javascript:;' && elemA.attr('target') === '_blank'; // 是否存在跳转 + var unselect = typeof othis.attr('lay-unselect') === 'string'; // 是否禁用选中 + var filter = parents.attr('lay-filter'); + var hasId = othis.attr('lay-id'); + + // 下标 + var index = 'index' in obj ? obj.index : othis.parent().children('li').index(othis); + + // 若非强制切换,则根据 tabBeforeChange 事件的返回结果决定是否切换 + if (!obj.force) { + var liThis = othis.siblings('.' + CONST.CLASS_THIS); + var shouldChange = layui.event.call(this, SUPER_MOD_NAME, 'tabBeforeChange(' + filter + ')', { + elem: parents, + from: { + index: othis.parent().children('li').index(liThis), + id: liThis.attr('lay-id') + }, + to: { + index: index, + id: hasId + } + }); + if (shouldChange === false) return; + } + + // 执行切换 + if (!(isJump || unselect)) { + othis.addClass(CONST.CLASS_THIS).siblings().removeClass(CONST.CLASS_THIS); + if (hasId) { + var contentElem = item.filter('[lay-id="' + hasId + '"]'); + contentElem = contentElem.length ? contentElem : item.eq(index); + contentElem.addClass(CONST.CLASS_SHOW).siblings().removeClass(CONST.CLASS_SHOW); + } else { + item.eq(index).addClass(CONST.CLASS_SHOW).siblings().removeClass(CONST.CLASS_SHOW); + } + } + layui.event.call(this, SUPER_MOD_NAME, 'tab(' + filter + ')', { + elem: parents, + index: index, + id: hasId + }); + }, + // Tab 删除 + tabDelete: function (obj) { + obj = obj || {}; + var li = obj.liElem || $(this).parent(); + var index = li.parent().children('li').index(li); + var tabElem = li.closest('.layui-tab'); + var item = tabElem.children('.layui-tab-content').children('.layui-tab-item'); + var filter = tabElem.attr('lay-filter'); + var hasId = li.attr('lay-id'); + + // 若非强制删除,则根据 tabBeforeDelete 事件的返回结果决定是否删除 + if (!obj.force) { + var shouldClose = layui.event.call(li[0], SUPER_MOD_NAME, 'tabBeforeDelete(' + filter + ')', { + elem: tabElem, + index: index, + id: hasId + }); + if (shouldClose === false) return; + } + if (li.hasClass(CONST.CLASS_THIS)) { + if (li.next()[0] && li.next().is('li')) { + events.tabClick.call(li.next()[0], { + index: index + 1 + }); + } else if (li.prev()[0] && li.prev().is('li')) { + events.tabClick.call(li.prev()[0], null, index - 1); + } + } + li.remove(); + if (hasId) { + var contentElem = item.filter('[lay-id="' + hasId + '"]'); + contentElem = contentElem.length ? contentElem : item.eq(index); + contentElem.remove(); + } else { + item.eq(index).remove(); + } + setTimeout(function () { + events.tabAuto(null, tabElem); + }, 50); + layui.event.call(this, SUPER_MOD_NAME, 'tabDelete(' + filter + ')', { + elem: tabElem, + index: index, + id: hasId + }); + }, + // Tab 自适应 + tabAuto: function (spread, elem) { + var targetElem = elem || $('.layui-tab'); + targetElem.each(function () { + var othis = $(this); + var title = othis.children('.' + CONST.HEADER); + var STOPE = 'lay-stope="tabmore"'; + var span = $(''); + + // 开启关闭图标 + var allowclose = othis.attr('lay-allowclose'); + if (allowclose && allowclose !== 'false') { + title.find('li').each(function () { + var li = $(this); + if (!li.find('.' + CONST.CLOSE)[0] && li.attr('lay-allowclose') !== 'false') { + var close = $(''); + close.on('click', function (e) { + events.tabDelete.call(this, { + e: e + }); + }); + li.append(close); + } + }); + } + if (typeof othis.attr('lay-unauto') === 'string') return; + + // 响应式 + if (title.prop('scrollWidth') > title.outerWidth() + 1 || title.find('li').length && title.height() > function (height) { + return height + height / 2; + }(title.find('li').eq(0).height())) { + // 若执行是来自于切换,则自动展开 + if (spread === 'change' && title.data('LAY_TAB_CHANGE')) { + title.addClass(CONST.MORE); + } + if (title.find('.' + CONST.BAR)[0]) return; + title.append(span); + othis.attr('overflow', ''); + + // 展开图标事件 + span.on('click', function () { + var isSpread = title.hasClass(CONST.MORE); + title[isSpread ? 'removeClass' : 'addClass'](CONST.MORE); + }); + } else { + title.find('.' + CONST.BAR).remove(); + othis.removeAttr('overflow'); + } + }); + }, + // 隐藏更多 Tab + hideTabMore: function (e) { + var tsbTitle = $('.' + CONST.HEADER); + if (e === true || $(e.target).attr('lay-stope') !== 'tabmore') { + tsbTitle.removeClass(CONST.MORE); + tsbTitle.find('.' + CONST.BAR).attr('title', ''); + } + } +}; + +// 扩展组件接口 +$.extend(component, { + // 新增 tab + tabAdd: function (filter, options) { + var tabElem = $('.layui-tab[lay-filter=' + filter + ']'); + var titElem = tabElem.children('.' + CONST.HEADER); + var barElem = titElem.children('.' + CONST.BAR); + var contElem = tabElem.children('.layui-tab-content'); + var li = ' 0) layAttr.unshift(''); //向前插,预留空格 + return layAttr.join(' '); + }() + '>' + (options.title || 'unnaming') + ''; + barElem[0] ? barElem.before(li) : titElem.append(li); + contElem.append('
                  ' + (options.content || '') + '
                  '); + // events.hideTabMore(true); + // 是否添加即切换 + options.change && this.tabChange(filter, options.id); + titElem.data('LAY_TAB_CHANGE', options.change); + events.tabAuto(options.change ? 'change' : null, tabElem); + return this; + }, + /** + * 外部 Tab 删除 + * @param {string} filter - 标签主容器 lay-filter 值 + * @param {string} layid - 标签头 lay-id 值 + * @param {boolean} force - 是否强制删除 + * @returns {this} + */ + tabDelete: function (filter, layid, force) { + var tabElem = $('.layui-tab[lay-filter=' + filter + ']'); + var titElem = tabElem.children('.' + CONST.HEADER); + var liElem = titElem.find('>li[lay-id="' + layid + '"]'); + events.tabDelete.call(liElem[0], { + liElem: liElem, + force: force + }); + return this; + }, + /** + * 外部 Tab 切换 + * @param {string} filter - 标签主容器 lay-filter 值 + * @param {string} layid - 标签头 lay-id 值 + * @param {boolean} force - 是否强制切换 + * @returns {this} + */ + tabChange: function (filter, layid, force) { + var tabElem = $('.layui-tab[lay-filter=' + filter + ']'); + var titElem = tabElem.children('.' + CONST.HEADER); + var liElem = titElem.find('>li[lay-id="' + layid + '"]'); + events.tabClick.call(liElem[0], { + liElem: liElem, + force: force + }); + return this; + }, + // 自定义 Tab 选项卡 + tab: function (options) { + options = options || {}; + $doc.on('click', options.headerElem, function () { + var index = $(options.headerElem).index($(this)); + events.tabClick.call(this, { + index: index, + options: options + }); + }); + } +}); +$doc.on('click', '.' + CONST.HEADER + ' li', events.tabClick); // tab 头部项点击 +$win.on('resize.lay_tab_auto_resize', events.tabAuto); // 自适应尺寸 + +export { component as tab }; diff --git a/dist/components/table.js b/dist/components/table.js new file mode 100644 index 000000000..371393d3d --- /dev/null +++ b/dist/components/table.js @@ -0,0 +1,3219 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { laytpl } from '../core/laytpl.js'; +import { laypage } from './laypage.js'; +import { util } from './util.js'; +import { layer } from './layer.js'; +import { form } from './form.js'; + +/** + * layui.table + * 表格组件 + */ +var hint = layui.hint(); +var device = layui.device(); + +// api +var table = { + config: { + // 全局配置项 + checkName: 'LAY_CHECKED', + // 是否选中状态的特定字段名 + indexName: 'LAY_INDEX', + // 下标索引 + initIndexName: 'LAY_INDEX_INIT', + // 初始下标索引名,仅用于内部恢复当前页表格排序 + numbersName: 'LAY_NUM', + // 序号 + disabledName: 'LAY_DISABLED' // 禁用状态的特定字段名 + }, + cache: {}, + // 数据缓存 + + // 设置全局项 + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + // 事件 + on: function (events, callback) { + return layui.onevent.call(this, MOD_NAME, events, callback); + } +}; + +// 操作当前实例 +var thisTable = function () { + var that = this; + var options = that.config; + var id = options.id || options.index; + return { + config: options, + reload: function (options, deep) { + that.reload.call(that, options, deep); + }, + reloadData: function (options, deep) { + table.reloadData(id, options, deep); + }, + setColsWidth: function () { + that.setColsWidth.call(that); + }, + resize: function () { + // 重置表格尺寸/结构 + that.resize.call(that); + } + }; +}; + +// 获取当前实例 +var getThisTable = function (id) { + var that = thisTable.that[id]; + if (!that) hint.error(id ? "The table instance with ID '" + id + "' not found" : 'ID argument required'); + return that || null; +}; + +// 获取当前实例配置项 +var getThisTableConfig = function (id) { + var config = thisTable.config[id]; + if (!config) hint.error(id ? "The table instance with ID '" + id + "' not found" : 'ID argument required'); + return config || null; +}; + +// lay 函数可以处理 Selector,HTMLElement,JQuery 类型 +// 无效的 CSS 选择器字符串,会抛出 SyntaxError 异常,此时直接返回 laytpl 模板字符串 +var resolveTplStr = function (templet) { + try { + return lay(templet).html(); + } catch { + return templet; + } +}; + +// 解析自定义模板数据 +var parseTempData = function (obj) { + obj = obj || {}; + var options = this.config || {}; + var item3 = obj.item3; // 表头数据 + var content = obj.content; // 原始内容 + if (item3.type === 'numbers') content = obj.tplData[table.config.numbersName]; + + // 是否编码 HTML + var escaped = 'escape' in item3 ? item3.escape : options.escape; + if (escaped) content = util.escape(content); + + // 获取模板 + var templet = obj.text && item3.exportTemplet || item3.templet || item3.toolbar; + + // 获取模板内容 + if (templet) { + content = typeof templet === 'function' ? templet.call(item3, obj.tplData, obj.obj) : laytpl(resolveTplStr(templet) || String(content)).render($.extend({ + LAY_COL: item3 + }, obj.tplData)); + } + + // 是否只返回文本 + return obj.text ? $('
                  ' + content + '
                  ').text() : content; +}; + +// 字符 +var MOD_NAME = 'table'; +var MOD_ID = 'lay-' + MOD_NAME + '-id'; +var ELEM = '.layui-table'; +// var THIS = 'layui-this'; +// var SHOW = 'layui-show'; +var HIDE = 'layui-hide'; +var HIDE_V = 'layui-hide-v'; +// var DISABLED = 'layui-disabled'; +var NONE = 'layui-none'; +var ELEM_VIEW = 'layui-table-view'; +var ELEM_TOOL = '.layui-table-tool'; +var ELEM_BOX = '.layui-table-box'; +var ELEM_INIT = '.layui-table-init'; +var ELEM_HEADER = '.layui-table-header'; +var ELEM_BODY = '.layui-table-body'; +var ELEM_MAIN = '.layui-table-main'; +var ELEM_FIXED = '.layui-table-fixed'; +var ELEM_FIXL = '.layui-table-fixed-l'; +var ELEM_FIXR = '.layui-table-fixed-r'; +var ELEM_TOTAL = '.layui-table-total'; +var ELEM_PAGE = '.layui-table-page'; +var ELEM_PAGE_VIEW = '.layui-table-pageview'; +var ELEM_SORT = '.layui-table-sort'; +var ELEM_CHECKED = 'layui-table-checked'; +var ELEM_EDIT = 'layui-table-edit'; +var ELEM_HOVER = 'layui-table-hover'; +var ELEM_GROUP = 'laytable-cell-group'; +var ELEM_COL_SPECIAL = 'layui-table-col-special'; +var ELEM_TOOL_PANEL = 'layui-table-tool-panel'; +var ELEM_EXPAND = 'layui-table-expanded'; +var DISABLED_TRANSITION = 'layui-table-disabled-transition'; +var FIXED_HEIGHT_PATCH = 'layui-table-fixed-height-patch'; +var DATA_MOVE_NAME = 'LAY_TABLE_MOVE_DICT'; +var resizeObserver = lay.createSharedResizeObserver(MOD_NAME); + +// thead 区域模板 +var TPL_HEADER = function (options) { + var rowCols = '{{#var colspan = layui.type(item2.colspan2) === \'number\' ? item2.colspan2 : item2.colspan; if(colspan){}} colspan="{{=colspan}}"{{#} if(item2.rowspan){}} rowspan="{{=item2.rowspan}}"{{#}}}'; + options = options || {}; + return ['', '', '{{# layui.each(d.data.cols, function(i1, item1){ }}', '', '{{# layui.each(item1, function(i2, item2){ }}', '{{# if(item2.fixed && item2.fixed !== "right"){ left = true; } }}', '{{# if(item2.fixed === "right"){ right = true; } }}', function () { + if (options.fixed && options.fixed !== 'right') { + return '{{# if(item2.fixed && item2.fixed !== "right"){ }}'; + } + if (options.fixed === 'right') { + return '{{# if(item2.fixed === "right"){ }}'; + } + return ''; + }(), '{{# var isSort = !(item2.colGroup) && item2.sort; }}', '', options.fixed ? '{{# }; }}' : '', '{{# }); }}', '', '{{# }); }}', '', '
                  ', '
                  ', '{{# if(item2.type === "checkbox"){ }}', + //复选框 + '', '{{# } else { }}', '{{-item2.title||""}}', '{{# if(isSort){ }}', '', '{{# } }}', '{{# } }}', '
                  ', '
                  '].join(''); +}; + +// tbody 区域模板 +var TPL_BODY = ['', '', '
                  '].join(''); + +// 主模板 +var TPL_MAIN = ['{{# if(d.data.toolbar){ }}', '
                  ', '
                  ', '
                  ', '
                  ', '{{# } }}', '
                  ', '{{# if(d.data.loading){ }}', '
                  ', '
                  ', '{{# if(typeof d.data.loading === "string"){ }}', '{{- d.data.loading}}', '{{# } else{ }}', '', '{{# } }}', '
                  ', '
                  ', '{{# } }}', '{{# var left, right; }}', '
                  ', TPL_HEADER(), '
                  ', '
                  ', TPL_BODY, '
                  ', '{{# if(left){ }}', '
                  ', '
                  ', TPL_HEADER({ + fixed: true +}), '
                  ', '
                  ', TPL_BODY, '
                  ', '
                  ', '{{# }; }}', '{{# if(right){ }}', '
                  ', '
                  ', TPL_HEADER({ + fixed: 'right' +}), '
                  ', '
                  ', '
                  ', TPL_BODY, '
                  ', '
                  ', '{{# }; }}', '
                  ', '{{# if(d.data.totalRow){ }}', '
                  ', '', '', '
                  ', '
                  ', '{{# } }}', '
                  ', '
                  ', '
                  '].join(''); +var _WIN = $(window); +var _DOC = $(document); + +// constructor +var Class = function (options) { + var that = this; + that.index = table.index = lay.autoIncrementer('table'); + that.config = $.extend({}, that.config, table.config, options); + that.unobserveResize = $.noop; + that.render(); +}; + +// 初始默认配置 +Class.prototype.config = { + limit: 10, + // 每页显示的数量 + loading: true, + // 请求数据时,是否显示 loading + escape: true, + // 是否开启 HTML 编码功能,即转义 html 原文 + cellMinWidth: 60, + // 所有单元格默认最小宽度 + cellMaxWidth: Number.MAX_VALUE, + // 所有单元格默认最大宽度 + editTrigger: 'click', + // 单元格编辑的事件触发方式 + defaultToolbar: ['filter', 'exports', 'print'], + // 工具栏右侧图标 + defaultContextmenu: true, + // 显示默认上下文菜单 + autoSort: true, + // 是否前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) + cols: [] +}; + +// 表格渲染 +Class.prototype.render = function (type) { + var that = this; + var options = that.config; + options.elem = $(options.elem); + options.where = options.where || {}; + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + var id = options.id = 'id' in options ? options.id : options.elem.attr('id') || that.index; + + // 重复 render 时清理旧实例 + if (thisTable.that[id] && thisTable.that[id] !== that) { + thisTable.that[id].dispose(); + } + thisTable.that[id] = that; // 记录当前实例对象 + thisTable.config[id] = options; // 记录当前实例配置项 + + // 请求参数的自定义格式 + options.request = $.extend({ + pageName: 'page', + limitName: 'limit' + }, options.request); + + // 响应数据的自定义格式 + options.response = $.extend({ + statusName: 'code', + //规定数据状态的字段名称 + statusCode: 0, + //规定成功的状态码 + msgName: 'msg', + //规定状态信息的字段名称 + dataName: 'data', + //规定数据总数的字段名称 + totalRowName: 'totalRow', + //规定数据统计的字段名称 + countName: 'count' + }, options.response); + + // 如果 page 传入 laypage 对象 + if (options.page !== null && typeof options.page === 'object') { + options.limit = options.page.limit || options.limit; + options.limits = options.page.limits || options.limits; + that.page = options.page.curr = options.page.curr || 1; + delete options.page.elem; + delete options.page.jump; + } + + // 加载 i18n 自定义文本 + options.text = $.extend(true, { + none: i18n.$t('table.noData') + }, options.text); + if (!options.elem[0]) return that; + + // 若元素未设 lay-filter 属性,则取实例 id 值 + if (!options.elem.attr('lay-filter')) { + options.elem.attr('lay-filter', options.id); + } + + // 仅重载数据 + if (type === 'reloadData') { + // 请求数据 + return that.pullData(that.page, { + type: 'reloadData' + }); + } + + // 初始化索引 + options.index = that.index; + that.key = options.id || options.index; + + // 初始化一些其他参数 + that.setInit(); + + // 高度铺满:full-差距值 + if (options.height && /^full-.+$/.test(options.height)) { + that.fullHeightGap = options.height.split('-')[1]; + options.height = _WIN.height() - (parseFloat(that.fullHeightGap) || 0); + } else if (options.height && /^#\w+\S*-.+$/.test(options.height)) { + var parentDiv = options.height.split('-'); + that.parentHeightGap = parentDiv.pop(); + that.parentDiv = parentDiv.join('-'); + options.height = $(that.parentDiv).height() - (parseFloat(that.parentHeightGap) || 0); + } else if (typeof options.height === 'function') { + that.customHeightFunc = options.height; + options.height = that.customHeightFunc(); + } + + // 开始插入替代元素 + var othis = options.elem; + var hasRender = othis.next('.' + ELEM_VIEW); + + // 主容器 + var reElem = that.elem = $('
                  '); + + // 添加 className + reElem.addClass(function () { + var arr = [ELEM_VIEW, ELEM_VIEW + '-' + that.index, 'layui-form', 'layui-border-box']; + if (options.className) arr.push(options.className); + return arr.join(' '); + }()).attr(function () { + var obj = { + 'lay-filter': 'LAY-TABLE-FORM-DF-' + that.index, + style: function () { + var arr = []; + if (options.width) arr.push('width:' + options.width + 'px;'); + // if(options.height) arr.push('height:'+ options.height + 'px;'); + return arr.join(''); + }() + }; + obj[MOD_ID] = options.id; + return obj; + }()).html(laytpl(TPL_MAIN, { + open: '{{', + // 标签符前缀 + close: '}}', + // 标签符后缀 + tagStyle: 'legacy' + }).render({ + data: options, + index: that.index, + //索引 + i18nMessages: { + table_sort_asc: i18n.$t('table.sort.asc'), + table_sort_desc: i18n.$t('table.sort.desc') + } + })); + + // 初始化样式 + that.renderStyle(); + + // 生成替代元素 + hasRender[0] && hasRender.remove(); // 如果已经渲染,则 Rerender + othis.after(reElem); + + // 各级容器 + that.layTool = reElem.find(ELEM_TOOL); + that.layBox = reElem.find(ELEM_BOX); + that.layHeader = reElem.find(ELEM_HEADER); + that.layMain = reElem.find(ELEM_MAIN); + that.layBody = reElem.find(ELEM_BODY); + that.layFixed = reElem.find(ELEM_FIXED); + that.layFixLeft = reElem.find(ELEM_FIXL); + that.layFixRight = reElem.find(ELEM_FIXR); + that.layTotal = reElem.find(ELEM_TOTAL); + that.layPage = reElem.find(ELEM_PAGE); + + // 初始化头部工具栏 + that.renderToolbar(); + + // 初始化底部分页栏 + that.renderPagebar(); + + // 让表格平铺 + that.fullSize(); + that.setColsWidth({ + isInit: true + }); + + // 请求数据 + that.pullData(that.page, { + done: function () { + that.observeResize(); // 观察尺寸变化 + } + }); + that.events(); // 事件 +}; + +// 根据列类型,定制化参数 +Class.prototype.initOpts = function (item) { + // var that = this; + // var options = that.config; + var initWidth = { + checkbox: 50, + radio: 50, + space: 30, + numbers: 60 + }; + + // 让 type 参数兼容旧版本 + if (item.checkbox) item.type = 'checkbox'; + if (item.space) item.type = 'space'; + if (!item.type) item.type = 'normal'; + if (item.type !== 'normal') { + item.unresize = true; + item.width = item.width || initWidth[item.type]; + } +}; + +//初始化一些参数 +Class.prototype.setInit = function (type) { + var that = this; + var options = that.config; + options.clientWidth = options.width || function () { + //获取容器宽度 + //如果父元素宽度为0(一般为隐藏元素),则继续查找上层元素,直到找到真实宽度为止 + var getWidth = function (parent) { + var width; + var isNone; + parent = parent || options.elem.parent(); + width = that.getContentWidth(parent); + try { + isNone = parent.css('display') === 'none'; + } catch { + // ignore + } + var parentElem = parent.parent(); + if (parent[0] && parentElem && parentElem[0] && (!width || isNone)) return getWidth(parentElem); + return width; + }; + return getWidth(); + }(); + if (type === 'width') return options.clientWidth; + // 初始化高度配置,如果设置了最高高度,以最高高度形式为准 + options.height = options.maxHeight || options.height; + + // 初始化 css 参数 + if (options.css && options.css.indexOf(ELEM_VIEW) === -1) { + var css = options.css.split('}'); + layui.each(css, function (index, value) { + if (value) { + css[index] = '.' + ELEM_VIEW + '-' + that.index + ' ' + value; + } + }); + options.css = css.join('}'); + } + + // 封装对 col 的配置处理 + var initChildCols = function (i1, item1, i2, item2) { + //如果列参数为空,则移除 + if (!item2) { + item1.splice(i2, 1); + return; + } + item2.key = [options.index, i1, i2].join('-'); + item2.colspan = item2.colspan || 0; + item2.rowspan = item2.rowspan || 0; + + //根据列类型,定制化参数 + that.initOpts(item2); + + //设置列的父列索引 + //如果是组合列,则捕获对应的子列 + var indexChild = i1 + (parseInt(item2.rowspan) || 1); + if (indexChild < options.cols.length) { + // 只要不是最后一层都会有子列 + item2.colGroup = true; + var childIndex = 0; + layui.each(options.cols[indexChild], function (i22, item22) { + //如果子列已经被标注为{HAS_PARENT},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环 + if (item22.HAS_PARENT || childIndex >= 1 && childIndex == (item2.colspan || 1)) return; + item22.HAS_PARENT = true; + item22.parentKey = [options.index, i1, i2].join('-'); // i1 + '-' + i2; + childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); + initChildCols(indexChild, options.cols[indexChild], i22, item22); + }); + } else { + item2.colGroup = false; + } + item2.hide = item2.hide && !item2.colGroup || false; // 初始化中中间节点的hide信息不做处理,否则会出错,如果需要必须将其子节点也都同步成hide + }; + + // 初始化列参数 + layui.each(options.cols, function (i1, item1) { + layui.each(item1, function (i2, item2) { + if (i1) { + delete item2.HAS_PARENT; // 去掉临时的计数排除标识,避免有新字段插入的时候重新计算被跳过导致下标出错的问题 + } else { + initChildCols(i1, item1, i2, item2); // 只解析顶层节点由递归完成解析 + } + }); + }); +}; + +// 初始化样式 +Class.prototype.renderStyle = function () { + var that = this; + var options = that.config; + var index = that.index; + var text = []; + + // 单元格宽度 + layui.each(options.cols, function (i1, item1) { + layui.each(item1, function (i2, item2) { + var key = [index, i1, i2].join('-'); + var val = ['width: ', item2.width || options.cellMinWidth, 'px'].join(''); + text.push('.laytable-cell-' + key + '{' + val + '}'); + }); + }); + + // 自定义行样式 + (function (lineStyle) { + if (!lineStyle) return; + var trClassName = '.layui-table-view-' + index + ' .layui-table-body .layui-table tr'; + var rules = lineStyle.split(';'); + var cellMaxHeight = 'none'; + + // 计算单元格最大高度 + layui.each(rules, function (i, rule) { + rule = rule.split(':'); + if (rule[0] === 'height') { + var val = parseFloat(rule[1]); + if (!isNaN(val)) cellMaxHeight = val - 1 + 'px'; + return true; + } + }); + + // 多行相关样式 + layui.each(['{' + lineStyle + '}', '.layui-table-cell{height: auto; max-height: ' + cellMaxHeight + '; white-space: normal; text-overflow: clip;}', '> td:hover > .layui-table-cell{overflow: auto;}'].concat(device.ie ? ['.layui-table-edit{height: ' + cellMaxHeight + ';}', 'td[data-edit]:hover:after{height: ' + cellMaxHeight + ';}'] : []), function (i, val) { + val && text.push(trClassName + ' ' + val); + }); + })(options.lineStyle); + + // 自定义 css 属性 + if (options.css) text.push(options.css); + text.push('.' + FIXED_HEIGHT_PATCH + '{height:auto;}'); + + // 生成 style + lay.style({ + target: that.elem[0], + text: text.join(''), + id: 'DF-table-' + index + }); +}; + +// 初始头部工具栏 +Class.prototype.renderToolbar = function () { + var that = this; + var options = that.config; + var filter = options.elem.attr('lay-filter'); + + // 添加工具栏左侧模板 + var leftDefaultTemp = ['
                  ', '
                  ', '
                  '].join(''); + var elemToolTemp = that.layTool.find('.layui-table-tool-temp'); + if (options.toolbar === 'default') { + elemToolTemp.html(leftDefaultTemp); + } else if (typeof options.toolbar === 'string') { + var toolbarHtml = $(options.toolbar).html() || ''; + toolbarHtml && elemToolTemp.html(laytpl(toolbarHtml).render(options)); + } + + // 头部工具栏右上角默认工具 + var defaultConfig = { + filter: { + title: i18n.$t('table.tools.filter.title'), + layEvent: 'LAYTABLE_COLS', + icon: 'layui-icon-cols', + onClick: function (obj) { + var options = obj.config; + var openPanel = obj.openPanel; + openPanel({ + list: function () { + var lis = []; + that.eachCols(function (i, item) { + if (item.field && item.type == 'normal') { + lis.push('
                • '); + } + }); + return lis.join(''); + }(), + done: function () { + form.on('checkbox(LAY_TABLE_TOOL_COLS)', function (obj) { + var othis = $(obj.elem); + var checked = this.checked; + var key = othis.data('key'); + var col = that.col(key); + var hide = col.hide; + var parentKey = othis.data('parentkey'); + if (!col.key) return; + + // 同步勾选列的 hide 值和隐藏样式 + col.hide = !checked; + that.elem.find('*[data-key="' + key + '"]')[checked ? 'removeClass' : 'addClass'](HIDE); + + // 根据列的显示隐藏,同步多级表头的父级相关属性值 + if (hide != col.hide) { + that.setParentCol(!checked, parentKey); + } + + // 重新适配尺寸 + that.resize(); + + // 列筛选(显示或隐藏)后的事件 + layui.event.call(this, MOD_NAME, 'colToggled(' + filter + ')', { + col: col, + config: options + }); + }); + } + }); + } + }, + exports: { + title: i18n.$t('table.tools.export.title'), + layEvent: 'LAYTABLE_EXPORT', + icon: 'layui-icon-export', + onClick: function (obj) { + // 自带导出 + var data = obj.data; + var options = obj.config; + var openPanel = obj.openPanel; + var elem = obj.elem; + if (!data.length) return layer.tips(i18n.$t('table.tools.export.noDataPrompt'), elem, { + tips: 3 + }); + if (device.ie) { + layer.tips(i18n.$t('table.tools.export.compatPrompt'), elem, { + tips: 3 + }); + } else { + openPanel({ + list: function () { + return ['
                • ' + i18n.$t('table.tools.export.csvText') + '
                • '].join(''); + }(), + done: function (panel, list) { + list.on('click', function () { + var type = $(this).data('type'); + table.exportFile.call(that, options.id, null, type); + }); + } + }); + } + } + }, + print: { + title: i18n.$t('table.tools.print.title'), + layEvent: 'LAYTABLE_PRINT', + icon: 'layui-icon-print', + onClick: function (obj) { + var data = obj.data; + // var options = obj.config; + var elem = obj.elem; + if (!data.length) return layer.tips(i18n.$t('table.tools.print.noDataPrompt'), elem, { + tips: 3 + }); + var printWin = window.open('about:blank', '_blank'); + var style = [''].join(''); + var html = $(that.layHeader.html()); // 输出表头 + + html.append(that.layMain.find('table').html()); // 输出表体 + html.append(that.layTotal.find('table').html()); // 输出合计行 + + html.find('th.layui-table-patch').remove(); // 移除补丁 + // 移除表头特殊列 + html.find('thead>tr>th.' + ELEM_COL_SPECIAL).filter(function (i, thElem) { + return !$(thElem).children('.' + ELEM_GROUP).length; // 父级表头除外 + }).remove(); + html.find('tbody>tr>td.' + ELEM_COL_SPECIAL).remove(); // 移除表体特殊列 + + printWin.document.write(style + html.prop('outerHTML')); + printWin.document.close(); + if (layui.device('edg').edg) { + printWin.onafterprint = printWin.close; + printWin.print(); + } else { + printWin.print(); + printWin.close(); + } + } + } + }; + + // 若开启 defaultToolbar + if (typeof options.defaultToolbar === 'object') { + var iconElem = []; + options.defaultToolbar = $.map(options.defaultToolbar, function (item) { + var itemIsName = typeof item === 'string'; + var thisItem = itemIsName ? defaultConfig[item] : item; + if (thisItem) { + // 根据 name 匹配默认工具并合并 + if (thisItem.name && defaultConfig[thisItem.name]) { + thisItem = $.extend({}, defaultConfig[thisItem.name], thisItem); + } + // 初始化默认工具 name + if (!thisItem.name && itemIsName) { + thisItem.name = item; + } + // 图标列表 + iconElem.push('
                  ' + '' + '
                  '); + } + return thisItem; + }); + that.layTool.find('.layui-table-tool-self').html(iconElem.join('')); + } +}; + +// 分页栏 +Class.prototype.renderPagebar = function () { + var that = this; + var options = that.config; + var layPagebar = that.layPagebar = $('
                  '); + + // 开启分页栏自定义模板 + if (options.pagebar) { + var pagebarHtml = $(options.pagebar).html() || ''; + pagebarHtml && layPagebar.append(laytpl(pagebarHtml).render(options)); + that.layPage.append(layPagebar); + } +}; + +// 同步表头父列的相关值 +Class.prototype.setParentCol = function (hide, parentKey) { + var that = this; + var options = that.config; + var parentTh = that.layHeader.find('th[data-key="' + parentKey + '"]'); // 获取父列元素 + var parentColspan = parseInt(parentTh.attr('colspan')) || 0; + if (parentTh[0]) { + var arrParentKey = parentKey.split('-'); + var getThisCol = options.cols[arrParentKey[1]][arrParentKey[2]]; + hide ? parentColspan-- : parentColspan++; + parentTh.attr('colspan', parentColspan); + parentTh[parentColspan ? 'removeClass' : 'addClass'](HIDE); // 如果子列显示,父列必然需要显示 + + getThisCol.colspan2 = parentColspan; // 更新实际的 colspan 数 + getThisCol.hide = parentColspan < 1; // 同步 hide 参数 + + // 递归,继续往上查询是否有父列 + var nextParentKey = parentTh.data('parentkey'); + nextParentKey && that.setParentCol(hide, nextParentKey); + } +}; + +// 多级表头补丁 +Class.prototype.setColsPatch = function () { + var that = this; + var options = that.config; + + // 同步表头父列的相关值 + layui.each(options.cols, function (i1, item1) { + layui.each(item1, function (i2, item2) { + if (item2.hide) { + that.setParentCol(item2.hide, item2.parentKey); + } + }); + }); +}; + +// 设置组合表头的最大宽度 +Class.prototype.setGroupWidth = function (th) { + var that = this; + var options = that.config; + if (options.cols.length <= 1) return; + + // 获取表头组合 + var groups = that.layHeader.find( + // 根据当前活动的表头 parentkey 属性查找其组合表头 + (th ? 'th[data-key=' + th.data('parentkey') + ']>' : '') + '.' + ELEM_GROUP); // 若无指向当前活动表头,则自下而上获取所有组合表头 + + groups.css('width', 0); + layui.each(groups.get().reverse(), function () { + var othis = $(this); + var key = othis.parent().data('key'); + var maxWidth = 0; + that.layHeader.eq(0).find('th[data-parentkey=' + key + ']').width(function (i, width) { + var oTh = $(this); + if (oTh.hasClass(HIDE)) return; + width > 0 && (maxWidth += width); + }); + + // 给组合表头赋值最大宽度 + if (maxWidth) othis.css('max-width', maxWidth - 1); + + // 若当前活动的组合表头仍存在上级,则继续向上设置 + if (th && othis.parent().data('parentkey')) { + that.setGroupWidth(othis.parent()); + } + }); + groups.css('width', 'auto'); +}; + +// 动态分配列宽 +Class.prototype.setColsWidth = function (opt) { + var that = this; + var options = that.config; + var colNums = 0; // 列个数 + var autoColNums = 0; // 自动列宽的列个数 + var autoWidth = 0; // 自动列分配的宽度 + var countWidth = 0; // 所有列总宽度和 + var cntrWidth = that.setInit('width'); + var borderWidth = parseFloat(layui.getStyle(that.elem[0], 'border-left-width')); + var lastSpreadCol; + var headerTableElem = that.layHeader.first().children('table'); + var mainTableElem = that.layMain.find('table'); + var isEmptyTable = that.layMain.find('tbody').is(':empty'); + var isInit = opt && opt.isInit; + + // 统计列个数和最后一个分配宽度的列 + that.eachCols(function (i, item) { + if (!item.hide) { + colNums++; + if (!(item.width || item.type !== 'normal')) { + lastSpreadCol = item; + } + } + }); + + // 减去边框差和滚动条宽 + cntrWidth = cntrWidth - function () { + return options.skin === 'line' || options.skin === 'nob' ? 2 : colNums + 1; + }() * borderWidth - that.getScrollWidth(that.layMain[0]); + + // 计算自动分配的宽度 + var getAutoWidth = function (back) { + // 遍历所有列 + layui.each(options.cols, function (i1, item1) { + layui.each(item1, function (i2, item2) { + var width = 0; + var minWidth = item2.minWidth || options.cellMinWidth; // 最小宽度 + var maxWidth = item2.maxWidth || options.cellMaxWidth; // 最大宽度 + + if (!item2) { + item1.splice(i2, 1); + return; + } + if (item2.colGroup || item2.hide) return; + if (!back) { + width = item2.width || 0; + if (/\d+%$/.test(width)) { + // 列宽为百分比 + width = parseFloat(width) / 100 * cntrWidth; + width < minWidth && (width = minWidth); + width > maxWidth && (width = maxWidth); + } else if (!width) { + // 列宽未填写 + item2.width = width = 0; + autoColNums++; + } else if (item2.type === 'normal') { + // 若 width 小于 minWidth, 则将 width 值自动设为 minWidth 的值 + width < minWidth && (item2.width = width = minWidth); + // 若 width 大于 maxWidth, 则将 width 值自动设为 maxWidth 的值 + width > maxWidth && (item2.width = width = maxWidth); + } + } else if (autoWidth && autoWidth < minWidth) { + autoColNums--; + width = minWidth; + } else if (autoWidth && autoWidth > maxWidth) { + autoColNums--; + width = maxWidth; + } + if (item2.hide) width = 0; + countWidth = countWidth + width; + }); + }); + + // 如果未填充满,则将剩余宽度平分 + cntrWidth > countWidth && autoColNums > 0 && (autoWidth = (cntrWidth - countWidth) / autoColNums); + }; + getAutoWidth(); + getAutoWidth(true); // 重新检测分配的宽度是否低于最小列宽 + + // 记录自动列数 + that.autoColNums = autoColNums = autoColNums > 0 ? autoColNums : 0; + var pixelsForLastCol = cntrWidth; + that.eachCols(function (i3, item3) { + var minWidth = item3.minWidth || options.cellMinWidth; + var maxWidth = item3.maxWidth || options.cellMaxWidth; + if (item3.colGroup || item3.hide || lastSpreadCol && lastSpreadCol.key === item3.key) return; + + // 给未分配宽的列平均分配宽 + if (item3.width === 0) { + that.cssRules(item3.key, function (item) { + var newWidth = Math.round(function () { + if (autoWidth < minWidth) return minWidth; + if (autoWidth > maxWidth) return maxWidth; + return autoWidth; + }()); + item.style.width = newWidth + 'px'; + pixelsForLastCol = pixelsForLastCol - newWidth; + }); + } + + // 给设定百分比的列分配列宽 + else if (/\d+%$/.test(item3.width)) { + that.cssRules(item3.key, function (item) { + var width = Math.round(parseFloat(item3.width) / 100 * cntrWidth); + width < minWidth && (width = minWidth); + width > maxWidth && (width = maxWidth); + item.style.width = width + 'px'; + pixelsForLastCol = pixelsForLastCol - width; + }); + } + + // 给拥有普通 width 值的列分配最新列宽 + else { + that.cssRules(item3.key, function (item) { + item.style.width = item3.width + 'px'; + pixelsForLastCol = pixelsForLastCol - item3.width; + }); + } + }); + // 最后一列获取剩余的空间,避免舍入导致的布局问题 + if (lastSpreadCol) { + that.cssRules(lastSpreadCol.key, function (item) { + var minWidth = lastSpreadCol.minWidth || options.cellMinWidth; + var maxWidth = lastSpreadCol.maxWidth || options.cellMaxWidth; + var newWidth = Math.max(Math.min(pixelsForLastCol, maxWidth), minWidth); + item.style.width = newWidth + 'px'; + if (!isInit && isEmptyTable) { + // 将表格宽度设置为跟表头一样的宽度,使之可以出现底部滚动条,以便滚动查看所有字段 + mainTableElem.width(that.getContentWidth(headerTableElem)); + } + // 二次校验,如果仍然出现横向滚动条(通常是 1px 的误差导致) + // 不同屏幕分辨率、缩放水平以及浏览器渲染差异,可能会触发这个问题 + if (that.layMain.prop('offsetHeight') > that.layMain.prop('clientHeight')) { + item.style.width = parseFloat(item.style.width) - borderWidth + 'px'; + } + }); + } + if (!isInit && isEmptyTable) { + // 将表格宽度设置为跟表头一样的宽度,使之可以出现底部滚动条,以便滚动查看所有字段 + mainTableElem.width(that.getContentWidth(headerTableElem)); + } else { + mainTableElem.width('auto'); + } + that.setGroupWidth(); +}; + +// 重置表格尺寸/结构 +var RESIZE_THRESHOLD = 2; +Class.prototype.resize = function (entry) { + var that = this; + + // 仅由 resizeObserver 触发时生效 + if (entry) { + // 当表格被隐藏时,不触发 resize + if (entry.contentRect.height === 0 && entry.contentRect.width === 0) { + return; + } + + // 忽略微小的尺寸变化 + var shouldIgnore = entry.target._lay_lastSize && Math.abs(entry.target._lay_lastSize.height - entry.contentRect.height) < RESIZE_THRESHOLD && Math.abs(entry.target._lay_lastSize.width - entry.contentRect.width) < RESIZE_THRESHOLD; + if (shouldIgnore) return; + entry.target._lay_lastSize = { + height: entry.contentRect.height, + width: entry.contentRect.width + }; + } + var tableElemIsConnected = that.layMain && ('isConnected' in that.layMain[0] ? that.layMain[0].isConnected : $.contains(document.body, that.layMain[0])); + if (!tableElemIsConnected) return; + that.fullSize(); // 让表格铺满 + that.setColsWidth(); // 自适应列宽 + that.scrollPatch(); // 滚动条补丁 +}; + +// 表格重载 +Class.prototype.reload = function (options, deep, type) { + var that = this; + options = options || {}; + delete that.haveInit; + + // 防止数组深度合并 + layui.each(options, function (key, item) { + if (layui.type(item) === 'array') delete that.config[key]; + }); + + // 对参数进行深度或浅扩展 + that.config = $.extend(deep, {}, that.config, options); + if (type !== 'reloadData') { + layui.each(that.config.cols, function (i1, item1) { + layui.each(item1, function (i2, item2) { + delete item2.colspan2; + }); + }); + delete that.config.HAS_SET_COLS_PATCH; + } + // 执行渲染 + that.render(type); +}; + +// 异常提示 +Class.prototype.errorView = function (html) { + var that = this, + elemNone = that.layMain.find('.' + NONE), + layNone = $('
                  ' + (html || 'Error') + '
                  '); + if (elemNone[0]) { + that.layNone.remove(); + elemNone.remove(); + } + that.layFixed.addClass(HIDE); + that.layMain.find('tbody').html(''); + that.layMain.append(that.layNone = layNone); + + // 异常情况下对 page 和 total 的内容处理 + that.layTotal.addClass(HIDE_V); + that.layPage.find(ELEM_PAGE_VIEW).addClass(HIDE_V); + table.cache[that.key] = []; //格式化缓存数据 + + that.syncCheckAll(); + that.renderForm(); + that.setColsWidth(); + that.loading(false); +}; + +// 初始页码 +Class.prototype.page = 1; + +// 获得数据 +Class.prototype.pullData = function (curr, opts) { + var that = this; + var options = that.config; + // 同步表头父列的相关值 + options.HAS_SET_COLS_PATCH || that.setColsPatch(); + options.HAS_SET_COLS_PATCH = true; + var request = options.request; + var response = options.response; + var res; + var sort = function () { + if (typeof options.initSort === 'object') { + that.sort({ + field: options.initSort.field, + type: options.initSort.type, + reloadType: opts.type + }); + } + }; + var done = function (res, origin) { + that.setColsWidth(); + that.loading(false); + typeof options.done === 'function' && options.done(res, curr, res[response.countName], origin); + typeof opts.done === 'function' && opts.done(); + }; + opts = opts || {}; + + // 数据拉取前的回调 + typeof options.before === 'function' && options.before(options); + that.startTime = new Date().getTime(); // 渲染开始时间 + + if (opts.renderData) { + // 将 cache 信息重新渲染 + res = {}; + res[response.dataName] = table.cache[that.key]; + res[response.countName] = options.url ? layui.type(options.page) === 'object' ? options.page.count : res[response.dataName].length : options.data.length; + + // 记录合计行数据 + if (typeof options.totalRow === 'object') { + res[response.totalRowName] = $.extend({}, that.totalRow); + } + that.renderData({ + res: res, + curr: curr, + count: res[response.countName], + type: opts.type, + sort: true + }), done(res, 'renderData'); + } else if (options.url) { + // Ajax请求 + var params = {}; + // 当 page 开启,默认自动传递 page、limit 参数 + if (options.page) { + params[request.pageName] = curr; + params[request.limitName] = options.limit; + } + + // 参数 + var data = $.extend(params, options.where); + if (options.contentType && options.contentType.indexOf('application/json') == 0) { + // 提交 json 格式 + data = JSON.stringify(data); + } + that.loading(true); + var ajaxOptions = { + type: options.method || 'get', + url: options.url, + contentType: options.contentType, + data: data, + dataType: options.dataType || 'json', + jsonpCallback: options.jsonpCallback, + headers: options.headers || {}, + complete: typeof options.complete === 'function' ? options.complete : undefined, + success: function (res) { + // 若有数据解析的回调,则获得其返回的数据 + if (typeof options.parseData === 'function') { + res = options.parseData(res) || res; + } + // 检查数据格式是否符合规范 + if (res[response.statusName] != response.statusCode) { + that.errorView(res[response.msgName] || i18n.$t('table.dataFormatError', { + statusName: response.statusName, + statusCode: response.statusCode + })); + } else { + // 当前页不能超过总页数 + var count = res[response.countName]; + var pages = Math.ceil(count / options.limit) || 1; + if (curr > pages) { + curr = pages; + } + that.totalRow = res[response.totalRowName]; + that.renderData({ + res: res, + curr: curr, + count: count, + type: opts.type + }), sort(); + + // 耗时(接口请求+视图渲染) + options.time = new Date().getTime() - that.startTime + ' ms'; + } + done(res, opts.type); + }, + error: function (e, msg) { + if (e && e.status === 0 && that._xhrAbort) { + that._xhrAbort = false; + return; + } + that.errorView(i18n.$t('table.xhrError', { + msg: msg + })); + typeof options.error === 'function' && options.error(e, msg); + } + }; + if (options.ajax) { + options.ajax(ajaxOptions, 'table'); + } else { + // 4:代表响应已完成 + if (that._xhr && that._xhr.readyState !== 4) { + that._xhrAbort = true; + that._xhr.abort(); + } + that._xhr = $.ajax(ajaxOptions); + } + } else if (layui.type(options.data) === 'array') { + //已知数据 + res = {}; + var startLimit = curr * options.limit - options.limit; + var newData = options.data.concat(); + res[response.dataName] = options.page ? newData.splice(startLimit, options.limit) : newData; + res[response.countName] = options.data.length; + + // 记录合计行数据 + if (typeof options.totalRow === 'object') { + res[response.totalRowName] = $.extend({}, options.totalRow); + } + that.totalRow = res[response.totalRowName]; + that.renderData({ + res: res, + curr: curr, + count: res[response.countName], + type: opts.type + }), sort(); + done(res, opts.type); + } +}; + +// 遍历表头 +Class.prototype.eachCols = function (callback) { + var that = this; + table.eachCols(null, callback, that.config.cols); + return that; +}; + +// 获取表头参数项 +Class.prototype.col = function (key) { + try { + key = key.split('-'); + return this.config.cols[key[1]][key[2]] || {}; + } catch (e) { + hint.error(e); + return {}; + } +}; +Class.prototype.getTrHtml = function (data, sort, curr, trsObj) { + var that = this; + var options = that.config; + var trs = trsObj && trsObj.trs || []; + var trs_fixed = trsObj && trsObj.trs_fixed || []; + var trs_fixed_r = trsObj && trsObj.trs_fixed_r || []; + curr = curr || 1; + layui.each(data, function (i1, item1) { + var tds = []; + var tds_fixed = []; + var tds_fixed_r = []; + var numbers = i1 + options.limit * (curr - 1) + 1; // 序号 + + // 数组值是否为 object,如果不是,则自动转为 object + if (typeof item1 !== 'object') { + data[i1] = item1 = { + LAY_KEY: item1 + }; + try { + table.cache[that.key][i1] = item1; + } catch { + // ignore + } + } + + //若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) + if (layui.type(item1) === 'array' && item1.length === 0) return; + + // 加入序号保留字段 + item1[table.config.numbersName] = numbers; + + // 记录下标, + item1[table.config.indexName] = i1; + if (!sort) item1[table.config.initIndexName] = i1; // 记录初始状态下标,仅用于内部恢复当前页表格排序 + + // 遍历表头 + that.eachCols(function (i3, item3) { + var field = item3.field || i3; + var key = item3.key; + var content = item1[field]; + if (content === undefined || content === null) content = ''; + if (item3.colGroup) return; + + // td 内容 + var td = ['', '
                  ' + function () { + var tplData = $.extend(true, { + LAY_COL: item3 + }, item1); + var checkName = table.config.checkName; + var disabledName = table.config.disabledName; + + // 渲染不同风格的列 + switch (item3.type) { + case 'checkbox': + // 复选 + return ''; + //break; + case 'radio': + // 单选 + return ''; + //break; + case 'numbers': + return numbers; + //break; + } + + //解析工具列模板 + if (item3.toolbar) { + return laytpl($(item3.toolbar).html() || '').render(tplData); + } + return parseTempData.call(that, { + item3: item3, + content: content, + tplData: tplData + }); + }(), '
                  '].join(''); + tds.push(td); + if (item3.fixed && item3.fixed !== 'right') tds_fixed.push(td); + if (item3.fixed === 'right') tds_fixed_r.push(td); + }); + + // 添加 tr 属性 + var trAttr = function () { + var arr = ['data-index="' + i1 + '"']; + if (item1[table.config.checkName]) arr.push('class="' + ELEM_CHECKED + '"'); + return arr.join(' '); + }(); + trs.push('' + tds.join('') + ''); + trs_fixed.push('' + tds_fixed.join('') + ''); + trs_fixed_r.push('' + tds_fixed_r.join('') + ''); + }); + return { + trs: trs, + trs_fixed: trs_fixed, + trs_fixed_r: trs_fixed_r + }; +}; + +// 返回行节点代码 +table.getTrHtml = function (id, data) { + var that = getThisTable(id); + return that.getTrHtml(data, null, that.page); +}; + +// 数据渲染 +Class.prototype.renderData = function (opts) { + var that = this; + var options = that.config; + var res = opts.res; + var curr = opts.curr; + var count = that.count = opts.count; + var sort = opts.sort; + var data = res[options.response.dataName] || []; //列表数据 + var totalRowData = res[options.response.totalRowName]; //合计行数据 + var trs = []; + var trs_fixed = []; + var trs_fixed_r = []; + + // 渲染视图 + var render = function () { + // 后续性能提升的重点 + if (!sort && that.sortKey) { + return that.sort({ + field: that.sortKey.field, + type: that.sortKey.sort, + pull: true, + reloadType: opts.type + }); + } + that.getTrHtml(data, sort, curr, { + trs: trs, + trs_fixed: trs_fixed, + trs_fixed_r: trs_fixed_r + }); + + // 容器的滚动条位置 + if (!(options.scrollPos === 'fixed' && opts.type === 'reloadData')) { + that.layBody.scrollTop(0); + } + if (options.scrollPos === 'reset') { + that.layBody.scrollLeft(0); + } + that.layMain.find('.' + NONE).remove(); + that.layMain.find('tbody').html(trs.join('')); + that.layFixLeft.find('tbody').html(trs_fixed.join('')); + that.layFixRight.find('tbody').html(trs_fixed_r.join('')); + + // 渲染表单 + that.syncCheckAll(); + that.renderForm(); + + // 因为 page 参数有可能发生变化 先重新铺满 + that.fullSize(); + + // 滚动条补丁 + that.haveInit ? that.scrollPatch() : setTimeout(function () { + that.scrollPatch(); + }, 50); + that.haveInit = true; + + // reloadData 或 renderData 时,tbody 高度可能不变,需要主动同步 + if (that.needSyncFixedRowHeight) { + that.calcFixedRowHeight(); + } + layer.close(that.tipsIndex); + }; + table.cache[that.key] = data; //记录数据 + + //显示隐藏合计栏 + that.layTotal[data.length == 0 ? 'addClass' : 'removeClass'](HIDE_V); + + //显示隐藏分页栏 + that.layPage[options.page || options.pagebar ? 'removeClass' : 'addClass'](HIDE); + that.layPage.find(ELEM_PAGE_VIEW)[!options.page || count == 0 || data.length === 0 && curr == 1 ? 'addClass' : 'removeClass'](HIDE_V); + + //如果无数据 + if (data.length === 0) { + return that.errorView(options.text.none); + } else { + that.layFixLeft.removeClass(HIDE); + } + + //如果执行初始排序 + if (sort) { + return render(); + } + + //正常初始化数据渲染 + render(); //渲染数据 + that.renderTotal(data, totalRowData); //数据合计 + that.layTotal && that.layTotal.removeClass(HIDE); + + //同步分页状态 + if (options.page) { + options.page = $.extend({ + elem: 'layui-table-page' + options.index, + count: count, + limit: options.limit, + limits: options.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90], + groups: 3, + layout: ['prev', 'page', 'next', 'skip', 'count', 'limit'], + prev: '', + next: '', + jump: function (obj, first) { + if (!first) { + //分页本身并非需要做以下更新,下面参数的同步,主要是因为其它处理统一用到了它们 + //而并非用的是 options.page 中的参数(以确保分页未开启的情况仍能正常使用) + that.page = obj.curr; //更新页码 + options.limit = obj.limit; //更新每页条数 + + that.pullData(obj.curr); + } + } + }, options.page); + options.page.count = count; //更新总条数 + laypage.render(options.page); + } +}; + +// 重新渲染数据 +table.renderData = function (id) { + var that = getThisTable(id); + if (!that) { + return; + } + that.pullData(that.page, { + renderData: true, + type: 'reloadData' + }); +}; + +// 数据合计行 +Class.prototype.renderTotal = function (data, totalRowData) { + var that = this; + var options = that.config; + var totalNums = {}; + if (!options.totalRow) return; + layui.each(data, function (i1, item1) { + // 若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) + if (layui.type(item1) === 'array' && item1.length === 0) return; + that.eachCols(function (i3, item3) { + var field = item3.field || i3, + content = item1[field]; + if (item3.totalRow) { + totalNums[field] = (totalNums[field] || 0) + (parseFloat(content) || 0); + } + }); + }); + that.dataTotal = []; // 记录合计行结果 + + var tds = []; + that.eachCols(function (i3, item3) { + var field = item3.field || i3; + + // 合计数据的特定字段 + var TOTAL_NUMS = totalRowData && totalRowData[item3.field]; + + // 合计数据的小数点位数处理 + var decimals = 'totalRowDecimals' in item3 ? item3.totalRowDecimals : 2; + var thisTotalNum = totalNums[field] ? parseFloat(totalNums[field] || 0).toFixed(decimals) : ''; + + // 合计内容 + var content = function () { + var text = item3.totalRowText || ''; + var tplData = { + LAY_COL: item3 + }; + tplData[field] = thisTotalNum; + + // 获取自动计算的合并内容 + var getContent = item3.totalRow ? parseTempData.call(that, { + item3: item3, + content: thisTotalNum, + tplData: tplData + }) || text : text; + + // 如果直接传入了合计行数据,则不输出自动计算的结果 + return TOTAL_NUMS || getContent; + }(); + + // td 显示内容 + var tdContent = function () { + var totalRow = item3.totalRow || options.totalRow; + + // 如果 totalRow 参数为字符类型,则解析为自定义模版 + if (typeof totalRow === 'string') { + return laytpl(totalRow).render($.extend({ + TOTAL_NUMS: TOTAL_NUMS || totalNums[field], + TOTAL_ROW: totalRowData || {}, + LAY_COL: item3 + }, item3)); + } + return content; + }(); + + // 合计原始结果 + item3.field && that.dataTotal.push({ + field: item3.field, + total: $('
                  ' + tdContent + '
                  ').text() + }); + + // td 容器 + var td = ['', '
                  ' + tdContent, '
                  '].join(''); + tds.push(td); + }); + var patchElem = that.layTotal.find('.layui-table-patch'); // 可能存在滚动条补丁 + that.layTotal.find('tbody').html('' + tds.join('') + (patchElem.length ? patchElem.get(0).outerHTML : '') + ''); +}; + +//找到对应的列元素 +Class.prototype.getColElem = function (parent, key) { + // var that = this; + //var options = that.config; + return parent.eq(0).find('.laytable-cell-' + key + ':eq(0)'); +}; + +// 渲染表单 +Class.prototype.renderForm = function (type) { + var that = this; + // var options = that.config; + var filter = that.elem.attr('lay-filter'); + form.render(type, filter); +}; + +// 定向渲染表单 +Class.prototype.renderFormByElem = function (elem) { + layui.each(['input', 'select'], function (i, formType) { + form.render(elem.find(formType)); + }); +}; + +// 同步全选按钮状态 +Class.prototype.syncCheckAll = function () { + var that = this; + var options = that.config; + var checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]'); + var syncColsCheck = function (checked) { + that.eachCols(function (i, item) { + if (item.type === 'checkbox') { + item[options.checkName] = checked; + } + }); + return checked; + }; + var checkStatus = table.checkStatus(that.key); + if (!checkAllElem[0]) return; + + // 选中状态 + syncColsCheck(checkStatus.isAll); + checkAllElem.prop({ + checked: checkStatus.isAll, + indeterminate: !checkStatus.isAll && checkStatus.data.length // 半选 + }); +}; + +// 标记当前活动行背景色 +Class.prototype.setRowActive = function (index, className, removeClass) { + var that = this; + // var options = that.config; + var tr = that.layBody.find('tr[data-index="' + index + '"]'); + className = className || 'layui-table-click'; + if (removeClass) return tr.removeClass(className); + tr.addClass(className); + tr.siblings('tr').removeClass(className); +}; + +// 设置行选中状态 +Class.prototype.setRowChecked = function (opts) { + var that = this; + var options = that.config; + var isCheckAll = opts.index === 'all'; // 是否操作全部 + var isCheckMult = layui.type(opts.index) === 'array'; // 是否操作多个 + var isCheckAllOrMult = isCheckAll || isCheckMult; // 是否全选或多选 + + // treeTable 内部已处理选中,此处不再处理 + if (options.tree && options.tree.view) return; + + // 全选或多选时 + if (isCheckAllOrMult) { + that.layBox.addClass(DISABLED_TRANSITION); // 减少回流 + if (opts.type === 'radio') return; // radio 不允许全选或多选 + } + if (isCheckMult) { + var makeMap = {}; + layui.each(opts.index, function (i, v) { + makeMap[v] = true; + }); + opts.index = makeMap; + } + + // 匹配行元素 + var tbody = that.layBody.children('.layui-table').children('tbody'); + var selector = isCheckAllOrMult ? 'tr' : 'tr[data-index="' + opts.index + '"]'; + var tr = function (tr) { + return isCheckAll ? tr : tr.filter(isCheckMult ? function () { + var dataIndex = $(this).data('index'); + return opts.index[dataIndex]; + } : '[data-index="' + opts.index + '"]'); + }(tbody.children(selector)); + + // 默认属性 + opts = $.extend({ + type: 'checkbox' // 选中方式 + }, opts); + + // 同步数据选中属性值 + var thisData = table.cache[that.key]; + var existChecked = 'checked' in opts; + + // 若为单选框,则单向选中;若为复选框,则切换选中。 + var getChecked = function (value) { + return opts.type === 'radio' ? true : existChecked ? opts.checked : !value; + }; + var radioCheckedIndex; + + // 给匹配行设置选中状态 + tr.each(function () { + var el = $(this); + var i = el.attr('data-index'); + var item = thisData[i]; + if (!i) return; // 此时 el 通常为静态表格嵌套时的原始模板 + + // 绕过空项和禁用项 + if (layui.type(item) === 'array' || item[options.disabledName]) { + return; + } + + // 标记数据选中状态 + var checked = item[options.checkName] = getChecked(el.hasClass(ELEM_CHECKED)); + + // 标记当前行背景色 + el.toggleClass(ELEM_CHECKED, !!checked); + + // 若为 radio 类型,则取消其他行选中背景色 + if (opts.type === 'radio') { + radioCheckedIndex = i; + el.siblings().removeClass(ELEM_CHECKED); + } + }); + + // 若为 radio 类型,移除其他行数据选中状态 + if (radioCheckedIndex) { + layui.each(thisData, function (i, item) { + if (Number(radioCheckedIndex) !== Number(i)) { + delete item[options.checkName]; + } + }); + } + + // 若存在复选框或单选框,则标注选中状态样式 + var td = tr.children('td').children('.layui-table-cell'); + var checkedElem = td.children('input[lay-type="' + ({ + radio: 'layTableRadio', + checkbox: 'layTableCheckbox' + }[opts.type] || 'checkbox') + '"]:not(:disabled)'); + var checkedSameElem = checkedElem.last(); + var fixRElem = checkedSameElem.closest(ELEM_FIXR); + (opts.type === 'radio' && fixRElem.hasClass(HIDE) ? checkedElem.first() : checkedElem).prop('checked', getChecked(checkedSameElem.prop('checked'))); + that.syncCheckAll(); + if (isCheckAllOrMult) { + setTimeout(function () { + that.layBox.removeClass(DISABLED_TRANSITION); + }, 100); + } +}; + +// 数据排序 +Class.prototype.sort = function (opts) { + // field, type, pull, fromEvent + var that = this; + var field; + var res = {}; + var options = that.config; + var filter = options.elem.attr('lay-filter'); + var data = table.cache[that.key], + thisData; + opts = opts || {}; + + // 字段匹配 + if (typeof opts.field === 'string') { + field = opts.field; + that.layHeader.find('th').each(function () { + var othis = $(this); + var _field = othis.data('field'); + if (_field === opts.field) { + opts.field = othis; + field = _field; + return false; + } + }); + } + try { + field = field || opts.field.data('field'); + var key = opts.field.data('key'); + + // 如果欲执行的排序已在状态中,则不执行渲染 + if (that.sortKey && !opts.pull) { + if (field === that.sortKey.field && opts.type === that.sortKey.sort) { + return; + } + } + var elemSort = that.layHeader.find('th .laytable-cell-' + key).find(ELEM_SORT); + that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); // 清除其它标题排序状态 + elemSort.attr('lay-sort', opts.type || null); + that.layFixed.find('th'); + } catch { + hint.error("Table modules: sort field '" + field + "' not matched"); + } + + // 记录排序索引和类型 + that.sortKey = { + field: field, + sort: opts.type + }; + + // 默认为前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) + if (options.autoSort) { + if (opts.type === 'asc') { + //升序 + thisData = layui.sort(data, field, null, true); + } else if (opts.type === 'desc') { + //降序 + thisData = layui.sort(data, field, true, true); + } else { + // 清除排序 + thisData = layui.sort(data, table.config.initIndexName, null, true); + delete that.sortKey; + delete options.initSort; + } + } + res[options.response.dataName] = thisData || data; + + // 重载数据 + that.renderData({ + res: res, + curr: that.page, + count: that.count, + sort: true, + type: opts.reloadType + }); + + // 排序是否来自于点击表头事件触发 + if (opts.fromEvent) { + options.initSort = { + field: field, + type: opts.type + }; + layui.event.call(opts.field, MOD_NAME, 'sort(' + filter + ')', $.extend({ + config: options + }, options.initSort)); + } +}; + +// 请求 loading +Class.prototype.loading = function (show) { + var that = this; + var options = that.config; + if (options.loading) { + that.layBox.find(ELEM_INIT).toggleClass(HIDE, !show); + } +}; + +// 获取对应单元格的 cssRules +Class.prototype.cssRules = function (key, callback) { + var that = this; + var style = that.elem.children('style')[0]; + lay.getStyleRules(style, function (item) { + if (item.selectorText === '.laytable-cell-' + key) { + callback(item); + return true; + } + }); +}; + +// 让表格铺满 +Class.prototype.fullSize = function () { + var that = this; + var options = that.config; + var height = options.height; + var bodyHeight; + var MIN_HEIGHT = 135; + if (that.fullHeightGap) { + height = _WIN.height() - that.fullHeightGap; + if (height < MIN_HEIGHT) height = MIN_HEIGHT; + // that.elem.css('height', height); + } else if (that.parentDiv && that.parentHeightGap) { + height = $(that.parentDiv).height() - that.parentHeightGap; + if (height < MIN_HEIGHT) height = MIN_HEIGHT; + // that.elem.css("height", height); + } else if (that.customHeightFunc) { + height = that.customHeightFunc(); + if (height < MIN_HEIGHT) height = MIN_HEIGHT; + } + + // 如果多级表头,则填补表头高度 + if (options.cols.length > 1) { + // 补全高度 + var th = that.layFixed.find(ELEM_HEADER).find('th'); + // 固定列表头同步跟本体 th 一致高度 + var headerMain = that.layHeader.first(); + layui.each(th, function (thIndex, thElem) { + thElem = $(thElem); + thElem.height(headerMain.find('th[data-key="' + thElem.attr('data-key') + '"]').height() + 'px'); + }); + } + if (!height) return; + + // 减去列头区域的高度 --- 此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题,只对默认尺寸表格做支持 + bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 39); + + // 减去工具栏的高度 + if (options.toolbar) { + bodyHeight -= that.layTool.outerHeight() || 51; + } + + // 减去统计栏的高度 + if (options.totalRow) { + bodyHeight -= that.layTotal.outerHeight() || 40; + } + + // 减去分页栏的高度 + if (options.page || options.pagebar) { + bodyHeight -= that.layPage.outerHeight() || 43; + } + if (options.maxHeight) { + layui.each({ + elem: height, + layMain: bodyHeight + }, function (elemName, elemHeight) { + that[elemName].css({ + height: 'auto', + maxHeight: elemHeight + 'px' + }); + }); + } else { + that.layMain.outerHeight(bodyHeight); + } +}; + +//获取滚动条宽度 +Class.prototype.getScrollWidth = function (elem) { + var width; + if (elem) { + width = elem.offsetWidth - elem.clientWidth; + } else { + elem = document.createElement('div'); + elem.style.width = '100px'; + elem.style.height = '100px'; + elem.style.overflowY = 'scroll'; + document.body.appendChild(elem); + width = elem.offsetWidth - elem.clientWidth; + document.body.removeChild(elem); + } + return width; +}; + +// 滚动条补丁 +Class.prototype.scrollPatch = function () { + var that = this; + var layMainTable = that.layMain.children('table'); + var scrollWidth = that.layMain.width() - that.layMain.prop('clientWidth'); // 纵向滚动条宽度 + var scrollHeight = that.layMain.height() - that.layMain.prop('clientHeight'); // 横向滚动条高度 + // var getScrollWidth = that.getScrollWidth(that.layMain[0]); // 获取主容器滚动条宽度,如果有的话 + var outWidth = layMainTable.outerWidth() - that.layMain.width(); // 表格内容器的超出宽度 + + // 添加补丁 + var addPatch = function (elem) { + if (scrollWidth && scrollHeight) { + elem = elem.eq(0); + if (!elem.find('.layui-table-patch')[0]) { + var patchElem = $('
                  '); // 补丁元素 + patchElem.find('div').css({ + width: scrollWidth + }); + elem.find('tr').append(patchElem); + } + } else { + elem.find('.layui-table-patch').remove(); + } + }; + addPatch(that.layHeader); + addPatch(that.layTotal); + + // 固定列区域高度 + var mainHeight = that.layMain.height(); + var fixHeight = mainHeight - scrollHeight; + that.layFixed.find(ELEM_BODY).css('height', layMainTable.height() >= fixHeight ? fixHeight : 'auto').scrollTop(that.layMain.scrollTop()); // 固定列滚动条高度 + + // 表格宽度小于容器宽度时,隐藏固定列 + that.layFixRight[table.cache[that.key] && table.cache[that.key].length && outWidth > 0 ? 'removeClass' : 'addClass'](HIDE); + + // 操作栏 + that.layFixRight.css('right', scrollWidth); +}; + +/** + * @typedef updateRowOptions + * @prop {number} index - 行索引 + * @prop {Object.} data - 行数据 + * @prop {boolean | ((field, index) => boolean)} [related] - 更新其他包含自定义模板且可能有所关联的列视图 + */ +/** + * 更新指定行 + * @param {updateRowOptions | updateRowOptions[]} opts + * @param {(field: string, value: any) => void} [callback] - 更新每个字段时的回调函数 + */ +Class.prototype.updateRow = function (opts, callback) { + opts = layui.type(opts) === 'array' ? opts : [opts]; + var that = this; + var ELEM_CELL = '.layui-table-cell'; + var dataCache = table.cache[that.key] || []; + var update = function (opt) { + var index = opt.index; + var row = opt.data; + var related = opt.related; + var data = dataCache[index] || {}; + var tr = that.layBody.find('tr[data-index="' + index + '"]'); + + // 更新缓存中的数据 + layui.each(row, function (key, value) { + data[key] = value; + callback && callback(key, value); + }); + + // 更新单元格 + that.eachCols(function (i, item3) { + var field = String(item3.field || i); + var shouldUpdate = field in row || (typeof related === 'function' ? related(field, i) : related) && (item3.templet || item3.toolbar); + if (shouldUpdate) { + var td = tr.children('td[data-field="' + field + '"]'); + var cell = td.children(ELEM_CELL); + var content = data[item3.field]; + cell.html(parseTempData.call(that, { + item3: item3, + content: content, + tplData: $.extend({ + LAY_COL: item3 + }, data) + })); + td.data('content', content); + that.renderFormByElem(cell); + } + }); + }; + layui.each(opts, function (i, opt) { + update(opt); + }); +}; + +/** + * 更新指定行 + * @param {string} id - table ID + * @param {updateRowOptions | updateRowOptions[]} options + */ +table.updateRow = function (id, options) { + var that = getThisTable(id); + return that.updateRow(options); +}; + +// 事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + var filter = options.elem.attr('lay-filter'); + var th = that.layHeader.find('th'); + var ELEM_CELL = '.layui-table-cell'; + var _BODY = $('body'); + var dict = {}; + + // 头部工具栏操作事件 + that.layTool.on('click', '*[lay-event]', function (e) { + var othis = $(this); + var events = othis.attr('lay-event'); + var data = table.cache[options.id]; + + // 弹出工具下拉面板 + var openPanel = function (sets) { + var list = $(sets.list); + var panel = $('
                    '); + panel.html(list); + + // 限制最大高度 + if (options.height) { + panel.css('max-height', options.height - (that.layTool.outerHeight() || 50)); + } + + // 插入元素 + othis.find('.' + ELEM_TOOL_PANEL)[0] || othis.append(panel); + that.renderForm(); + panel.on('click', function (e) { + layui.stope(e); + }); + sets.done && sets.done(panel, list); + }; + layui.stope(e); + _DOC.trigger('table.tool.panel.remove'); + layer.close(that.tipsIndex); + + // 头部工具栏右侧图标 + layui.each(options.defaultToolbar, function (index, item) { + if (item.layEvent === events) { + typeof item.onClick === 'function' && item.onClick({ + data: data, + config: options, + openPanel: openPanel, + elem: othis + }); + return true; + } + }); + + // table toolbar 事件 + layui.event.call(this, MOD_NAME, 'toolbar(' + filter + ')', $.extend({ + event: events, + config: options + }, {})); + }); + + // 表头自定义元素事件 + that.layHeader.on('click', '*[lay-event]', function () { + var othis = $(this); + var events = othis.attr('lay-event'); + var th = othis.closest('th'); + var key = th.data('key'); + var col = that.col(key); + layui.event.call(this, MOD_NAME, 'colTool(' + filter + ')', $.extend({ + event: events, + config: options, + col: col + }, {})); + }); + + // 分页栏操作事件 + that.layPagebar.on('click', '*[lay-event]', function () { + var othis = $(this); + var events = othis.attr('lay-event'); + layui.event.call(this, MOD_NAME, 'pagebar(' + filter + ')', $.extend({ + event: events, + config: options + }, {})); + }); + + // 拖拽调整宽度 + th.on('mousemove', function (e) { + var othis = $(this); + var oLeft = othis.offset().left; + var pLeft = e.clientX - oLeft; + if (othis.data('unresize') || thisTable.eventMoveElem) { + return; + } + dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域 + _BODY.css('cursor', dict.allowResize ? 'col-resize' : ''); + }).on('mouseleave', function () { + // var othis = $(this); + if (thisTable.eventMoveElem) return; + dict.allowResize = false; + _BODY.css('cursor', ''); + }).on('mousedown', function (e) { + var othis = $(this); + if (dict.allowResize) { + var key = othis.data('key'); + e.preventDefault(); + dict.offset = [e.clientX, e.clientY]; //记录初始坐标 + + that.cssRules(key, function (item) { + var width = item.style.width || othis.outerWidth(); + dict.rule = item; + dict.ruleWidth = parseFloat(width); + dict.minWidth = othis.data('minwidth') || options.cellMinWidth; + dict.maxWidth = othis.data('maxwidth') || options.cellMaxWidth; + }); + + // 临时记录当前拖拽信息 + othis.data(DATA_MOVE_NAME, dict); + thisTable.eventMoveElem = othis; + } + }); + + // 拖拽中 + if (!thisTable.docEvent) { + _DOC.on('mousemove', function (e) { + if (thisTable.eventMoveElem) { + var dict = thisTable.eventMoveElem.data(DATA_MOVE_NAME) || {}; + thisTable.eventMoveElem.data('resizing', 1); + e.preventDefault(); + if (dict.rule) { + var setWidth = dict.ruleWidth + e.clientX - dict.offset[0]; + var id = thisTable.eventMoveElem.closest('.' + ELEM_VIEW).attr(MOD_ID); + var thatTable = getThisTable(id); + if (!thatTable) return; + if (setWidth < dict.minWidth) setWidth = dict.minWidth; + if (setWidth > dict.maxWidth) setWidth = dict.maxWidth; + dict.rule.style.width = setWidth + 'px'; + thatTable.setGroupWidth(thisTable.eventMoveElem); + layer.close(that.tipsIndex); + } + } + }).on('mouseup', function () { + if (thisTable.eventMoveElem) { + var th = thisTable.eventMoveElem; // 当前触发拖拽的 th 元素 + var id = th.closest('.' + ELEM_VIEW).attr(MOD_ID); + var thatTable = getThisTable(id); + if (!thatTable) return; + var key = th.data('key'); + var col = thatTable.col(key); + var filter = thatTable.config.elem.attr('lay-filter'); + + // 重置过度信息 + dict = {}; + _BODY.css('cursor', ''); + thatTable.scrollPatch(); + + // 清除当前拖拽信息 + th.removeData(DATA_MOVE_NAME); + delete thisTable.eventMoveElem; + + // 列拖拽宽度后的事件 + thatTable.cssRules(key, function (item) { + col.width = parseFloat(item.style.width); + layui.event.call(th[0], MOD_NAME, 'colResized(' + filter + ')', { + col: col, + config: thatTable.config + }); + }); + } + }); + } + + // 已给 document 执行全局事件,避免重复绑定 + thisTable.docEvent = true; + + // 排序 + th.on('click', function (e) { + var othis = $(this); + var elemSort = othis.find(ELEM_SORT); + var nowType = elemSort.attr('lay-sort'); + var type; + + // 表头工具元素不触发排序 + if ($(e.target).closest('[lay-event]')[0]) { + return; + } + + // 其他条件不触发排序 + if (!elemSort[0] || othis.data('resizing') === 1) { + return othis.removeData('resizing'); + } + if (nowType === 'asc') { + type = 'desc'; + } else if (nowType === 'desc') { + type = null; + } else { + type = 'asc'; + } + that.sort({ + field: othis, + type: type, + fromEvent: true + }); + }).find(ELEM_SORT + ' .layui-edge ').on('click', function (e) { + var othis = $(this); + var index = othis.index(); + var field = othis.parents('th').eq(0).data('field'); + layui.stope(e); + if (index === 0) { + that.sort({ + field: field, + type: 'asc', + fromEvent: true + }); + } else { + that.sort({ + field: field, + type: 'desc', + fromEvent: true + }); + } + }); + + //数据行中的事件返回的公共对象成员 + var commonMember = that.commonMember = function (sets) { + var othis = $(this); + var index = othis.parents('tr').eq(0).data('index'); + var tr = that.layBody.find('tr[data-index="' + index + '"]'); + var data = table.cache[that.key] || []; + data = data[index] || {}; + + // 事件返回的公共成员 + var obj = { + tr: tr, + // 行元素 + config: options, + data: table.clearCacheKey(data), + // 当前行数据 + dataCache: data, + // 当前行缓存中的数据 + index: index, + del: function () { + // 删除行数据 + table.cache[that.key][index] = []; + tr.remove(); + that.scrollPatch(); + }, + update: function (fields, related) { + // 修改行数据 + fields = fields || {}; + that.updateRow({ + index: index, + data: fields, + related: related + }, function (key, value) { + obj.data[key] = value; + }); + }, + // 设置行选中状态 + setRowChecked: function (opts) { + that.setRowChecked($.extend({ + index: index + }, opts)); + } + // 获取当前列 + }; + return $.extend(obj, sets); + }; + + // 复选框选择(替代元素的 click 事件) + that.elem.on('click', 'input[name="layTableCheckbox"]+', function (e) { + var othis = $(this); + var td = othis.closest('td'); + var checkbox = othis.prev(); + // var children = that.layBody.find('input[name="layTableCheckbox"]'); + var index = checkbox.parents('tr').eq(0).data('index'); + var checked = checkbox[0].checked; + var isAll = checkbox.attr('lay-filter') === 'layTableAllChoose'; + if (checkbox[0].disabled) return; + + // 全选 + if (isAll) { + that.setRowChecked({ + index: 'all', + checked: checked + }); + } else { + that.setRowChecked({ + index: index, + checked: checked + }); + } + layui.stope(e); + + // 事件 + layui.event.call(checkbox[0], MOD_NAME, 'checkbox(' + filter + ')', commonMember.call(checkbox[0], { + checked: checked, + type: isAll ? 'all' : 'one', + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + } + })); + }); + + // 单选框选择 + that.elem.on('click', 'input[lay-type="layTableRadio"]+', function (e) { + var othis = $(this); + var td = othis.closest('td'); + var radio = othis.prev(); + var checked = radio[0].checked; + var index = radio.parents('tr').eq(0).data('index'); + layui.stope(e); + if (radio[0].disabled) return false; + + // 标注选中样式 + that.setRowChecked({ + type: 'radio', + index: index + }); + + // 事件 + layui.event.call(radio[0], MOD_NAME, 'radio(' + filter + ')', commonMember.call(radio[0], { + checked: checked, + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + } + })); + }); + + // 行事件 + that.layBody.on('mouseenter', 'tr', function () { + // 鼠标移入行 + var othis = $(this); + var index = othis.index(); + if (othis.data('off')) return; // 不触发事件 + var trsElem = that.layBody.find('tr:eq(' + index + ')'); + trsElem.addClass(ELEM_HOVER); + if (that.needSyncFixedRowHeight) { + that.fixedRowHeightPatchOnHover(this, trsElem, true); + } + }).on('mouseleave', 'tr', function () { + // 鼠标移出行 + var othis = $(this); + var index = othis.index(); + if (othis.data('off')) return; // 不触发事件 + var trsElem = that.layBody.find('tr:eq(' + index + ')'); + trsElem.removeClass(ELEM_HOVER); + if (that.needSyncFixedRowHeight) { + that.fixedRowHeightPatchOnHover(this, trsElem, false); + } + }).on('click', 'tr', function (e) { + // 单击行 + setRowEvent.call(this, 'row', e); + }).on('dblclick', 'tr', function (e) { + // 双击行 + setRowEvent.call(this, 'rowDouble', e); + }).on('contextmenu', 'tr', function (e) { + // 菜单 + if (!options.defaultContextmenu) e.preventDefault(); + setRowEvent.call(this, 'rowContextmenu', e); + }); + + // 创建行单击、双击、菜单事件 + var setRowEvent = function (eventType, e) { + var othis = $(this); + if (othis.data('off')) return; // 不触发事件 + + // 不触发「行单/双击事件」的子元素 + if (eventType !== 'rowContextmenu') { + var UNROW = ['.layui-form-checkbox', '.layui-form-switch', '.layui-form-radio', '[lay-unrow]', '[lay-type="layTableCheckbox"]', '[lay-type="layTableRadio"]'].join(','); + if ($(e.target).is(UNROW) || $(e.target).closest(UNROW)[0]) { + return; + } + } + layui.event.call(this, MOD_NAME, eventType + '(' + filter + ')', commonMember.call(othis.children('td')[0], { + e: e + })); + }; + + // 渲染单元格编辑状态 + var renderGridEdit = function (othis, e) { + othis = $(othis); + if (othis.data('off')) return; // 不触发事件 + + var field = othis.data('field'); + var key = othis.data('key'); + var col = that.col(key); + var index = othis.closest('tr').data('index'); + var data = table.cache[that.key][index]; + // var elemCell = othis.children(ELEM_CELL); + + // 是否开启编辑 + // 若 edit 传入函数,则根据函数的返回结果判断是否开启编辑 + var editType = typeof col.edit === 'function' ? col.edit(data) : col.edit; + + // 显示编辑表单 + if (editType) { + var input = $(function () { + var inputElem = ''; + if (editType === 'textarea') { + inputElem = ''; + } + return inputElem; + }()); + input[0].value = function (val) { + return val === undefined || val === null ? '' : val; + }(othis.data('content') || data[field]); + othis.find('.' + ELEM_EDIT)[0] || othis.append(input); + input.focus(); + e && layui.stope(e); + } + }; + + // 单元格编辑 - 输入框内容被改变的事件 + that.layBody.on('change', '.' + ELEM_EDIT, function () { + var othis = $(this); + var td = othis.parent(); + var value = this.value; + var field = othis.parent().data('field'); + var index = othis.closest('tr').data('index'); + var data = table.cache[that.key][index]; + + //事件回调的参数对象 + var params = commonMember.call(td[0], { + value: value, + field: field, + oldValue: data[field], + // 编辑前的值 + td: td, + reedit: function () { + // 重新编辑 + setTimeout(function () { + // 重新渲染为编辑状态 + renderGridEdit(params.td); + + // 将字段缓存的值恢复到编辑之前的值 + var obj = {}; + obj[field] = params.oldValue; + params.update(obj); + }); + }, + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + } + }); + + // 更新缓存中的值 + var obj = {}; //变更的键值 + obj[field] = value; + params.update(obj); + + // 执行 API 编辑事件 + layui.event.call(td[0], MOD_NAME, 'edit(' + filter + ')', params); + }).on('blur', '.' + ELEM_EDIT, function () { + // 单元格编辑 - 恢复非编辑状态事件 + $(this).remove(); // 移除编辑状态 + }); + + // 表格主体单元格触发编辑的事件 + that.layBody.on(options.editTrigger, 'td', function (e) { + renderGridEdit(this, e); + }).on('mouseenter', 'td', function () { + showGridExpandIcon.call(this); + }).on('mouseleave', 'td', function () { + showGridExpandIcon.call(this, 'hide'); + }); + + // 表格合计栏单元格 hover 显示展开图标 + that.layTotal.on('mouseenter', 'td', function () { + showGridExpandIcon.call(this); + }).on('mouseleave', 'td', function () { + showGridExpandIcon.call(this, 'hide'); + }); + + // 显示单元格展开图标 + // var ELEM_GRID = 'layui-table-grid'; + var ELEM_GRID_DOWN = 'layui-table-grid-down'; + // var ELEM_GRID_PANEL = 'layui-table-grid-panel'; + var showGridExpandIcon = function (hide) { + var othis = $(this); + var elemCell = othis.children(ELEM_CELL); + if (othis.data('off')) return; // 不触发事件 + if (othis.parent().hasClass(ELEM_EXPAND)) return; // 是否已为展开状态 + + if (hide) { + othis.find('.layui-table-grid-down').remove(); + } else if ((elemCell.prop('scrollWidth') > elemCell.prop('clientWidth') || elemCell.find('br').length > 0) && !options.lineStyle) { + if (elemCell.find('.' + ELEM_GRID_DOWN)[0]) return; + othis.append('
                    '); + } + }; + // 展开单元格内容 + var gridExpand = function (e, expandedMode) { + var othis = $(this); + var td = othis.parent(); + var key = td.data('key'); + var col = that.col(key); + var index = td.parent().data('index'); + var elemCell = td.children(ELEM_CELL); + var ELEM_CELL_C = 'layui-table-cell-c'; + var elemCellClose = $(''); + expandedMode = expandedMode || col.expandedMode || options.cellExpandedMode; + + // 展开风格 + if (expandedMode === 'tips') { + // TIPS 展开风格 + that.tipsIndex = layer.tips(['
                    ', elemCell.html(), '
                    ', ''].join(''), elemCell[0], { + tips: [3, ''], + time: -1, + anim: -1, + maxWidth: device.ios || device.android ? 300 : that.elem.width() / 2, + isOutAnim: false, + skin: 'layui-table-tips', + success: function (layero, index) { + layero.find('.layui-table-tips-c').on('click', function () { + layer.close(index); + }); + } + }); + } else { + // 多行展开风格 + // 恢复其他已经展开的单元格 + that.elem.find('.' + ELEM_CELL_C).trigger('click'); + + // 设置当前单元格展开宽度 + that.cssRules(key, function (item) { + var width = item.style.width; + var expandedWidth = col.expandedWidth || options.cellExpandedWidth; + + // 展开后的宽度不能小于当前宽度 + if (expandedWidth < parseFloat(width)) expandedWidth = parseFloat(width); + elemCellClose.data('cell-width', width); + item.style.width = expandedWidth + 'px'; + setTimeout(function () { + that.scrollPatch(); // 滚动条补丁 + }); + }); + + // 设置当前单元格展开样式 + that.setRowActive(index, ELEM_EXPAND); + + // 插入关闭按钮 + if (!elemCell.next('.' + ELEM_CELL_C)[0]) { + elemCell.after(elemCellClose); + } + + // 关闭展开状态 + elemCellClose.on('click', function () { + var $this = $(this); + that.setRowActive(index, [ELEM_EXPAND, ELEM_HOVER].join(' '), true); // 移除单元格展开样式 + that.cssRules(key, function (item) { + item.style.width = $this.data('cell-width'); // 恢复单元格展开前的宽度 + setTimeout(function () { + that.resize(); // 滚动条补丁 + }); + }); + $this.remove(); + // 重置单元格滚动条位置 + elemCell.scrollTop(0); + elemCell.scrollLeft(0); + }); + } + othis.remove(); + layui.stope(e); + }; + + // 表格主体单元格展开事件 + that.layBody.on('click', '.' + ELEM_GRID_DOWN, function (e) { + gridExpand.call(this, e); + }); + // 表格合计栏单元格展开事件 + that.layTotal.on('click', '.' + ELEM_GRID_DOWN, function (e) { + gridExpand.call(this, e, 'tips'); // 强制采用 tips 风格 + }); + + // 行工具条操作事件 + var toolFn = function (type) { + var othis = $(this); + var td = othis.closest('td'); + var index = othis.parents('tr').eq(0).data('index'); + // 标记当前活动行 + that.setRowActive(index); + + // 执行事件 + layui.event.call(this, MOD_NAME, (type || 'tool') + '(' + filter + ')', commonMember.call(this, { + event: othis.attr('lay-event'), + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + } + })); + }; + + // 行工具条单击事件 + that.layBody.on('click', '*[lay-event]', function (e) { + toolFn.call(this); + layui.stope(e); + }).on('dblclick', '*[lay-event]', function (e) { + //行工具条双击事件 + toolFn.call(this, 'toolDouble'); + layui.stope(e); + }); + + // 同步滚动条 + that.layMain.on('scroll', function () { + var othis = $(this); + var scrollLeft = othis.scrollLeft(); + var scrollTop = othis.scrollTop(); + that.layHeader.scrollLeft(scrollLeft); + that.layTotal.scrollLeft(scrollLeft); + that.layFixed.find(ELEM_BODY).scrollTop(scrollTop); + layer.close(that.tipsIndex); + }); + var rAF = window.requestAnimationFrame || function (fn) { + return setTimeout(fn, 1000 / 60); + }; + + // 固定列滚轮事件 - 临时兼容方案 + that.layFixed.find(ELEM_BODY).on('mousewheel DOMMouseScroll', function (e) { + var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail; + var scrollTop = that.layMain.scrollTop(); + var step = 100; + var rAFStep = 10; + e.preventDefault(); + var cb = function () { + if (step > 0) { + step -= rAFStep; + scrollTop += delta > 0 ? -rAFStep : rAFStep; + that.layMain.scrollTop(scrollTop); + rAF(cb); + } + }; + rAF(cb); + }); +}; + +/** + * 获取元素的大小 + * @param {HTMLElement} elem - HTML 元素 + */ +Class.prototype.getElementSize = function (elem) { + if (!window.getComputedStyle) return; + var style = window.getComputedStyle(elem, null); + return { + height: parseFloat(style.height || '0'), + width: parseFloat(style.width || '0'), + borderTopWidth: parseFloat(style.borderTopWidth || '0'), + borderRightWidth: parseFloat(style.borderRightWidth || '0'), + borderBottomWidth: parseFloat(style.borderBottomWidth || '0'), + borderLeftWidth: parseFloat(style.borderLeftWidth || '0'), + paddingTop: parseFloat(style.paddingTop || '0'), + paddingRight: parseFloat(style.paddingRight || '0'), + paddingBottom: parseFloat(style.paddingBottom || '0'), + paddingLeft: parseFloat(style.paddingLeft || '0'), + marginTop: parseFloat(style.marginTop || '0'), + marginRight: parseFloat(style.marginRight || '0'), + marginBottom: parseFloat(style.marginBottom || '0'), + marginLeft: parseFloat(style.marginLeft || '0'), + boxSizing: style.boxSizing + }; +}; + +/** + * 获取元素 content 区域宽度值 + * + * layui 内置 jQuery v1.12.4 中的 jQuery.fn.width 始终对值四舍五入(3.x 已修复), + * 在支持 subpixel Rendering 的浏览器中渲染表格,由于列宽分配时计算值精度不足, + * 可能会导致一些小问题(#1726) + * + * 这个方法使用 getComputedStyle 获取精确的宽度值进行计算,为了尽可能和以前的行为 + * 保持一致(主要是隐藏元素内渲染 table 递归获取父元素宽度 https://github.com/layui/layui/discussions/2398), + * 任何非预期的值,都回退到 jQuery.fn.width。未来的版本使用 ResizeObserver 时,可以直接获取表格视图元素的宽度, + * 并移除兼容性代码 + * + * @param {JQuery} elem - 元素的 jQuery 对象 + * + * @see {@link https://learn.microsoft.com/zh-cn/archive/blogs/ie_cn/css-3} + */ +Class.prototype.getContentWidth = function (elem) { + var that = this; + if ( + // document + elem[0].nodeType === 9 || + // IE 中 border-box 盒模型,getComputedStyle 得到的 width/height 是按照 content-box 计算出来的 + lay.ie && elem.css('box-sizing') === 'border-box' || elem.css('display') === 'none') { + return elem.width(); + } + var size = that.getElementSize(elem[0]); + + // display: none|inline 元素,getComputedStyle 无法得到准确的 width/height + if (typeof size === 'undefined' || !size.width) { + return elem.width(); + } else { + return size.boxSizing === 'border-box' ? size.width - size.paddingLeft - size.paddingRight - size.borderLeftWidth - size.borderRightWidth : size.width; + } +}; +Class.prototype.dispose = function () { + var that = this; + that.unobserveResize(); + for (var propName in that) { + if (lay.hasOwn(that, propName) && propName !== 'config') { + that[propName] = null; + } + } +}; +Class.prototype.calcFixedRowHeight = function () { + var that = this; + var tableElem = that.layMain.children('table'); + var leftTrs = that.layFixLeft.find('>.layui-table-body>table>tbody>tr'); + var rightTrs = that.layFixRight.find('>.layui-table-body>table>tbody>tr'); + var mainTrs = tableElem.find('>tbody>tr'); + + // 批量获取主表格行高,设置高度以优化性能 + var heights = []; + mainTrs.each(function () { + heights.push(that.getElementSize(this).height); + }); + if (leftTrs.length) { + leftTrs.each(function (i) { + if (heights[i]) { + this.style.height = heights[i] + 'px'; + } + }); + } + if (rightTrs.length) { + rightTrs.each(function (i) { + if (heights[i]) { + this.style.height = heights[i] + 'px'; + } + }); + } +}; + +// 鼠标悬停于某一列纵向移动时,若单元格会出现横向滚动条,此时 tbody 高度不变,需要修复行高 +Class.prototype.fixedRowHeightPatchOnHover = function (targetEl, trsElem, isEnter) { + var that = this; + var style = that.elem.children('style')[0]; + var selector = '.' + FIXED_HEIGHT_PATCH; + trsElem.toggleClass(FIXED_HEIGHT_PATCH, isEnter); + // 将当前鼠标悬停行的高度同步到 FIXED_HEIGHT_PATCH (所有区域)类名的样式中 + if (isEnter) { + lay.getStyleRules(style, function (item) { + if (item.selectorText === selector) { + item.style.setProperty('height', that.getElementSize(targetEl).height + 'px', 'important'); + } + }); + } else { + // 将当前鼠标悬停行主区域的行高同步到固定列行 + var height; + lay.getStyleRules(style, function (item) { + if (item.selectorText === selector) { + item.style.setProperty('height', 'auto'); + } + }); + trsElem = trsElem.filter(function () { + var tr = $(this); + var isFixed = tr.closest(ELEM_FIXED, that.layBox).length > 0; + if (!isFixed) { + height = that.getElementSize(tr[0]).height; + } + return isFixed; + }); + trsElem.css('height', height); + } +}; +Class.prototype.observeResize = function () { + var that = this; + if (!resizeObserver) return; + that.unobserveResize(); + var el = that.elem[0]; + var tableEl = that.layMain.children('table')[0]; + + // 显示或隐藏时重置列宽 + resizeObserver.observe(el, that.resize.bind(that)); + + // 同步固定列表格和主表格高度 + var lineStyle = that.config.lineStyle; + var isAutoHeight = lineStyle && /\bheight\s*:\s*auto\b/g.test(lineStyle); + + // 只重载数据时需要主动同步高度,因为 tbody 大小可能不变 + var needSyncFixedRowHeight = that.needSyncFixedRowHeight = that.layBody.length > 1 && (that.config.syncFixedRowHeight || that.config.syncFixedRowHeight !== false && isAutoHeight); + if (needSyncFixedRowHeight) { + resizeObserver.observe(tableEl, that.calcFixedRowHeight.bind(that)); + } + that.unobserveResize = function () { + resizeObserver.unobserve(el); + if (needSyncFixedRowHeight) { + resizeObserver.unobserve(tableEl); + } + that.unobserveResize = $.noop; + }; +}; + +// 全局事件 +(function () { + // 自适应尺寸 + _WIN.on('resize', function () { + layui.each(thisTable.that, function () { + this.resize(); + }); + }); + + // 全局点击 + _DOC.on('click', function () { + _DOC.trigger('table.remove.tool.panel'); + }); + + // 工具面板移除事件 + _DOC.on('table.remove.tool.panel', function () { + $('.' + ELEM_TOOL_PANEL).remove(); + }); +})(); + +// 初始化 +table.init = function (filter, settings) { + settings = settings || {}; + var that = this; + // var inst = null; + var elemTable = typeof filter === 'object' ? filter : typeof filter === 'string' ? $('table[lay-filter="' + filter + '"]') : $(ELEM + '[lay-data], ' + ELEM + '[lay-options]'); + var errorTips = 'Table element property lay-data configuration item has a syntax error: '; + + //遍历数据表格 + elemTable.each(function () { + var othis = $(this); + var attrData = othis.attr('lay-data'); + var tableData = lay.options(this, { + attr: attrData ? 'lay-data' : null, + errorText: errorTips + (attrData || othis.attr('lay-options')) + }); + var options = $.extend({ + elem: this, + cols: [], + data: [], + skin: othis.attr('lay-skin'), + //风格 + size: othis.attr('lay-size'), + //尺寸 + even: typeof othis.attr('lay-even') === 'string' //偶数行背景 + }, table.config, settings, tableData); + filter && othis.hide(); + + //获取表头数据 + othis.find('thead>tr').each(function (i) { + options.cols[i] = []; + $(this).children().each(function () { + var th = $(this); + var attrData = th.attr('lay-data'); + var itemData = lay.options(this, { + attr: attrData ? 'lay-data' : null, + errorText: errorTips + (attrData || th.attr('lay-options')) + }); + var row = $.extend({ + title: th.text(), + colspan: parseInt(th.attr('colspan')) || 1, + //列单元格 + rowspan: parseInt(th.attr('rowspan')) || 1 //行单元格 + }, itemData); + options.cols[i].push(row); + }); + }); + + //缓存静态表体数据 + var trElem = othis.find('tbody>tr'); + + //执行渲染 + var tableIns = table.render(options); + + //获取表体数据 + if (trElem.length && !settings.data && !tableIns.config.url) { + var tdIndex = 0; + table.eachCols(tableIns.config.id, function (i3, item3) { + trElem.each(function (i1) { + options.data[i1] = options.data[i1] || {}; + var tr = $(this); + var field = item3.field; + options.data[i1][field] = tr.children('td').eq(tdIndex).html(); + }); + tdIndex++; + }); + tableIns.reloadData({ + data: options.data + }); + } + }); + return that; +}; + +//记录所有实例 +thisTable.that = {}; //记录所有实例对象 +thisTable.config = {}; //记录所有实例配置项 + +var eachChildCols = function (index, cols, i1, item2) { + //如果是组合列,则捕获对应的子列 + if (item2.colGroup) { + var childIndex = 0; + index++; + item2.CHILD_COLS = []; + // 找到它的子列所在cols的下标 + var i2 = i1 + (parseInt(item2.rowspan) || 1); + layui.each(cols[i2], function (i22, item22) { + if (item22.parentKey) { + // 如果字段信息中包含了parentKey和key信息 + if (item22.parentKey === item2.key) { + item22.PARENT_COL_INDEX = index; + item2.CHILD_COLS.push(item22); + eachChildCols(index, cols, i2, item22); + } + } else { + // 没有key信息以colspan数量所谓判断标准 + //如果子列已经被标注为{PARENT_COL_INDEX},或者子列累计 colspan 数等于父列定义的 colspan,则跳出当前子列循环 + if (item22.PARENT_COL_INDEX || childIndex >= 1 && childIndex == (item2.colspan || 1)) return; + item22.PARENT_COL_INDEX = index; + item2.CHILD_COLS.push(item22); + childIndex = childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); + eachChildCols(index, cols, i2, item22); + } + }); + } +}; + +// 遍历表头 +table.eachCols = function (id, callback, cols) { + var config = thisTable.config[id] || {}; + var arrs = [], + index = 0; + cols = $.extend(true, [], cols || config.cols); + + //重新整理表头结构 + layui.each(cols, function (i1, item1) { + if (i1) return true; // 只需遍历第一层 + layui.each(item1, function (i2, item2) { + eachChildCols(index, cols, i1, item2); + if (item2.PARENT_COL_INDEX) return; //如果是子列,则不进行追加,因为已经存储在父列中 + arrs.push(item2); + }); + }); + + //重新遍历列,如果有子列,则进入递归 + var eachArrs = function (obj) { + layui.each(obj || arrs, function (i, item) { + if (item.CHILD_COLS) return eachArrs(item.CHILD_COLS); + typeof callback === 'function' && callback(i, item); + }); + }; + eachArrs(); +}; + +// 获取表格选中状态 +table.checkStatus = function (id) { + var invalidNum = 0; + var arr = []; + var dataCache = []; + var data = table.cache[id] || []; + + // 过滤禁用或已删除的数据 + layui.each(data, function (i, item) { + if (layui.type(item) === 'array' || item[table.config.disabledName]) { + invalidNum++; // 无效数据数量 + return; + } + if (item[table.config.checkName]) { + arr.push(table.clearCacheKey(item)); + dataCache.push(item); + } + }); + return { + data: arr, + // 选中的数据 + dataCache: dataCache, + // 选中的原始缓存数据,包含内部特定字段 + isAll: data.length && arr.length ? arr.length === data.length - invalidNum : false // 是否全选 + }; +}; + +// 设置行选中状态 +table.setRowChecked = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + that.setRowChecked(opts); +}; + +// 获取表格当前页的所有行数据 +table.getData = function (id) { + var arr = []; + var data = table.cache[id] || []; + layui.each(data, function (i, item) { + if (layui.type(item) === 'array') { + return; + } + arr.push(table.clearCacheKey(item)); + }); + return arr; +}; + +// 重置表格尺寸结构 +table.resize = function (id) { + // 若指定表格唯一 id,则只执行该 id 对应的表格实例 + if (id) { + var config = getThisTableConfig(id); // 获取当前实例配置项 + if (!config) return; + getThisTable(id).resize(); + } else { + // 否则重置所有表格实例尺寸 + layui.each(thisTable.that, function () { + this.resize(); + }); + } +}; + +// 表格导出 +table.exportFile = function (id, data, opts) { + data = data || table.clearCacheKey(table.cache[id]); + opts = typeof opts === 'object' ? opts : function () { + var obj = {}; + opts && (obj.type = opts); + return obj; + }(); + var type = opts.type || 'csv'; + var thatTable = thisTable.that[id]; + var config = thisTable.config[id] || {}; + var textType = { + csv: 'text/csv', + xls: 'application/vnd.ms-excel' + }[type]; + var alink = document.createElement('a'); + if (device.ie) return hint.error('IE_NOT_SUPPORT_EXPORTS'); + + // 处理 treeTable 数据 + var isTreeTable = config.tree && config.tree.view; + if (isTreeTable) { + try { + data = $.extend(true, [], table.cache[id]); + data = function fn(data) { + return data.reduce(function (acc, obj) { + var children = obj.children || []; + delete obj.children; + return acc.concat(obj, fn(children)); + }, []); + }(Array.from(data)); + } catch { + // ignore + } + } + alink.href = 'data:' + textType + ';charset=utf-8,\ufeff' + encodeURIComponent(function () { + var dataTitle = []; + var dataMain = []; + var dataTotal = []; + var fieldsIsHide = {}; + + // 表头和表体 + layui.each(data, function (i1, item1) { + var vals = []; + if (typeof id === 'object') { + // 若 id 参数直接为表头数据 + layui.each(id, function (i, item) { + i1 == 0 && dataTitle.push(item || ''); + }); + layui.each(layui.isArray(item1) ? $.extend([], item1) : table.clearCacheKey(item1), function (i2, item2) { + vals.push('"' + (item2 || '') + '"'); + }); + } else { + table.eachCols(id, function (i3, item3) { + if (item3.ignoreExport === false || item3.field && item3.type == 'normal') { + // 不导出隐藏列,除非设置 ignoreExport 强制导出 + if (item3.hide && item3.ignoreExport !== false || item3.ignoreExport === true // 忽略导出 + ) { + if (i1 == 0) fieldsIsHide[item3.field] = true; // 记录隐藏列 + return; + } + var content = item1[item3.field]; + if (content === undefined || content === null) content = ''; + i1 == 0 && dataTitle.push(item3.fieldTitle || item3.title || item3.field || ''); + + // 解析内容 + content = parseTempData.call(thatTable, { + item3: item3, + content: content, + tplData: item1, + text: 'text', + obj: { + td: function (field) { + if (isTreeTable) i1 = item1['LAY_DATA_INDEX']; // 兼容 treeTable 索引 + var td = thatTable.layBody.find('tr[data-index="' + i1 + '"]>td'); + return td.filter('[data-field="' + field + '"]'); + } + } + }); + + // 异常处理 + content = content.replace(/"/g, '""'); // 避免内容存在「双引号」导致异常分隔 + // content += '\t'; // 加「水平制表符」 避免内容被转换格式 + content = '"' + content + '"'; // 避免内容存在「逗号」导致异常分隔 + + // 插入内容 + vals.push(content); + } else if (item3.field && item3.type !== 'normal') { + // https://gitee.com/layui/layui/issues/I8PHCR + if (i1 == 0) fieldsIsHide[item3.field] = true; + } + }); + } + dataMain.push(vals.join(',')); + }); + + // 表合计 + thatTable && layui.each(thatTable.dataTotal, function (i, o) { + fieldsIsHide[o.field] || dataTotal.push('"' + (o.total || '') + '"'); + }); + return dataTitle.join(',') + '\r\n' + dataMain.join('\r\n') + '\r\n' + dataTotal.join(','); + }()); + alink.download = (opts.title || config.title || 'table_' + (config.index || '')) + '.' + type; + document.body.appendChild(alink); + alink.click(); + document.body.removeChild(alink); +}; + +// 获取表格配置信息 +table.getOptions = function (id) { + return getThisTableConfig(id); +}; + +// 显示或隐藏列 +table.hideCol = function (id, cols) { + var that = getThisTable(id); + if (!that) { + return; + } + if (layui.type(cols) === 'boolean') { + // 显示全部或者隐藏全部 + that.eachCols(function (i2, item2) { + var key = item2.key; + var col = that.col(key); + var parentKey = item2.parentKey; + // 同步勾选列的 hide 值和隐藏样式 + if (col.hide != cols) { + var hide = col.hide = cols; + that.elem.find('*[data-key="' + key + '"]')[hide ? 'addClass' : 'removeClass'](HIDE); + // 根据列的显示隐藏,同步多级表头的父级相关属性值 + that.setParentCol(hide, parentKey); + } + }); + } else { + cols = layui.isArray(cols) ? cols : [cols]; + layui.each(cols, function (i1, item1) { + that.eachCols(function (i2, item2) { + if (item1.field === item2.field) { + var key = item2.key; + var col = that.col(key); + var parentKey = item2.parentKey; + // 同步勾选列的 hide 值和隐藏样式 + if ('hide' in item1 && col.hide != item1.hide) { + var hide = col.hide = !!item1.hide; + that.elem.find('*[data-key="' + key + '"]')[hide ? 'addClass' : 'removeClass'](HIDE); + // 根据列的显示隐藏,同步多级表头的父级相关属性值 + that.setParentCol(hide, parentKey); + } + } + }); + }); + } + $('.' + ELEM_TOOL_PANEL).remove(); // 关闭字段筛选面板如果打开的话 + // 重新适配尺寸 + that.resize(); +}; + +// 重载 +table.reload = function (id, options, deep, type) { + var config = getThisTableConfig(id); //获取当前实例配置项 + if (!config) return; + var that = getThisTable(id); + that.reload(options, deep, type); + return thisTable.call(that); +}; + +// 仅重载数据 +table.reloadData = function () { + var args = $.extend([], arguments); + args[3] = 'reloadData'; + + // 重载时,影响整个结构的参数,不适合更新的参数 + var dataParams = new RegExp('^(' + ['elem', 'id', 'cols', 'width', 'height', 'maxHeight', 'toolbar', 'defaultToolbar', 'className', 'css', 'pagebar'].join('|') + ')$'); + + // 过滤与数据无关的参数 + layui.each(args[1], function (key) { + if (dataParams.test(key)) { + delete args[1][key]; + } + }); + return table.reload.apply(null, args); +}; + +// 核心入口 +table.render = function (options) { + var inst = new Class(options); + return thisTable.call(inst); +}; + +// 清除临时 Key +table.clearCacheKey = function (data) { + data = $.extend({}, data); + delete data[table.config.checkName]; + delete data[table.config.indexName]; + delete data[table.config.initIndexName]; + delete data[table.config.numbersName]; + delete data[table.config.disabledName]; + return data; +}; + +// 自动完成渲染 +$(function () { + table.init(); +}); + +export { table }; diff --git a/dist/components/tabs.js b/dist/components/tabs.js new file mode 100644 index 000000000..9f6172807 --- /dev/null +++ b/dist/components/tabs.js @@ -0,0 +1,758 @@ +import { layui } from '../core/layui.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; + +/** + * tabs + * 标签页组件 + */ + + +// 创建组件 +var component = component$1({ + name: 'tabs', + // 组件名 + + // 默认配置 + config: { + elem: '.layui-tabs', + trigger: 'click', + // 标签切换的触发事件 + headerMode: 'auto' // 标签头部的显示模式 auto | scroll | normal + }, + CONST: { + ELEM: 'layui-tabs', + HEADER: 'layui-tabs-header', + CLOSE: 'layui-tabs-close', + BODY: 'layui-tabs-body', + ITEM: 'layui-tabs-item', + CARD: 'layui-tabs-card' + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 标签页元素项 + that.headerElem = ['.' + component.CONST.HEADER + ':eq(0)', '>li']; + that.bodyElem = ['.' + component.CONST.BODY + ':eq(0)', '>.' + component.CONST.ITEM]; + + // 获取标签容器中的 header body 相关元素 + that.getContainer = function () { + var elem = that.documentElem || options.elem; + return { + header: { + elem: elem.find(that.headerElem[0]), + items: elem.find(that.headerElem.join('')) + }, + body: { + elem: elem.find(that.bodyElem[0]), + items: elem.find(that.bodyElem.join('')) + } + }; + }; + + // 若 header 选项类型为数组 + if (layui.type(options.header) === 'array') { + // if (options.header.length === 0) return; + + // 给任意元素绑定 tabs 切换功能 + if (typeof options.header[0] === 'string') { + that.headerElem = options.header.concat(); + that.documentElem = $(document); + } else { + // 方法传值渲染 + that.elemView = $('
                    '); + if (options.className) that.elemView.addClass(options.className); + var headerElem = $('
                      '); + var bodyElem = $('
                      '); + + // 生成标签项 + layui.each(options.header, function (i, item) { + var elemHeaderItem = that.renderHeaderItem(item); + headerElem.append(elemHeaderItem); + }); + layui.each(options.body, function (i, item) { + var elemBodyItem = that.renderBodyItem(item); + bodyElem.append(elemBodyItem); + }); + that.elemView.append(headerElem).append(bodyElem); + options.elem.html(that.elemView); + } + } else { + that.renderClose(); // 初始化标签关闭结构 + } + + // 若 body 选项类型为数组 + if (layui.type(options.body) === 'array') { + if (typeof options.body[0] === 'string') { + that.documentElem = $(document); + that.bodyElem = options.body.concat(); + } + } + + // 初始选中项 + var data = that.data(); + if ('index' in options && data.index != options.index) { + that.change(that.findHeaderItem(options.index), true); + } else if (data.index === -1) { + // 初始选中项为空时,默认选中第一个 + that.change(that.findHeaderItem(0), true); + } + + // 初始化滚动结构 + that.roll('auto'); + + // 清除隐藏占位 + if (options.elem.hasClass(component.CONST.CLASS_HIDEV)) { + options.elem.removeClass(component.CONST.CLASS_HIDEV); + } + + // 回调 + typeof options.afterRender === 'function' && options.afterRender(data); + + // 渲染成功后的事件 + layui.event.call(options.elem[0], component.CONST.MOD_NAME, 'afterRender(' + options.id + ')', data); + }, + // 事件 + events: function () { + var that = this; + var options = that.config; + var container = that.getContainer(); + var MOD_NAME = component.CONST.MOD_NAME; + var TRIGGER_NAMESPACE = '.lay_' + MOD_NAME + '_trigger'; + var delegatedElement = that.documentElem ? container.header.elem : options.elem; + + // 标签头部事件 + var trigger = options.trigger + TRIGGER_NAMESPACE; + var elemHeaderItem = that.documentElem ? that.headerElem[1] : that.headerElem.join(''); + delegatedElement.off(trigger).on(trigger, elemHeaderItem, function () { + that.change($(this)); + }); + + // 窗口 resize 事件 + if (!inner.onresize) { + var timer; + $(window).on('resize', function () { + clearTimeout(timer); + timer = setTimeout(function () { + layui.each(component.cache.id, function (key) { + var that = component.getInst(key); + if (!that) return; + that.roll('init'); + }); + }, 50); + }); + inner.onresize = true; + } + } +}); + +// 内部变量集 +var inner = {}; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +/** + * 增加标签 + * @param {Object} opts + * @param {string} opts.title - 标签标题 + * @param {string} opts.content - 标签内容 + * @param {string} opts.id - 标签的 lay-id 属性值 + * @param {string} [opts.index] - 活动标签索引,默认取当前选中标签的索引 + * @param {('append'|'prepend'|'after'|'before')} [opts.mode='append'] - 标签插入方式 + * @param {boolean} [opts.active] - 是否将新增项设置为活动标签 + * @param {boolean} [opts.closable] - 标签是否可关闭。初始值取决于 options.closable + * @param {string} [opts.headerItem] - 自定义标签头部元素 + * @param {string} [opts.bodyItem] - 自定义标签内容元素 + * @param {Function} [opts.done] - 标签添加成功后执行的回调函数 + */ +Class.prototype.add = function (opts) { + var that = this; + // var options = that.config; + var container = that.getContainer(); + var newHeaderItem = that.renderHeaderItem(opts); + var newBodyItem = that.renderBodyItem(opts); + var data = that.data(); + + // 选项默认值 + opts = $.extend({ + active: true + }, opts); + + // 插入方式 + if (/(before|after)/.test(opts.mode)) { + // 在活动标签前后插入 + var hasOwnIndex = Object.prototype.hasOwnProperty.call(opts, 'index'); + var headerItem = hasOwnIndex ? that.findHeaderItem(opts.index) : data.thisHeaderItem; + var bodyItem = hasOwnIndex ? that.findBodyItem(opts.index) : data.thisHeaderItem; + headerItem[opts.mode](newHeaderItem); + bodyItem[opts.mode](newBodyItem); + } else { + // 在标签最前后插入 + var mode = { + prepend: 'prepend', + // 插入标签到最前 + append: 'append' // 插入标签到最后 + }[opts.mode || 'append'] || 'append'; + container.header.elem[mode](newHeaderItem); + container.body.elem[mode](newBodyItem); + } + + // 是否将新增项设置为活动标签 + if (opts.active) { + that.change(newHeaderItem, true); + } else { + that.roll('auto'); + } + + // 回调 + typeof opts.done === 'function' && opts.done($.extend(data, { + headerItem: newHeaderItem, + bodyItem: newBodyItem + })); +}; + +/** + * 关闭指定标签 + * @param {Object} thisHeaderItem - 当前标签头部项元素 + * @param {boolean} force - 是否强制删除 + */ +Class.prototype.close = function (thisHeaderItem, force) { + if (!thisHeaderItem || !thisHeaderItem[0]) return; + var that = this; + var options = that.config; + var layid = thisHeaderItem.attr('lay-id'); + var index = thisHeaderItem.index(); + + // 标签是否不可关闭 + if (thisHeaderItem.attr('lay-closable') === 'false') { + return; + } + + // 当前标签相关数据 + var data = that.data(); + + // 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭 + if (!force) { + var closable = layui.event.call(thisHeaderItem[0], component.CONST.MOD_NAME, 'beforeClose(' + options.id + ')', $.extend(data, { + index: index + })); + + // 是否阻止关闭 + if (closable === false) { + return; + } + } + + // 如果关闭的是当前标签,则更换当前标签索引 + if (thisHeaderItem.hasClass(component.CONST.CLASS_THIS)) { + if (thisHeaderItem.next()[0]) { + that.change(thisHeaderItem.next(), true); + } else if (thisHeaderItem.prev()[0]) { + that.change(thisHeaderItem.prev(), true); + } + } + + // 移除元素 + that.findBodyItem(layid || index).remove(); + thisHeaderItem.remove(); + that.roll('auto', index); + + // 获取当前标签相关数据 + data = that.data(); + + // 标签关闭后的事件 + layui.event.call(data.thisHeaderItem[0], component.CONST.MOD_NAME, 'afterClose(' + options.id + ')', data); +}; + +/** + * 批量关闭标签 + * @see tabs.close + */ +Class.prototype.closeMult = function (mode, index) { + var that = this; + var options = that.config; + var container = that.getContainer(); + var data = that.data(); + var headers = container.header.items; + // var bodys = container.body.items; + var DISABLED_CLOSE_SELECTOR = '[lay-closable="false"]'; // 不可关闭标签选择器 + // var FILTER = ':not(' + DISABLED_CLOSE_SELECTOR + ')'; // 不可关闭标签过滤器 + + index = index === undefined ? data.index : index; + var headerItem = that.findHeaderItem(index); + // var bodyItem = that.findBodyItem(index); + var itemIndex = headerItem.index(); + + // 若当前选中标签也允许关闭,则尝试寻找不可关闭的标签并将其选中 + if (data.thisHeaderItem.attr('lay-closable') !== 'false') { + if (mode === 'all' || !mode) { + var nextHeader = headers.filter(':gt(' + data.index + ')' + DISABLED_CLOSE_SELECTOR).eq(0); + var prevHeader = $(headers.filter(':lt(' + data.index + ')' + DISABLED_CLOSE_SELECTOR).get().reverse()).eq(0); + if (nextHeader[0]) { + that.change(nextHeader, true); + } else if (prevHeader[0]) { + that.change(prevHeader, true); + } + } else if (index !== data.index) { + // 自动切换到活动标签 + that.change(headerItem, true); + } + } + + // 执行批量关闭标签 + headers.each(function (i) { + var $this = $(this); + var layid = $this.attr('lay-id'); + var bodyItem = that.findBodyItem(layid || i); + + // 标签是否不可关闭 + if ($this.attr('lay-closable') === 'false') { + return; + } + + // 批量关闭方式 + var isCloseOther = mode === 'other' && i !== itemIndex; // 关闭其他标签 + var isCloseRight = mode === 'right' && i > itemIndex; // 关闭右侧标签 + var isCloseLeft = mode === 'left' && i < itemIndex; // 关闭左侧标签(不推荐) + var isCloseAll = mode === 'all'; // 关闭所有标签 + + if (isCloseOther || isCloseRight || isCloseLeft || isCloseAll) { + $this.remove(); + bodyItem.remove(); + } + }); + that.roll('auto'); + + // 回调 + data = that.data(); + + // 标签关闭后的事件 + layui.event.call(data.thisHeaderItem[0], component.CONST.MOD_NAME, 'afterClose(' + options.id + ')', data); +}; + +/** + * 切换标签 + * @param {Object} thisHeaderItem - 当前标签头部项元素 + * @param {boolean} [force=false] - 是否强制切换 + * @returns + */ +Class.prototype.change = function (thisHeaderItem, force) { + if (!thisHeaderItem || !thisHeaderItem[0]) return; + var that = this; + var options = that.config; + var layid = thisHeaderItem.attr('lay-id'); + var index = thisHeaderItem.index(); + var thatA = thisHeaderItem.find('a'); + // 是否存在跳转链接 + var isLink = typeof thatA.attr('href') === 'string' && thatA.attr('target') === '_blank'; + // 是否不允许选中 + var unselect = typeof thisHeaderItem.attr('lay-unselect') === 'string'; + + // 不满足切换的条件 + if (isLink || unselect) { + return; + } + + // 当前标签相关数据 + var data = that.data(); + + // 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭 + if (!force) { + var enable = layui.event.call(thisHeaderItem[0], component.CONST.MOD_NAME, 'beforeChange(' + options.id + ')', $.extend(data, { + from: { + index: data.index, + headerItem: data.thisHeaderItem + }, + to: { + index: index, + headerItem: thisHeaderItem + } + })); + + // 是否阻止切换 + if (enable === false) { + return; + } + } + + // 执行标签头部切换 + thisHeaderItem.addClass(component.CONST.CLASS_THIS).siblings().removeClass(component.CONST.CLASS_THIS); + + // 执行标签内容切换 + that.findBodyItem(layid || index).addClass(component.CONST.CLASS_SHOW).siblings().removeClass(component.CONST.CLASS_SHOW); + that.roll('auto', index); + + // 重新获取标签相关数据 + data = that.data(); + + // 标签切换后的事件 + layui.event.call(data.thisHeaderItem[0], component.CONST.MOD_NAME, 'afterChange(' + options.id + ')', data); +}; + +/** + * 渲染标签头部项 + * @param {Object} opts - 标签项配置信息 + */ +Class.prototype.renderHeaderItem = function (opts) { + var that = this; + var options = that.config; + var headerItem = $(opts.headerItem || options.headerItem || '
                    • '); + headerItem.html(opts.title || 'New Tab').attr('lay-id', opts.id); + that.appendClose(headerItem, opts); // 追加标签关闭元素 + return headerItem; +}; + +/** + * 渲染标签内容项 + * @param {Object} opts - 标签项配置信息 + */ +Class.prototype.renderBodyItem = function (opts) { + var that = this; + var options = that.config; + var bodyItem = $(opts.bodyItem || options.bodyItem || '
                      '); + bodyItem.html(opts.content || '').attr('lay-id', opts.id); + return bodyItem; +}; + +/** + * 给某一个标签项追加可关闭元素 + * @param {Object} headerItem - 标签项元素 + * @param {Object} opts - 标签项配置信息 + */ +Class.prototype.appendClose = function (headerItem, opts) { + var that = this; + var options = that.config; + if (!options.closable) return; + opts = opts || {}; + + // 不可关闭项 + if (opts.closable == false) { + headerItem.attr('lay-closable', 'false'); + } + if (headerItem.attr('lay-closable') === 'false') { + return; + } + + // 可关闭项追加关闭按钮 + if (!headerItem.find('.' + component.CONST.CLOSE)[0]) { + var close = $(''); + close.on('click', function () { + that.close($(this).parent()); + return false; + }); + headerItem.append(close); + } +}; + +// 渲染标签可关闭元素 +Class.prototype.renderClose = function () { + var that = this; + var options = that.config; + var container = that.getContainer(); + container.header.items.each(function () { + var $this = $(this); + // 是否开启关闭 + if (options.closable) { + that.appendClose($this); + } else { + $this.find('.' + component.CONST.CLOSE).remove(); + } + }); +}; + +/** + * 标签头滚动 + * @param {('auto'|'prev'|'next'|'init')} [mode='next'] - 滚动方式 + * @param {number} index - 标签索引。默认取当前选中标签的索引值 + * @returns + */ +Class.prototype.roll = function (mode, index) { + var that = this; + var options = that.config; + var container = that.getContainer(); + var headerElem = container.header.elem; + var headerItems = container.header.items; + var scrollWidth = headerElem.prop('scrollWidth'); // 实际总长度 + var outerWidth = Math.ceil(headerElem.outerWidth()); // 可视区域的长度 + var tabsLeft = headerElem.data('left') || 0; + var scrollMode = options.headerMode === 'scroll'; // 标签头部是否始终保持滚动模式 + + // 让选中标签始终保持在可视区域 + var rollToVisibleArea = function () { + index = isNaN(index) ? that.data().index : index; + var thisItemElem = headerItems.eq(index); + if (!thisItemElem[0]) return; + + // 当前标签的相对水平坐标值 + var thisLeft = Math.ceil(thisItemElem.position().left); + var padding = 1; // 让边界额外保持一定间距 + + // 当选中标签溢出在可视区域「左侧」时 + var countWidth = thisLeft - (thisItemElem.prev().outerWidth() || 0); // 始终空出上一个标签 + if (countWidth > 0) countWidth = countWidth - padding; + + // 左侧临界值 + if (tabsLeft + countWidth < 0) { + tabsLeft = countWidth >= 0 ? countWidth : 0; // 标签的复原位移不能超出 0 + return headerElem.css('left', -tabsLeft).data('left', -tabsLeft); + } + + // 当选中标签溢出在可视区域「右侧」时, + countWidth = thisLeft + thisItemElem.outerWidth() + (thisItemElem.next().outerWidth() || 0) + padding; // 始终空出下一个标签 + + // 右侧临界值 + if (tabsLeft + countWidth - outerWidth > 0) { + tabsLeft = countWidth - outerWidth; + headerElem.css('left', -tabsLeft).data('left', -tabsLeft); + } + }; + + // css 类名 + var CLASS_SCROLL = 'layui-tabs-scroll'; + var CLASS_BAR = 'layui-tabs-bar'; + var CLASS_BAR_ICON = ['layui-icon-prev', 'layui-icon-next']; + + // 滚动结构 + var rollElem = { + elem: $('
                      '), + bar: $(['
                      ', '', '', '
                      '].join('')) + }; + + // 不渲染头部滚动结构 + if (options.headerMode === 'normal') return; + + // 是否渲染滚动结构 + var elemScroll = headerElem.parent('.' + CLASS_SCROLL); + if (scrollMode || !scrollMode && scrollWidth > outerWidth) { + if (!elemScroll[0]) { + if (options.elem.hasClass(component.CONST.CARD)) { + rollElem.elem.addClass(component.CONST.CARD); + } + headerElem.wrap(rollElem.elem); + headerElem.after(rollElem.bar); + + // 点击左右箭头 + rollElem.bar.children().on('click', function () { + var othis = $(this); + var mode = othis.attr('lay-mode'); + if ($(this).hasClass(component.CONST.CLASS_DISABLED)) return; + mode && that.roll(mode); + }); + } + } else if (!scrollMode) { + if (elemScroll[0]) { + elemScroll.find('.' + CLASS_BAR).remove(); + headerElem.unwrap().css('left', 0).data('left', 0); + } else { + return; + } + } + + // 初始化滚动模式 + if (mode === 'init') return; + + // 重新获取 + scrollWidth = headerElem.prop('scrollWidth'); // 实际总长度 + outerWidth = headerElem.outerWidth(); // 可视区域的长度 + elemScroll = headerElem.parent('.' + CLASS_SCROLL); + + // 左箭头(往右滚动) + if (mode === 'prev') { + // 当前的 left 减去可视宽度,用于与上一轮的页签比较 + var prevLeft = -tabsLeft - outerWidth; + if (prevLeft < 0) prevLeft = 0; + headerItems.each(function (i, item) { + var li = $(item); + var left = Math.ceil(li.position().left); + if (left >= prevLeft) { + headerElem.css('left', -left).data('left', -left); + return false; + } + }); + } else if (mode === 'auto') { + // 自动识别滚动 + rollToVisibleArea(); + } else { + // 右箭头(往左滚动) 默认 next + headerItems.each(function (i, item) { + var li = $(item); + var left = Math.ceil(li.position().left); + if (left + li.outerWidth() >= outerWidth - tabsLeft) { + headerElem.css('left', -left).data('left', -left); + return false; + } + }); + } + + // 同步箭头状态 + tabsLeft = headerElem.data('left') || 0; + + // 左 + elemScroll.find('.' + CLASS_BAR_ICON[0])[tabsLeft < 0 ? 'removeClass' : 'addClass'](component.CONST.CLASS_DISABLED); + // 右 + elemScroll.find('.' + CLASS_BAR_ICON[1])[parseFloat(tabsLeft + scrollWidth) - outerWidth > 0 ? 'removeClass' : 'addClass'](component.CONST.CLASS_DISABLED); +}; + +/** + * 获取标签头部项 + * @param {number|string} index - 标签索引或 lay-id + */ +Class.prototype.findHeaderItem = function (index) { + var container = this.getContainer(); + var headerItems = container.header.items; + + // 根据 lay-id 匹配 + if (typeof index === 'string') { + return headerItems.filter('[lay-id="' + index + '"]'); + } + return headerItems.eq(index); +}; + +/** + * 获取标签内容项 + * @param {number|string} index - 标签索引或 lay-id + */ +Class.prototype.findBodyItem = function (index) { + var container = this.getContainer(); + var bodyItems = container.body.items; + + // 根据 lay-id 匹配 + if (typeof index === 'string') { + var bodyItem = bodyItems.filter('[lay-id="' + index + '"]'); + return bodyItem[0] ? bodyItem : function () { + // 若未匹配到 lay-id 对应内容项,则通过对应头部项的索引匹配内容项 + var headerItems = container.header.items; + var headerItemIndex = headerItems.filter('[lay-id="' + index + '"]').index(); + return headerItemIndex !== -1 ? bodyItems.eq(headerItemIndex) : bodyItem; + }(); + } + return bodyItems.eq(index); +}; + +/** + * 返回给回调的公共信息 + * @returns + */ +Class.prototype.data = function () { + var that = this; + var options = that.config; + var container = that.getContainer(); + var thisHeaderItem = container.header.items.filter('.' + component.CONST.CLASS_THIS); + var index = thisHeaderItem.index(); + var layid = thisHeaderItem.attr('lay-id'); + return { + options: options, + // 标签配置信息 + container: container, + // 标签容器的相关元素 + thisHeaderItem: thisHeaderItem, + // 当前活动标签头部项 + thisBodyItem: that.findBodyItem(layid || index), + // 当前活动标签内容项 + index: index, + // 当前活动标签索引 + length: container.header.items.length // 标签数量 + }; +}; + +// 扩展组件接口 +$.extend(component, { + /** + * 添加标签 + * @param {string} id - 渲染时的实例 ID + * @param {Object} opts - 添加标签的配置项,详见 Class.prototype.add + */ + add: function (id, opts) { + var that = component.getInst(id); + if (!that) return; + that.add(opts); + }, + /** + * 关闭标签 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引 + * @param {boolean} [force=false] - 是否强制关闭 + */ + close: function (id, index, force) { + var that = component.getInst(id); + if (!that) return; + // index 若不传,则表示关闭当前标签 + if (index === undefined) { + index = that.data().index; + } + that.close(that.findHeaderItem(index), force); + }, + /** + * 关闭多个标签 + * @param {string} id - 渲染时的实例 ID + * @param {('other'|'right'|'all')} [mode="all"] - 关闭方式 + * @param {number} index - 活动标签的索引,默认取当前选中标签的索引。一般用于标签右键事件 + */ + closeMult: function (id, mode, index) { + var that = component.getInst(id); + if (!that) return; + that.closeMult(mode, index); + }, + /** + * 切换标签 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引 + */ + change: function (id, index, force) { + var that = component.getInst(id); + if (!that) return; + that.change(that.findHeaderItem(index), force); + }, + /** + * 获取标签信息 + * @param {string} id - 渲染时的实例 ID + */ + data: function (id) { + var that = component.getInst(id); + return that ? that.data() : {}; + }, + /** + * 获取标签指定头部项 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引或 lay-id 值 + * @returns + */ + getHeaderItem: function (id, index) { + var that = component.getInst(id); + if (!that) return; + return that.findHeaderItem(index); + }, + /** + * 获取标签指定内容项 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引或 lay-id 值 + * @returns + */ + getBodyItem: function (id, index) { + var that = component.getInst(id); + if (!that) return; + return that.findBodyItem(index); + }, + /** + * 刷新标签视图结构 + * @param {string} id - 渲染时的实例 ID + */ + refresh: function (id) { + var that = component.getInst(id); + if (!that) return; + that.roll('auto'); + } +}); + +// 初始化渲染 +$(function () { + component.render(); +}); + +export { component as tabs }; diff --git a/dist/components/transfer.js b/dist/components/transfer.js new file mode 100644 index 000000000..64998a9d2 --- /dev/null +++ b/dist/components/transfer.js @@ -0,0 +1,404 @@ +import { layui } from '../core/layui.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; +import { laytpl } from '../core/laytpl.js'; +import { form } from './form.js'; + +/** + * transfer + * 穿梭框组件 + */ + +var component = component$1({ + name: 'transfer', + // 默认配置 + config: { + width: 200, + height: 360, + data: [], + // 数据源 + value: [], + // 选中的数据 + showSearch: false, + // 是否开启搜索 + id: '' // 唯一索引,默认自增 index + }, + CONST: { + ELEM: 'layui-transfer', + ELEM_BOX: 'layui-transfer-box', + ELEM_HEADER: 'layui-transfer-header', + ELEM_SEARCH: 'layui-transfer-search', + ELEM_ACTIVE: 'layui-transfer-active', + ELEM_DATA: 'layui-transfer-data', + BTN_DISABLED: 'layui-btn-disabled' + }, + beforeRender: function (options) { + var that = this; + that.config = $.extend({ + title: i18n.$t('transfer.title'), + text: { + none: i18n.$t('transfer.noData'), + searchNone: i18n.$t('transfer.noMatch') + } + }, that.config, options); + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 穿梭框模板 + var TPL_BOX = function (obj) { + obj = obj || {}; + return ['
                      ', '
                      ', '', '
                      ', '{{ if(d.data.showSearch){ }}', '', '{{ } }}', '
                        ', '
                        '].join(''); + }; + + // 主模板 + var TPL_MAIN = ['
                        ', TPL_BOX({ + index: 0, + checkAllName: 'layTransferLeftCheckAll' + }), '
                        ', '', '', '
                        ', TPL_BOX({ + index: 1, + checkAllName: 'layTransferRightCheckAll' + }), '
                        '].join(''); + + // 解析模板 + var thisElem = that.elem = $(laytpl(TPL_MAIN, { + open: '{{', + // 标签符前缀 + close: '}}', + // 标签符后缀 + tagStyle: 'modern' + }).render({ + data: options, + index: that.index // 索引 + })); + var othis = options.elem; + if (!othis[0]) return; + + // 初始化属性 + options.data = options.data || []; + options.value = options.value || []; + + // 插入组件结构 + othis.html(that.elem); + + // 各级容器 + that.layBox = that.elem.find('.' + CONST.ELEM_BOX); + that.layHeader = that.elem.find('.' + CONST.ELEM_HEADER); + that.laySearch = that.elem.find('.' + CONST.ELEM_SEARCH); + that.layData = thisElem.find('.' + CONST.ELEM_DATA); + that.layBtn = thisElem.find('.' + CONST.ELEM_ACTIVE + ' .layui-btn'); + + // 初始化尺寸 + that.layBox.css({ + width: options.width, + height: options.height + }); + that.layData.css({ + height: function () { + var height = options.height - that.layHeader.outerHeight(); + if (options.showSearch) { + height -= that.laySearch.outerHeight(); + } + return height - 2; + }() + }); + that.renderData(); // 渲染数据 + that.events(); // 事件 + }, + // 扩展实例方法 + extendsInstance: function () { + var that = this; + // var options = that.config; + return { + // 获取右侧数据 + getData: function () { + return that.getData.call(that); + } + }; + } +}); +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 渲染数据 +Class.prototype.renderData = function () { + var that = this; + var options = that.config; + + // 左右穿梭框差异数据 + var arr = [{ + checkName: 'layTransferLeftCheck', + views: [] + }, { + checkName: 'layTransferRightCheck', + views: [] + }]; + + // 解析格式 + that.parseData(function (item) { + // 标注为 selected 的为右边的数据 + var _index = item.selected ? 1 : 0; + var listElem = ['
                      • ', '', '
                      • '].join(''); + // 按照 options.value 顺序排列右侧数据 + if (_index) { + layui.each(options.value, function (i, v) { + if (v == item.value && item.selected) { + arr[_index].views[i] = listElem; + } + }); + } else { + arr[_index].views.push(listElem); + } + delete item.selected; + }); + that.layData.eq(0).html(arr[0].views.join('')); + that.layData.eq(1).html(arr[1].views.join('')); + that.renderCheckBtn(); +}; + +// 渲染表单 +Class.prototype.renderForm = function (type) { + form.render(type, 'LAY-transfer-' + this.index); +}; + +// 同步复选框和按钮状态 +Class.prototype.renderCheckBtn = function (obj) { + var that = this; + var options = that.config; + obj = obj || {}; + that.layBox.each(function (_index) { + var othis = $(this); + var thisDataElem = othis.find('.' + CONST.ELEM_DATA); + var allElemCheckbox = othis.find('.' + CONST.ELEM_HEADER).find('input[type="checkbox"]'); + var listElemCheckbox = thisDataElem.find('input[type="checkbox"]'); + + // 同步复选框和按钮状态 + var nums = 0; + var haveChecked = false; + listElemCheckbox.each(function () { + var isHide = $(this).data('hide'); + if (this.checked || this.disabled || isHide) { + nums++; + } + if (this.checked && !isHide) { + haveChecked = true; + } + }); + allElemCheckbox.prop('checked', haveChecked && nums === listElemCheckbox.length); // 全选复选框状态 + that.layBtn.eq(_index)[haveChecked ? 'removeClass' : 'addClass'](CONST.BTN_DISABLED); // 对应的按钮状态 + + // 无数据视图 + if (!obj.stopNone) { + var isNone = thisDataElem.children('li:not(.' + CONST.CLASS_HIDE + ')').length; + that.noneView(thisDataElem, isNone ? '' : options.text.none); + } + }); + that.renderForm('checkbox'); +}; + +// 无数据视图 +Class.prototype.noneView = function (thisDataElem, text) { + var createNoneElem = $('

                        ' + (text || '') + '

                        '); + if (thisDataElem.find('.' + CONST.CLASS_NONE)[0]) { + thisDataElem.find('.' + CONST.CLASS_NONE).remove(); + } + text.replace(/\s/g, '') && thisDataElem.append(createNoneElem); +}; + +// 同步 value 属性值 +Class.prototype.setValue = function () { + var that = this; + var options = that.config; + var arr = []; + that.layBox.eq(1).find('.' + CONST.ELEM_DATA + ' input[type="checkbox"]').each(function () { + var isHide = $(this).data('hide'); + isHide || arr.push(this.value); + }); + options.value = arr; + return that; +}; + +// 解析数据 +Class.prototype.parseData = function (callback) { + var that = this; + var options = that.config; + var newData = []; + layui.each(options.data, function (index, item) { + // 解析格式 + item = (typeof options.parseData === 'function' ? options.parseData(item) : item) || item; + newData.push(item = $.extend({}, item)); + layui.each(options.value, function (index2, item2) { + if (item2 == item.value) { + item.selected = true; + } + }); + callback && callback(item); + }); + options.data = newData; + return that; +}; + +// 获得右侧面板数据 +Class.prototype.getData = function (value) { + var that = this; + var options = that.config; + var selectedData = []; + that.setValue(); + layui.each(value || options.value, function (index, item) { + layui.each(options.data, function (index2, item2) { + delete item2.selected; + if (item == item2.value) { + selectedData.push(item2); + } + }); + }); + return selectedData; +}; + +// 执行穿梭 +Class.prototype.transfer = function (_index, elem) { + var that = this; + var options = that.config; + var thisBoxElem = that.layBox.eq(_index); + var arr = []; + if (!elem) { + // 通过按钮触发找到选中的进行移动 + thisBoxElem.each(function () { + var othis = $(this); + var thisDataElem = othis.find('.' + CONST.ELEM_DATA); + thisDataElem.children('li').each(function () { + var thisList = $(this); + var thisElemCheckbox = thisList.find('input[type="checkbox"]'); + var isHide = thisElemCheckbox.data('hide'); + if (thisElemCheckbox[0].checked && !isHide) { + thisElemCheckbox[0].checked = false; + thisBoxElem.siblings('.' + CONST.ELEM_BOX).find('.' + CONST.ELEM_DATA).append(thisList.clone()); + thisList.remove(); + + // 记录当前穿梭的数据 + arr.push(thisElemCheckbox[0].value); + } + that.setValue(); + }); + }); + } else { + // 双击单条记录移动 + var thisList = elem; + var thisElemCheckbox = thisList.find('input[type="checkbox"]'); + thisElemCheckbox[0].checked = false; + thisBoxElem.siblings('.' + CONST.ELEM_BOX).find('.' + CONST.ELEM_DATA).append(thisList.clone()); + thisList.remove(); + + // 记录当前穿梭的数据 + arr.push(thisElemCheckbox[0].value); + that.setValue(); + } + that.renderCheckBtn(); + + // 穿梭时,如果另外一个框正在搜索,则触发匹配 + var siblingInput = thisBoxElem.siblings('.' + CONST.ELEM_BOX).find('.' + CONST.ELEM_SEARCH + ' input'); + siblingInput.val() === '' || siblingInput.trigger('keyup'); + + // 穿梭时的回调 + options.onchange && options.onchange(that.getData(arr), _index); +}; + +// 事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 左右复选框 + that.elem.on('click', 'input[lay-filter="layTransferCheckbox"]+', function () { + var thisElemCheckbox = $(this).prev(); + var checked = thisElemCheckbox[0].checked; + var thisDataElem = thisElemCheckbox.parents('.' + CONST.ELEM_BOX).eq(0).find('.' + CONST.ELEM_DATA); + if (thisElemCheckbox[0].disabled) return; + + // 判断是否全选 + if (thisElemCheckbox.attr('lay-type') === 'all') { + thisDataElem.find('input[type="checkbox"]').each(function () { + if (this.disabled) return; + this.checked = checked; + }); + } + setTimeout(function () { + that.renderCheckBtn({ + stopNone: true + }); + }, 0); + }); + + // 双击穿梭 + that.elem.on('dblclick', '.' + CONST.ELEM_DATA + '>li', function () { + var elemThis = $(this); + var thisElemCheckbox = elemThis.children('input[type="checkbox"]'); + var thisDataElem = elemThis.parent(); + var thisBoxElem = thisDataElem.parent(); + var index = thisBoxElem.data('index'); + if (thisElemCheckbox[0].disabled) return; + + // 根据 dblclick 回调函数返回值决定是否执行穿梭 --- 2.9.3+ + var ret = typeof options.dblclick === 'function' ? options.dblclick({ + elem: elemThis, + data: that.getData([thisElemCheckbox[0].value])[0], + index: index + }) : null; + if (ret === false) return; + that.transfer(index, elemThis); + }); + + // 穿梭按钮事件 + that.layBtn.on('click', function () { + var othis = $(this); + var _index = othis.data('index'); + if (othis.hasClass(CONST.BTN_DISABLED)) return; + that.transfer(_index); + }); + + // 搜索 + that.laySearch.find('input').on('keyup', function () { + var value = this.value; + var thisDataElem = $(this).parents('.' + CONST.ELEM_SEARCH).eq(0).siblings('.' + CONST.ELEM_DATA); + var thisListElem = thisDataElem.children('li'); + thisListElem.each(function () { + var thisList = $(this); + var thisElemCheckbox = thisList.find('input[type="checkbox"]'); + var title = thisElemCheckbox[0].title; + + // 是否区分大小写 + if (options.showSearch !== 'cs') { + title = title.toLowerCase(); + value = value.toLowerCase(); + } + var isMatch = title.indexOf(value) !== -1; + thisList[isMatch ? 'removeClass' : 'addClass'](CONST.CLASS_HIDE); + thisElemCheckbox.data('hide', isMatch ? false : true); + }); + that.renderCheckBtn(); + + // 无匹配数据视图 + var isNone = thisListElem.length === thisDataElem.children('li.' + CONST.CLASS_HIDE).length; + that.noneView(thisDataElem, isNone ? options.text.searchNone : ''); + }); +}; + +// 扩展组件接口 +$.extend(component, { + // 获得选中的数据(右侧面板) + getData: function (id) { + var that = component.getInst(id); + if (!that) return; + return that.getData(); + } +}); + +export { component as transfer }; diff --git a/dist/components/tree.js b/dist/components/tree.js new file mode 100644 index 000000000..0c9c2d68d --- /dev/null +++ b/dist/components/tree.js @@ -0,0 +1,809 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { component as component$1 } from '../core/component.js'; +import { layer } from './layer.js'; +import { form } from './form.js'; + +/** + * tree 树组件 + */ + + +// 创建组件 +var component = component$1({ + name: 'tree', + // 默认配置 + config: { + data: [], + // 数据 + showCheckbox: false, + // 是否显示复选框 + showLine: true, + // 是否开启连接线 + accordion: false, + // 是否开启手风琴模式 + onlyIconControl: false, + // 是否仅允许节点左侧图标控制展开收缩 + isJump: false, + // 是否允许点击节点时弹出新窗口跳转 + edit: false, + // 是否开启节点的操作图标 + customName: { + // 自定义 data 字段名 + id: 'id', + title: 'title', + children: 'children' + } + }, + CONST: { + ELEM: 'layui-tree', + ELEM_SET: 'layui-tree-set', + ICON_CLICK: 'layui-tree-iconClick', + ICON_ADD: 'layui-icon-addition', + ICON_SUB: 'layui-icon-subtraction', + ELEM_ENTRY: 'layui-tree-entry', + ELEM_MAIN: 'layui-tree-main', + ELEM_TEXT: 'layui-tree-txt', + ELEM_PACK: 'layui-tree-pack', + ELEM_SPREAD: 'layui-tree-spread', + ELEM_LINE_SHORT: 'layui-tree-setLineShort', + ELEM_SHOW: 'layui-tree-showLine', + ELEM_EXTEND: 'layui-tree-lineExtend' + }, + // 渲染之前 + beforeRender: function (options) { + var that = this; + that.config = $.extend({ + text: { + defaultNodeName: i18n.$t('tree.defaultNodeName'), + // 节点默认名称 + none: i18n.$t('tree.noData') // 数据为空时的文本提示 + } + }, that.config, options); + + // 扁平化数据 + var customName = options.customName || {}; + that.config.flatData = lay.treeToFlat(that.config.data, { + idKey: customName.id, + childrenKey: customName.children, + keepChildren: true + }); + }, + // 渲染 + render: function () { + var that = this; + var options = that.config; + that.checkids = []; + var wrapper = $('
                        '); + that.tree(wrapper); + var othis = options.elem; + if (!othis[0]) return; + + // 插入组件结构 + that.elem = wrapper; + that.elemNone = $('
                        ' + options.text.none + '
                        '); + othis.html(that.elem); + if (that.elem.find('.' + CONST.ELEM_SET).length == 0) { + return that.elem.append(that.elemNone); + } + + // 复选框渲染 + if (options.showCheckbox) { + that.renderForm('checkbox'); + } + that.elem.find('.' + CONST.ELEM_SET).each(function () { + var othis = $(this); + + // 最外层 + if (!othis.parent('.layui-tree-pack')[0]) { + othis.addClass('layui-tree-setHide'); + } + + // 没有下一个节点 上一层父级有延伸线 + if (!othis.next()[0] && othis.parents('.layui-tree-pack').eq(1).hasClass('layui-tree-lineExtend')) { + othis.addClass(CONST.ELEM_LINE_SHORT); + } + + // 没有下一个节点 外层最后一个 + if (!othis.next()[0] && !othis.parents('.' + CONST.ELEM_SET).eq(0).next()[0]) { + othis.addClass(CONST.ELEM_LINE_SHORT); + } + }); + }, + // 扩展实例方法 + extendsInstance: function () { + var that = this; + // var options = that.config; + return { + getChecked: function () { + return that.getChecked.call(that); + }, + setChecked: function (id) { + // 设置值 + return that.setChecked.call(that, id); + } + }; + } +}); +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 重载实例 +Class.prototype.reload = function (options, type) { + var that = this; + + // 数组直接覆盖 + layui.each(options, function (key, item) { + if (layui.type(item) === 'array') { + delete that.config[key]; + } + }); + that.config = $.extend(true, {}, that.config, options); + that.init(true, type); +}; + +// 渲染表单 +Class.prototype.renderForm = function (type) { + form.render(type, 'LAY-tree-' + this.index); +}; + +// 节点解析 +Class.prototype.tree = function (elem, children) { + var that = this; + var options = that.config; + var customName = options.customName; + var data = children || options.data; + + // 遍历数据 + layui.each(data, function (index, item) { + var hasChild = item[customName.children] && item[customName.children].length > 0; + var packDiv = $('
                        '); + var entryDiv = $(['
                        ', '
                        ', '
                        ', + // 箭头 + function () { + if (options.showLine) { + if (hasChild) { + return ''; + } else { + return ''; + } + } else { + return ''; + } + }(), + // 复选框 + function () { + return options.showCheckbox ? '' : ''; + }(), + // 节点 + function () { + if (options.isJump && item.href) { + return '' + (item[customName.title] || item.label || options.text.defaultNodeName) + ''; + } else { + return '' + (item[customName.title] || item.label || options.text.defaultNodeName) + ''; + } + }(), '
                        ', + // 节点操作图标 + function () { + if (!options.edit) { + return ''; + } + var editIcon = { + add: '', + update: '', + del: '' + }; + var arr = ['
                        ']; + if (options.edit === true) { + options.edit = ['update', 'del']; + } + if (typeof options.edit === 'object') { + layui.each(options.edit, function (i, val) { + arr.push(editIcon[val] || ''); + }); + return arr.join('') + '
                        '; + } + }(), '
                        ', '
                        '].join('')); + + // 如果有子节点,则递归继续生成树 + if (hasChild) { + entryDiv.append(packDiv); + that.tree(packDiv, item[customName.children]); + } + elem.append(entryDiv); + + // 若有前置节点,前置节点加连接线 + if (entryDiv.prev('.' + CONST.ELEM_SET)[0]) { + entryDiv.prev().children('.layui-tree-pack').addClass('layui-tree-showLine'); + } + + // 若无子节点,则父节点加延伸线 + if (!hasChild) { + entryDiv.parent('.layui-tree-pack').addClass('layui-tree-lineExtend'); + } + + // 展开节点操作 + that.spread(entryDiv, item); + + // 选择框 + if (options.showCheckbox) { + item.checked && that.checkids.push(item[customName.id]); + that.checkClick(entryDiv, item); + } + + // 操作节点 + options.edit && that.operate(entryDiv, item); + }); +}; + +// 展开节点 +Class.prototype.spread = function (elem, item) { + var that = this; + var options = that.config; + var entry = elem.children('.' + CONST.ELEM_ENTRY); + var elemMain = entry.children('.' + CONST.ELEM_MAIN); + var elemCheckbox = elemMain.find('input[same="layuiTreeCheck"]'); + var elemIcon = entry.find('.' + CONST.ICON_CLICK); + var elemText = entry.find('.' + CONST.ELEM_TEXT); + var touchOpen = options.onlyIconControl ? elemIcon : elemMain; // 判断展开通过节点还是箭头图标 + var state = ''; + + // 展开收缩 + touchOpen.on('click', function () { + var packCont = elem.children('.' + CONST.ELEM_PACK); + var iconClick = touchOpen.children('.layui-icon')[0] ? touchOpen.children('.layui-icon') : touchOpen.find('.layui-tree-icon').children('.layui-icon'); + + // 若没有子节点 + if (!packCont[0]) { + state = 'normal'; + } else { + if (elem.hasClass(CONST.ELEM_SPREAD)) { + elem.removeClass(CONST.ELEM_SPREAD); + packCont.slideUp(200); + iconClick.removeClass(CONST.ICON_SUB).addClass(CONST.ICON_ADD); + that.updateFieldValue(item, 'spread', false); + } else { + elem.addClass(CONST.ELEM_SPREAD); + packCont.slideDown(200); + iconClick.addClass(CONST.ICON_SUB).removeClass(CONST.ICON_ADD); + that.updateFieldValue(item, 'spread', true); + + // 是否手风琴 + if (options.accordion) { + var sibls = elem.siblings('.' + CONST.ELEM_SET); + sibls.removeClass(CONST.ELEM_SPREAD); + sibls.children('.' + CONST.ELEM_PACK).slideUp(200); + sibls.find('.layui-tree-icon').children('.layui-icon').removeClass(CONST.ICON_SUB).addClass(CONST.ICON_ADD); + } + } + } + }); + + // 点击回调 + elemText.on('click', function () { + var othis = $(this); + + // 判断是否禁用状态 + if (othis.hasClass(CONST.CLASS_DISABLED)) return; + + // 判断展开收缩状态 + if (elem.hasClass(CONST.ELEM_SPREAD)) { + state = options.onlyIconControl ? 'open' : 'close'; + } else { + state = options.onlyIconControl ? 'close' : 'open'; + } + + // 获取选中状态 + if (elemCheckbox[0]) { + that.updateFieldValue(item, 'checked', elemCheckbox.prop('checked')); + } + + // 点击产生的回调 + options.click && options.click({ + elem: elem, + state: state, + data: item + }); + }); +}; + +// 更新数据源 checked,spread 字段值 +Class.prototype.updateFieldValue = function (obj, field, value) { + if (field in obj) { + obj[field] = value; + } +}; + +/** + * 同步节点选中状态 + * @param {JQuery} elemCheckbox - 复选框元素的 jQuery 对象 + * @param {Object} item - 当前节点数据 + * @param {boolean} isManual - 是否手动触发 + * @returns + */ +Class.prototype.syncCheckedState = function (elemCheckbox, item, isManual) { + var that = this; + var options = that.config; + var customName = options.customName; + var checked = elemCheckbox.prop('checked'); + var nodeWrapper = elemCheckbox.closest('.' + CONST.ELEM_SET); + if (elemCheckbox.prop('disabled')) return; + + // 同步子节点选中状态 + var setChildrenChecked = function (thisNodeElem, item) { + var children = item[customName.children]; + if (!children || children.length === 0) return; + var childrenPack = thisNodeElem.children('.' + CONST.ELEM_PACK); + var childrenWrapper = childrenPack.children('.' + CONST.ELEM_SET); + var elemCheckboxs = childrenWrapper.children('.' + CONST.ELEM_ENTRY).find('input[same="layuiTreeCheck"]'); + elemCheckboxs.each(function (i) { + if (this.disabled) return; // 不可点击则跳过 + var child = children[i]; + // 手动触发时,子节点跟随父节点选中状态;自动渲染时,子节点优先跟随 checked 字段值 + var childChecked = isManual ? checked : 'checked' in child ? child.checked : checked; + this.checked = childChecked; + that.updateFieldValue(child, 'checked', childChecked); + if (child[customName.children]) { + setChildrenChecked(childrenWrapper.eq(i), child); + } + }); + }; + + // 同步父节点选中状态 + var setParentsChecked = function (thisNodeElem) { + // 若无父节点,则终止递归 + if (!thisNodeElem.parents('.' + CONST.ELEM_SET)[0]) return; + var descendantsChecked; // 后代节点选中状态 + var parentPack = thisNodeElem.parent('.' + CONST.ELEM_PACK); + var parentNodeElem = parentPack.parent(); + var parentCheckbox = parentPack.prev().find('input[same="layuiTreeCheck"]'); + if (parentCheckbox.prop('disabled')) return; + + // 如果后代节点有任意一条选中,则父节点为选中状态(考虑到兼容性,暂时不支持半选状态) + if (checked) { + parentCheckbox.prop('checked', checked); + } else { + // 如果当前节点取消选中,则根据计算后代节点选中状态,来同步父节点选中状态 + parentPack.find('input[same="layuiTreeCheck"]').each(function () { + if (this.checked) { + descendantsChecked = true; + } + }); + + // 如果后代节点全部未选中,则父节点也应为非选中状态 + descendantsChecked || parentCheckbox.prop('checked', false); + } + + // 向父节点递归 + setParentsChecked(parentNodeElem); + }; + setChildrenChecked(nodeWrapper, item); + setParentsChecked(nodeWrapper); + that.renderForm('checkbox'); +}; + +// 复选框选择 +Class.prototype.checkClick = function (elem, item) { + var that = this; + var options = that.config; + var entry = elem.children('.' + CONST.ELEM_ENTRY); + var elemMain = entry.children('.' + CONST.ELEM_MAIN); + + // 点击复选框 + elemMain.on('click', 'input[same="layuiTreeCheck"]', layui.stope); + elemMain.on('click', 'input[same="layuiTreeCheck"]+', function (e) { + layui.stope(e); // 阻止点击节点事件 + + var elemCheckbox = $(this).prev(); + var checked = elemCheckbox.prop('checked'); + if (elemCheckbox.prop('disabled')) return; + that.syncCheckedState(elemCheckbox, item, 'manual'); + that.updateFieldValue(item, 'checked', checked); + + // 复选框点击产生的回调 + options.oncheck && options.oncheck({ + elem: elem, + checked: checked, + data: item + }); + }); +}; + +// 节点操作 +Class.prototype.operate = function (elem, item) { + var that = this; + var options = that.config; + var customName = options.customName; + var entry = elem.children('.' + CONST.ELEM_ENTRY); + var elemMain = entry.children('.' + CONST.ELEM_MAIN); + entry.children('.layui-tree-btnGroup').on('click', '.layui-icon', function (e) { + layui.stope(e); // 阻止节点操作 + + var type = $(this).data('type'); + var packCont = elem.children('.' + CONST.ELEM_PACK); + var returnObj = { + data: item, + type: type, + elem: elem + }; + // 增加 + if (type == 'add') { + // 若节点本身无子节点 + if (!packCont[0]) { + // 若开启连接线,更改图标样式 + if (options.showLine) { + elemMain.find('.' + CONST.ICON_CLICK).addClass('layui-tree-icon'); + elemMain.find('.' + CONST.ICON_CLICK).children('.layui-icon').addClass(CONST.ICON_ADD).removeClass('layui-icon-leaf'); + // 若未开启连接线,显示箭头 + } else { + elemMain.find('.layui-tree-iconArrow').removeClass(CONST.CLASS_HIDE); + } + // 节点添加子节点容器 + elem.append('
                        '); + } + + // 新增节点 + var key = options.operate && options.operate(returnObj); + var obj = {}; + obj[customName.title] = options.text.defaultNodeName; + obj[customName.id] = key; + that.tree(elem.children('.' + CONST.ELEM_PACK), [obj]); + + // 放在新增后面,因为要对元素进行操作 + if (options.showLine) { + // 节点本身无子节点 + if (!packCont[0]) { + // 遍历兄弟节点,判断兄弟节点是否有子节点 + var siblings = elem.siblings('.' + CONST.ELEM_SET); + var num = 1; + var parentPack = elem.parent('.' + CONST.ELEM_PACK); + layui.each(siblings, function (index, i) { + if (!$(i).children('.' + CONST.ELEM_PACK)[0]) { + num = 0; + } + }); + + // 若兄弟节点都有子节点 + if (num == 1) { + // 兄弟节点添加连接线 + siblings.children('.' + CONST.ELEM_PACK).addClass(CONST.ELEM_SHOW); + siblings.children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).removeClass(CONST.ELEM_LINE_SHORT); + elem.children('.' + CONST.ELEM_PACK).addClass(CONST.ELEM_SHOW); + // 父级移除延伸线 + parentPack.removeClass(CONST.ELEM_EXTEND); + // 同层节点最后一个更改线的状态 + parentPack.children('.' + CONST.ELEM_SET).last().children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).last().addClass(CONST.ELEM_LINE_SHORT); + } else { + elem.children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).addClass(CONST.ELEM_LINE_SHORT); + } + } else { + // 添加延伸线 + if (!packCont.hasClass(CONST.ELEM_EXTEND)) { + packCont.addClass(CONST.ELEM_EXTEND); + } + // 子节点添加延伸线 + elem.find('.' + CONST.ELEM_PACK).each(function () { + $(this).children('.' + CONST.ELEM_SET).last().addClass(CONST.ELEM_LINE_SHORT); + }); + // 如果前一个节点有延伸线 + if (packCont.children('.' + CONST.ELEM_SET).last().prev().hasClass(CONST.ELEM_LINE_SHORT)) { + packCont.children('.' + CONST.ELEM_SET).last().prev().removeClass(CONST.ELEM_LINE_SHORT); + } else { + // 若之前的没有,说明处于连接状态 + packCont.children('.' + CONST.ELEM_SET).last().removeClass(CONST.ELEM_LINE_SHORT); + } + // 若是最外层,要始终保持相连的状态 + if (!elem.parent('.' + CONST.ELEM_PACK)[0] && elem.next()[0]) { + packCont.children('.' + CONST.ELEM_SET).last().removeClass(CONST.ELEM_LINE_SHORT); + } + } + } + if (!options.showCheckbox) return; + // 若开启复选框,同步新增节点状态 + if (elemMain.find('input[same="layuiTreeCheck"]')[0].checked) { + var packLast = elem.children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).last(); + packLast.find('input[same="layuiTreeCheck"]')[0].checked = true; + } + that.renderForm('checkbox'); + + // 修改 + } else if (type == 'update') { + var text = elemMain.children('.' + CONST.ELEM_TEXT).html(); + elemMain.children('.' + CONST.ELEM_TEXT).html(''); + // 添加输入框,覆盖在文字上方 + elemMain.append(''); + // 获取焦点 + elemMain.children('.layui-tree-editInput').val(lay.unescape(text)).focus(); + // 嵌入文字移除输入框 + var getVal = function (input) { + var textNew = lay.escape(input.val().trim()); + textNew = textNew ? textNew : options.text.defaultNodeName; + input.remove(); + elemMain.children('.' + CONST.ELEM_TEXT).html(textNew); + + // 同步数据 + returnObj.data[customName.title] = textNew; + + // 节点修改的回调 + options.operate && options.operate(returnObj); + }; + // 失去焦点 + elemMain.children('.layui-tree-editInput').blur(function () { + getVal($(this)); + }); + // 回车 + elemMain.children('.layui-tree-editInput').on('keydown', function (e) { + if (e.keyCode === 13) { + e.preventDefault(); + getVal($(this)); + } + }); + + // 删除 + } else { + var i18nText = i18n.$t('tree.deleteNodePrompt', { + name: item[customName.title] || '' + }); + layer.confirm(i18nText, function (index) { + options.operate && options.operate(returnObj); // 节点删除的回调 + returnObj.status = 'remove'; // 标注节点删除 + + layer.close(index); + + // 若删除最后一个,显示空数据提示 + if (!elem.prev('.' + CONST.ELEM_SET)[0] && !elem.next('.' + CONST.ELEM_SET)[0] && !elem.parent('.' + CONST.ELEM_PACK)[0]) { + elem.remove(); + that.elem.append(that.elemNone); + return; + } + // 若有兄弟节点 + if (elem.siblings('.' + CONST.ELEM_SET).children('.' + CONST.ELEM_ENTRY)[0]) { + // 若开启复选框 + if (options.showCheckbox) { + // 若开启复选框,进行下步操作 + var elemDel = function (elem) { + // 若无父结点,则不执行 + if (!elem.parents('.' + CONST.ELEM_SET)[0]) return; + var siblingTree = elem.siblings('.' + CONST.ELEM_SET).children('.' + CONST.ELEM_ENTRY); + var parentTree = elem.parent('.' + CONST.ELEM_PACK).prev(); + var checkState = parentTree.find('input[same="layuiTreeCheck"]')[0]; + var state = 1; + var num = 0; + + // 若父节点未勾选 + if (checkState.checked == false) { + // 遍历兄弟节点 + siblingTree.each(function (i, item1) { + var input = $(item1).find('input[same="layuiTreeCheck"]')[0]; + if (input.checked == false && !input.disabled) { + state = 0; + } + // 判断是否全为不可勾选框 + if (!input.disabled) { + num = 1; + } + }); + // 若有可勾选选择框并且已勾选 + if (state == 1 && num == 1) { + // 勾选父节点 + checkState.checked = true; + that.renderForm('checkbox'); + // 向上遍历祖先节点 + elemDel(parentTree.parent('.' + CONST.ELEM_SET)); + } + } + }; + elemDel(elem); + } + // 若开启连接线 + if (options.showLine) { + // 遍历兄弟节点,判断兄弟节点是否有子节点 + var siblings = elem.siblings('.' + CONST.ELEM_SET); + var num = 1; + var parentPack = elem.parent('.' + CONST.ELEM_PACK); + layui.each(siblings, function (index, i) { + if (!$(i).children('.' + CONST.ELEM_PACK)[0]) { + num = 0; + } + }); + // 若兄弟节点都有子节点 + if (num == 1) { + // 若节点本身无子节点 + if (!packCont[0]) { + // 父级去除延伸线,因为此时子节点里没有空节点 + parentPack.removeClass(CONST.ELEM_EXTEND); + siblings.children('.' + CONST.ELEM_PACK).addClass(CONST.ELEM_SHOW); + siblings.children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).removeClass(CONST.ELEM_LINE_SHORT); + } + // 若为最后一个节点 + if (!elem.next()[0]) { + elem.prev().children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).last().addClass(CONST.ELEM_LINE_SHORT); + } else { + parentPack.children('.' + CONST.ELEM_SET).last().children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).last().addClass(CONST.ELEM_LINE_SHORT); + } + // 若为最外层最后一个节点,去除前一个结点的连接线 + if (!elem.next()[0] && !elem.parents('.' + CONST.ELEM_SET)[1] && !elem.parents('.' + CONST.ELEM_SET).eq(0).next()[0]) { + elem.prev('.' + CONST.ELEM_SET).addClass(CONST.ELEM_LINE_SHORT); + } + } else { + // 若为最后一个节点且有延伸线 + if (!elem.next()[0] && elem.hasClass(CONST.ELEM_LINE_SHORT)) { + elem.prev().addClass(CONST.ELEM_LINE_SHORT); + } + } + } + } else { + // 若无兄弟节点 + var prevDiv = elem.parent('.' + CONST.ELEM_PACK).prev(); + // 若开启了连接线 + if (options.showLine) { + prevDiv.find('.' + CONST.ICON_CLICK).removeClass('layui-tree-icon'); + prevDiv.find('.' + CONST.ICON_CLICK).children('.layui-icon').removeClass(CONST.ICON_SUB).addClass('layui-icon-leaf'); + // 父节点所在层添加延伸线 + var pare = prevDiv.parents('.' + CONST.ELEM_PACK).eq(0); + pare.addClass(CONST.ELEM_EXTEND); + + // 兄弟节点最后子节点添加延伸线 + pare.children('.' + CONST.ELEM_SET).each(function () { + $(this).children('.' + CONST.ELEM_PACK).children('.' + CONST.ELEM_SET).last().addClass(CONST.ELEM_LINE_SHORT); + }); + } else { + // 父节点隐藏箭头 + prevDiv.find('.layui-tree-iconArrow').addClass(CONST.CLASS_HIDE); + } + // 移除展开属性 + elem.parents('.' + CONST.ELEM_SET).eq(0).removeClass(CONST.ELEM_SPREAD); + // 移除节点容器 + elem.parent('.' + CONST.ELEM_PACK).remove(); + } + elem.remove(); + }); + } + }); +}; + +// 部分事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 初始选中 + that.setChecked(that.checkids); + + // 搜索 + that.elem.find('.layui-tree-search').on('keyup', function () { + var input = $(this); + var val = input.val(); + var pack = input.nextAll(); + var arr = []; + + // 遍历所有的值 + pack.find('.' + CONST.ELEM_TEXT).each(function () { + var entry = $(this).parents('.' + CONST.ELEM_ENTRY); + // 若值匹配,加一个类以作标识 + if ($(this).html().indexOf(val) != -1) { + arr.push($(this).parent()); + var select = function (div) { + div.addClass('layui-tree-searchShow'); + // 向上父节点渲染 + if (div.parent('.' + CONST.ELEM_PACK)[0]) { + select(div.parent('.' + CONST.ELEM_PACK).parent('.' + CONST.ELEM_SET)); + } + }; + select(entry.parent('.' + CONST.ELEM_SET)); + } + }); + + // 根据标志剔除 + pack.find('.' + CONST.ELEM_ENTRY).each(function () { + var parent = $(this).parent('.' + CONST.ELEM_SET); + if (!parent.hasClass('layui-tree-searchShow')) { + parent.addClass(CONST.CLASS_HIDE); + } + }); + if (pack.find('.layui-tree-searchShow').length == 0) { + that.elem.append(that.elemNone); + } + + // 节点过滤的回调 + options.onsearch && options.onsearch({ + elem: arr + }); + }); + + // 还原搜索初始状态 + that.elem.find('.layui-tree-search').on('keydown', function () { + $(this).nextAll().find('.' + CONST.ELEM_ENTRY).each(function () { + var parent = $(this).parent('.' + CONST.ELEM_SET); + parent.removeClass('layui-tree-searchShow ' + CONST.CLASS_HIDE); + }); + if ($('.layui-tree-emptyText')[0]) $('.layui-tree-emptyText').remove(); + }); +}; + +// 得到选中节点 +Class.prototype.getChecked = function () { + var that = this; + var options = that.config; + var customName = options.customName; + var checkedId = []; + var checkedData = []; + + // 遍历节点找到选中索引 + that.elem.find('.layui-form-checked').each(function () { + checkedId.push($(this).prev()[0].value); + }); + + // 遍历节点 + var eachNodes = function (data, checkNode) { + layui.each(data, function (index, item) { + layui.each(checkedId, function (index2, item2) { + if (item[customName.id] == item2) { + that.updateFieldValue(item, 'checked', true); + var cloneItem = $.extend({}, item); + delete cloneItem[customName.children]; + checkNode.push(cloneItem); + if (item[customName.children]) { + cloneItem[customName.children] = []; + eachNodes(item[customName.children], cloneItem[customName.children]); + } + return true; + } + }); + }); + }; + eachNodes($.extend({}, options.data), checkedData); + return checkedData; +}; + +// 设置选中节点 +Class.prototype.setChecked = function (checkedId) { + var that = this; + var options = that.config; + var flatData = options.flatData; + if (typeof checkedId !== 'object') { + checkedId = [checkedId]; + } + + // 初始选中状态 + that.elem.find('.' + CONST.ELEM_SET).each(function (i) { + var thisId = $(this).data('id'); + var input = $(this).children('.' + CONST.ELEM_ENTRY).find('input[same="layuiTreeCheck"]'); + var checked = input.prop('checked'); + layui.each(checkedId, function (_i, id) { + if (thisId == id) { + if (input.prop('disabled')) return; + if (!checked) { + input.prop('checked', true); + that.syncCheckedState(input, flatData[i]); + return true; + } + } + }); + }); +}; + +// 扩展组件接口 +$.extend(component, { + // 获得选中的节点数据 + getChecked: function (id) { + var that = component.getInst(id); + if (!that) return; + return that.getChecked(); + }, + // 设置选中节点 + setChecked: function (id, checkedId) { + var that = component.getInst(id); + if (!that) return; + return that.setChecked(checkedId); + } +}); + +export { component as tree }; diff --git a/dist/components/treeTable.js b/dist/components/treeTable.js new file mode 100644 index 000000000..041168a3c --- /dev/null +++ b/dist/components/treeTable.js @@ -0,0 +1,2041 @@ +import { layui } from '../core/layui.js'; +import $ from 'jquery'; +import { form } from './form.js'; +import { table } from './table.js'; + +/** + * layui.treeTable + * 树表组件 + */ + +var hint = layui.hint(); + +// api +var treeTable = { + config: {}, + // 事件 + on: table.on, + // 遍历字段 + eachCols: table.eachCols, + index: table.index, + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + resize: table.resize, + getOptions: table.getOptions, + hideCol: table.hideCol, + renderData: table.renderData +}; + +// 操作当前实例 +var thisTreeTable = function () { + var that = this; + var options = that.config; + var id = options.id || options.index; + return { + config: options, + reload: function (options, deep) { + that.reload.call(that, options, deep); + }, + reloadData: function (options, deep) { + treeTable.reloadData(id, options, deep); + } + }; +}; + +/** + * 获取当前实例 + * @param {string} id 表格id + * @returns {Class} + */ +var getThisTable = function (id) { + var that = thisTreeTable.that[id]; + if (!that) hint.error(id ? "The treeTable instance with ID '" + id + "' not found" : 'ID argument required'); + return that || null; +}; + +// 字符 +// var MOD_NAME = 'treeTable'; +var MOD_ID = 'lay-table-id'; +var HIDE = 'layui-hide'; +var ELEM_VIEW = '.layui-table-view'; +// var ELEM_TREE = '.layui-table-tree'; +// var ELEM_TOOL = '.layui-table-tool'; +// var ELEM_BOX = '.layui-table-box'; +// var ELEM_HEADER = '.layui-table-header'; +var ELEM_BODY = '.layui-table-body'; +var ELEM_MAIN = '.layui-table-main'; +// var ELEM_FIXED = '.layui-table-fixed'; +var ELEM_FIXL = '.layui-table-fixed-l'; +var ELEM_FIXR = '.layui-table-fixed-r'; +var ELEM_CHECKED = 'layui-table-checked'; +var TABLE_TREE = 'layui-table-tree'; +var LAY_DATA_INDEX = 'LAY_DATA_INDEX'; +var LAY_DATA_INDEX_HISTORY = 'LAY_DATA_INDEX_HISTORY'; +var LAY_PARENT_INDEX = 'LAY_PARENT_INDEX'; +var LAY_CHECKBOX_HALF = 'LAY_CHECKBOX_HALF'; +var LAY_EXPAND = 'LAY_EXPAND'; +var LAY_HAS_EXPANDED = 'LAY_HAS_EXPANDED'; +var LAY_ASYNC_STATUS = 'LAY_ASYNC_STATUS'; +var LAY_CASCADE = ['all', 'parent', 'children', 'none']; +var HTML_TAG_RE = /<[^>]+?>/; +var ICON_PROPS = ['flexIconClose', 'flexIconOpen', 'iconClose', 'iconOpen', 'iconLeaf', 'icon']; + +/** + * 构造器 + * @class + */ +var Class = function (options) { + var that = this; + that.index = ++treeTable.index; + that.config = $.extend(true, {}, that.config, treeTable.config, options); + // 处理一些属性 + that.init(); + that.render(); +}; +var updateCache = function (id, childrenKey, data) { + var tableCache = table.cache[id]; + layui.each(data || tableCache, function (index, item) { + var itemDataIndex = item[LAY_DATA_INDEX] || ''; + if (itemDataIndex.indexOf('-') !== -1) { + tableCache[itemDataIndex] = item; + } + item[childrenKey] && updateCache(id, childrenKey, item[childrenKey]); + }); +}; +var updateOptions = function (id, options, reload) { + var that = getThisTable(id); + reload === 'reloadData' || (that.status = { + // 用于记录一些状态信息 + expand: {} // 折叠状态 + }); + var thatOptionsTemp = $.extend(true, {}, that.getOptions(), options); + var treeOptions = thatOptionsTemp.tree; + var childrenKey = treeOptions.customName.children; + var idKey = treeOptions.customName.id; + // 处理属性 + delete options.hasNumberCol; + delete options.hasChecboxCol; + delete options.hasRadioCol; + table.eachCols(null, function (i1, item1) { + if (item1.type === 'numbers') { + options.hasNumberCol = true; + } else if (item1.type === 'checkbox') { + options.hasChecboxCol = true; + } else if (item1.type === 'radio') { + options.hasRadioCol = true; + } + }, thatOptionsTemp.cols); + var parseData = options.parseData; + var done = options.done; + + // treeTable重载数据时,会先加载显示顶层节点,然后根据重载数据前的子节点展开状态,展开相应的子节点, + // 那么如果重载数据前有滚动条滚动在某个位子,重新加载时顶层节点如果比较少,只显示顶层节点时没有滚动条的情况下, + // 自动展开子节点后,滚动条就会显示在顶部,无法保持在重载数据之前的位置。 + // 处理保持滚动条的问题,重载数据前记录滚动条的位置 + if (reload === 'reloadData' && thatOptionsTemp.scrollPos === 'fixed') { + that.scrollTopCache = that.config.elem.next().find(ELEM_BODY).scrollTop(); + } + if (thatOptionsTemp.url) { + // 异步加载的时候需要处理parseData进行转换 + if (!reload || reload && parseData && !parseData.mod) { + options.parseData = function () { + var parseDataThat = this; + var args = arguments; + var retData = args[0]; + if (layui.type(parseData) === 'function') { + retData = parseData.apply(parseDataThat, args) || args[0]; + } + var dataName = parseDataThat.response.dataName; + // 处理 isSimpleData + if (treeOptions.data.isSimpleData && !treeOptions.async.enable) { + // 异步加载和 isSimpleData 不应该一起使用 + retData[dataName] = that.flatToTree(retData[dataName]); + } + // 处理节点状态 + updateStatus(retData[dataName], function (item) { + item[LAY_EXPAND] = LAY_EXPAND in item ? item[LAY_EXPAND] : item[idKey] !== undefined && that.status.expand[item[idKey]]; + }, childrenKey); + if (parseDataThat.autoSort && parseDataThat.initSort && parseDataThat.initSort.type) { + layui.sort(retData[dataName], parseDataThat.initSort.field, parseDataThat.initSort.type === 'desc', true); + } + that.initData(retData[dataName]); + return retData; + }; + options.parseData.mod = true; + } + } else { + if (options.data !== undefined) { + options.data = options.data || []; + // 处理 isSimpleData + if (treeOptions.data.isSimpleData) { + options.data = that.flatToTree(options.data); + } + that.initData(options.data); + } + } + if (!reload || reload && done && !done.mod) { + options.done = function () { + var args = arguments; + var doneThat = this; + // undefined: 初始 render 或 reload,两者本质没有区别可以不做区分 + // 'reloadData': 重载数据 + // 'renderData': 重新渲染数据 + var renderType = args[3]; + var isRenderData = renderType === 'renderData'; + if (!isRenderData) { + delete that.isExpandAll; + } + var tableView = this.elem.next(); + that.updateStatus(null, { + LAY_HAS_EXPANDED: false // 去除已经打开过的状态 + }); + // 更新cache中的内容 将子节点也存到cache中 + updateCache(id, childrenKey); + // 更新全选框的状态 + var layTableAllChooseElem = tableView.find('[name="layTableCheckbox"][lay-filter="layTableAllChoose"]'); + if (layTableAllChooseElem.length) { + var checkStatus = treeTable.checkStatus(id); + layTableAllChooseElem.prop({ + checked: checkStatus.isAll && checkStatus.data.length, + indeterminate: !checkStatus.isAll && checkStatus.data.length + }); + } + if (!isRenderData && thatOptionsTemp.autoSort && thatOptionsTemp.initSort && thatOptionsTemp.initSort.type) { + treeTable.sort(id); + } + that.renderTreeTable(tableView); + + // 恢复滚动条位置 + if (renderType === 'reloadData' && doneThat.scrollPos === 'fixed') { + tableView.find(ELEM_BODY).scrollTop(that.scrollTopCache); + } + if (layui.type(done) === 'function') { + return done.apply(doneThat, args); + } + }; + options.done.mod = true; + } + + // 处理图标 + if (options && options.tree && options.tree.view) { + layui.each(ICON_PROPS, function (i, iconProp) { + if (options.tree.view[iconProp] !== undefined) { + options.tree.view[iconProp] = that.normalizedIcon(options.tree.view[iconProp]); + } + }); + } +}; +Class.prototype.init = function () { + var that = this; + var options = that.config; + var cascade = options.tree.data.cascade; + if (LAY_CASCADE.indexOf(cascade) === -1) { + options.tree.data.cascade = 'all'; // 超出范围的都重置为全联动 + } + + // 先初始一个空的表格以便拿到对应的表格实例信息 + var tableIns = table.render($.extend({}, options, { + data: [], + url: '', + done: null + })); + var id = tableIns.config.id; + thisTreeTable.that[id] = that; // 记录当前实例对象 + that.tableIns = tableIns; + updateOptions(id, options); +}; + +// 初始默认配置 +Class.prototype.config = { + tree: { + customName: { + children: 'children', + // 节点数据中保存子节点数据的属性名称 + isParent: 'isParent', + // 节点数据保存节点是否为父节点的属性名称 + name: 'name', + // 节点数据保存节点名称的属性名称 + id: 'id', + // 唯一标识的属性名称 + pid: 'parentId', + // 父节点唯一标识的属性名称 + icon: 'icon' // 图标的属性名称 + }, + view: { + indent: 14, + // 层级缩进量 + flexIconClose: '', + // 关闭时候的折叠图标 + flexIconOpen: '', + // 打开时候的折叠图标 + showIcon: true, + // 是否显示图标(节点类型图标) + icon: '', + // 节点图标,如果设置了这个属性或者数据中有这个字段信息,不管打开还是关闭都以这个图标的值为准 + iconClose: '', + // 关闭时候的图标 + iconOpen: '', + // 打开时候的图标 + iconLeaf: '', + // 叶子节点的图标 + showFlexIconIfNotParent: false, + // 当节点不是父节点的时候是否显示折叠图标 + dblClickExpand: true, + // 双击节点时,是否自动展开父节点的标识 + expandAllDefault: false // 默认展开所有节点 + }, + data: { + isSimpleData: false, + // 是否简单数据模式 + rootPid: null, + // 根节点的父 ID 值 + cascade: 'all' // 级联方式 默认全部级联:all 可选 级联父 parent 级联子 children + }, + async: { + enable: false, + // 是否开启异步加载模式,只有开启的时候其他参数才起作用 + url: '', + // 异步加载的接口,可以根据需要设置与顶层接口不同的接口,如果相同可以不设置该参数 + type: null, + // 请求的接口类型,设置可缺省同上 + contentType: null, + // 提交参数的数据类型,设置可缺省同上 + headers: null, + // 设置可缺省同上 + where: null, + // 设置可缺省同上 + autoParam: [] // 自动参数 + }, + callback: { + beforeExpand: null, + // 展开前的回调 return false 可以阻止展开的动作 + onExpand: null // 展开之后的回调 + } + } +}; +Class.prototype.normalizedIcon = function (iconStr) { + return iconStr ? HTML_TAG_RE.test(iconStr) ? iconStr : '' : ''; +}; +Class.prototype.getOptions = function () { + var that = this; + if (that.tableIns) { + return table.getOptions(that.tableIns.config.id); // 获取表格的实时配置信息 + } else { + return that.config; + } +}; +function flatToTree(flatArr, idKey, pIdKey, childrenKey, rootPid) { + idKey = idKey || 'id'; + pIdKey = pIdKey || 'parentId'; + childrenKey = childrenKey || 'children'; + // 创建一个空的 map 对象,用于保存所有的节点 + var map = {}; + var rootNodes = []; + var idTemp = ''; + var pidTemp = ''; + layui.each(flatArr, function (index, item) { + idTemp = idKey + item[idKey]; + pidTemp = idKey + item[pIdKey]; + + // 将节点存入 map 对象 + if (!map[idTemp]) { + map[idTemp] = {}; + map[idTemp][childrenKey] = []; + } + + // 合并节点 + var tempObj = {}; + tempObj[childrenKey] = map[idTemp][childrenKey]; + map[idTemp] = $.extend({}, item, tempObj); + var isRootNode = rootPid ? map[idTemp][pIdKey] === rootPid : !map[idTemp][pIdKey]; + if (isRootNode) { + rootNodes.push(map[idTemp]); + } else { + if (!map[pidTemp]) { + map[pidTemp] = {}; + map[pidTemp][childrenKey] = []; + } + map[pidTemp][childrenKey].push(map[idTemp]); + } + }); + return rootNodes; +} +Class.prototype.flatToTree = function (tableData) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var tableId = options.id; + tableData = tableData || table.cache[tableId]; + return flatToTree(tableData, customName.id, customName.pid, customName.children, treeOptions.data.rootPid); +}; +Class.prototype.treeToFlat = function (tableData, parentId, parentIndex) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var childrenKey = customName.children; + var pIdKey = customName.pid; + var flat = []; + layui.each(tableData, function (i1, item1) { + var dataIndex = (parentIndex ? parentIndex + '-' : '') + i1; + var dataNew = $.extend({}, item1); + dataNew[pIdKey] = typeof item1[pIdKey] !== 'undefined' ? item1[pIdKey] : parentId; + flat.push(dataNew); + flat = flat.concat(that.treeToFlat(item1[childrenKey], item1[customName.id], dataIndex)); + }); + return flat; +}; + +// 通过当前行数据返回 treeNode 信息 +Class.prototype.getTreeNode = function (data) { + var that = this; + if (!data) { + return hint.error('Node data not found'); + } + // var options = that.getOptions(); + // var treeOptions = options.tree; + // var tableId = options.id; + // var customName = treeOptions.customName; + + // 带上一些常用的方法 + return { + data: data, + dataIndex: data[LAY_DATA_INDEX], + getParentNode: function () { + return that.getNodeByIndex(data[LAY_PARENT_INDEX]); + } + }; +}; + +// 通过 index 返回节点信息 +Class.prototype.getNodeByIndex = function (index) { + var that = this; + var treeNodeData = that.getNodeDataByIndex(index); + if (!treeNodeData) { + return hint.error('Node data not found by index: ' + index); + } + var options = that.getOptions(); + // var treeOptions = options.tree; + // var customName = treeOptions.customName; + // var parentKey = customName.parent; + var tableId = options.id; + var treeNode = { + data: treeNodeData, + dataIndex: treeNodeData[LAY_DATA_INDEX], + getParentNode: function () { + return that.getNodeByIndex(treeNodeData[LAY_PARENT_INDEX]); + }, + update: function (data) { + return treeTable.updateNode(tableId, index, data); + }, + remove: function () { + return treeTable.removeNode(tableId, index); + }, + expand: function (opts) { + return treeTable.expandNode(tableId, $.extend({}, opts, { + index: index + })); + }, + setChecked: function (opts) { + return treeTable.setRowChecked(tableId, $.extend({}, opts, { + index: index + })); + } + }; + treeNode.dataIndex = index; + return treeNode; +}; + +// 通过 id 获取节点信息 +Class.prototype.getNodeById = function (id) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var idKey = customName.id; + + // 通过 id 拿到数据的 dataIndex + var dataIndex = ''; + var tableDataFlat = treeTable.getData(options.id, true); + layui.each(tableDataFlat, function (i1, item1) { + if (item1[idKey] === id) { + dataIndex = item1[LAY_DATA_INDEX]; + return true; + } + }); + if (!dataIndex) { + return; + } + + // 用 index + return that.getNodeByIndex(dataIndex); +}; + +// 通过 index 获取节点数据 +Class.prototype.getNodeDataByIndex = function (index, clone, newValue) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var tableCache = table.cache[tableId]; + + // 获取当前行中的数据 + var dataCache = tableCache[index]; + + // 若非删除操作,则返回合并后的数据 + if (newValue !== 'delete' && dataCache) { + $.extend(dataCache, newValue); + return clone ? $.extend({}, dataCache) : dataCache; + } + + // 删除操作 + var dataRet = tableCache; + var indexArr = String(index).split('-'); + + // if (options.url || indexArr.length > 1) tableCache = null // 只有在删除根节点的时候才需要处理 + + // 根据 index 进行数据处理 + for (var i = 0, childrenKey = treeOptions.customName.children; i < indexArr.length; i++) { + if (newValue && i === indexArr.length - 1) { + if (newValue === 'delete') { + // 删除并返回当前数据 + // 同步 cache --- 此段代码注释缘由:data 属性模式造成数据重复执行 splice (@Gitee: #I7Z0A/I82E2S) + /*if (tableCache) { + layui.each(tableCache, function (i1, item1) { + if (item1[LAY_DATA_INDEX] === index) { + tableCache.splice(i1, 1); + return true; + } + }) + }*/ + return (i ? dataRet[childrenKey] : dataRet).splice(indexArr[i], 1)[0]; + } else { + // 更新值 + $.extend((i ? dataRet[childrenKey] : dataRet)[indexArr[i]], newValue); + } + } + dataRet = i ? dataRet[childrenKey][indexArr[i]] : dataRet[indexArr[i]]; + } + return clone ? $.extend({}, dataRet) : dataRet; +}; +treeTable.getNodeDataByIndex = function (id, index) { + var that = getThisTable(id); + if (!that) return; + return that.getNodeDataByIndex(index, true); +}; + +// 判断是否是父节点 +/* var checkIsParent = function (data, isParentKey, childrenKey) { + isParentKey = isParentKey || 'isParent'; + childrenKey = childrenKey || 'children'; + layui.each(data, function (i1, item1) { + if (!(isParentKey in item1)) { + item1[isParentKey] = !!(item1[childrenKey] && item1[childrenKey].length); + checkIsParent(item1[childrenKey]); + } + }); +}; */ + +Class.prototype.initData = function (data, parentIndex) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + data = data || that.getTableData(); + var customName = treeOptions.customName; + var isParentKey = customName.isParent; + var childrenKey = customName.children; + var update = function (data, parentIndex) { + layui.each(data, function (i1, item1) { + if (!(isParentKey in item1)) { + item1[isParentKey] = !!(item1[childrenKey] && item1[childrenKey].length); + } + item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; + item1[LAY_PARENT_INDEX] = parentIndex = parentIndex || ''; + var dataIndex = item1[LAY_DATA_INDEX] = (parentIndex ? parentIndex + '-' : '') + i1; + update(item1[childrenKey] || [], dataIndex); + }); + }; + update(data, parentIndex); + updateCache(tableId, childrenKey, data); + return data; +}; + +// 与 tableId 有关带防抖的方法 +var debounceFn = function () { + var fn = {}; + return function (tableId, func, wait) { + if (!fn[tableId]) { + fn[tableId] = layui.debounce(func, wait); + } + return fn[tableId]; + }; +}(); + +// 优化参数,添加一个 getNodeByIndex 方法 只传 表格id 和行 dataIndex 分几步优化 todo +var expandNode = function (treeNode, expandFlag, sonSign, focus, callbackFlag, done) { + // treeNode // 需要展开的节点 + var trElem = treeNode.trElem; + var tableViewElem = treeNode.tableViewElem || trElem.closest(ELEM_VIEW); + var tableId = treeNode.tableId || tableViewElem.attr(MOD_ID); + var options = treeNode.options || table.getOptions(tableId); + var dataIndex = treeNode.dataIndex || trElem.attr('lay-data-index'); // 可能出现多层 + var treeTableThat = getThisTable(tableId); + var treeOptions = options.tree || {}; + var customName = treeOptions.customName || {}; + var isParentKey = customName.isParent; + var trData = treeTableThat.getNodeDataByIndex(dataIndex); + + // 后续调优:对已经展开的节点进行展开和已经关闭的节点进行关闭应该做优化减少不必要的代码执行 todo + var isToggle = layui.type(expandFlag) !== 'boolean'; + var trExpand = isToggle ? !trData[LAY_EXPAND] : expandFlag; + var retValue = trData[isParentKey] ? trExpand : null; + if (callbackFlag && trExpand != trData[LAY_EXPAND] && (!trData[LAY_ASYNC_STATUS] || trData[LAY_ASYNC_STATUS] === 'local')) { + var beforeExpand = treeOptions.callback.beforeExpand; + if (layui.type(beforeExpand) === 'function') { + if (beforeExpand(tableId, trData, expandFlag) === false) { + return retValue; + } + } + } + var trExpanded = trData[LAY_HAS_EXPANDED]; // 展开过,包括异步加载 + + // 找到表格中的同类节点(需要找到lay-data-index一致的所有行) + var trsElem = tableViewElem.find('tr[lay-data-index="' + dataIndex + '"]'); + var flexIconElem = trsElem.find('.layui-table-tree-flexIcon'); + treeTableThat.updateNodeIcon({ + scopeEl: trsElem, + isExpand: trExpand, + isParent: trData[isParentKey] + }); + trData[LAY_EXPAND] = trExpand; + var trDataId = trData[customName.id]; + trDataId !== undefined && (treeTableThat.status.expand[trDataId] = trExpand); + if (retValue === null) { + return retValue; + } + var childNodes = trData[customName.children] || []; + // 处理子节点展示与否 + if (trExpand) { + // 展开 + if (trExpanded) { + // 已经展开过 + if (!childNodes.length) return; //异步如果子节点没有数据情况下双点行展开所有已展开的节点问题解决 + trsElem.nextAll(childNodes.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }).join(',')).removeClass(HIDE); + layui.each(childNodes, function (i1, item1) { + if (!item1[isParentKey]) { + return; + } + if (sonSign && !isToggle && !item1[LAY_EXPAND]) { + // 非状态切换的情况下 + // 级联展开子节点 + expandNode({ + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem.find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]').first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options + }, expandFlag, sonSign, focus, callbackFlag, done); + } else if (item1[LAY_EXPAND]) { + // 初始化级联展开 + expandNode({ + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem.find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]').first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options + }, true, undefined, undefined, undefined, done); + } + }); + } else { + var asyncSetting = treeOptions.async || {}; + var asyncUrl = asyncSetting.url || options.url; + if (asyncSetting.enable && trData[isParentKey] && (!trData[LAY_ASYNC_STATUS] || trData[LAY_ASYNC_STATUS] === 'error')) { + trData[LAY_ASYNC_STATUS] = 'loading'; + flexIconElem.html(''); + + // 异步获取子节点数据成功之后处理方法 + var asyncSuccessFn = function (data) { + trData[LAY_ASYNC_STATUS] = 'success'; + trData[customName.children] = data; + treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX]); + expandNode(treeNode, true, isToggle ? false : sonSign, focus, callbackFlag, done); + }; + var format = asyncSetting.format; // 自定义数据返回方法 + if (layui.type(format) === 'function') { + format(trData, options, asyncSuccessFn); + return retValue; + } + var params = {}; + // 参数 + var data = $.extend(params, asyncSetting.where || options.where); + var asyncAutoParam = asyncSetting.autoParam; + layui.each(asyncAutoParam, function (index, item) { + // var itemStr = item; + var itemArr = item.split('='); + data[itemArr[0].trim()] = trData[(itemArr[1] || itemArr[0]).trim()]; + }); + var asyncContentType = asyncSetting.contentType || options.contentType; + if (asyncContentType && asyncContentType.indexOf('application/json') == 0) { + // 提交 json 格式 + data = JSON.stringify(data); + } + var asyncType = asyncSetting.method || options.method; + var asyncDataType = asyncSetting.dataType || options.dataType; + var asyncJsonpCallback = asyncSetting.jsonpCallback || options.jsonpCallback; + var asyncHeaders = asyncSetting.headers || options.headers; + var asyncParseData = asyncSetting.parseData || options.parseData; + var asyncResponse = asyncSetting.response || options.response; + var ajaxOptions = { + type: asyncType || 'get', + url: asyncUrl, + contentType: asyncContentType, + data: data, + dataType: asyncDataType || 'json', + jsonpCallback: asyncJsonpCallback, + headers: asyncHeaders || {}, + success: function (res) { + // 若有数据解析的回调,则获得其返回的数据 + if (typeof asyncParseData === 'function') { + res = asyncParseData.call(options, res) || res; + } + // 检查数据格式是否符合规范 + if (res[asyncResponse.statusName] != asyncResponse.statusCode) { + trData[LAY_ASYNC_STATUS] = 'error'; + trData[LAY_EXPAND] = false; + // 异常处理 todo + flexIconElem.html(''); + // 事件 + } else { + // 正常返回 + asyncSuccessFn(res[asyncResponse.dataName]); + } + }, + error: function (e, msg) { + trData[LAY_ASYNC_STATUS] = 'error'; + trData[LAY_EXPAND] = false; + // 异常处理 todo + typeof options.error === 'function' && options.error(e, msg); + } + }; + if (options.ajax) { + options.ajax(ajaxOptions, 'treeNodes'); + } else { + $.ajax(ajaxOptions); + } + return retValue; + } + trExpanded = trData[LAY_HAS_EXPANDED] = true; + if (childNodes.length) { + // 判断是否需要排序 + if (options.initSort && (!options.url || options.autoSort)) { + var initSort = options.initSort; + if (initSort.type) { + layui.sort(childNodes, initSort.field, initSort.type === 'desc', true); + } else { + // 恢复默认 + layui.sort(childNodes, table.config.indexName, null, true); + } + } + treeTableThat.initData(trData[customName.children], trData[LAY_DATA_INDEX]); + // 将数据通过模板得出节点的html代码 + var str2 = table.getTrHtml(tableId, childNodes, null, null, dataIndex); + var str2Obj = { + trs: $(str2.trs.join('')), + trs_fixed: $(str2.trs_fixed.join('')), + trs_fixed_r: $(str2.trs_fixed_r.join('')) + }; + var dataLevel = dataIndex.split('-').length - 1; + var dataLevelNew = (dataLevel || 0) + 1; + layui.each(childNodes, function (childIndex, childItem) { + str2Obj.trs.eq(childIndex).attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew + }).data('index', childItem[LAY_DATA_INDEX]); + str2Obj.trs_fixed.eq(childIndex).attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew + }).data('index', childItem[LAY_DATA_INDEX]); + str2Obj.trs_fixed_r.eq(childIndex).attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew + }).data('index', childItem[LAY_DATA_INDEX]); + }); + tableViewElem.find(ELEM_MAIN).find('tbody tr[lay-data-index="' + dataIndex + '"]').after(str2Obj.trs); + tableViewElem.find(ELEM_FIXL).find('tbody tr[lay-data-index="' + dataIndex + '"]').after(str2Obj.trs_fixed); + tableViewElem.find(ELEM_FIXR).find('tbody tr[lay-data-index="' + dataIndex + '"]').after(str2Obj.trs_fixed_r); + + // 初始化新增的节点中的内容 + treeTableThat.renderTreeTable(str2Obj.trs, dataLevelNew); + if (sonSign && !isToggle) { + // 非状态切换的情况下 + // 级联展开/关闭子节点 + layui.each(childNodes, function (i1, item1) { + expandNode({ + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem.find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]').first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options + }, expandFlag, sonSign, focus, callbackFlag, done); + }); + } + } + } + } else { + treeTableThat.isExpandAll = false; + // 关闭 + if (sonSign && !isToggle) { + // 非状态切换的情况下 + layui.each(childNodes, function (i1, item1) { + expandNode({ + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem.find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]').first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options + }, expandFlag, sonSign, focus, callbackFlag, done); + }); + tableViewElem.find(childNodes.map(function (value) { + // 只隐藏直接子节点,其他由递归的处理 + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }).join(',')).addClass(HIDE); + } else { + var childNodesFlat = treeTableThat.treeToFlat(childNodes, trData[customName.id], dataIndex); + tableViewElem.find(childNodesFlat.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }).join(',')).addClass(HIDE); + } + } + debounceFn('resize-' + tableId, function () { + treeTable.resize(tableId); + }, 0)(); + if (callbackFlag && trData[LAY_ASYNC_STATUS] !== 'loading') { + var onExpand = treeOptions.callback.onExpand; + layui.type(onExpand) === 'function' && onExpand(tableId, trData, trExpand); + } + if (layui.type(done) === 'function' && trData[LAY_ASYNC_STATUS] !== 'loading') { + done(tableId, trData, trExpand); + } + return retValue; +}; + +/** + * 展开或关闭一个节点 + * @param {String} id 树表id + * @param {Object} opts + * @param {Number|String} opts.index 展开行的数据下标 + * @param {Boolean} [opts.expandFlag] 展开、关闭、切换 + * @param {Boolean} [opts.inherit] 是否级联子节点 + * @param {Boolean} [opts.callbackFlag] 是否触发 tree.callback 事件 + * @param {Boolean} [opts.done] 节点操作完成后的回调函数 + * @return [{Boolean}] 状态结果 + * */ +treeTable.expandNode = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + opts = opts || {}; + var index = opts.index; + var expandFlag = opts.expandFlag; + var sonSign = opts.inherit; + var callbackFlag = opts.callbackFlag; + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + return expandNode({ + trElem: tableViewElem.find('tr[lay-data-index="' + index + '"]').first() + }, expandFlag, sonSign, null, callbackFlag, opts.done); +}; + +/** + * 展开或关闭全部节点 + * @param {String} id 树表id + * @param {Boolean} expandFlag 展开或关闭 + * */ +treeTable.expandAll = function (id, expandFlag) { + if (layui.type(expandFlag) !== 'boolean') { + return hint.error('treeTable.expandAll param "expandFlag" must be a boolean value.'); + } + var that = getThisTable(id); + if (!that) return; + that.isExpandAll = expandFlag; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableView = options.elem.next(); + var isParentKey = treeOptions.customName.isParent; + var idKey = treeOptions.customName.id; + var showFlexIconIfNotParent = treeOptions.view.showFlexIconIfNotParent; + if (!expandFlag) { + // 关闭所有 + // 将所有已经打开的节点的状态设置为关闭, + that.updateStatus(null, function (d) { + if (d[isParentKey] || showFlexIconIfNotParent) { + d[LAY_EXPAND] = false; + d[idKey] !== undefined && (that.status.expand[d[idKey]] = false); + } + }); // 只处理当前页,如果需要处理全部表格,需要用treeTable.updateStatus + // 隐藏所有非顶层的节点 + tableView.find('.layui-table-box tbody tr[data-level!="0"]').addClass(HIDE); + tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconClose); + treeOptions.view.showIcon && tableView.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)').html(treeOptions.view.iconClose); + } else { + var tableDataFlat = treeTable.getData(id, true); + // 展开所有 + // 存在异步加载 + if (treeOptions.async.enable) { + // 判断是否有未加载过的节点 + var isAllAsyncDone = true; + layui.each(tableDataFlat, function (i1, item1) { + if (item1[isParentKey] && !item1[LAY_ASYNC_STATUS]) { + isAllAsyncDone = false; + return true; + } + }); + // 有未加载过的节点 + if (!isAllAsyncDone) { + // 逐个展开 + layui.each(treeTable.getData(id), function (i1, item1) { + treeTable.expandNode(id, { + index: item1[LAY_DATA_INDEX], + expandFlag: true, + inherit: true + }); + }); + return; + } + } + + // 先判断是否全部打开过了 + var isAllExpanded = true; + layui.each(tableDataFlat, function (i1, item1) { + if (item1[isParentKey] && !item1[LAY_HAS_EXPANDED]) { + isAllExpanded = false; + return true; + } + }); + // 如果全部节点已经都打开过,就可以简单处理跟隐藏所有节点反操作 + if (isAllExpanded) { + that.updateStatus(null, function (d) { + if (d[isParentKey] || showFlexIconIfNotParent) { + d[LAY_EXPAND] = true; + d[idKey] !== undefined && (that.status.expand[d[idKey]] = true); + } + }); + // 显示所有子节点 + tableView.find('tbody tr[data-level!="0"]').removeClass(HIDE); + // 处理节点的图标 + tableView.find('.layui-table-tree-flexIcon').html(treeOptions.view.flexIconOpen); + treeOptions.view.showIcon && tableView.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom,.layui-table-tree-iconLeaf)').html(treeOptions.view.iconOpen); + } else { + // 如果有未打开过的父节点,将 tr 内容全部重新生成 + that.updateStatus(null, function (d) { + if (d[isParentKey] || showFlexIconIfNotParent) { + d[LAY_EXPAND] = true; + d[LAY_HAS_EXPANDED] = true; + d[idKey] !== undefined && (that.status.expand[d[idKey]] = true); + } + }); + if (options.initSort && options.initSort.type && options.autoSort) { + return treeTable.sort(id); + } + var trAll = table.getTrHtml(id, tableDataFlat); + var trAllObj = { + trs: $(trAll.trs.join('')), + trs_fixed: $(trAll.trs_fixed.join('')), + trs_fixed_r: $(trAll.trs_fixed_r.join('')) + }; + var props; + layui.each(tableDataFlat, function (dataIndex, dataItem) { + var dataLevel = dataItem[LAY_DATA_INDEX].split('-').length - 1; + props = { + 'data-index': dataItem[LAY_DATA_INDEX], + 'lay-data-index': dataItem[LAY_DATA_INDEX], + 'data-level': dataLevel + }; + trAllObj.trs.eq(dataIndex).attr(props).data('index', dataItem[LAY_DATA_INDEX]); + trAllObj.trs_fixed.eq(dataIndex).attr(props).data('index', dataItem[LAY_DATA_INDEX]); + trAllObj.trs_fixed_r.eq(dataIndex).attr(props).data('index', dataItem[LAY_DATA_INDEX]); + }); + layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) { + tableView.find('.layui-table-' + item + ' tbody').html(trAllObj[['trs', 'trs_fixed', 'trs_fixed_r'][i]]); + }); + that.renderTreeTable(tableView, 0, false); + } + } + treeTable.resize(id); +}; + +/** + * @typedef updateNodeIconOptions + * @prop {JQuery} scopeEl - tr 元素 + * @prop {boolean} isExpand - 是否是展开图标 + * @prop {boolean} isParent - 是否是父节点图标 + */ +/** + * 更新节点图标 + * @param {updateNodeIconOptions} opts + */ +Class.prototype.updateNodeIcon = function (opts) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree || {}; + var scopeEl = opts.scopeEl; + var isExpand = opts.isExpand; + var isParent = opts.isParent; + + // 处理折叠按钮图标 + var flexIconElem = scopeEl.find('.layui-table-tree-flexIcon'); + flexIconElem.css('visibility', isParent || treeOptions.view.showFlexIconIfNotParent ? 'visible' : 'hidden').html(isExpand ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose); + // 处理节点图标 + if (treeOptions.view.showIcon) { + var nodeIconElem = scopeEl.find('.layui-table-tree-nodeIcon:not(.layui-table-tree-iconCustom)'); + var nodeIcon = isParent ? isExpand ? treeOptions.view.iconOpen : treeOptions.view.iconClose : treeOptions.view.iconLeaf; + nodeIconElem.toggleClass('layui-table-tree-iconLeaf', !isParent).html(nodeIcon); + } +}; +Class.prototype.renderTreeTable = function (tableView, level, sonSign) { + var that = this; + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + !tableViewElem.hasClass(TABLE_TREE) && tableViewElem.addClass(TABLE_TREE); + var tableId = options.id; + var treeOptions = options.tree || {}; + // var treeOptionsData = treeOptions.data || {}; + var treeOptionsView = treeOptions.view || {}; + var customName = treeOptions.customName || {}; + var isParentKey = customName.isParent; + // var tableFilterId = tableViewElem.attr('lay-filter'); + var treeTableThat = that; + var existsData = options.data.length; // 是否直接赋值 data + // var tableData = treeTableThat.getTableData(); + + level = level || 0; + if (!level) { + // 初始化的表格里面没有level信息,可以作为顶层节点的判断 + tableViewElem.find('.layui-table-body tr:not([data-level])').attr('data-level', level); + layui.each(table.cache[tableId], function (dataIndex, dataItem) { + // fix: 修正直接赋值 data 时顶层节点 LAY_DATA_INDEX 值的异常问题 + if (existsData) { + dataItem[LAY_DATA_INDEX] = String(dataIndex); + } + var layDataIndex = dataItem[LAY_DATA_INDEX]; + tableViewElem.find('.layui-table-main tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('lay-data-index', layDataIndex); + tableViewElem.find('.layui-table-fixed-l tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('lay-data-index', layDataIndex); + tableViewElem.find('.layui-table-fixed-r tbody tr[data-level="0"]:eq(' + dataIndex + ')').attr('lay-data-index', layDataIndex); + }); + } + var dataExpand = null; // 记录需要展开的数据 + var nameKey = customName.name; + var indent = treeOptionsView.indent || 14; + layui.each(tableView.find('td[data-field="' + nameKey + '"]'), function (index, item) { + item = $(item); + var trElem = item.closest('tr'); + var itemCell = item.children('.layui-table-cell'); + if (itemCell.hasClass('layui-table-tree-item')) { + return; + } + var trIndex = trElem.attr('lay-data-index'); + if (!trIndex) { + // 排除在统计行中的节点 + return; + } + trElem = tableViewElem.find('tr[lay-data-index="' + trIndex + '"]'); + var trData = treeTableThat.getNodeDataByIndex(trIndex); + if (trData[LAY_EXPAND] && trData[isParentKey]) { + // 需要展开 + dataExpand = dataExpand || {}; + dataExpand[trIndex] = true; + } + if (trData[LAY_CHECKBOX_HALF]) { + trElem.find('input[type="checkbox"][name="layTableCheckbox"]').prop('indeterminate', true); + } + var htmlTemp = itemCell.html(); + itemCell = trElem.find('td[data-field="' + nameKey + '"]>div.layui-table-cell'); + itemCell.addClass('layui-table-tree-item'); + var flexIconElem = itemCell.html(['
                        ', trData[LAY_EXPAND] ? treeOptionsView.flexIconOpen : treeOptionsView.flexIconClose, + // 折叠图标 + '
                        ', treeOptionsView.showIcon ? '
                        ' + (that.normalizedIcon(trData[customName.icon]) || treeOptionsView.icon || (trData[isParentKey] ? trData[LAY_EXPAND] ? treeOptionsView.iconOpen : treeOptionsView.iconClose : treeOptionsView.iconLeaf) || '') + '
                        ' : '', + // 区分父子节点 + htmlTemp].join('')) // 图标要可定制 + .find('.layui-table-tree-flexIcon'); + + // 添加展开按钮的事件 + flexIconElem.on('click', function (event) { + layui.stope(event); + // 处理数据 + // var trElem = item.closest('tr'); + expandNode({ + trElem: trElem + }, null, null, null, true); + }); + }); + if (!level && treeOptions.view.expandAllDefault && that.isExpandAll === undefined) { + return treeTable.expandAll(tableId, true); // 默认展开全部 + } + + // 当前层的数据看看是否需要展开 + if (sonSign !== false && dataExpand) { + layui.each(dataExpand, function (index) { + var trDefaultExpand = tableViewElem.find('tr[lay-data-index="' + index + '"]'); + trDefaultExpand.find('.layui-table-tree-flexIcon').html(treeOptionsView.flexIconOpen); + expandNode({ + trElem: trDefaultExpand.first() + }, true); + }); + // #1463 expandNode 中已经展开过的节点不会重新渲染 + debounceFn('renderTreeTable2-' + tableId, function () { + form.render($('.layui-table-tree[' + MOD_ID + '="' + tableId + '"]')); + }, 0)(); + } else { + debounceFn('renderTreeTable-' + tableId, function () { + options.hasNumberCol && formatNumber(that); + form.render($('.layui-table-tree[' + MOD_ID + '="' + tableId + '"]')); + }, 0)(); + } +}; +var formatNumber = function (that) { + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + var num = 0; + var trMain = tableViewElem.find('.layui-table-main tbody tr'); + var trFixedL = tableViewElem.find('.layui-table-fixed-l tbody tr'); + var trFixedR = tableViewElem.find('.layui-table-fixed-r tbody tr'); + layui.each(that.treeToFlat(table.cache[options.id]), function (i1, item1) { + if (item1['LAY_HIDE']) return; + var itemData = that.getNodeDataByIndex(item1[LAY_DATA_INDEX]); + itemData['LAY_NUM'] = ++num; + trMain.eq(i1).find('.laytable-cell-numbers').html(num); + trFixedL.eq(i1).find('.laytable-cell-numbers').html(num); + trFixedR.eq(i1).find('.laytable-cell-numbers').html(num); + }); +}; + +// 树表渲染 +Class.prototype.render = function (type) { + var that = this; + that.tableIns = table[type === 'reloadData' ? 'reloadData' : 'reload'](that.tableIns.config.id, $.extend(true, {}, that.config)); + that.config = that.tableIns.config; +}; + +// 表格重载 +Class.prototype.reload = function (options, deep, type) { + var that = this; + options = options || {}; + delete that.haveInit; + + // 防止数组深度合并 + layui.each(options, function (key, item) { + if (layui.type(item) === 'array') delete that.config[key]; + }); + + // 根据需要处理options中的一些参数 + updateOptions(that.getOptions().id, options, type || true); + + // 对参数进行深度或浅扩展 + that.config = $.extend(deep, {}, that.config, options); + + // 执行渲染 + that.render(type); +}; + +// 仅重载数据 +treeTable.reloadData = function () { + var args = $.extend(true, [], arguments); + args[3] = 'reloadData'; + return treeTable.reload.apply(null, args); +}; +var updateStatus = function (data, statusObj, childrenKey, notCascade) { + var dataUpdated = []; + layui.each(data, function (i1, item1) { + if (layui.type(statusObj) === 'function') { + statusObj(item1); + } else { + $.extend(item1, statusObj); + } + dataUpdated.push($.extend({}, item1)); + notCascade || (dataUpdated = dataUpdated.concat(updateStatus(item1[childrenKey], statusObj, childrenKey, notCascade))); + }); + return dataUpdated; +}; +Class.prototype.updateStatus = function (data, statusObj, notCascade) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + data = data || table.cache[options.id]; + return updateStatus(data, statusObj, treeOptions.customName.children, notCascade); +}; +Class.prototype.getTableData = function () { + var that = this; + var options = that.getOptions(); + // return options.url ? table.cache[options.id] : options.data; + return table.cache[options.id]; +}; +treeTable.updateStatus = function (id, statusObj, data) { + var that = getThisTable(id); + var options = that.getOptions(); + if (!data) { + if (options.url) { + data = table.cache[options.id]; + } else { + data = options.data; + } + } + return that.updateStatus(data, statusObj); +}; +treeTable.sort = function (id) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableData = treeTable.getData(id); + var customName = treeOptions.customName; + var childrenKey = customName.children; + + // 只和同级节点排序 + var sort = function (data, field, type) { + layui.sort(data, field, type, true); + layui.each(data, function (rowIndex, trData) { + sort(trData[childrenKey] || [], field, type); + }); + }; + if (options.autoSort) { + var initSort = options.initSort; + if (initSort.type) { + sort(tableData, initSort.field, initSort.type === 'desc'); + } else { + // 恢复默认 + sort(tableData, table.config.indexName, null); + } + // 更新缓存中数据的顺序 + table.cache[id] = tableData; + // 重新初始化缓存数据 + that.initData(tableData); + treeTable.renderData(id); + } +}; + +// 处理事件 +var updateObjParams = function (obj) { + var tableId = obj.config.id; + var tableThat = getThisTable(tableId); + var trData = obj.data = treeTable.getNodeDataByIndex(tableId, obj.index); // 克隆的 + var trIndex = trData[LAY_DATA_INDEX]; + obj.dataIndex = trIndex; + + // 处理update方法 + var updateFn = obj.update; + obj.update = function () { + var updateThat = this; + var args = arguments; + $.extend(tableThat.getNodeDataByIndex(trIndex), args[0]); + var ret = updateFn.apply(updateThat, args); // 主要负责更新节点内容 + var nameKey = obj.config.tree.customName.name; + nameKey in args[0] && obj.tr.find('td[data-field="' + nameKey + '"]').children('div.layui-table-cell').removeClass('layui-table-tree-item'); + tableThat.renderTreeTable(obj.tr, obj.tr.attr('data-level'), false); + return ret; + }; + + // 处理del方法 + obj.del = function () { + treeTable.removeNode(tableId, trData); + }; + + // 处理setRowChecked + obj.setRowChecked = function (checked) { + treeTable.setRowChecked(tableId, { + index: trData, + checked: checked + }); + }; +}; + +// 更新数据 +treeTable.updateNode = function (id, index, newNode) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + // var treeOptions = options.tree; + var tableView = options.elem.next(); + var trElem = tableView.find('tr[lay-data-index="' + index + '"]'); + var trIndex = trElem.attr('data-index'); + var trLevel = trElem.attr('data-level'); + if (!newNode) { + return; + } + // 更新值 + var newNodeTemp = that.getNodeDataByIndex(index, false, newNode); + // 获取新的tr替换 + var trNew = table.getTrHtml(id, [newNodeTemp]); + // 重新渲染tr + layui.each(['main', 'fixed-l', 'fixed-r'], function (i, item) { + tableView.find('.layui-table-' + item + ' tbody tr[lay-data-index="' + index + '"]').replaceWith($(trNew[['trs', 'trs_fixed', 'trs_fixed_r'][i]].join('')).attr({ + 'data-index': trIndex, + 'lay-data-index': index, + 'data-level': trLevel + }).data('index', trIndex)); + }); + that.renderTreeTable(tableView.find('tr[lay-data-index="' + index + '"]'), trLevel); +}; + +// 删除数据 +// _keepParent 暂时为私有参数,仅供内部使用 +treeTable.removeNode = function (id, node, _keepParent) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var treeOptions = options.tree; + var isParentKey = treeOptions.customName.isParent; + var childrenKey = treeOptions.customName.children; + var tableView = options.elem.next(); + var delNode; + var indexArr = []; + var tableCache = table.cache[id]; + delNode = that.getNodeDataByIndex(layui.type(node) === 'string' ? node : node[LAY_DATA_INDEX], false, 'delete'); + var nodeP = that.getNodeDataByIndex(delNode[LAY_PARENT_INDEX]); + that.updateCheckStatus(nodeP); + var delNodesFlat = that.treeToFlat([delNode], delNode[treeOptions.customName.pid], delNode[LAY_PARENT_INDEX]); + layui.each(delNodesFlat, function (i2, delNode) { + var delNodeDataIndex = delNode[LAY_DATA_INDEX]; + indexArr.push('tr[lay-data-index="' + delNodeDataIndex + '"]'); + // 删除临时 key + if (delNodeDataIndex.indexOf('-') !== -1) { + delete tableCache[delNodeDataIndex]; + } + }); + tableView.find(indexArr.join(',')).remove(); // 删除行 + + var deleteCacheKey = function () { + for (var key in tableCache) { + // 根节点 getNodeDataByIndex 内部已处理 + if (key.indexOf('-') !== -1) { + // L93 updateCache() 中,cacheKey 取自 rowData 中的 LAY_DATA_INDEX, + // 两者不同说明当前 cacheKey 引用的 rowData 已被更新 + if (key !== tableCache[key][LAY_DATA_INDEX]) { + delete tableCache[key]; + } + } + } + }; + + // 重新整理数据 + var tableData = that.initData(); + deleteCacheKey(); + // index发生变化需要更新页面tr中对应的lay-data-index 新增和删除都要注意数据结构变动之后的index问题 + layui.each(that.treeToFlat(tableData), function (i3, item3) { + if (item3[LAY_DATA_INDEX_HISTORY] && item3[LAY_DATA_INDEX_HISTORY] !== item3[LAY_DATA_INDEX]) { + tableView.find('tr[lay-data-index="' + item3[LAY_DATA_INDEX_HISTORY] + '"]').attr({ + 'data-index': item3[LAY_DATA_INDEX], + 'lay-data-index': item3[LAY_DATA_INDEX] + }).data('index', item3[LAY_DATA_INDEX]); + // item3[LAY_DATA_INDEX_HISTORY] = item3[LAY_DATA_INDEX] + } + }); + // 重新更新顶层节点的data-index; + layui.each(tableCache, function (i4, item4) { + tableView.find('tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]').attr('data-index', i4).data('index', i4); + }); + options.hasNumberCol && formatNumber(that); + // 更新父节点状态 + if (nodeP) { + var trEl = tableView.find('tr[lay-data-index="' + nodeP[LAY_DATA_INDEX] + '"]'); + if (!_keepParent) { + nodeP[isParentKey] = !!(nodeP[childrenKey] && nodeP[childrenKey].length); + } + that.updateNodeIcon({ + scopeEl: trEl, + isExpand: nodeP[LAY_EXPAND], + isParent: nodeP[isParentKey] + }); + } + + // 重新适配尺寸 + treeTable.resize(id); +}; + +/** + * 新增数据节点 + * @param {String} id 树表id + * @param {Object} opts + * @param {String|Number} opts.parentIndex 指定的父节点,如果增加根节点,请设置 parentIndex 为 null 即可 + * @param {Number} opts.index 新节点插入的位置(从 0 开始)index = -1(默认) 时,插入到最后 + * @param {Object|Array} opts.data 新增的节点,单个或者多个 + * @param {Boolean} opts.focus 新增的节点,单个或者多个 + * @return {Array} 新增的节点 + * */ +treeTable.addNodes = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableViewElem = options.elem.next(); + var checkName = table.config.checkName; + opts = opts || {}; + var parentIndex = opts.parentIndex; + var index = opts.index; + var newNodes = opts.data; + var focus = opts.focus; + parentIndex = layui.type(parentIndex) === 'number' ? parentIndex.toString() : parentIndex; + var parentNode = parentIndex ? that.getNodeDataByIndex(parentIndex) : null; + index = layui.type(index) === 'number' ? index : -1; + + // 添加数据 + newNodes = $.extend(true, [], layui.isArray(newNodes) ? newNodes : [newNodes]); + + // 若未传入 LAY_CHECKED 属性,则继承父节点的 checked 状态 + layui.each(newNodes, function (i, item) { + if (!(checkName in item) && parentNode) { + item[checkName] = parentNode[checkName]; + } + }); + + // var tableData = that.getTableData(); + var dataAfter; + if (!parentNode) { + // 添加到根节点 + dataAfter = table.cache[id].splice(index === -1 ? table.cache[id].length : index); + table.cache[id] = table.cache[id].concat(newNodes, dataAfter); + if (!options.url) { + // 静态data模式 + if (!options.page) { + options.data = table.cache[id]; + } else { + var pageOptions = options.page; + options.data.splice.apply(options.data, [pageOptions.limit * (pageOptions.curr - 1), pageOptions.limit].concat(table.cache[id])); + } + } + // 将新节点添加到页面 + // tableData = that.initData(); + + if (tableViewElem.find('.layui-none').length) { + table.renderData(id); + return newNodes; + } + var newNodesHtml = table.getTrHtml(id, newNodes); + var newNodesHtmlObj = { + trs: $(newNodesHtml.trs.join('')), + trs_fixed: $(newNodesHtml.trs_fixed.join('')), + trs_fixed_r: $(newNodesHtml.trs_fixed_r.join('')) + }; + var attrs = {}; + layui.each(newNodes, function (newNodeIndex, newNodeItem) { + attrs = { + 'data-index': newNodeItem[LAY_DATA_INDEX], + 'lay-data-index': newNodeItem[LAY_DATA_INDEX], + 'data-level': '0' + }; + newNodesHtmlObj.trs.eq(newNodeIndex).attr(attrs).data('index', newNodeItem[LAY_DATA_INDEX]); + newNodesHtmlObj.trs_fixed.eq(newNodeIndex).attr(attrs).data('index', newNodeItem[LAY_DATA_INDEX]); + newNodesHtmlObj.trs_fixed_r.eq(newNodeIndex).attr(attrs).data('index', newNodeItem[LAY_DATA_INDEX]); + }); + var trIndexPrev = parseInt(newNodes[0][LAY_DATA_INDEX]) - 1; + var tableViewElemMAIN = tableViewElem.find(ELEM_MAIN); + var tableViewElemFIXL = tableViewElem.find(ELEM_FIXL); + var tableViewElemFIXR = tableViewElem.find(ELEM_FIXR); + if (trIndexPrev === -1) { + // 插入到开头 + var hasTr = tableViewElemMAIN.find('tr[data-level="0"][data-index="0"]')[0]; + if (hasTr) { + tableViewElemMAIN.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tr[data-level="0"][data-index="0"]').before(newNodesHtmlObj.trs_fixed_r); + } else { + tableViewElemMAIN.find('tbody').prepend(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tbody').prepend(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tbody').prepend(newNodesHtmlObj.trs_fixed_r); + } + } else { + if (index === -1) { + // 追加到最后 + tableViewElemMAIN.find('tbody').append(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tbody').append(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tbody').append(newNodesHtmlObj.trs_fixed_r); + } else { + var trIndexNext = dataAfter[0][LAY_DATA_INDEX_HISTORY]; + tableViewElemMAIN.find('tr[data-level="0"][data-index="' + trIndexNext + '"]').before(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tr[data-level="0"][data-index="' + trIndexNext + '"]').before(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tr[data-level="0"][data-index="' + trIndexNext + '"]').before(newNodesHtmlObj.trs_fixed_r); + } + } + + // 重新更新顶层节点的data-index; + layui.each(table.cache[id], function (i4, item4) { + tableViewElem.find('tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]').attr('data-index', i4).data('index', i4); + }); + that.renderTreeTable(tableViewElem.find(newNodes.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }).join(','))); + } else { + var isParentKey = treeOptions.customName.isParent; + var childKey = treeOptions.customName.children; + parentNode[isParentKey] = true; + var childrenNodes = parentNode[childKey]; + if (!childrenNodes) { + childrenNodes = parentNode[childKey] = newNodes; + } else { + dataAfter = childrenNodes.splice(index === -1 ? childrenNodes.length : index); + childrenNodes = parentNode[childKey] = childrenNodes.concat(newNodes, dataAfter); + } + // 删除已经存在的同级节点以及他们的子节点,并且把中间节点的已展开过的状态设置为false + that.updateStatus(childrenNodes, function (d) { + if (d[isParentKey] || treeOptions.view.showFlexIconIfNotParent) { + d[LAY_HAS_EXPANDED] = false; + } + }); + var childrenNodesFlat = that.treeToFlat(childrenNodes); + tableViewElem.find(childrenNodesFlat.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }).join(',')).remove(); + + // tableData = that.initData(); + // 去掉父节点的已经展开过的状态,重新执行一次展开的方法 + parentNode[LAY_HAS_EXPANDED] = false; + parentNode[LAY_ASYNC_STATUS] = 'local'; // 转为本地数据,应该规定异步加载子节点的时候addNodes的规则 + expandNode({ + trElem: tableViewElem.find('tr[lay-data-index="' + parentIndex + '"]') + }, true); + } + that.updateCheckStatus(parentNode); + // 更新父节点图标状态 + if (parentNode) { + var trEl = tableViewElem.find('tr[lay-data-index="' + parentNode[LAY_DATA_INDEX] + '"]'); + that.updateNodeIcon({ + scopeEl: trEl, + isExpand: parentNode[LAY_EXPAND], + isParent: parentNode[isParentKey] + }); + } + treeTable.resize(id); + if (focus) { + // 滚动到第一个新增的节点 + tableViewElem.find(ELEM_MAIN).find('tr[lay-data-index="' + newNodes[0][LAY_DATA_INDEX] + '"]').get(0).scrollIntoViewIfNeeded(); + } + return newNodes; +}; + +// 获取表格选中状态 +treeTable.checkStatus = function (id, includeHalfCheck) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var treeOptions = options.tree; + var checkName = table.config.checkName; + + // 需要区分单双选 + var tableData = treeTable.getData(id, true); + var checkedData = tableData.filter(function (value) { + return value[checkName] || includeHalfCheck && value[LAY_CHECKBOX_HALF]; + }); + var isAll = true; + layui.each(treeOptions.data.cascade === 'all' ? table.cache[id] : treeTable.getData(id, true), function (i1, item1) { + if (!item1[checkName]) { + isAll = false; + return true; + } + }); + return { + data: checkedData, + isAll: isAll + }; +}; + +// 排序之后重新渲染成树表 +treeTable.on('sort', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + if (tableView.hasClass(TABLE_TREE)) { + treeTable.sort(tableId); + } +}); + +// 行点击 +treeTable.on('row', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + } +}); + +// 行双击 +treeTable.on('rowDouble', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + var treeOptions = options.tree || {}; + if (treeOptions.view.dblClickExpand) { + expandNode({ + trElem: obj.tr.first() + }, null, null, null, true); + } + } +}); + +// 菜单 +treeTable.on('rowContextmenu', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + } +}); + +// tr中带lay-event节点点击 +treeTable.on('tool', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + } +}); + +// 行内编辑 +treeTable.on('edit', function (obj) { + // 如果编辑涉及到关键的name字段需要重新更新一下tr节点 + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + if (obj.field === options.tree.customName.name) { + var updateData = {}; + updateData[obj.field] = obj.value; + obj.update(updateData); // 通过update调用执行tr节点的更新 + } + } +}); + +// 单选 +treeTable.on('radio', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + if (tableView.hasClass(TABLE_TREE)) { + var that = getThisTable(tableId); + updateObjParams(obj); + checkNode.call(that, obj.tr, obj.checked); + } +}); + +// 设置或取消行选中样式 +Class.prototype.setRowCheckedClass = function (tr, checked) { + var that = this; + var options = that.getOptions(); + + // var index = tr.data('index'); + var tableViewElem = options.elem.next(); + tr[checked ? 'addClass' : 'removeClass'](ELEM_CHECKED); // 主体行 + + // 右侧固定行 + tr.each(function () { + var index = $(this).data('index'); + var trFixedR = tableViewElem.find('.layui-table-fixed-r tbody tr[data-index="' + index + '"]'); + trFixedR[checked ? 'addClass' : 'removeClass'](ELEM_CHECKED); + }); +}; + +// 更新表格的复选框状态 +Class.prototype.updateCheckStatus = function (dataP, checked) { + var that = this; + var options = that.getOptions(); + if (!options.hasChecboxCol) { + return false; // 如果没有复选列则不需要更新状态 + } + var treeOptions = options.tree; + var tableId = options.id; + var tableView = options.elem.next(); + var checkName = table.config.checkName; + var cascade = treeOptions.data.cascade; + var isCascadeParent = cascade === 'all' || cascade === 'parent'; + + // 如有必要更新父节点们的状态 + if (isCascadeParent && dataP) { + var trsP = that.updateParentCheckStatus(dataP, layui.type(checked) === 'boolean' ? checked : null); + layui.each(trsP, function (indexP, itemP) { + var checkboxElem = tableView.find('tr[lay-data-index="' + itemP[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'); + var checked = itemP[checkName]; + + // 标记父节点行背景色 + that.setRowCheckedClass(checkboxElem.closest('tr'), checked); + + // 设置原始复选框 checked 属性值并渲染 + checkboxElem.prop({ + checked: checked, + indeterminate: itemP[LAY_CHECKBOX_HALF] + }); + }); + } + + // 更新全选的状态 + var isAll = true; + var isIndeterminate = false; + var data = treeOptions.data.cascade === 'all' ? table.cache[tableId] : treeTable.getData(tableId, true); + data = data.filter(function (item) { + return !item[options.disabledName]; + }); + if (data.length > 0) { + layui.each(data, function (i1, item1) { + if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { + isIndeterminate = true; + } + if (!item1[checkName]) { + isAll = false; + } + if (isIndeterminate && !isAll) { + return true; + } + }); + } else { + isAll = false; + } + isIndeterminate = isIndeterminate && !isAll; + tableView.find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]').prop({ + checked: isAll, + indeterminate: isIndeterminate + }); + return isAll; +}; + +// 更新父节点的选中状态 +Class.prototype.updateParentCheckStatus = function (dataP, checked) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var checkName = table.config.checkName; + var childrenKey = treeOptions.customName.children; + var dataRet = []; + dataP[LAY_CHECKBOX_HALF] = false; // 先设置为非半选,是否为半选又下面逻辑判断 + if (checked === true) { + // 为真需要判断子节点的情况 + if (!dataP[childrenKey].length) { + checked = false; + } else { + layui.each(dataP[childrenKey], function (index, item) { + if (!item[checkName]) { + // 只要有一个子节点为false + checked = false; + dataP[LAY_CHECKBOX_HALF] = true; + return true; // 跳出循环 + } + }); + } + } else if (checked === false) { + // 判断是否为半选 + layui.each(dataP[childrenKey], function (index, item) { + if (item[checkName] || item[LAY_CHECKBOX_HALF]) { + // 只要有一个子节点为选中或者半选状态 + dataP[LAY_CHECKBOX_HALF] = true; + return true; + } + }); + } else { + // 状态不确定的情况下根据子节点的信息 + checked = false; + var checkedNum = 0; + layui.each(dataP[childrenKey], function (index, item) { + if (item[checkName]) { + checkedNum++; + } + }); + checked = dataP[childrenKey].length ? dataP[childrenKey].length === checkedNum : dataP[checkName]; // 如果没有子节点保留原来的状态; + dataP[LAY_CHECKBOX_HALF] = checked ? false : checkedNum > 0; + } + dataP[checkName] = checked; + dataRet.push($.extend({}, dataP)); + if (dataP[LAY_PARENT_INDEX]) { + dataRet = dataRet.concat(that.updateParentCheckStatus(table.cache[tableId][dataP[LAY_PARENT_INDEX]], checked)); + } + return dataRet; +}; +var checkNode = function (trElem, checked, callbackFlag) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var tableView = options.elem.next(); + var inputElem = (trElem.length ? trElem : tableView).find('.laytable-cell-radio, .laytable-cell-checkbox').children('input').last(); + // 判断是单选还是多选 不应该同时存在radio列和checkbox列 + var isRadio = inputElem.attr('type') === 'radio'; + if (callbackFlag) { + var triggerEvent = function () { + var fn = function (event) { + layui.stope(event); + }; + inputElem.parent().on('click', fn); // 添加临时的阻止冒泡事件 + inputElem.next().click(); + inputElem.parent().off('click', fn); + }; + // 如果需要触发事件可以简单的触发对应节点的click事件 + if (isRadio) { + // 单选只能选中或者切换其他的不能取消选中 后续看是否有支持的必要 todo + if (checked && !inputElem.prop('checked')) { + triggerEvent(); + } + } else { + if (layui.type(checked) === 'boolean') { + if (inputElem.prop('checked') !== checked) { + // 如果当前已经是想要修改的状态则不做处理 + triggerEvent(); + } + } else { + // 切换 + triggerEvent(); + } + } + } else { + var trData = that.getNodeDataByIndex(trElem.attr('data-index')); + var checkName = table.config.checkName; + // 如果不触发事件应该有一个方法可以更新数据以及页面的节点 + if (isRadio) { + if (!trData) { + // 单选必须是一个存在的行 + return; + } + var statusChecked = {}; + statusChecked[checkName] = false; + // that.updateStatus(null, statusChecked); // 取消其他的选中状态 + that.updateStatus(null, function (d) { + if (d[checkName]) { + var radioElem = tableView.find('tr[lay-data-index="' + d[LAY_DATA_INDEX] + '"] input[type="radio"][lay-type="layTableRadio"]'); + d[checkName] = false; + + // 取消当前选中行背景色 + that.setRowCheckedClass(radioElem.closest('tr'), false); + radioElem.prop('checked', false); + } + }); // 取消其他的选中状态 + trData[checkName] = checked; + that.setRowCheckedClass(trElem, checked); // 标记当前选中行背景色 + that.setRowCheckedClass(trElem.siblings(), false); // 取消其他行背景色 + + trElem.find('input[type="radio"][lay-type="layTableRadio"]').prop('checked', checked); + } else { + // 切换只能用到单条,全选到这一步的时候应该是一个确定的状态 + checked = layui.type(checked) === 'boolean' ? checked : !trData[checkName]; // 状态切换,如果遇到不可操作的节点待处理 todo + // 全选或者是一个父节点,将子节点的状态同步为当前节点的状态 + // 处理不可操作的信息 + var checkedStatusFn = function (d) { + if (!d[table.config.disabledName]) { + // 节点不可操作的不处理 + d[checkName] = checked; + d[LAY_CHECKBOX_HALF] = false; + } + }; + var trs = that.updateStatus(trData ? [trData] : table.cache[tableId], checkedStatusFn, trData && ['parent', 'none'].indexOf(treeOptions.data.cascade) !== -1); + var checkboxElem = tableView.find(trs.map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"] input[name="layTableCheckbox"]:not(:disabled)'; + }).join(',')); + that.setRowCheckedClass(checkboxElem.closest('tr'), checked); // 标记当前选中行背景色 + checkboxElem.prop({ + checked: checked, + indeterminate: false + }); + var trDataP; + + // 更新父节点以及更上层节点的状态 + if (trData && trData[LAY_PARENT_INDEX]) { + // 找到父节点,然后判断父节点的子节点是否全部选中 + trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); + } + return that.updateCheckStatus(trDataP, checked); + } + } +}; + +// 多选 +treeTable.on('checkbox', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + if (tableView.hasClass(TABLE_TREE)) { + var that = getThisTable(tableId); + var checked = obj.checked; + updateObjParams(obj); + obj.isAll = checkNode.call(that, obj.tr, checked); + } +}); + +/** + * 设置行选中状态 + * @param {String} id 树表id + * @param {Object} opts + * @param {Object|String} opts.index 节点下标 + * @param {Boolean} opts.checked 选中或取消 + * @param {Boolean} [opts.callbackFlag] 是否触发事件回调 + * */ +treeTable.setRowChecked = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var tableView = options.elem.next(); + opts = opts || {}; + var node = opts.index; + var checked = opts.checked; + var callbackFlag = opts.callbackFlag; + var dataIndex = layui.type(node) === 'string' ? node : node[LAY_DATA_INDEX]; + // 判断是否在当前页面中 + var nodeData = that.getNodeDataByIndex(dataIndex); + if (!nodeData) { + // 目前只能处理当前页的数据 + return; + } + var collectNeedExpandNodeIndex = function (index) { + needExpandIndex.push(index); + var trElem = tableView.find('tr[lay-data-index="' + index + '"]'); + if (!trElem.length) { + var nodeData = that.getNodeDataByIndex(index); + var parentIndex = nodeData[LAY_PARENT_INDEX]; + parentIndex && collectNeedExpandNodeIndex(parentIndex); + } + }; + + // 判断是否展开过 + var trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]'); + if (!trElem.length) { + var parentIndex = nodeData[LAY_PARENT_INDEX]; + var needExpandIndex = []; + collectNeedExpandNodeIndex(parentIndex); + // 如果还没有展开没有渲染的要先渲染出来 + layui.each(needExpandIndex.reverse(), function (index, nodeIndex) { + treeTable.expandNode(id, { + index: nodeIndex, + expandFlag: true + }); + }); + trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]'); + } + checkNode.call(that, trElem, checked, callbackFlag); +}; +treeTable.checkAllNodes = function (id, checked) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var tableView = options.elem.next(); + checkNode.call(that, tableView.find('tr[data-index="NONE"]'), !!checked); +}; + +/** + * 获得数据 + * @param {String} id 表格id + * @param {Boolean} [isSimpleData] 是否返回平铺结构的数据 + * @return {Array} 表格数据 + * */ +treeTable.getData = function (id, isSimpleData) { + var that = getThisTable(id); + if (!that) return; + var tableData = []; + layui.each($.extend(true, [], table.cache[id] || []), function (index, item) { + // 遍历排除掉临时的数据 + tableData.push(item); + }); + return isSimpleData ? that.treeToFlat(tableData) : tableData; +}; + +/** + * 重新加载子节点 + * @param {String} id 表格id + * @param {String} dataIndex 父节点的dataIndex + * */ +treeTable.reloadAsyncNode = function (id, dataIndex) { + var that = getThisTable(id); + if (!that) { + return; + } + var options = that.getOptions(); + var treeOptions = options.tree; + if (!treeOptions.async || !treeOptions.async.enable) { + return; + } + var dataP = that.getNodeDataByIndex(dataIndex); + if (!dataP) { + return; + } + dataP[LAY_HAS_EXPANDED] = false; + dataP[LAY_EXPAND] = false; + dataP[LAY_ASYNC_STATUS] = false; + layui.each(that.treeToFlat(dataP[treeOptions.customName.children]).reverse(), function (i1, item1) { + treeTable.removeNode(id, item1[LAY_DATA_INDEX], true); + }); + // 重新展开 + treeTable.expandNode(id, { + index: dataIndex, + expandFlag: true, + callbackFlag: true + }); +}; + +/** + * 通过数据id获取节点对象 + * */ +treeTable.getNodeById = function (id, dataId) { + var that = getThisTable(id); + if (!that) return; + return that.getNodeById(dataId); +}; + +/** + * 根据自定义规则搜索节点数据 + * @param {String} id 树表id + * @param {Function} filter 自定义过滤器函数 + * @param {Object} [opts] + * @param {Boolean} [opts.isSingle] 是否只找到第一个 + * @param {Object} [opts.parentNode] 在指定在某个父节点下的子节点中搜索 + * @return {Object} 节点对象 + * */ +treeTable.getNodesByFilter = function (id, filter, opts) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + opts = opts || {}; + var isSingle = opts.isSingle; + var parentNode = opts.parentNode; + var dataP = parentNode && parentNode.data; + // dataP = dataP || table.cache[id]; + var nodes = that.treeToFlat(dataP ? dataP[options.tree.customName.children] || [] : table.cache[id]).filter(filter); + var nodesResult = []; + layui.each(nodes, function (i1, item1) { + nodesResult.push(that.getNodeByIndex(item1[LAY_DATA_INDEX])); + if (isSingle) { + return true; + } + }); + return nodesResult; +}; + +// 记录所有实例 +thisTreeTable.that = {}; // 记录所有实例对象 +// thisTreeTable.config = {}; // 记录所有实例配置项 + +// 重载 +treeTable.reload = function (id, options, deep, type) { + // deep = deep !== false; // 默认采用深拷贝 + var that = getThisTable(id); + if (!that) return; + that.reload(options, deep, type); + return thisTreeTable.call(that); +}; + +// 核心入口 +treeTable.render = function (options) { + var inst = new Class(options); + return thisTreeTable.call(inst); +}; + +export { treeTable }; diff --git a/dist/components/upload.js b/dist/components/upload.js new file mode 100644 index 000000000..4fb01c1c5 --- /dev/null +++ b/dist/components/upload.js @@ -0,0 +1,824 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; +import { layer } from './layer.js'; + +/** + * upload + * 上传组件 + */ + +var device = layui.device(); +var hint = layui.hint(); + +// 模块名 +var MOD_NAME = 'upload'; +var MOD_INDEX = 'layui_' + MOD_NAME + '_index'; // 模块索引名 + +// 外部接口 +var upload = { + config: {}, + // 全局配置项 + // 设置全局项 + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + // 事件 + on: function (events, callback) { + return layui.onevent.call(this, MOD_NAME, events, callback); + } +}; + +// 操作当前实例 +var thisModule = function () { + var that = this; + var options = that.config; + var id = options.id; + thisModule.that[id] = that; // 记录当前实例对象 + + return { + upload: function (files) { + that.upload.call(that, files); + }, + reload: function (options) { + that.reload.call(that, options); + }, + config: that.config + }; +}; +var ELEM_FILE = 'layui-upload-file'; +var ELEM_FORM = 'layui-upload-form'; +var ELEM_IFRAME = 'layui-upload-iframe'; +var ELEM_CHOOSE = 'layui-upload-choose'; +var UPLOADING = 'UPLOADING'; + +// 构造器 +var Class = function (options) { + var that = this; + that.index = upload.index = lay.autoIncrementer('upload'); + that.config = $.extend({}, that.config, upload.config, options); + that.render(); +}; + +// 默认配置 +Class.prototype.config = { + accept: 'images', + // 允许上传的文件类型:images/file/video/audio + exts: '', + // 允许上传的文件后缀名 + auto: true, + // 是否选完文件后自动上传 + bindAction: '', + // 手动上传触发的元素 + url: '', + // 上传地址 + force: '', + // 强制规定返回的数据格式,目前只支持是否强制 json + field: 'file', + // 文件字段名 + acceptMime: '', + // 筛选出的文件类型,默认为所有文件 + method: 'post', + // 请求上传的 http 类型 + data: {}, + // 请求上传的额外参数 + drag: true, + // 是否允许拖拽上传 + size: 0, + // 文件限制大小,默认不限制 + number: 0, + // 允许同时上传的文件数,默认不限制 + multiple: false, + // 是否允许多文件上传,不支持 ie8-9 + text: { + // 自定义提示文本 + 'cross-domain': 'Cross-domain requests are not supported', + // 跨域 + 'data-format-error': 'Please return JSON data format', + // 数据格式错误 + 'check-error': '', + // 文件格式校验失败 + error: '', + // 上传失败 + 'limit-number': null, + // 限制 number 属性的提示 --- function + 'limit-size': null // 限制 size 属性的提示 --- function + } +}; + +// 重载实例 +Class.prototype.reload = function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + that.render(true); +}; + +// 初始渲染 +Class.prototype.render = function (rerender) { + var that = this; + var options = that.config; + + // 若 elem 非唯一 + var elem = $(options.elem); + if (elem.length > 1) { + layui.each(elem, function () { + upload.render($.extend({}, options, { + elem: this + })); + }); + return that; + } + + // 合并 lay-options 属性上的配置信息 + $.extend(options, lay.options(elem[0], { + attr: elem.attr('lay-data') ? 'lay-data' : null // 兼容旧版的 lay-data 属性 + })); + + // 若重复执行 render,则视为 reload 处理 + if (!rerender && elem[0] && elem.data(MOD_INDEX)) { + var newThat = thisModule.getThis(elem.data(MOD_INDEX)); + if (!newThat) return; + return newThat.reload(options); + } + options.elem = $(options.elem); + options.bindAction = $(options.bindAction); + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + options.id = 'id' in options ? options.id : elem.attr('id') || that.index; + that.file(); + that.events(); +}; + +//追加文件域 +Class.prototype.file = function () { + var that = this; + var options = that.config; + var elemFile = that.elemFile = $([''].join('')); + var next = options.elem.next(); + if (next.hasClass(ELEM_FILE) || next.hasClass(ELEM_FORM)) { + next.remove(); + } + + //包裹ie8/9容器 + if (device.ie && device.ie < 10) { + options.elem.wrap('
                        '); + } + that.isFile() ? (that.elemFile = options.elem, options.field = options.elem[0].name) : options.elem.after(elemFile); + + //初始化ie8/9的Form域 + if (device.ie && device.ie < 10) { + that.initIE(); + } +}; + +//ie8-9初始化 +Class.prototype.initIE = function () { + var that = this; + var options = that.config; + var iframe = $(''); + var elemForm = $(['
                        ', '
                        '].join('')); + + //插入iframe + $('#' + ELEM_IFRAME)[0] || $('body').append(iframe); + + //包裹文件域 + if (!options.elem.next().hasClass(ELEM_FORM)) { + that.elemFile.wrap(elemForm); + + //追加额外的参数 + options.elem.next('.' + ELEM_FORM).append(function () { + var arr = []; + layui.each(options.data, function (key, value) { + value = typeof value === 'function' ? value() : value; + arr.push(''); + }); + return arr.join(''); + }()); + } +}; + +//异常提示 +Class.prototype.msg = function (content) { + return layer.msg(content, { + icon: 2, + shift: 6 + }); +}; + +//判断绑定元素是否为文件域本身 +Class.prototype.isFile = function () { + var elem = this.config.elem[0]; + if (!elem) return; + return elem.tagName.toLocaleLowerCase() === 'input' && elem.type === 'file'; +}; + +//预读图片信息 +Class.prototype.preview = function (callback) { + var that = this; + if (window.FileReader) { + layui.each(that.chooseFiles, function (index, file) { + var reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + callback && callback(index, file, this.result); + }; + }); + } +}; + +// 执行上传 +Class.prototype.upload = function (files, type) { + var that = this; + var options = that.config; + var text = options.text || {}; + var elemFile = that.elemFile[0]; + + // 获取文件队列 + var getFiles = function () { + return files || that.files || that.chooseFiles || elemFile.files; + }; + + // 高级浏览器处理方式,支持跨域 + var ajaxSend = function () { + var successful = 0; + var failed = 0; + var items = getFiles(); + + // 多文件全部上传完毕的回调 + var allDone = function () { + if (options.multiple && successful + failed === that.fileLength) { + typeof options.allDone === 'function' && options.allDone({ + total: that.fileLength, + successful: successful, + failed: failed + }); + } + }; + + // 发送请求 + var request = function (sets) { + var formData = new FormData(); + + // 恢复文件状态 + var resetFileState = function (file) { + if (sets.unified) { + layui.each(items, function (index, file) { + delete file[UPLOADING]; + }); + } else { + delete file[UPLOADING]; + } + }; + + // 追加额外的参数 + layui.each(options.data, function (key, value) { + value = typeof value === 'function' ? sets.unified ? value() : value(sets.index, sets.file) : value; + formData.append(key, value); + }); + + /* + * 添加 file 到表单域 + */ + + // 是否统一上传 + if (sets.unified) { + layui.each(items, function (index, file) { + if (file[UPLOADING]) return; + file[UPLOADING] = true; // 上传中的标记 + formData.append(options.field, file); + }); + } else { + // 逐一上传 + if (sets.file[UPLOADING]) return; + formData.append(options.field, sets.file); + sets.file[UPLOADING] = true; // 上传中的标记 + } + + // ajax 参数 + var opts = { + url: options.url, + type: 'post', + // 统一采用 post 上传 + data: formData, + dataType: options.dataType || 'json', + contentType: false, + processData: false, + headers: options.headers || {}, + success: function (res) { + // 成功回调 + options.unified ? successful += that.fileLength : successful++; + done(sets.index, res); + allDone(sets.index); + resetFileState(sets.file); + }, + error: function (e) { + // 异常回调 + options.unified ? failed += that.fileLength : failed++; + that.msg(text['error'] || ['Upload failed, please try again.', 'status: ' + (e.status || '') + ' - ' + (e.statusText || 'error')].join('
                        ')); + error(sets.index, e.responseText, e); + allDone(sets.index); + resetFileState(sets.file); + } + }; + + // 进度条 + if (typeof options.progress === 'function') { + opts.xhr = function () { + var xhr = $.ajaxSettings.xhr(); + // 上传进度 + xhr.upload.addEventListener('progress', function (obj) { + if (obj.lengthComputable) { + var percent = Math.floor(obj.loaded / obj.total * 100); // 百分比 + options.progress(percent, options.item ? options.item[0] : options.elem[0], obj, sets.index); + } + }); + return xhr; + }; + } + $.ajax(opts); + }; + + // 多文件是否一起上传 + if (options.unified) { + request({ + unified: true, + index: 0 + }); + } else { + layui.each(items, function (index, file) { + request({ + index: index, + file: file + }); + }); + } + }; + + // 低版本 IE 处理方式,不支持跨域 + var iframeSend = function () { + var iframe = $('#' + ELEM_IFRAME); + that.elemFile.parent().submit(); + + // 获取响应信息 + clearInterval(Class.timer); + Class.timer = setInterval(function () { + var res, + iframeBody = iframe.contents().find('body'); + try { + res = iframeBody.text(); + } catch { + that.msg(text['cross-domain']); + clearInterval(Class.timer); + error(); + } + if (res) { + clearInterval(Class.timer); + iframeBody.html(''); + done(0, res); + } + }, 30); + }; + + // 强制返回的数据格式 + var forceConvert = function (src) { + if (options.force === 'json') { + if (typeof src !== 'object') { + try { + return { + status: 'CONVERTED', + data: JSON.parse(src) + }; + } catch { + that.msg(text['data-format-error']); + return { + status: 'FORMAT_ERROR', + data: {} + }; + } + } + } + return { + status: 'DO_NOTHING', + data: {} + }; + }; + + // 统一回调 + var done = function (index, res) { + that.elemFile.next('.' + ELEM_CHOOSE).remove(); + elemFile.value = ''; + var convert = forceConvert(res); + switch (convert.status) { + case 'CONVERTED': + res = convert.data; + break; + case 'FORMAT_ERROR': + return; + } + typeof options.done === 'function' && options.done(res, index || 0, function (files) { + that.upload(files); + }); + }; + + // 统一网络异常回调 + var error = function (index, res, xhr) { + if (options.auto) { + elemFile.value = ''; + } + var convert = forceConvert(res); + switch (convert.status) { + case 'CONVERTED': + res = convert.data; + break; + case 'FORMAT_ERROR': + return; + } + typeof options.error === 'function' && options.error(index || 0, function (files) { + that.upload(files); + }, res, xhr); + }; + var check; + var exts = options.exts; + var value = function () { + var arr = []; + layui.each(files || that.chooseFiles, function (i, item) { + arr.push(item.name); + }); + return arr; + }(); + + // 回调函数返回的参数 + var args = { + // 预览 + preview: function (callback) { + that.preview(callback); + }, + // 上传 + upload: function (index, file) { + var thisFile = {}; + thisFile[index] = file; + that.upload(thisFile); + }, + // 追加文件到队列 + pushFile: function () { + that.files = that.files || {}; + layui.each(that.chooseFiles, function (index, item) { + that.files[index] = item; + }); + return that.files; + }, + // 重置文件 + resetFile: function (index, file, filename) { + var newFile = new File([file], filename); + that.files = that.files || {}; + that.files[index] = newFile; + }, + // 获取本次选取的文件 + getChooseFiles: function () { + return that.chooseFiles; + } + }; + + // 提交上传 + var send = function () { + var ready = function () { + // IE 兼容处理 + if (device.ie) { + return device.ie > 9 ? ajaxSend() : iframeSend(); + } + ajaxSend(); + }; + // 上传前的回调 - 如果回调函数明确返回 false 或 Promise.reject,则停止上传 + if (typeof options.before === 'function') { + upload.util.promiseLikeResolve(options.before(args)).then(function (result) { + if (result !== false) { + ready(); + } else { + if (options.auto) { + elemFile.value = ''; + } + } + }, function (error) { + if (options.auto) { + elemFile.value = ''; + } + error !== undefined && hint.error(error); + }); + } else { + ready(); + } + }; + + // 文件类型名称 + var typeName = { + file: i18n.$t('upload.fileType.file'), + images: i18n.$t('upload.fileType.image'), + video: i18n.$t('upload.fileType.video'), + audio: i18n.$t('upload.fileType.audio') + }[options.accept] || i18n.$t('upload.fileType.file'); + + // 校验文件格式 + value = value.length === 0 ? elemFile.value.match(/[^/\\]+\..+/g) || [] || '' : value; + + // 若文件域值为空 + if (value.length === 0) return; + + // 根据文件类型校验 + switch (options.accept) { + case 'file': + // 一般文件 + layui.each(value, function (i, item) { + if (exts && !RegExp('.\\.(' + exts + ')$', 'i').test(escape(item))) { + return check = true; + } + }); + break; + case 'video': + // 视频文件 + layui.each(value, function (i, item) { + if (!RegExp('.\\.(' + (exts || 'avi|mp4|wma|rmvb|rm|flash|3gp|flv') + ')$', 'i').test(escape(item))) { + return check = true; + } + }); + break; + case 'audio': + // 音频文件 + layui.each(value, function (i, item) { + if (!RegExp('.\\.(' + (exts || 'mp3|wav|mid') + ')$', 'i').test(escape(item))) { + return check = true; + } + }); + break; + default: + // 图片文件 + layui.each(value, function (i, item) { + if (!RegExp('.\\.(' + (exts || 'jpg|png|gif|bmp|jpeg|svg|webp') + ')$', 'i').test(escape(item))) { + return check = true; + } + }); + break; + } + + // 校验失败提示 + if (check) { + that.msg(text['check-error'] || i18n.$t('upload.validateMessages.fileExtensionError', { + fileType: typeName + })); + return elemFile.value = ''; + } + + // 选择文件的回调 + if (type === 'choose' || options.auto) { + options.choose && options.choose(args); + if (type === 'choose') { + return; + } + } + + // 检验文件数量 + that.fileLength = function () { + var length = 0; + var items = getFiles(); + layui.each(items, function () { + length++; + }); + return length; + }(); + if (options.number && that.fileLength > options.number) { + return that.msg(typeof text['limit-number'] === 'function' ? text['limit-number'](options, that.fileLength) : i18n.$t('upload.validateMessages.filesOverLengthLimit', { + length: options.number + }) + '
                        ' + i18n.$t('upload.validateMessages.currentFilesLength', { + length: that.fileLength + })); + } + + // 检验文件大小 + if (options.size > 0 && !(device.ie && device.ie < 10)) { + var limitSize; + layui.each(getFiles(), function (index, file) { + if (file.size > 1024 * options.size) { + var size = options.size / 1024; + size = size >= 1 ? size.toFixed(2) + 'MB' : options.size + 'KB'; + elemFile.value = ''; + limitSize = size; + } + }); + if (limitSize) return that.msg(typeof text['limit-size'] === 'function' ? text['limit-size'](options, limitSize) : i18n.$t('upload.validateMessages.fileOverSizeLimit', { + size: limitSize + })); + } + send(); +}; + +//事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 设置当前选择的文件队列 + var setChooseFile = function (files) { + that.chooseFiles = {}; + layui.each(files, function (i, item) { + var time = new Date().getTime(); + that.chooseFiles[time + '-' + i] = item; + }); + }; + + // 设置选择的文本 + var setChooseText = function (files) { + var elemFile = that.elemFile; + // var item = options.item ? options.item : options.elem; + var value = files.length > 1 ? i18n.$t('upload.chooseText', { + length: files.length + }) : (files[0] || {}).name || elemFile[0].value.match(/[^/\\]+\..+/g) || [] || ''; + if (elemFile.next().hasClass(ELEM_CHOOSE)) { + elemFile.next().remove(); + } + that.upload(null, 'choose'); + if (that.isFile() || options.choose) return; + elemFile.after('' + value + ''); + }; + + /** + * 判断文件是否加入排队 + * @param {File} file + * @return {boolean} + */ + var checkFile = function (file) { + var result = true; + layui.each(that.files, function (index, item) { + result = !(item.name === file.name); + if (!result) return true; + }); + return result; + }; + + /** + * 扩展文件信息 + * @template {File | FileList} T + * @param {T} obj + * @return {T} + */ + var extendInfo = function (obj) { + var extInfo = function (file) { + //文件扩展名 + file.ext = file.name.substr(file.name.lastIndexOf('.') + 1).toLowerCase(); + // 文件大小 + file.sizes = upload.util.parseSize(file.size); + // 可以继续扩展 + }; + + //FileList对象 + if (obj instanceof FileList) { + layui.each(obj, function (index, item) { + extInfo(item); + }); + } else { + extInfo(obj); + } + return obj; + }; + + /** + * 检查获取文件 + * @param {FileList} files + * @return {Array|FileList} + */ + var getFiles = function (files) { + files = files || []; + if (!files.length) return []; + if (!that.files) return extendInfo(files); + var result = []; + layui.each(files, function (index, item) { + if (checkFile(item)) { + result.push(extendInfo(item)); + } + }); + return result; + }; + + // 点击上传容器 + options.elem.off('upload.start').on('upload.start', function () { + var othis = $(this); + that.config.item = othis; + that.elemFile[0].click(); + }); + + // 拖拽上传 + if (!(device.ie && device.ie < 10)) { + options.elem.off('upload.over').on('upload.over', function () { + var othis = $(this); + othis.attr('lay-over', ''); + }).off('upload.leave').on('upload.leave', function () { + var othis = $(this); + othis.removeAttr('lay-over'); + }).off('upload.drop').on('upload.drop', function (e, param) { + var othis = $(this); + var files = getFiles(param.originalEvent.dataTransfer.files); + othis.removeAttr('lay-over'); + setChooseFile(files); + options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传 + }); + } + + // 文件选择 + that.elemFile.on('change', function () { + var files = getFiles(this.files); + if (files.length === 0) return; + setChooseFile(files); + options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传 + }); + + // 手动触发上传 + options.bindAction.off('upload.action').on('upload.action', function () { + that.upload(); + }); + + // 防止事件重复绑定 + if (options.elem.data(MOD_INDEX)) return; + + // 目标元素 click 事件 + options.elem.on('click', function () { + if (that.isFile()) return; + $(this).trigger('upload.start'); + }); + + // 目标元素 drop 事件 + if (options.drag) { + options.elem.on('dragover', function (e) { + e.preventDefault(); + $(this).trigger('upload.over'); + }).on('dragleave', function () { + $(this).trigger('upload.leave'); + }).on('drop', function (e) { + e.preventDefault(); + $(this).trigger('upload.drop', e); + }); + } + + // 手动上传时触发上传的元素 click 事件 + options.bindAction.on('click', function () { + $(this).trigger('upload.action'); + }); + + // 绑定元素索引 + options.elem.data(MOD_INDEX, options.id); +}; + +/** + * 上传组件辅助方法 + */ +upload.util = { + /** + * 文件大小处理 + * @param {number | string} size -文件大小 + * @param {number} [precision] - 数值精度 + * @return {string} + */ + parseSize: function (size, precision) { + precision = precision || 2; + if (null == size || !size) { + return '0'; + } + var unitArr = ['Bytes', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb']; + var index; + var formatSize = typeof size === 'string' ? parseFloat(size) : size; + index = Math.floor(Math.log(formatSize) / Math.log(1024)); + size = formatSize / Math.pow(1024, index); + size = size % 1 === 0 ? size : parseFloat(size.toFixed(precision)); //保留的小数位数 + return size + unitArr[index]; + }, + /** + * 将给定的值转换为一个 JQueryDeferred 对象 + */ + promiseLikeResolve: function (value) { + var deferred = $.Deferred(); + if (value && typeof value.then === 'function') { + value.then(deferred.resolve, deferred.reject); + } else { + deferred.resolve(value); + } + return deferred.promise(); + } +}; + +// 记录所有实例 +thisModule.that = {}; // 记录所有实例对象 + +// 获取当前实例对象 +thisModule.getThis = function (id) { + var that = thisModule.that[id]; + if (!that) hint.error(id ? MOD_NAME + " instance with ID '" + id + "' not found" : 'ID argument required'); + return that; +}; + +// 核心入口 +upload.render = function (options) { + var inst = new Class(options); + return thisModule.call(inst); +}; + +export { upload }; diff --git a/dist/components/util.js b/dist/components/util.js new file mode 100644 index 000000000..a76533b1e --- /dev/null +++ b/dist/components/util.js @@ -0,0 +1,455 @@ +import { layui } from '../core/layui.js'; +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import $ from 'jquery'; + +/** + * util 工具组件 + */ + +var hint = layui.hint(); + +// 引用自 dayjs +// https://github.com/iamkun/dayjs/blob/v1.11.9/src/constant.js#L30 +var REGEX_FORMAT = /\[([^\]]+)]|y{1,4}|M{1,2}|d{1,2}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g; +var REGEX_PARSE = /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[T\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/i; + +// 外部接口 +var util = { + // 固定块 + fixbar: function (options) { + var ELEM = 'layui-fixbar'; + var $doc = $(document); + + // 默认可选项 + options = $.extend(true, { + target: 'body', + // fixbar 的插入目标选择器 + bars: [], + // bar 信息 + default: true, + // 是否显示默认 bar + margin: 160, + // 出现 top bar 的滚动条高度临界值 + duration: 320 // top bar 等动画时长(毫秒) + }, options); + + // 目标元素对象 + var $target = $(options.target); + + // 滚动条所在元素对象 + var $scroll = options.scroll ? $(options.scroll) : $(options.target === 'body' ? $doc : $target); + + // 是否提供默认图标 + if (options['default']) { + // 兼容旧版本的一些属性 + if (options.bar1) { + options.bars.push({ + type: 'bar1', + icon: 'layui-icon-chat' + }); + } + if (options.bar2) { + options.bars.push({ + type: 'bar2', + icon: 'layui-icon-help' + }); + } + // 默认 top bar + options.bars.push({ + type: 'top', + icon: 'layui-icon-top' + }); + } + var elem = $('
                          ').addClass(ELEM); + var elemTopBar; + + // 遍历生成 bars 节点 + layui.each(options.bars, function (i, item) { + var elemBar = $('
                        • '); + + // 设置 bar 相关属性 + elemBar.addClass(item.icon).attr({ + 'lay-type': item.type, + style: item.style || (options.bgcolor ? 'background-color: ' + options.bgcolor : '') + }).html(item.content); + + // bar 点击事件 + elemBar.on('click', function () { + var type = $(this).attr('lay-type'); + if (type === 'top') { + (options.target === 'body' ? $('html,body') : $scroll).animate({ + scrollTop: 0 + }, options.duration); + } + typeof options.click === 'function' && options.click.call(this, type); + }); + + // 自定义任意事件 + if (layui.type(options.on) === 'object') { + layui.each(options.on, function (eventName, callback) { + elemBar.on(eventName, function () { + var type = $(this).attr('lay-type'); + typeof callback === 'function' && callback.call(this, type); + }); + }); + } + + // 获得 top bar 节点 + if (item.type === 'top') { + elemBar.addClass('layui-fixbar-top'); + elemTopBar = elemBar; + } + elem.append(elemBar); // 插入 bar 节点 + }); + + // 若目标元素已存在 fixbar,则移除旧的节点 + $target.find('.' + ELEM).remove(); + + // 向目标元素插入 fixbar 节点 + typeof options.css === 'object' && elem.css(options.css); + $target.append(elem); + + // top bar 的显示隐藏 + if (elemTopBar) { + var lock; + var setTopBar = function setTopBar() { + var top = $scroll.scrollTop(); + if (top >= options.margin) { + lock || (elemTopBar.show(), lock = 1); + } else { + lock && (elemTopBar.hide(), lock = 0); + } + return setTopBar; + }(); + } + + // 根据 scrollbar 设置 fixbar 相关状态 + var timer; + $scroll.on('scroll', function () { + if (!setTopBar) return; + clearTimeout(timer); + timer = setTimeout(function () { + setTopBar(); + }, 100); + }); + }, + // 倒计时 + countdown: function (options) { + // var that = this; + + // 默认可选项 + options = $.extend(true, { + date: new Date(), + now: new Date() + }, options); + + // 兼容旧版参数 + var args = arguments; + if (args.length > 1) { + options.date = new Date(args[0]); + options.now = new Date(args[1]); + options.clock = args[2]; + } + + // 实例对象 + var inst = { + options: options, + clear: function () { + // 清除计时器 + clearTimeout(inst.timer); + }, + reload: function (opts) { + // 重置倒计时 + this.clear(); + $.extend(true, this.options, { + now: new Date() + }, opts); + count(); + } + }; + typeof options.ready === 'function' && options.ready(); + + // 计算倒计时 + var count = function fn() { + var date = new Date(options.date); + var now = new Date(options.now); + var countTime = function (time) { + return time > 0 ? time : 0; + }(date.getTime() - now.getTime()); + var result = { + d: Math.floor(countTime / (1000 * 60 * 60 * 24)), + // 天 + h: Math.floor(countTime / (1000 * 60 * 60)) % 24, + // 时 + m: Math.floor(countTime / (1000 * 60)) % 60, + // 分 + s: Math.floor(countTime / 1000) % 60 // 秒 + }; + var next = function () { + now.setTime(now.getTime() + 1000); + options.now = now; + count(); + }; + + // 兼容旧版返回值 + if (args.length > 1) result = [result.d, result.h, result.m, result.s]; + + // 计时 - 以秒间隔 + inst.timer = setTimeout(next, 1000); + typeof options.clock === 'function' && options.clock(result, inst); + + // 计时完成 + if (countTime <= 0) { + clearTimeout(inst.timer); + typeof options.done === 'function' && options.done(result, inst); + } + return fn; + }(); + return inst; + }, + // 某个时间在当前时间的多久前 + timeAgo: function (time, onlyDate) { + var that = this; + var arr = [[], []]; + var stamp = new Date().getTime() - new Date(time).getTime(); + + // 返回具体日期 + if (stamp > 1000 * 60 * 60 * 24 * 31) { + stamp = new Date(time); + arr[0][0] = that.digit(stamp.getFullYear(), 4); + arr[0][1] = that.digit(stamp.getMonth() + 1); + arr[0][2] = that.digit(stamp.getDate()); + + // 是否输出时间 + if (!onlyDate) { + arr[1][0] = that.digit(stamp.getHours()); + arr[1][1] = that.digit(stamp.getMinutes()); + arr[1][2] = that.digit(stamp.getSeconds()); + } + return arr[0].join('-') + ' ' + arr[1].join(':'); + } + + // 30 天以内,返回「多久前」 + if (stamp >= 1000 * 60 * 60 * 24) { + return i18n.$t('util.timeAgo.days', { + days: stamp / 1000 / 60 / 60 / 24 | 0 + }); + } else if (stamp >= 1000 * 60 * 60) { + return i18n.$t('util.timeAgo.hours', { + hours: stamp / 1000 / 60 / 60 | 0 + }); + } else if (stamp >= 1000 * 60 * 3) { + // 3 分钟以内为:刚刚 + return i18n.$t('util.timeAgo.minutes', { + minutes: stamp / 1000 / 60 | 0 + }); + } else if (stamp < 0) { + return i18n.$t('util.timeAgo.future'); + } else { + return i18n.$t('util.timeAgo.justNow'); + } + }, + // 数字前置补零 + digit: function (num, length) { + var str = ''; + num = String(num); + length = length || 2; + for (var i = num.length; i < length; i++) { + str += '0'; + } + return num < Math.pow(10, length) ? str + (num | 0) : num; + }, + // 转化为日期格式字符 + toDateString: function (time, format, options) { + // 若 null 或空字符,则返回空字符 + if (time === null || time === '') return ''; + var that = this; + var normalizeDate = function (date) { + if (typeof date === 'undefined') { + return new Date(); + } + if (!isNaN(date)) { + return new Date(typeof date === 'string' ? parseInt(date) : date); + } + if (typeof date === 'string' && !/Z$/i.test(date)) { + var d = date.match(REGEX_PARSE); + if (d) { + var m = d[2] - 1 || 0; + var ms = (d[7] || '0').substring(0, 3); + return new Date(d[1], m, d[3] || 1, d[4] || 0, d[5] || 0, d[6] || 0, ms); + } + } + return new Date(date); + }; + var date = normalizeDate(time); + if (!date.getDate()) return hint.error('Invalid millisecond for "util.toDateString(millisecond)"'), ''; + var years = date.getFullYear(); + var month = date.getMonth(); + var days = date.getDate(); + var hours = date.getHours(); + var minutes = date.getMinutes(); + var seconds = date.getSeconds(); + var milliseconds = date.getMilliseconds(); + var defaultMeridiem = i18n.$t('util.toDateString.meridiem'); + var meridiem = options && options.customMeridiem || defaultMeridiem; + var matches = { + yy: function () { + return String(years).slice(-2); + }, + yyyy: function () { + return that.digit(years, 4); + }, + M: function () { + return String(month + 1); + }, + MM: function () { + return that.digit(month + 1); + }, + d: function () { + return String(days); + }, + dd: function () { + return that.digit(days); + }, + H: function () { + return String(hours); + }, + HH: function () { + return that.digit(hours); + }, + h: function () { + return String(hours % 12 || 12); + }, + hh: function () { + return that.digit(hours % 12 || 12); + }, + A: function () { + return meridiem(hours, minutes); + }, + m: function () { + return String(minutes); + }, + mm: function () { + return that.digit(minutes); + }, + s: function () { + return String(seconds); + }, + ss: function () { + return that.digit(seconds); + }, + SSS: function () { + return that.digit(milliseconds, 3); + } + }; + format = format || 'yyyy-MM-dd HH:mm:ss'; + return format.replace(REGEX_FORMAT, function (match, $1) { + return $1 || matches[match] && matches[match]() || match; + }); + }, + // 转义 html + escape: lay.escape, + // 还原转义的 html + unescape: lay.unescape, + // 打开新窗口 + openWin: function (options) { + var win; + options = options || {}; + win = options.window || window.open(options.url || '', options.target, options.specs); + if (options.url) return; + win.document.open('text/html', 'replace'); + win.document.write(options.content || ''); + win.document.close(); + }, + // 让指定的元素保持在可视区域 + toVisibleArea: function (options) { + options = $.extend({ + margin: 160, + // 触发动作的边界值 + duration: 200, + // 动画持续毫秒数 + type: 'y' // 触发方向,x 水平、y 垂直 + }, options); + if (!options.scrollElem[0] || !options.thisElem[0]) return; + var scrollElem = options.scrollElem; // 滚动元素 + var thisElem = options.thisElem; // 目标元素 + var vertical = options.type === 'y'; // 是否垂直方向 + var SCROLL_NAME = vertical ? 'scrollTop' : 'scrollLeft'; // 滚动方法 + var OFFSET_NAME = vertical ? 'top' : 'left'; // 坐标方式 + var scrollValue = scrollElem[SCROLL_NAME](); // 当前滚动距离 + var size = scrollElem[vertical ? 'height' : 'width'](); // 滚动元素的尺寸 + var scrollOffset = scrollElem.offset()[OFFSET_NAME]; // 滚动元素所处位置 + var thisOffset = thisElem.offset()[OFFSET_NAME] - scrollOffset; // 目标元素当前的所在位置 + var obj = {}; + + // 边界满足条件 + if (thisOffset > size - options.margin || thisOffset < options.margin) { + obj[SCROLL_NAME] = thisOffset - size / 2 + scrollValue; + scrollElem.animate(obj, options.duration); + } + }, + /** + * 批量事件 + * @param {string} [attr="lay-on"] - 触发事件的元素属性名 + * @param {Object.} events - 事件集合 + * @param {Object} [options] - 参数的更多选项 + * @param {(string|HTMLElement|JQuery)} [options.elem="body"] - 触发事件的委托元素 + * @param {string} [options.trigger="click"] - 事件触发的方式 + * @returns {Object} 返回当前 events 参数设置的事件集合 + */ + on: function (attr, events, options) { + // 若参数一为 object 类型,则为事件集,且省略 attr + if (typeof attr === 'object') { + options = events || {}; + events = attr; + attr = options.attr || 'lay-on'; // 默认属性名 + } + + // 更多选项 + options = $.extend({ + elem: 'body', + trigger: 'click' + }, typeof options === 'object' ? options : { + trigger: options // 兼容旧版 + }); + var elem = options.elem = $(options.elem); + var attrSelector = '[' + attr + ']'; + var DATANAME = 'UTIL_ON_DATA'; // 缓存在委托元素上的 data-* 属性名 + + if (!elem[0]) return; // 若委托元素不存在 + + // 初始化 data 默认值,以委托元素为存储单元 + if (!elem.data(DATANAME)) { + elem.data(DATANAME, { + events: {} + }); + } + + // 读取 data 缓存 + var dataCache = elem.data(DATANAME); + + // 根据 attr 和 trigger 的组合作为 key + var key = attr + '_' + options.trigger; + + // 根据 key 记录事件集合 + events = dataCache.events[key] = $.extend(true, dataCache.events[key], events); + + // 清除事件委托,避免重复绑定 + var trigger = options.trigger + '.lay_util_on'; + elem.off(trigger, attrSelector); + + // 绑定事件委托 + elem.on(trigger, attrSelector, function (e) { + var othis = $(this); + var attrValue = othis.attr(attr); + typeof events[attrValue] === 'function' && events[attrValue].call(this, othis, e); + }); + return events; + } +}; + +// 兼容旧版 +util.event = util.on; + +export { util }; diff --git a/dist/core/component.js b/dist/core/component.js new file mode 100644 index 000000000..2720dd789 --- /dev/null +++ b/dist/core/component.js @@ -0,0 +1,249 @@ +import { layui } from './layui.js'; +import { lay } from './lay.js'; +import $ from 'jquery'; + +/** + * component + * Layui 2 组件构建器 + */ + + +// export +function component(settings) { + // 默认设置 + settings = $.extend(true, { + isDeepReload: false // 是否默认为深度重载 + }, settings); + + // 组件名 + var MOD_NAME = settings.name; + var MOD_ID = 'lay-' + MOD_NAME + '-id'; // 用于记录组件实例 id 的属性名 + + // 组件基础对外接口 + var component = { + config: {}, + // 全局配置项,一般通过 component.set() 设置 + + // 通用常量集,一般存放固定字符,如类名等 + CONST: $.extend(true, { + MOD_NAME: MOD_NAME, + MOD_ID: MOD_ID, + CLASS_THIS: 'layui-this', + CLASS_SHOW: 'layui-show', + CLASS_HIDE: 'layui-hide', + CLASS_HIDEV: 'layui-hide-v', + CLASS_DISABLED: 'layui-disabled', + CLASS_NONE: 'layui-none' + }, settings.CONST), + // 设置全局项 + set: function (options) { + var that = this; + $.extend(true, that.config, options); + return that; + }, + // 事件 + on: function (events, callback) { + return layui.onevent.call(this, MOD_NAME, events, callback); + } + }; + + // 操作当前实例 + var instance = function () { + var that = this; + var options = that.config; + var id = options.id; + + // 实例对象 + var inst = { + config: options, + id: id, + index: that.index, + // 重置实例 + reload: function (options) { + that.reload.call(that, options); + } + }; + + // 扩展实例对象的回调 + if (typeof settings.extendsInstance === 'function') { + $.extend(true, inst, settings.extendsInstance.call(that)); + } + + // 返回实例对象 + return inst; + }; + + // 构造器 + var Class = function (options) { + var that = this; + that.index = component.index = lay.autoIncrementer(MOD_NAME); + + // 扩展配置项:传入选项 -> 全局选项 -> 默认选项 = 当前选项 + that.config = $.extend(true, {}, that.config, component.config, options); + + // 初始化之前的回调 + if (typeof settings.beforeInit === 'function') { + settings.beforeInit.call(that, that.config); + } + + // 初始化 + that.init(); + }; + + // 默认配置 + Class.prototype.config = settings.config; + + // 重载实例 + Class.prototype.reload = function (options, type) { + var that = this; + that.config = $.extend(settings.isDeepReload, {}, that.config, options); + that.init(true, type); + }; + + // 初始化准备(若由事件触发渲染,则必经此步) + Class.prototype.init = function (rerender, type) { + var that = this; + var options = that.config; + var elem = $(options.elem); + + // 若 elem 非唯一,则拆分为多个实例 + if (elem.length > 1) { + layui.each(elem, function () { + component.render($.extend({}, options, { + elem: this + })); + }); + return that; + } + + // 合并 lay-options 属性上的配置信息 + var layOptions = lay.options(elem[0]); + if (rerender) { + // 若重载渲染,则重载传入的 options 配置优先 + options = that.config = $.extend(layOptions, options); + } else { + $.extend(options, layOptions); // 若首次渲染,则 lay-options 配置优先 + } + + // 若重复执行 render,则视为 reload 处理 + if (!rerender && elem.attr(MOD_ID)) { + var newThat = component.getInst(elem.attr(MOD_ID)); + if (!newThat) return; + return newThat.reload(options, type); + } + options.elem = $(options.elem); + + // 初始化 id 属性 - 优先取 options.id > 元素 id > 自增索引 + options.id = lay.hasOwn(options, 'id') ? options.id : elem.attr('id') || that.index; + + // 记录当前实例对象 + instance.that[options.id] = that; + + // 渲染之前的回调 + if (typeof settings.beforeRender === 'function') { + settings.beforeRender.call(that, options); + } + + // 渲染 + if (typeof that.render === 'function') { + component.cache.id[options.id] = null; // 记录所有实例 id,用于批量操作(如 resize) + elem.attr(MOD_ID, options.id); // 目标元素已渲染过的标记 + that.render(rerender); // 渲染核心 + } + + // 事件 + typeof that.events === 'function' && that.events(); + }; + + // 组件必传项 + Class.prototype.render = settings.render; // 渲染 + Class.prototype.events = settings.events; // 事件 + + /** + * 元素缓存操作 + * @param {string} key - 缓存键 + * @param {*} value - 缓存值 + * @param {boolean} remove - 是否删除缓存 + * @returns {*} - 若 value 未传,则返回缓存值 + */ + Class.prototype.cache = function (key, value, remove) { + var that = this; + var options = that.config; + var elem = options.elem; + var MOD_CACHE_NAME = MOD_ID + '-cache'; + if (!elem) return; + var cache = elem.data(MOD_CACHE_NAME) || {}; + + // value 未传则获取缓存值 + if (value === undefined) { + return cache[key]; + } + if (remove) { + delete cache[key]; // 删除缓存 + } else { + cache[key] = value; // 设置缓存 + } + elem.data(MOD_CACHE_NAME, cache); + }; + + // 清除缓存 + Class.prototype.removeCache = function (key) { + this.cache(key, null, true); + }; + + // 缓存所有实例对象 + instance.that = {}; + + // 获取指定的实例对象 + component.getInst = component.getThis = function (id) { + if (id === undefined) { + throw new Error('ID argument required'); + } + return instance.that[id]; + }; + + // 获取所有实例 + component.getAllInst = function () { + return instance.that; + }; + + // 移除指定的实例对象 + component.removeInst = function (id) { + delete instance.that[id]; + delete component.cache.id[id]; + }; + + // 组件缓存 + component.cache = { + id: {} + }; + + // 用于扩展原型 + component.Class = Class; + + /** + * 组件完整重载 + * @param {string} id - 实例 id + * @param {Object} options - 配置项 + * @returns + */ + component.reload = function (id, options) { + var that = component.getInst(id); + if (!that) return; + that.reload(options); + return instance.call(that); + }; + + /** + * 组件渲染 + * @param {Object} options - 配置项 + * @returns + */ + component.render = function (options) { + var inst = new Class(options); + return instance.call(inst); + }; + return component; +} + +export { component, component as componentBuilder }; diff --git a/dist/core/i18n.js b/dist/core/i18n.js new file mode 100644 index 000000000..936df8024 --- /dev/null +++ b/dist/core/i18n.js @@ -0,0 +1,342 @@ +import { layui } from './layui.js'; +import { lay } from './lay.js'; + +/** + * i18n + * 国际化 + */ + +var hint = layui.hint(); +// var MOD_NAME = 'i18n'; + +// 识别预先可能定义的指定全局对象 +var GLOBAL = window.LAYUI_GLOBAL || {}; + +// 简体中文 +var zhCN = { + code: { + copy: '复制代码', + copied: '已复制', + copyError: '复制失败', + maximize: '最大化显示', + restore: '还原显示', + preview: '在新窗口预览' + }, + colorpicker: { + clear: '清除', + confirm: '确定' + }, + dropdown: { + noData: '暂无数据' + }, + flow: { + loadMore: '加载更多', + noMore: '没有更多了' + }, + form: { + select: { + noData: '暂无数据', + noMatch: '无匹配数据', + placeholder: '请选择' + }, + validateMessages: { + required: '必填项不能为空', + phone: '手机号格式不正确', + email: '邮箱格式不正确', + url: '链接格式不正确', + number: '只能填写数字', + date: '日期格式不正确', + identity: '身份证号格式不正确' + }, + verifyErrorPromptTitle: '提示' + }, + laydate: { + months: ['1月', '2月', '3月', '4月', '5月', '6月', '7月', '8月', '9月', '10月', '11月', '12月'], + weeks: ['日', '一', '二', '三', '四', '五', '六'], + time: ['时', '分', '秒'], + literal: { + year: '年' + }, + selectDate: '选择日期', + selectTime: '选择时间', + startTime: '开始时间', + endTime: '结束时间', + tools: { + confirm: '确定', + clear: '清空', + now: '现在', + reset: '重置' + }, + rangeOrderPrompt: '结束时间不能早于开始时间\n请重新选择', + invalidDatePrompt: '不在有效日期或时间范围内\n', + formatErrorPrompt: '日期格式不合法\n必须遵循:\n{format}\n', + autoResetPrompt: '已自动重置', + preview: '当前选中的结果' + }, + layer: { + confirm: '确定', + cancel: '取消', + defaultTitle: '信息', + prompt: { + InputLengthPrompt: '最多输入 {length} 个字符' + }, + photos: { + noData: '没有图片', + tools: { + rotate: '旋转', + scaleX: '水平变换', + zoomIn: '放大', + zoomOut: '缩小', + reset: '还原', + close: '关闭' + }, + viewPicture: '查看原图', + urlError: { + prompt: '当前图片地址异常,\n是否继续查看下一张?', + confirm: '下一张', + cancel: '不看了' + } + } + }, + laypage: { + prev: '上一页', + next: '下一页', + first: '首页', + last: '尾页', + total: '共 {total} 条', + pagesize: '条/页', + goto: '到第', + page: '页', + confirm: '确定' + }, + table: { + sort: { + asc: '升序', + desc: '降序' + }, + noData: '暂无数据', + tools: { + filter: { + title: '筛选列' + }, + export: { + title: '导出', + noDataPrompt: '当前表格无数据', + compatPrompt: '导出功能不支持 IE,请用 Chrome 等高级浏览器导出', + csvText: '导出 CSV 文件' + }, + print: { + title: '打印', + noDataPrompt: '当前表格无数据' + } + }, + dataFormatError: '返回的数据不符合规范,正确的成功状态码应为:"{statusName}": {statusCode}', + xhrError: '请求异常,错误提示:{msg}' + }, + transfer: { + noData: '暂无数据', + noMatch: '无匹配数据', + title: ['列表一', '列表二'], + searchPlaceholder: '关键词搜索' + }, + tree: { + defaultNodeName: '未命名', + noData: '暂无数据', + deleteNodePrompt: '确认删除"{name}"节点吗?' + }, + upload: { + fileType: { + file: '文件', + image: '图片', + video: '视频', + audio: '音频' + }, + validateMessages: { + fileExtensionError: '选择的{fileType}中包含不支持的格式', + filesOverLengthLimit: '同时最多只能上传: {length} 个文件', + currentFilesLength: '当前已经选择了: {length} 个文件', + fileOverSizeLimit: '文件大小不能超过 {size}' + }, + chooseText: '{length} 个文件' + }, + util: { + timeAgo: { + days: '{days} 天前', + hours: '{hours} 小时前', + minutes: '{minutes} 分钟前', + future: '未来', + justNow: '刚刚' + }, + toDateString: { + // https://www.unicode.org/cldr/charts/47/supplemental/day_periods.html + meridiem: function (hours, minutes) { + var hm = hours * 100 + minutes; + if (hm < 500) { + return '凌晨'; + } else if (hm < 800) { + return '早上'; + } else if (hm < 1200) { + return '上午'; + } else if (hm < 1300) { + return '中午'; + } else if (hm < 1900) { + return '下午'; + } + return '晚上'; + } + } + } +}; + +// 默认配置 +var config = lay.extend({ + locale: 'zh-CN', + // 全局内置语言 + messages: { + // 全局国际化消息对象 + 'zh-CN': zhCN + } +}, GLOBAL.i18n); // 读取全局预设配置,确保打包后的版本初始调用时机 + +var OBJECT_REPLACE_REGEX = /\{(\w+)\}/g; + +/** + * 获取对象中指定路径的值,类似于 lodash 的 _.get 方法(简易版) + * @param {Record} obj - 要查找的对象 + * @param {string} path - 要查找的路径,支持类似 'a[0].b.c' 的格式 + * @param {any} defaultValue - 若未找到对应值时返回的默认值 + * @returns {any} - 找到的值或默认值 + */ +function get(obj, path, defaultValue) { + // 'a[0].b.c' ==> ['a', '0', 'b', 'c'] + var casePath = path.replace(/\[(\d+)\]/g, '.$1').split('.'); + var result = obj; + for (var i = 0; i < casePath.length; i++) { + result = result && result[casePath[i]]; + if (result === null || result === undefined) { + return defaultValue; + } + } + return result; +} + +/** + * 为纯函数创建具有缓存功能的版本,类似于 lodash 的 _.memoize 方法(简易版) + * @template T + * @param {(key: string, ...args) => T} fn - 需要缓存的函数,第一个参数为键 + * @returns {{(key: string, ...args): T, cleanup: () => void}} - 带有缓存的函数 + */ +function memoize(fn) { + /** @type Record */ + var cache = Object.create(null); + function cachedFn(key) { + var hit = cache[key]; + return hit || (cache[key] = fn.apply(cache, arguments)); + } + cachedFn.cleanup = function () { + cache = Object.create(null); + }; + return cachedFn; +} + +/** + * 对传入的值进行转义处理 + * 若值为字符串,直接进行转义;若为函数,对函数返回的字符串进行转义;若为数组,对数组中的字符串元素进行转义 + * @param {any} value - 需要进行转义处理的值 + * @returns {any} - 转义后的结果 + */ +function escape(value) { + if (typeof value === 'string') { + value = lay.escape(value); + } else if (typeof value === 'function') { + var origFn = value; + value = function () { + var val = origFn.apply(this, arguments); + return typeof val === 'string' ? lay.escape(val) : val; + }; + } else if (layui.type(value) === 'array') { + value = value.map(function (v) { + return typeof v === 'string' ? lay.escape(v) : v; + }); + } + return value; +} +function isDef(value) { + return value !== null && value !== undefined; +} +var resolveValue = memoize(function (path, obj, defaultValue) { + var pathParts = path.split(':'); + var locale = pathParts[0]; + path = pathParts[1]; + var value = get(obj, path, defaultValue); + if (layui.cache.debug) { + var isFallback = defaultValue === value || value === path; + var isNotFound = !isDef(value) || isFallback; + if (isNotFound) { + hint.errorOnce("Not found '" + path + "' key in '" + locale + "' locale messages.", 'warn'); + } + if (isFallback) { + hint.errorOnce("Fallback to default message for key: '" + path + "'", 'warn'); + } + } + return isDef(value) ? value : path; +}); +var i18n = { + config: config, + set: function (options) { + lay.extend(config, options); + resolveValue.cleanup(); + } +}; + +/** + * 根据给定的键从国际化消息中获取翻译后的内容 + * 未文档化的私有方法,仅限内部使用 + * + * @internal + * @param {string} keypath 要翻译的键路径 + * @param {Record | any[]} [parameters] 可选的占位符替换参数: + * - 对象形式:用于替换 `{key}` 形式的占位符; + * - 数组形式:用于替换 `{0}`, `{1}` 等占位符; + * @param {{locale: string, default: string}} [options] 翻译选项 + * @returns {string} 翻译后的文本 + * + * @example 使用对象替换命名占位符 + * message: { + * hello: '{msg} world' + * } + * i18n.$t('message.hello', { msg: 'Hello' }) + * + * @example 使用数组替换索引占位符 + * message: { + * hello: '{0} world' + * } + * i18n.$t('message.hello', ['Hello']) + */ +i18n.translation = function (keypath, parameters, options) { + var locale = options && options.locale || config.locale; + var i18nMessages = config.messages[locale]; + var namespace = locale + ':'; + var hasDefault = options && lay.hasOwn(options, 'default'); + var fallbackMessage = hasDefault ? options.default : undefined; + if (!i18nMessages && !hasDefault) { + hint.errorOnce("Locale '" + locale + "' not found. Please add i18n messages for this locale first.", 'warn'); + } + var result = resolveValue(namespace + keypath, i18nMessages, fallbackMessage); + + // 替换占位符 + if (typeof result === 'string' && parameters) { + // 第二个参数为对象或数组,替换占位符 {key} 或 {0}, {1}... + result = result.replace(OBJECT_REPLACE_REGEX, function (match, key) { + return parameters[key] !== undefined ? parameters[key] : match; + }); + } + return escape(result); +}; + +/** + * i18n.translation 的别名,用于简化代码书写,未文档化仅限内部使用 + */ +i18n.$t = i18n.translation; + +export { i18n }; diff --git a/dist/core/lay.js b/dist/core/lay.js new file mode 100644 index 000000000..1579bf525 --- /dev/null +++ b/dist/core/lay.js @@ -0,0 +1,1206 @@ +import { layui } from './layui.js'; + +/** + * lay + * 基础模块 + */ + +var document = window.document; + +/** + * 元素查找 + * @param {string | HTMLElement | JQuery} selector + */ +var lay = function (selector) { + return new Class(selector); +}; + +// 构造器 +var Class = function (selector) { + var that = this; + var elem = typeof selector === 'object' ? function () { + // 仅适配简单元素对象 + return layui.isArray(selector) ? selector : [selector]; + }() : (this.selector = selector, document.querySelectorAll(selector || null)); + lay.each(elem, function (index) { + that.push(elem[index]); + }); +}; +var fnToString = Function.prototype.toString; +var ObjectFunctionString = fnToString.call(Object); +var hasOwnProperty = Object.prototype.hasOwnProperty; + +/* + lay 对象操作 +*/ + +Class.fn = Class.prototype = []; +Class.fn.constructor = Class; + +/** + * 将一个或多个对象合并到目标对象中 + * 对象类型值始终进行「深拷贝」合并。若需浅拷贝合并,请使用 Object.assign() + * @param {*} target - 目标对象 + * @param {...*} objectN - 一个或多个包含要应用的属性的源对象 + * @param {Function} customizer - 可选的自定义合并函数 + * @returns {*} 返回合并后的对象 + * @example + *```js + * console.log(lay.extend({}, {a:1})); // expected: {a:1} + * console.log(lay.extend({a:1}, {a:3}, {a:5,b:5})); // expected: {a:5,b:5} + * // 多个相同源对象的不同合并方式 + * const objN = [ + * { + * a: [1, 3], + * b: {ba: 1} + * }, + * { + * a: [5], + * b: {bb: 2} + * }, + * { + * b: {ba: 3}, + * c: 3 + * } + * ]; + * console.log(lay.extend({}, ...objN)); // expected: {a:[5,3],b:{ba:3,bb:2},c:3} + * // 使用 customizer 实现数组覆盖而非合并 + * const obj1 = lay.extend({}, ...objN, function(objValue, srcValue) { + * if (Array.isArray(objValue) && Array.isArray(srcValue)) { + * return srcValue; + * } + * }); + * console.log(obj1); // expected: {a:[5],b:{ba:3,bb:2},c:3} + * // 使用 customizer 实现特定字段跳过合并 + * const obj2 = lay.extend({}, ...objN, function(objValue, srcValue, key, target, source) { + * if (key === 'b') { + * return objValue; + * } + * }); + * console.log(obj2); // expected: {a:[5,3],b:{ba:1},c:3} + * ``` + */ +lay.extend = function () { + var args = [].slice.call(arguments); + + // 最后一个参数是否为 customizer + var customizer = typeof args[args.length - 1] === 'function' ? args.pop() : false; + + // 深拷贝合并 + return args.reduce(function (target, source) { + // 确保 target 始终是一个对象 + if (typeof target !== 'object' || target === null) { + target = {}; + } + for (var key in source) { + if (!hasOwnProperty.call(source, key)) continue; // 仅处理自有属性 + + var targetValue = target[key]; + var sourceValue = source[key]; + + // 自定义合并逻辑(如数组覆盖、特定字段跳过等) + if (customizer) { + var customResult = customizer(targetValue, sourceValue, key, target, source); + if (customResult !== undefined) { + target[key] = customResult; + continue; + } + } + + // 默认深拷贝逻辑 + if (Array.isArray(sourceValue)) { + targetValue = Array.isArray(targetValue) ? targetValue : []; + } else if (lay.isPlainObject(sourceValue)) { + targetValue = lay.isPlainObject(targetValue) ? targetValue : {}; + } + target[key] = lay.isPlainObject(sourceValue) || Array.isArray(sourceValue) ? lay.extend(targetValue, sourceValue, customizer) : sourceValue; + } + return target; + }); +}; + +/** + * 判断是否为纯对象 + * @param {*} obj - 要检查的对象 + * @returns {boolean} + */ +lay.isPlainObject = function (obj) { + if (obj === null || typeof obj !== 'object' || Object.prototype.toString.call(obj) !== '[object Object]') { + return false; + } + var proto = Object.getPrototypeOf(obj); + + // Object.create(null) 创建的对象 + if (proto === null) { + return true; + } + + // 判定具有原型且由全局 Object 构造函数创建的对象为纯对象(来自 jQuery 方案) + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor === 'function' && fnToString.call(Ctor) === ObjectFunctionString; +}; + +/** + * IE 版本 + * @type {string | boolean} - 如果是 IE 返回版本字符串,否则返回 false + */ +lay.ie = function () { + var agent = navigator.userAgent.toLowerCase(); + return !!window.ActiveXObject || 'ActiveXObject' in window ? (agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识 + : false; +}(); + +/** + * 获取 layui 常见方法,以便用于组件单独版 + */ + +lay.layui = layui || {}; +lay.getPath = layui.cache.dir; // 获取当前 JS 所在目录 +lay.stope = layui.stope; // 中止冒泡 +lay.each = function () { + // 遍历 + layui.each.apply(layui, arguments); + return this; +}; + +/** + * 数字前置补零 + * @param {number | string} num - 原始数字 + * @param {number} [length=2] - 数字长度,如果原始数字长度小于 length,则前面补零 + * @returns {string} 返回补 0 后的数字 + * @example + * ```js + * lay.digit(6, 2); // "06" + * lay.digit('7', 3); // "007" + * ``` + */ +lay.digit = function (num, length) { + if (!(typeof num === 'string' || typeof num === 'number')) return ''; + var str = ''; + num = String(num); + length = length || 2; + for (var i = num.length; i < length; i++) { + str += '0'; + } + return num < Math.pow(10, length) ? str + num : num; +}; + +/** + * 创建元素 + * @param {string} elemName - 元素的标签名 + * @param {Object.} [attr] - 添加到元素上的属性 + * @returns {HTMLElement} 返回创建的 HTML 元素 + * @example + * ```js + * lay.elem('div', {id: 'test'}) //
                          + * ``` + */ +lay.elem = function (elemName, attr) { + var elem = document.createElement(elemName); + lay.each(attr || {}, function (key, value) { + elem.setAttribute(key, value); + }); + return elem; +}; + +/** + * 当前页面是否存在滚动条 + * @returns {boolean} 是否存在滚动条 + * @example + * ``` + * lay.hasScrollbar() // true 或 false + * ``` + */ +lay.hasScrollbar = function () { + return document.body.scrollHeight > (window.innerHeight || document.documentElement.clientHeight); +}; + +/** + * 自动递增器,一般用于组件自增索引 + */ +lay.autoIncrementer = function (key, opts = {}) { + const { + target = document.body + } = opts; + const name = '_LAY_AUTOINCREMENTER_ID_'; + const incrementer = target[name] = target[name] || {}; + incrementer[key] = incrementer[key] || 0; + return ++incrementer[key]; +}; + +/** + * 获取 style rules + * @param {HTMLStyleElement} style - HTMLStyle 元素 + * @param {(ruleItem: CSSStyleRule, index: number) => boolean} [callback] - 用来返回 style 元素中的每个 `style rule` 的函数,返回 true 终止遍历 + * @returns {CSSRuleList} 返回 `style rules` + * @example + * ``` + * + * + * lay.getStyleRules($('#test')[0], function(rule, index){ + * if(rule.selectorText === '.lay-card'){ + * console.log(index, rule.cssText) // 0 '.lay-card{color: #000}' + * rule.style.color = '#EEE'; + * return true; // 终止遍历 + * } + * }) // RuleList + * ``` + */ +lay.getStyleRules = function (style, callback) { + if (!style) return; + var sheet = style.sheet || style.styleSheet || {}; + var rules = sheet.cssRules || sheet.rules; + if (typeof callback === 'function') { + layui.each(rules, function (i, item) { + if (callback(item, i)) return true; + }); + } + return rules; +}; + +/** + * 创建 style 样式 + * @param {Object} options - 可配置的选项 + * @param {string | HTMLElement | JQuery} [options.target] - 目标容器,指定后会将样式追加到目标容器 + * @param {string} [options.id] - 样式元素的 id,默认自增 + * @param {string} options.text - 样式内容 + * @returns {HTMLStyleElement} 返回创建的样式元素 + * @example + * ```html + *
                          + * + * + *
                          + * + * lay.style({ + * target: '#targetEl', + * text: '.card{color: #000}' + * }) // + * ``` + */ +lay.style = function (options) { + options = options || {}; + var style = lay.elem('style'); + var styleText = options.text || ''; + var target = options.target; + if (!styleText) return; + + // 添加样式 + if ('styleSheet' in style) { + style.setAttribute('type', 'text/css'); + style.styleSheet.cssText = styleText; + } else { + style.innerHTML = styleText; + } + + // ID + style.id = 'LAY-STYLE-' + (options.id || function (index) { + lay.style.index++; + return 'DF-' + index; + }(lay.style.index || 0)); + + // 是否向目标容器中追加 style 元素 + if (target) { + var styleElem = lay(target).find('#' + style.id); + styleElem[0] && styleElem.remove(); + lay(target).append(style); + } + return style; +}; + +/** + * 将元素定位到指定目标元素附近 + * @param {HTMLElement} target - 目标元素 + * @param {HTMLElement} elem - 定位元素 + * @param {Object} [opts] - 可配置的选项 + * @param {'absolute' | 'fixed'} [opts.position] - 元素的定位类型 + * @param {'left' | 'right'} [opts.clickType="left"] - 点击类型,默认为 'left',如果 {@link target} 是 document 或 body 元素,则为 'right' + * @param {'left' | 'right' | 'center'} [opts.align="left"] - 对齐方式 + * @param {boolean} [opts.allowBottomOut=false] - 顶部没有足够区域显示时,是否允许底部溢出 + * @param {string | number} [opts.margin=5] - 边距 + * @param {Event} [opts.e] - 事件对象,仅右键生效 + * @param {boolean} [opts.SYSTEM_RELOAD] - 是否重载,用于出现滚动条时重新计算位置 + * @param {[offsetX:number, offsetY:number]} [opts.offset] - 相对于触发元素的额外偏移量[x,y] + * @example + * ```js + * + * + * + * // 下拉菜单将被定位到按钮附近 + * lay.position( + * $('#targetEl')[0], + * $('#contentEl')[0], + * { + * position: 'fixed', + * align: 'center' + * } + * ) + * ``` + */ +lay.position = function (target, elem, opts) { + if (!elem) return; + opts = opts || {}; + + // 如果绑定的是 document 或 body 元素,则直接获取鼠标坐标 + if (target === document || target === lay('body')[0]) { + opts.clickType = 'right'; + } + + // 绑定绑定元素的坐标 + var rect = opts.clickType === 'right' ? function () { + var e = opts.e || window.event || {}; + return { + left: e.clientX, + top: e.clientY, + right: e.clientX, + bottom: e.clientY + }; + }() : target.getBoundingClientRect(); + var elemWidth = elem.offsetWidth; // 控件的宽度 + var elemHeight = elem.offsetHeight; // 控件的高度 + + // 滚动条高度 + var scrollArea = function (type) { + type = type ? 'scrollLeft' : 'scrollTop'; + return document.body[type] | document.documentElement[type]; + }; + + // 窗口宽高 + var winArea = function (type) { + return document.documentElement[type ? 'clientWidth' : 'clientHeight']; + }; + var margin = 'margin' in opts ? opts.margin : 5; + var left = rect.left; + var top = rect.bottom; + + // 相对元素居中 + if (opts.align === 'center') { + left = left - (elemWidth - target.offsetWidth) / 2; + } else if (opts.align === 'right') { + left = left - elemWidth + target.offsetWidth; + } + + // 判断右侧是否超出边界 + if (left + elemWidth + margin > winArea('width')) { + left = winArea('width') - elemWidth - margin; // 如果超出右侧,则将面板向右靠齐 + } + // 左侧是否超出边界 + if (left < margin) left = margin; + + // 判断底部和顶部是否超出边界 + if (rect.bottom + elemHeight + margin > winArea()) { + // 底部超出边界 + // 优先判断顶部是否有足够区域显示完全,且底部不能超出边界 + if (rect.top > elemHeight + margin && rect.top <= winArea()) { + top = rect.top - elemHeight - margin * 2; // 顶部有足够的区域显示 + } else if (!opts.allowBottomOut) { + // 顶部没有足够区域显示时,是否允许底部溢出 + top = winArea() - elemHeight - margin * 2; // 面板向底部靠齐 + if (top < 0) top = 0; // 如果面板底部靠齐时,又溢出窗口顶部,则只能将顶部靠齐 + } + } + /* + if(top + elemHeight + margin > winArea()){ + // 优先顶部是否有足够区域显示完全 + if(rect.top > elemHeight + margin){ + top = rect.top - elemHeight - margin*2; // 顶部有足够的区域显示 + } else { + // 如果面板是鼠标右键弹出,且顶部没有足够区域显示,则将面板向底部靠齐 + if(obj.clickType === 'right'){ + top = winArea() - elemHeight - margin*2; + if(top < 0) top = 0; // 不能溢出窗口顶部 + } else { + top = margin; // 位置计算逻辑完备性处理 + } + } + } + */ + + // 定位类型 + var position = opts.position; + if (position) elem.style.position = position; + var offsetX = opts.offset ? opts.offset[0] : 0; + var offsetY = opts.offset ? opts.offset[1] : 0; + + // 设置坐标 + elem.style.left = left + (position === 'fixed' ? 0 : scrollArea(1)) + offsetX + 'px'; + elem.style.top = top + (position === 'fixed' ? 0 : scrollArea()) + offsetY + 'px'; + + // 防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差 + if (!lay.hasScrollbar()) { + var rect1 = elem.getBoundingClientRect(); + // 如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标 + if (!opts.SYSTEM_RELOAD && rect1.bottom + margin > winArea()) { + opts.SYSTEM_RELOAD = true; + setTimeout(function () { + lay.position(target, elem, opts); + }, 50); + } + } +}; + +/** + * 获取元素上的属性配置项 + * @param {string | HTMLElement | JQuery} elem - HTML 元素 + * @param {{attr: string} | string} [opts="lay-options"] - 可配置的选项,string 类型指定属性名 + * @returns {Object.} 返回元素上的属性配置项 + * @example + * ```js + *
                          + * + * var elem = $('#testEl') + * lay.options(elem) // {color:red} + * lay.options(elem[0]) // {color:red} + * lay.options('#testEl') // {color:red} + * lay.options('#testEl', {attr: 'lay-toc'}) // {hot: true} + * lay.options('#testEl', 'lay-toc') // {hot: true} + * + * $('#testEl').attr('lay-toc') // '{hot: true}' + * ``` + */ +lay.options = function (elem, opts) { + opts = typeof opts === 'object' ? opts : { + attr: opts + }; + if (elem === document) return {}; + var othis = lay(elem); + var attrName = opts.attr || 'lay-options'; + var attrValue = othis.attr(attrName); + try { + /** + * 请注意: 开发者在使用 lay-options="{}" 配置组件选项时,需确保属性值不来自于网页用户, + * 即属性值必须在网页开发者自身的可控范围内,否则请勿在 HTML 标签属性中获取组件选项。 + */ + return new Function('return ' + (attrValue || '{}'))(); + } catch (ev) { + layui.hint().error(opts.errorText || [attrName + '="' + attrValue + '"', '\n parseerror: ' + ev].join('\n'), 'error'); + return {}; + } +}; + +/** + * 元素是否属于顶级元素(document 或 body) + * @param {HTMLElement} elem - HTML 元素 + * @returns {boolean} 是否属于顶级元素 + * @example + * ```js + * lay.isTopElem(document) // true + * ``` + */ +lay.isTopElem = function (elem) { + var topElems = [document, lay('body')[0]], + matched = false; + lay.each(topElems, function (index, item) { + if (item === elem) { + return matched = true; + } + }); + return matched; +}; + +// 剪切板 +lay.clipboard = { + /** + * 写入文本 + * @param {Object} options - 可配置的选项 + * @param {string} options.text - 写入剪贴板的文本 + * @param {() => void} [options.done] - 写入成功/完成回调 + * @param {(err?: any) => void} [options.error] - 写入失败回调 + * @example + * ```js + * lay.clipboard.writeText({ + * text: '测试文本', + * done: function(){ layer.msg('copied')}, + * error: function(){ layer.msg('error')} + * }) + * ``` + */ + writeText: function (options) { + var text = String(options.text); + if (navigator && 'clipboard' in navigator) { + navigator.clipboard.writeText(text).then(options.done, function () { + legacyCopy(); + }); + } else { + legacyCopy(); + } + function legacyCopy() { + var elem = document.createElement('textarea'); + elem.value = text; + elem.style.position = 'fixed'; + elem.style.opacity = '0'; + elem.style.top = '0px'; + elem.style.left = '0px'; + document.body.appendChild(elem); + elem.select(); + try { + document.execCommand('copy'); + typeof options.done === 'function' && options.done(); + } catch (err) { + typeof options.error === 'function' && options.error(err); + } finally { + elem.remove ? elem.remove() : document.body.removeChild(elem); + } + } + } +}; + +/** + * 检测是否支持 Passive Event Listeners + * 引用自 https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + * @type {boolean} + */ +lay.passiveSupported = function () { + var passiveSupported = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { + passiveSupported = true; + return passiveSupported; + } + }); + window.addEventListener('test', null, opts); + window.removeEventListener('test', null, opts); + } catch { + // ignore + } + return passiveSupported; +}(); + +/** + * 是否支持 touch 事件 + */ +lay.touchEventsSupported = function () { + return 'ontouchstart' in window; +}; + +/** + * @typedef touchSwipeState + * @prop {{x: number,y: number}} pointerStart - 初始坐标 + * @prop {{x: number,y: number}} pointerEnd - 结束坐标 + * @prop {number} distanceX - X 轴移动距离 + * @prop {number} distanceY - Y 轴移动距离 + * @prop {'none'|'right'|'left'|'up'|'down'} direction - 滑动方向 + * @prop {Date} timeStart 开始时间 + */ +/** + * @callback touchSwipeCallback + * @param {TouchEvent} e 滑动事件 + * @param {touchSwipeState} state 滑动相关的状态 + */ +/** + * 基于 touch 事件的触摸滑动 + * @param {string | HTMLElement | JQuery} elem - HTML 元素 + * @param {{onTouchStart?: touchSwipeCallback; onTouchMove?: touchSwipeCallback; onTouchEnd?: touchSwipeCallback; preventDefault?: boolean}} opts - 配置项 + */ +lay.touchSwipe = function (elem, opts) { + var options = opts; + var targetElem = lay(elem)[0]; + var preventDefault = 'preventDefault' in options ? options.preventDefault : true; + if (!targetElem || !lay.touchEventsSupported()) return; + var state = { + pointerStart: { + x: 0, + y: 0 + }, + pointerEnd: { + x: 0, + y: 0 + }, + distanceX: 0, + distanceY: 0, + direction: 'none', + // 'up','down','left','right','none + timeStart: null + }; + var onStart = function (e) { + if (e.touches.length !== 1) return; + bindEvents(); + // 重置状态 + state.timeStart = Date.now(); + state.pointerStart.x = state.pointerEnd.x = e.touches[0].clientX; + state.pointerStart.y = state.pointerEnd.y = e.touches[0].clientY; + state.distanceX = state.distanceY = 0; + state.direction = 'none'; + options.onTouchStart && options.onTouchStart(e, state); + }; + var onMove = function (e) { + if (preventDefault) { + e.preventDefault(); + } + state.pointerEnd.x = e.touches[0].clientX; + state.pointerEnd.y = e.touches[0].clientY; + state.distanceX = state.pointerStart.x - state.pointerEnd.x; + state.distanceY = state.pointerStart.y - state.pointerEnd.y; + if (Math.abs(state.distanceX) > Math.abs(state.distanceY)) { + state.direction = state.distanceX > 0 ? 'left' : 'right'; + } else { + state.direction = state.distanceY > 0 ? 'up' : 'down'; + } + options.onTouchMove && options.onTouchMove(e, state); + }; + var onEnd = function (e) { + options.onTouchEnd && options.onTouchEnd(e, state); + unbindEvents(); + }; + var bindEvents = function () { + targetElem.addEventListener('touchmove', onMove, lay.passiveSupported ? { + passive: false + } : false); + targetElem.addEventListener('touchend', onEnd); + targetElem.addEventListener('touchcancel', onEnd); + }; + var unbindEvents = function () { + targetElem.removeEventListener('touchmove', onMove); + targetElem.removeEventListener('touchend', onEnd, lay.passiveSupported ? { + passive: false + } : false); + targetElem.removeEventListener('touchcancel', onEnd); + }; + + // 防止事件重复绑定 + if (targetElem.__lay_touchswipe_cb_) { + targetElem.removeEventListener('touchstart', targetElem.__lay_touchswipe_cb_); + } + targetElem.__lay_touchswipe_cb_ = onStart; + targetElem.addEventListener('touchstart', onStart); +}; + +/** @type {(elem: Element|Document|Window,eventName: string,fn:EventListenerOrEventListenerObject,options: boolean | AddEventListenerOptions) => any}*/ +lay.addEvent = function () { + if (document.addEventListener) { + return function (elem, eventName, fn, options) { + elem.addEventListener(eventName, fn, options); + }; + } else { + return function (elem, eventName, fn) { + var prefix = '_lay_on_'; + var eventsCacheName = prefix + eventName; + var listener = function (e) { + e.target = e.srcElement; + fn.call(elem, e); + }; + listener._rawFn = fn; + if (!elem[eventsCacheName]) { + elem[eventsCacheName] = []; + } + var include = false; + lay.each(elem[eventsCacheName], function (_, listener) { + if (listener._rawFn === fn) { + include = true; + return true; + } + }); + if (!include) { + elem[eventsCacheName].push(listener); + elem.attachEvent('on' + eventName, listener); + } + }; + } +}(); + +/** @type {(elem: Element|Document|Window,eventName: string,fn:EventListenerOrEventListenerObject,options: boolean | EventListenerOptions) => any}*/ +lay.removeEvent = function () { + if (document.removeEventListener) { + return function (elem, eventName, fn, options) { + elem.removeEventListener(eventName, fn, options); + }; + } else { + return function (elem, eventName, fn) { + var prefix = '_lay_on_'; + var eventsCacheName = prefix + eventName; + var events = elem[eventsCacheName]; + if (layui.isArray(events)) { + var newEvents = []; + lay.each(events, function (_, listener) { + if (listener._rawFn === fn) { + elem.detachEvent('on' + eventName, listener); + } else { + newEvents.push(listener); + } + }); + elem[eventsCacheName] = newEvents; + } + }; + } +}(); + +/** + * 绑定指定元素外部的点击事件 + * @param {HTMLElement} target - 响应事件的元素 + * @param {(e: Event) => void} handler - 事件触发时执行的函数 + * @param {object} [options] - 选项 + * @param {string} [options.event="pointerdown"] - 事件类型 + * @param {HTMLElement | Window} [options.scope=document] - 事件范围 + * @param {Array} [options.ignore] - 忽略触发事件的元素或选择器字符串 + * @param {boolean} [options.capture=true] - 对内部事件 listener 使用捕获阶段 + * @param {boolean} [options.detectIframe] - 是否检测 iframe + * @returns {() => void} - 返回一个停止事件响应的函数 + */ +lay.onClickOutside = function (target, handler, options) { + options = options || {}; + var eventType = options.event || ('onpointerdown' in window ? 'pointerdown' : 'mousedown'); + var scopeTarget = options.scope || document; + var ignore = options.ignore || []; + var useCapture = 'capture' in options ? options.capture : true; + var detectIframe = options.detectIframe; + var listener = function (event) { + var el = target; + var eventTarget = event.target || event.srcElement; + var eventPath = getEventPath(event); + if (!el || el === eventTarget || eventPath.indexOf(el) !== -1) { + return; + } + if (shouldIgnore(event, eventPath)) { + return; + } + handler(event); + }; + function shouldIgnore(event, eventPath) { + var eventTarget = event.target || event.srcElement; + for (var i = 0; i < ignore.length; i++) { + var target = ignore[i]; + if (typeof target === 'string') { + var targetElements = document.querySelectorAll(target); + for (var j = 0; j < targetElements.length; j++) { + var targetEl = targetElements[i]; + if (targetEl === eventTarget || eventPath.indexOf(targetEl) !== -1) { + return true; + } + } + } else { + if (target && (target === eventTarget || eventPath.indexOf(target) !== -1)) { + return true; + } + } + } + } + function getEventPath(event) { + var path = event.composedPath && event.composedPath() || event.path; + var eventTarget = event.target || event.srcElement; + if (path !== null && path !== undefined) { + return path; + } + function getParents(node, memo) { + memo = memo || []; + var parentNode = node.parentNode; + return parentNode ? getParents(parentNode, memo.concat([parentNode])) : memo; + } + return [eventTarget].concat(getParents(eventTarget)); + } + function bindEventListener(elem, eventName, handler, opts) { + elem.addEventListener ? elem.addEventListener(eventName, handler, opts) : elem.attachEvent('on' + eventName, handler); + return function () { + elem.removeEventListener ? elem.removeEventListener(eventName, handler, opts) : elem.detachEvent('on' + eventName, handler); + }; + } + var cleanup = [bindEventListener(scopeTarget, eventType, listener, lay.passiveSupported ? { + passive: true, + capture: useCapture + } : useCapture), detectIframe && bindEventListener(window, 'blur', function (event) { + setTimeout(function () { + if (document.activeElement && document.activeElement.tagName === 'IFRAME' && target.contains && !target.contains(document.activeElement)) { + handler(event); + } + }, 0); + })]; + return function () { + for (var i = 0; i < cleanup.length; i++) { + cleanup[i] && cleanup[i](); + } + cleanup = null; + }; +}; + +/** + * 检查对象是否具有指定的属性 + * @param {Record} obj 要检查的对象 + * @param {string} prop 要检查的属性名 + * @returns {boolean} 如果对象具有指定的属性,则为 true;否则为 false + */ +lay.hasOwn = function (obj, prop) { + return hasOwnProperty.call(obj, prop); +}; + +/** + * 转义 HTML 字符串中的特殊字符 + * @param {string} html 要转义的 HTML 字符串 + * @returns {string} 转义后的 HTML 字符串 + */ +lay.escape = function (html) { + var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g; + if (html === undefined || html === null) return ''; + html += ''; + if (!exp.test(html)) return html; + return html.replace(/&(?=#?[a-zA-Z0-9]+;?)/g, '&').replace(//g, '>').replace(/'/g, ''').replace(/"/g, '"'); +}; + +/** + * 还原转义的 HTML 字符串中的特殊字符 + * @param {string} html 要还原转义的 HTML 字符串 + * @returns {string} 还原转义后的 HTML 字符串 + */ +lay.unescape = function (html) { + if (html === undefined || html === null) return ''; + return String(html).replace(/"/g, '"').replace(/'/g, "'").replace(/>/g, '>').replace(/</g, '<').replace(/&/g, '&'); +}; + +/** + * 生成唯一的 ID 字符串 + * @param {string} prefix ID 前缀,默认为'id' + * @returns {string} 唯一 ID 字符串 + */ +var generateUniqueId = function () { + var counter = 0; + var lastTimestamp = null; + return function (prefix) { + prefix = prefix || 'id'; + var timestamp = new Date().getTime(); + + // 如果时间戳与上一次相同,增加计数器 + // 否则重置计数器 + if (timestamp === lastTimestamp) { + counter++; + } else { + counter = 0; + lastTimestamp = timestamp; + } + + // 结合时间戳、随机数和计数器生成 ID + var random = Math.floor(Math.random() * 10000); + return prefix + '-' + timestamp + '-' + random + '-' + counter; + }; +}(); + +/** + * 创建共享的 ResizeObserver 实例 + * @param {string} namespace 命名空间,用于区分不同的 ResizeObserver 实例 + * @returns {ResizeObserver | null} ResizeObserver 实例或 null(如果不支持) + */ +lay.createSharedResizeObserver = function (namespace) { + if (typeof window.ResizeObserver === 'undefined') { + console.warn('ResizeObserver is not supported in this browser.'); + return null; + } + namespace = namespace || ''; + var ATTR_NAME = 'lay-' + namespace + '-resizeobserver-key'; + var handlerCache = {}; + var o = new ResizeObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var attrValue = entries[i].target.getAttribute(ATTR_NAME); + if (attrValue) { + var callback = handlerCache[attrValue]; + if (typeof callback === 'function') { + callback(entries[i]); + } + } + } + }); + return Object.freeze({ + observe: function (element, callback) { + if (!element || !(element instanceof Element)) { + console.warn('createSharedResizeObserver: Cannot observe non-Element.'); + return; + } + var attrValue = element.getAttribute(ATTR_NAME); + if (!attrValue) { + attrValue = generateUniqueId(namespace); + element.setAttribute(ATTR_NAME, attrValue); + } + + // 使用同一个观察者实例多次观察同一个元素,不会重复添加 + handlerCache[attrValue] = callback; + o.observe(element); + }, + unobserve: function (element) { + if (!element || !(element instanceof Element)) { + console.warn('createSharedResizeObserver: Cannot unobserve non-Element.'); + return; + } + var attrValue = element.getAttribute(ATTR_NAME); + if (!attrValue) { + return; + } + + // 清除相关回调 + if (handlerCache[attrValue]) { + delete handlerCache[attrValue]; + } + element.removeAttribute(ATTR_NAME); + o.unobserve(element); + }, + disconnect: function () { + for (var key in handlerCache) { + if (lay.hasOwn(handlerCache, key)) { + delete handlerCache[key]; + var elem = document.querySelector('[' + ATTR_NAME + '="' + key + '"]'); + if (elem) { + elem.removeAttribute(ATTR_NAME); + } + } + } + o.disconnect(); + } + }); +}; + +/** + * 树状数据转平铺 + * @param {Object[]} data - 树状数据 + * @param {Object} options - 可选项 + * @param {string} [options.childrenKey='children'] - 子节点字段名 + * @param {string} [options.idKey='id'] - 节点 id 字段名 + * @param {string} [options.parentKey='parentId'] - 父节点 id 字段名 + * @param {boolean} [options.keepChildren=true] - 是否保留子节点数据 + * @returns {Object[]} 返回平铺数据 + */ +lay.treeToFlat = function (data, options) { + options = Object.assign({ + childrenKey: 'children', + idKey: 'id', + parentKey: 'parentId', + keepChildren: true + }, options); + + // 展平 + var toFlat = function (initData, nodes, parentId) { + return nodes.reduce(function (acc, currNode) { + var children = currNode[options.childrenKey]; + if (!options.keepChildren) { + delete currNode[options.childrenKey]; + } + currNode[options.parentKey] = parentId; // 设置父节点 id + acc.push(currNode); + + // 递归子节点 + if (children && children.length) { + return toFlat(acc, children, currNode[options.idKey]); + } + return acc; + }, initData); + }; + return toFlat([], JSON.parse(JSON.stringify(data)), null); +}; + +/** + * 平铺数据转树状 + * @param {Array} data - 平铺数据 + * @param {Object} options - 可选项 + * @param {string} [options.childrenKey='children'] - 子节点字段名 + * @param {string} [options.idKey='id'] - 节点 id 字段名 + * @param {string} [options.parentKey='parentId'] - 父节点 id 字段名 + */ +lay.flatToTree = function (data, options) { + options = Object.assign({ + childrenKey: 'children', + idKey: 'id', + parentKey: 'parentId' + }, options); + data = JSON.parse(JSON.stringify(data)); // 深拷贝,防止修改原数据 + + // 先创建节点映射,确保无论平铺数据的顺序如何,组装树时都能正确匹配 + var map = data.reduce(function (acc, currNode) { + var id = currNode[options.idKey]; + acc[id] = currNode; + acc[id][options.childrenKey] = []; + return acc; + }, {}); + + // 组装树 + return data.reduce(function (acc, currNode) { + var id = currNode[options.idKey]; + var parentId = currNode[options.parentKey]; + + // 根节点 + if (parentId === null || !map[parentId]) { + acc.push(map[id]); + } else { + // 子节点 + map[parentId][options.childrenKey].push(currNode); + } + return acc; + }, []); +}; + +/* + * lay 元素操作 + */ + +// 追加字符 +Class.addStr = function (str, new_str) { + str = str.replace(/\s+/, ' '); + new_str = new_str.replace(/\s+/, ' ').split(' '); + lay.each(new_str, function (ii, item) { + if (!new RegExp('\\b' + item + '\\b').test(str)) { + str = str + ' ' + item; + } + }); + return str.replace(/^\s|\s$/, ''); +}; + +// 移除值 +Class.removeStr = function (str, new_str) { + str = str.replace(/\s+/, ' '); + new_str = new_str.replace(/\s+/, ' ').split(' '); + lay.each(new_str, function (ii, item) { + var exp = new RegExp('\\b' + item + '\\b'); + if (exp.test(str)) { + str = str.replace(exp, ''); + } + }); + return str.replace(/\s+/, ' ').replace(/^\s|\s$/, ''); +}; + +// 查找子元素 +Class.fn.find = function (selector) { + // var that = this; + var elem = []; + var isObject = typeof selector === 'object'; + this.each(function (i, item) { + var children = isObject && item.contains(selector) ? selector : item.querySelectorAll(selector || null); + lay.each(children, function (index, child) { + elem.push(child); + }); + }); + return lay(elem); +}; + +// 元素遍历 +Class.fn.each = function (fn) { + return lay.each.call(this, this, fn); +}; + +// 添加 className +Class.fn.addClass = function (className, type) { + return this.each(function (index, item) { + item.className = Class[type ? 'removeStr' : 'addStr'](item.className, className); + }); +}; + +// 移除 className +Class.fn.removeClass = function (className) { + return this.addClass(className, true); +}; + +// 是否包含 css 类 +Class.fn.hasClass = function (className) { + var has = false; + this.each(function (index, item) { + if (new RegExp('\\b' + className + '\\b').test(item.className)) { + has = true; + } + }); + return has; +}; + +// 添加或获取 css style +Class.fn.css = function (key, value) { + var that = this; + var parseValue = function (v) { + return isNaN(v) ? v : v + 'px'; + }; + return typeof key === 'string' && value === undefined ? function () { + if (that.length > 0) return that[0].style[key]; + }() : that.each(function (index, item) { + typeof key === 'object' ? lay.each(key, function (thisKey, thisValue) { + item.style[thisKey] = parseValue(thisValue); + }) : item.style[key] = parseValue(value); + }); +}; + +// 添加或获取宽度 +Class.fn.width = function (value) { + var that = this; + return value === undefined ? function () { + if (that.length > 0) return that[0].offsetWidth; // 此处还需做兼容 + }() : that.each(function () { + that.css('width', value); + }); +}; + +// 添加或获取高度 +Class.fn.height = function (value) { + var that = this; + return value === undefined ? function () { + if (that.length > 0) return that[0].offsetHeight; // 此处还需做兼容 + }() : that.each(function () { + that.css('height', value); + }); +}; + +// 添加或获取属性 +Class.fn.attr = function (key, value) { + var that = this; + return value === undefined ? function () { + if (that.length > 0) return that[0].getAttribute(key); + }() : that.each(function (index, item) { + item.setAttribute(key, value); + }); +}; + +// 移除属性 +Class.fn.removeAttr = function (key) { + return this.each(function (index, item) { + item.removeAttribute(key); + }); +}; + +// 设置或获取 HTML 内容 +Class.fn.html = function (html) { + var that = this; + return html === undefined ? function () { + if (that.length > 0) return that[0].innerHTML; + }() : this.each(function (index, item) { + item.innerHTML = html; + }); +}; + +// 设置或获取值 +Class.fn.val = function (value) { + var that = this; + return value === undefined ? function () { + if (that.length > 0) return that[0].value; + }() : this.each(function (index, item) { + item.value = value; + }); +}; + +// 追加内容 +Class.fn.append = function (elem) { + return this.each(function (index, item) { + typeof elem === 'object' ? item.appendChild(elem) : item.innerHTML = item.innerHTML + elem; + }); +}; + +// 移除内容 +Class.fn.remove = function (elem) { + return this.each(function (index, item) { + elem ? item.removeChild(elem) : item.parentNode.removeChild(item); + }); +}; + +// 事件绑定 +Class.fn.on = function (eventName, fn, options) { + return this.each(function (index, item) { + lay.addEvent(item, eventName, fn, options); + }); +}; + +// 解除事件 +Class.fn.off = function (eventName, fn, options) { + return this.each(function (index, item) { + lay.removeEvent(item, eventName, fn, options); + }); +}; + +export { lay }; diff --git a/dist/core/laytpl.js b/dist/core/laytpl.js new file mode 100644 index 000000000..66956a459 --- /dev/null +++ b/dist/core/laytpl.js @@ -0,0 +1,466 @@ +/** + * laytpl + * 轻量级通用模板引擎 + */ + +// 实例接口 +var thisModule = function () { + var that = this; + var options = that.config; + return { + config: options, + /** + * 渲染模板 + * @param {Object} data - 模板数据 + * @param {Function} callback - 回调函数 + * @returns {string} 渲染后的模板 + */ + render: function (data, callback) { + options.data = data; + var html = that.render(); + + // 如果传入目标元素选择器,则直接将模板渲染到目标元素中 + if (options.target) { + var elem = document.querySelector(options.target); + if (elem) { + elem.innerHTML = html; + } + } + + // 返回结果 + return typeof callback === 'function' ? (callback(html), this) : html; + }, + /** + * 编译新的模板 + * @param {string} template - 模板 + * @returns {this} + */ + compile: function (template) { + options.template = template; + delete that.compilerCache; // 清除模板缓存 + // that.compile(template); + return this; + }, + /** + * 模板编译错误事件 + * @param {Function} callback + * @returns {this} + */ + error: function (callback) { + callback && (options.error = callback); + return this; + }, + /** + * 以下为兼容旧版本相关方法 + */ + + // 解析并渲染模板 + parse: function (template, data) { + return this.compile(template).render(data); + } + }; +}; + +// 模板内部变量 +var vars = { + // 字符转义 + escape: function (html) { + var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g; + if (html === undefined || html === null) return ''; + html += ''; + if (!exp.test(html)) return html; + return html.replace(exp, function (str) { + return '&#' + str.charCodeAt(0) + ';'; + }); + } +}; + +// 组件工具类方法 +var tools = { + /** + * 创建动态正则表达式 + * @param {string} str - 表达式字符 + * @param {string} mod - 修饰符 + * @returns {RegExp} - 正则表达式 + */ + regex: function (str, mod) { + return new RegExp(str, mod || 'g'); + }, + /** + * 错误提示 + * @param {string} e - 原始错误信息 + * @param {Object} opts - 自定义选项 + * @param {Function} error - 错误回调 + * @returns {string} - 错误提示 + */ + error: function (e, opts, error) { + opts = opts || {}; + opts = Object.assign({ + errorContext: '' + }, opts); + + // 向控制台输出错误信息 + var message = 'Laytpl ' + (opts.type || '') + 'Error: ' + e; + var errorContext = opts.errorContext; + delete opts.errorContext; + typeof console === 'object' && console.error(message, '\n', errorContext, '\n', opts); + typeof error === 'function' && error(opts); // 执行错误回调 + return message; // 向视图返回错误提示 + } +}; + +// 默认配置 +var config = { + open: '{{', + // 起始界定符 + close: '}}', + // 结束界定符 + cache: true, + // 是否开启模板缓存,以便下次渲染时不重新编译模板 + condense: true, + // 是否压缩模板空白符,如:将多个连续的空白符压缩为单个空格 + tagStyle: '' // 标签风格。默认采用 < 2.11 的风格,设置 modern 则采用 2.11+ 风格 +}; + +// 构造器 +var Class = function (template, options) { + var that = this; + + // 选项合并 + options = that.config = Object.assign({ + template: template + }, config, options); + + // 当前实例的模板内工具 + that.vars = Object.assign({ + /** + * 引用外部模板。若在 Node.js 环境,可通过重置该方法实现模板文件导入 + * @param {string} id - 模板 ID + * @param {Object} data - 模板数据 + * @returns {string} 模板渲染后内容 + */ + include: function (id, data) { + var elem = document.getElementById(id); + var template = elem ? elem.innerHTML : ''; + return template ? that.render(template, data) : ''; + } + }, vars); + + // 编译模板 + that.compile(options.template); +}; + +/** + * 渲染 + * @param {Object} template - 模板 + * @param {Object} data - 数据 + * @returns {string} 渲染后的模板内容 + */ +Class.prototype.render = function (template, data) { + var that = this; + var options = that.config; + + // 获得模板渲染函数 + var compiler = template ? that.compile(template) : that.compilerCache || that.compile(options.template); + + // 获取渲染后的字符 + var html = function () { + data = data || options.data || {}; + try { + return compiler(data); + } catch (e) { + template = template || options.template; + return tools.error(e, { + errorContext: that.extractErrorContext(template, data), + template: template, + type: 'Render' + }, options.error); + } + }(); + + // 缓存编译器 + if (options.cache && !template) { + that.compilerCache = compiler; + } + return html; // 返回渲染后的字符 +}; + +/** + * 编译模板 + * @param {string} template - 原始模板 + * @returns {Function} 模板编译器,用于后续数据渲染 + */ +Class.prototype.compile = function (template) { + var that = this; + var options = that.config; + var openDelimiter = options.open; + var closeDelimiter = options.close; + var condense = options.condense; + var regex = tools.regex; + var placeholder = '\u2028'; // Unicode 行分隔符 + + // console.log('compile'); + + // 模板必须为 string 类型,且不能为空 + if (typeof template !== 'string' || !template) { + return function () { + return ''; + }; + } + + /** + * 完整标签正则 + * @param {string[]} cores - 标签内部核心表达式,含:前置、主体、后置 + * @param {Object} sides - 标签两侧外部表达式 + * @returns {RegExp} + */ + var tagRegex = function (cores, sides) { + var arr = ['(?:' + openDelimiter + (cores[0] || '') + '\\s*)', + // 界定符前置 + '(' + (cores[1] || '[\\s\\S]') + '*?)', + // 标签主体 + '(?:\\s*' + (cores[2] || '') + closeDelimiter + ')' // 界定符后置 + ]; + sides = sides || {}; + sides.before && arr.unshift(sides.before); // 标签前面的表达式 + sides.after && arr.push(sides.after); // 标签后面的表达式 + return regex(arr.join('')); + }; + + // 匹配非输出类型标签两侧的换行符和空白符,避免渲染后占用一行 + var sidesRegex = condense ? ['', ''] : ['(?:(?:\\n)*\\s*)', '(?:\\s*?)']; + var delimSides = { + before: sidesRegex[0], + after: sidesRegex[1] + }; + + /** + * 清理多余符号 + * @param {string} body - 标签主体字符 + * @param {boolean} nowrap - 是否强制不换行 + * @returns {string} 清理后的字符 + */ + var clear = function (body, nowrap) { + if (!condense) { + // 还原语句中的 Unicode 行分隔符 + body = body.replace(regex(placeholder), nowrap ? '' : '\n'); + } + body = body.replace(/\\(\\|")/g, '$1'); // 去除多余反斜杠 + return body; + }; + + // 纠正标签结构 + var correct = function (tpl) { + return tpl.replace(regex('([}\\]])' + closeDelimiter), '$1 ' + closeDelimiter); + }; + + // 模板解析 + var parse = that.parse = function (tpl) { + tpl = tpl || ''; + if (!tpl) return tpl; + + // 压缩连续空白符 + if (condense) { + tpl = tpl.replace(/\t/g, ' ').replace(/\s+/g, ' '); + } + + // 初始整理 + tpl = correct(tpl) // 纠正标签 + .replace(/(?=\\|")/g, '\\') // 转义反斜杠和双引号 + .replace(/\r?\n/g, condense ? '' : placeholder); // 整理换行符 + + // 忽略标签 - 即区域中的内容不进行标签解析 + tpl = tpl.replace(tagRegex(['!', '', '!'], delimSides), function (str, body) { + body = body.replace(regex(openDelimiter + '|' + closeDelimiter), function (tag) { + return tag.replace(/(?=.)/g, '\\'); + }); + return body; + }); + + // 模板字符拼接 + var strConcatenation = function (body) { + // 通过对 20k+ 行的模板进行编译测试, 发现 Chrome `+=` 性能竟优于 `push` + // 1k 次循环 + 1k 行数据量进行模板编译+渲染,发现 `+=` 性能仍然优于 `push` + // 考虑可能是 V8 做了 Ropes 结构优化? 或跟模板采用「静态拼接」的实现有关(可能性更大) + return ['";', body, '__laytpl__+="'].join('\n'); + // return ['");', body, '__laytpl__.push("'].join('\n'); + }; + + // 解析输出标签 + var output = function (str, delimiter, body) { + var _escape; + if (!body) return ''; + body = clear(body, true); + + // 输出方式 + if (delimiter === '-') { + // 原文输出,即不对 HTML 原文进行转义 + _escape = ''; + } else { + // 转义输出 + _escape = '_escape'; + } + return body ? strConcatenation('__laytpl__+=' + _escape + '(' + body + ');' + // '__laytpl__.push('+ _escape +'('+ body +'));' + ) : ''; + }; + + // 解析 Scriptlet + var statement = function (str, body) { + if (!body) return ''; + body = clear(body); + return strConcatenation(body); + }; + + // 标签风格 + if (options.tagStyle === 'modern') { + // 2.11+ 版本风格 + // 注释标签 - 仅在模板中显示,不进行解析,也不在视图中输出 + tpl = tpl.replace(tagRegex(['#'], delimSides), ''); + // 输出标签 + tpl = tpl.replace(tagRegex(['(=|-)']), output); + // Scriptlet 标签 + tpl = tpl.replace(tagRegex([], delimSides), statement); + } else { + // < 2.11 版本风格 + // Scriptlet 标签 + tpl = tpl.replace(tagRegex(['#'], delimSides), statement); + // 输出标签 + tpl = tpl.replace(tagRegex(['(=|-)*']), output); + } + + // 恢复换行符 + if (!condense) { + tpl = tpl.replace(regex(placeholder), '\\n'); + } + return tpl; + }; + + /** + * 创建模板编译器 + * 请注意: 开发者在使用模板语法时,需确保模板中的 JS 语句不来自于页面用户输入。 + * 即模板中的 JS 语句必须在页面开发者自身的可控范围内,否则请避免使用该模板解析。 + */ + var createCompiler = that.createCompiler = function (template, builder) { + builder = builder || createBuilder(template); + return new Function('laytpl', 'return ' + builder)(that.vars); + }; + var createBuilder = that.createBuilder = function (template, builder) { + builder = builder || ['function(d){', '"use strict";', 'var __laytpl__="",' + function () { + // 内部变量 + // 内部方法 + var arr = []; + for (var key in that.vars) { + arr.push((key === 'escape' ? '_' : '') + key + '=laytpl.' + key); + } + return arr.join(','); + }() + ';', '__laytpl__="' + parse(template) + '";', 'return __laytpl__;', + // '__laytpl__.push("'+ parse(template) +'");', + // 'return __laytpl__.join("");', + '};'].join('\n'); + // console.log(builder); + return builder; + }; + try { + return createCompiler(template); // 返回编译器 + } catch (e) { + delete that.compilerCache; + return function () { + return tools.error(e, { + errorContext: that.extractErrorContext(template), + template: template, + type: 'Compile' + }, options.error); + }; + } +}; + +/** + * 获取模板出错行上下文 + * @param {string} template - 原始模板 + * @param {Object} data - 数据 + * @returns {string} + */ +Class.prototype.extractErrorContext = function (template, data) { + var that = this; + + // 给模板每行开头添加行号标记 + var lineNum = 1; // 行号 + var templateArr = template.split(/\r?\n/g); + template = template.replace(/(?=^)/gm, function () { + return '/*LINE:' + lineNum++ + '*/'; + }); + var builder = that.createBuilder(template); + var builderArr = builder.split(/\r?\n/); + var sourceURL = 'laytpl.builder.map'; + + // 模板出错行上下文 + var errorContext = function (errLineNum) { + errLineNum = parseInt(errLineNum) - 1; + var arr = ['']; + var contextLines = 3; // 错误行上下延伸的行数 + var start = Math.max(0, errLineNum - contextLines); + var end = Math.min(templateArr.length, errLineNum + contextLines); + for (; start <= end; start++) { + arr.push((start == errLineNum ? '? ' : ' ') + (start + 1 + '| ') + templateArr[start]); + } + return arr.join('\n') + '\n'; + }; + try { + builder += '\n//# sourceURL=' + sourceURL; // 添加映射 + var compiler = that.createCompiler(template, builder); + if (data) compiler(data); + } catch (e) { + // 提取堆栈报错行号 + var stackLineNumRegxp = tools.regex(sourceURL.replace(/\./g, '\\.') + ':(\\d+)', 'i'); + var stackLineNum = (e.stack.match(stackLineNumRegxp) || [])[1] || 0; + + // 提取模板实际行号 + var extractErrLineNum = function (stackLineNum, isRecursion) { + var lineNumRegxp = isRecursion ? /\/\*LINE:(\d+)\*\/[^*]*$/ : /\/\*LINE:(\d+)\*\//; + var errLineNum = String(builderArr[stackLineNum - 1]).match(lineNumRegxp) || []; + errLineNum = errLineNum[1]; + + // 若当前行未找到行号映射,则递归查找上一行 + if (!errLineNum && stackLineNum > 0) { + return extractErrLineNum(stackLineNum - 1, true); + } + return errLineNum; + }; + + // 此处减去 anonymous 开头占用的 2 行 + var errLineNum = extractErrLineNum(stackLineNum - 2); + + // 若未找到映射行号,则直接返回 SyntaxError 对象(通过 DevTools 映射源查看模板行号标记) + return errLineNum ? errorContext(errLineNum) : e; + } +}; + +/** + * 创建实例 + * @param {string} template - 模板 + * @param {Object} options - 选项 + * @returns {Object} + */ +var laytpl = function (template, options) { + var inst = new Class(template, options); + return thisModule.call(inst); +}; + +/** + * 扩展模板内部变量 + * @param {Object} variables - 扩展内部变量,变量值通常为函数 + */ +laytpl.extendVars = function (variables) { + Object.assign(vars, variables); +}; + +/** + * 设置默认配置 + * @param {Object} options - 选项 + */ +laytpl.config = laytpl.set = function (options) { + Object.assign(config, options); +}; + +export { laytpl }; diff --git a/dist/core/layui.js b/dist/core/layui.js new file mode 100644 index 000000000..fc33ffcfd --- /dev/null +++ b/dist/core/layui.js @@ -0,0 +1,1023 @@ +/** + * Layui + * MIT Licensed + */ + +// 便于打包时的字符压缩 +var document = window.document; +var location = window.location; + +// 基础配置 +var config = { + timeout: 10, + // 符合规范的模块请求最长等待秒数 + debug: false, + // 是否开启调试模式 + version: false // 是否在模块请求时加入版本号参数(以更新模块缓存) +}; + +// 模块加载缓存信息 +var cache = { + modules: {}, + // 模块物理路径 + status: {}, + // 模块加载就绪状态 + event: {}, + // 模块自定义事件 + callback: {} // 模块的回调 +}; + +// constructor +var Class = function () { + this.v = '3.0.0-alpha.3'; // 版本号 +}; + +// 识别预先可能定义的指定全局对象 +var GLOBAL = window.LAYUI_GLOBAL || {}; + +// 获取 layui 所在目录 +var getPath = function () { + var jsPath = document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT' ? document.currentScript.src : function () { + var js = document.getElementsByTagName('script'); + var last = js.length - 1; + var src; + for (var i = last; i > 0; i--) { + if (js[i].readyState === 'interactive') { + src = js[i].src; + break; + } + } + return src || js[last].src; + }(); + return config.dir = GLOBAL.dir || jsPath.substring(0, jsPath.lastIndexOf('/') + 1); +}(); + +// 异常提示 +var error = function (msg, type) { + type = type || 'warn'; + msg = '[Layui warn]: ' + msg; + + // 仅允许 error 或 warn 两种类型的提示 + if (/warn|error/.test(type.trim())) { + type = 'warn'; + } + window.console[type](msg); +}; +var warned = Object.create(null); +var errorOnce = function (msg, type) { + if (warned._size && warned._size > 100) { + warned = Object.create(null); + warned._size = 0; + } + if (!warned[msg]) { + warned[msg] = true; + warned._size = (warned._size || 0) + 1; + error(msg, type); + } +}; + +// 内置模块 +var builtinModules = config.builtin = { + lay: 'lay', + // 基础 DOM 操作 + layer: 'layer', + // 弹层 + laydate: 'laydate', + // 日期 + laypage: 'laypage', + // 分页 + laytpl: 'laytpl', + // 模板引擎 + form: 'form', + // 表单集 + upload: 'upload', + // 上传 + dropdown: 'dropdown', + // 下拉菜单 + transfer: 'transfer', + // 穿梭框 + tree: 'tree', + // 树结构 + table: 'table', + // 表格 + treeTable: 'treeTable', + // 树表 + tabs: 'tabs', + // 标签页 + tab: 'tab', + // 选项卡(兼容保留) + nav: 'nav', + // 导航菜单 + breadcrumb: 'breadcrumb', + // 面包屑 + progress: 'progress', + // 进度条 + collapse: 'collapse', + // 折叠面板 + element: 'element', + // 常用元素操作 + rate: 'rate', + // 评分组件 + colorpicker: 'colorpicker', + // 颜色选择器 + slider: 'slider', + // 滑块 + carousel: 'carousel', + // 轮播 + flow: 'flow', + // 流加载 + util: 'util', + // 工具块 + code: 'code', + // 代码修饰器 + jquery: 'jquery', + // DOM 库(第三方) + component: 'component', + // 组件构建器 + i18n: 'i18n', + // 国际化 + + all: 'all', + 'layui.all': 'layui.all' // 聚合标识(功能性的,非真实模块) +}; + +/** + * 节点加载事件 + * @param {HTMLElement} node - script 或 link 节点 + * @param {Function} done + * @param {Function} error + */ +var onNodeLoad = function (node, done, error) { + // 资源加载完毕 + var onCompleted = function (e) { + var readyRegExp = /^(complete|loaded)$/; + if (e.type === 'load' || readyRegExp.test((e.currentTarget || e.srcElement).readyState)) { + removeListener(); + typeof done === 'function' && done(e); + } + }; + // 资源加载失败 + var onError = function (e) { + removeListener(); + typeof error === 'function' && error(e); + }; + + // 移除事件 + var removeListener = function () { + if (node.detachEvent) { + node.detachEvent('onreadystatechange', onCompleted); + } else { + node.removeEventListener('load', onCompleted, false); + node.removeEventListener('error', onError, false); + } + }; + + // 添加事件 + if (node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0)) { + // 此处考虑到 IE9+ load 的稳定性,固仍然采用 onreadystatechange + node.attachEvent('onreadystatechange', onCompleted); + } else { + node.addEventListener('load', onCompleted, false); + node.addEventListener('error', onError, false); + } +}; + +// 获取配置及临时缓存信息 +Class.prototype.cache = Object.assign(config, cache); + +/** + * 全局配置 + * @param {Object} options - 配置对象 + */ +Class.prototype.config = function (options) { + Object.assign(config, options); + return this; +}; + +/** + * 定义模块 + * @param {(string|string[])} deps - 依赖的模块列表 + * @param {Function} callback - 模块的回调 + */ +Class.prototype.define = function (deps, callback) { + var that = this; + var useCallback = function () { + var setModule = function (mod, exports$1) { + layui[mod] = exports$1; // 将模块接口赋值在 layui 对象中 + cache.status[mod] = true; // 标记模块注册完成 + }; + // 执行模块的回调 + typeof callback === 'function' && callback(function (mod, exports$1) { + setModule(mod, exports$1); + // 记录模块回调,以便需要时再执行 + cache.callback[mod] = function () { + callback(setModule); + }; + }); + return this; + }; + + // 若未依赖模块 + if (typeof deps === 'function') { + callback = deps; + deps = []; + } + that.use(deps, useCallback, null, 'define'); + return that; +}; + +/** + * 使用模块 + * @param {(string|string[])} mods - 模块列表 + * @param {Function} callback - 回调 + */ +Class.prototype.use = function (mods, callback, exports$1, from) { + var that = this; + var dir = config.dir = config.dir ? config.dir : getPath; + + // 整理模块队列 + mods = function () { + if (typeof mods === 'string') { + return [mods]; + } + // 若第一个参数为 function ,则自动加载所有内置模块,且执行的回调即为该 function 参数; + else if (typeof mods === 'function') { + callback = mods; + return ['all']; + } + return mods; + }(); + + // 获取 layui 静态资源所在 host + if (!config.host) { + config.host = (dir.match(/\/\/([\s\S]+?)\//) || ['//' + location.host + '/'])[0]; + } + + // 若参数异常 + if (!mods) return that; + + // 若页面已经存在 jQuery 且所定义的模块依赖 jQuery,则不加载内部 jquery 模块 + if (window.jQuery && window.jQuery.fn.on) { + that.each(mods, function (index, item) { + if (item === 'jquery') { + mods.splice(index, 1); + } + }); + layui.jquery = layui.$ = window.jQuery; + } + + // 将模块的接口作为回调的参数传递 + exports$1 = exports$1 || []; + + // 加载当前队列的第一个模块 + var item = mods[0]; + var modInfo = that.modules[item]; // 当前模块信息 + // 是否为外部模块,即无需遵循 layui 轻量级模块规范的任意第三方组件。 + var isExternalModule = typeof modInfo === 'object'; + + // 回调触发 + var onCallback = function () { + exports$1.push(layui[item]); + mods.length > 1 ? that.use(mods.slice(1), callback, exports$1, from) : typeof callback === 'function' && function () { + // 保证文档加载完毕再执行回调 + if (layui.jquery && typeof layui.jquery === 'function' && from !== 'define') { + return layui.jquery(function () { + callback.apply(layui, exports$1); + }); + } + callback.apply(layui, exports$1); + }(); + }; + + // 回调轮询 + var pollCallback = function () { + var timeout = 0; // 超时计数器(秒) + var delay = 5; // 轮询等待毫秒数 + + // 轮询模块加载完毕状态 + (function poll() { + if (++timeout > config.timeout * 1000 / delay) { + return error(item + ' is not a valid module', 'error'); + } + + // 根据模块加载完毕的标志来完成轮询 + // 若为任意外部模块,则标志为该模块接口是否存在; + // 若为遵循 layui 规范的模块,则标志为模块的 status 状态值 + (isExternalModule ? layui[item] = window[modInfo.api] : cache.status[item]) ? onCallback() : setTimeout(poll, delay); + })(); + }; + + // 若为发行版,则内置模块不必异步加载 + if (mods.length === 0 || layui['layui.all'] && builtinModules[item]) { + return onCallback(), that; + } + + // 当前模块所在路径 + var modSrc = isExternalModule ? modInfo.src : modInfo; + + // 基础路径 + var basePath = builtinModules[item] ? dir + 'modules/' // 若为内置模块,则按照默认 dir 参数拼接模块 URL + : modSrc ? '' : config.base; // 若为扩展模块,且模块路径已设置,则不必再重复拼接基础路径 + + // 若从 layui.modules 为获取到模块路径, 则将传入的模块名视为路径名 + if (!modSrc) modSrc = item; + + // 过滤空格符和 .js 后缀 + modSrc = modSrc.replace(/\s/g, '').replace(/\.js[^/.]*$/, ''); + + // 拼接最终模块 URL + var url = basePath + modSrc + '.js'; + + // 若扩展模块对象已经存在,则不必再重复加载 + if (!cache.modules[item] && layui[item]) { + cache.modules[item] = url; // 并记录起该扩展模块的 url + } + + // 首次加载模块 + if (!cache.modules[item]) { + var head = document.getElementsByTagName('head')[0]; + var node = document.createElement('script'); + node.async = true; + node.charset = 'utf-8'; // 避免 IE9 的编码问题 + node.src = url + function () { + var version = config.version === true ? config.v || new Date().getTime() : config.version || ''; + return version ? '?v=' + version : ''; + }(); + head.appendChild(node); + + // 节点加载事件 + onNodeLoad(node, function () { + head.removeChild(node); + pollCallback(); + }, function () { + head.removeChild(node); + }); + + // 模块已首次加载的标记 + cache.modules[item] = url; + } else { + // 再次 use 模块 + pollCallback(); + } + return that; +}; + +// 记录全部模块 +Class.prototype.modules = Object.assign({}, builtinModules); + +/** + * 拓展模块 + * @param {Object} settings - 拓展模块的配置 + */ +Class.prototype.extend = function (settings) { + var that = this; + var base = config.base || ''; + var firstSymbolEXP = /^\{\/\}/; // 模块单独路径首字符表达式 + + settings = settings || {}; + + // 遍历拓展模块 + for (var modName in settings) { + if (that[modName] || that.modules[modName]) { + // 验证模块是否被占用 + error('the ' + modName + ' module already exists, extend failure'); + } else { + var modInfo = settings[modName]; + // 若直接传入模块路径字符 + if (typeof modInfo === 'string') { + // 判断传入的模块路径是否特定首字符 + // 若存在特定首字符,则模块 URL 即为该首字符后面紧跟的字符 + // 否则,则按照 config.base 路径进行拼接 + if (firstSymbolEXP.test(modInfo)) base = ''; + modInfo = (base + modInfo).replace(firstSymbolEXP, ''); + } + that.modules[modName] = modInfo; + } + } + return that; +}; + +/** + * 弃用指定的模块,以便重新扩展新的同名模块。 + * @param {(string|string[])} mods - 模块列表 + */ +Class.prototype.disuse = function (mods) { + var that = this; + mods = that.isArray(mods) ? mods : [mods]; + that.each(mods, function (index, item) { + delete that[item]; + delete builtinModules[item]; + delete that.modules[item]; + delete cache.status[item]; + delete cache.modules[item]; + }); + return that; +}; + +/** + * 获取节点的 style 属性值 + * currentStyle.getAttribute 参数为 camelCase 形式的字符串 + * @param {HTMLElement} node - 节点 + * @param {string} name - 属性名 + * @returns 属性值 + */ +Class.prototype.getStyle = function (node, name) { + var style = node.currentStyle ? node.currentStyle : window.getComputedStyle(node, null); + return style.getPropertyValue ? style.getPropertyValue(name) : style.getAttribute(name.replace(/-(\w)/g, function (_, c) { + return c ? c.toUpperCase() : ''; + })); +}; + +/** + * CSS 外部加载器 + * @param {string} href - 外部 CSS 文件路径 + * @param {Function} callback - 回调函数 + * @param {string} id - 定义 link 标签的 id + */ +Class.prototype.link = function (href, callback, id) { + var that = this; + var head = document.getElementsByTagName('head')[0]; + var hasCallback = typeof callback === 'function'; + + // 若第二个参数为 string 类型,则该参数为 id + if (typeof callback === 'string') { + id = callback; + } + + // 若加载多个 + if (typeof href === 'object') { + var isArr = that.type(id) === 'array'; + return that.each(href, function (index, value) { + that.link(value, index === href.length - 1 && callback, isArr && id[index]); + }); + } + + // 若未传入 id ,则取路径 `//` 后面的字符拼接为 id,不含.与参数 + id = id || href.replace(/^(#|(http(s?)):\/\/|\/\/)|\.|\/|\?.+/g, ''); + id = 'layuicss-' + id; + var link = document.getElementById(id); + + // 初始创建节点 + if (!link) { + link = document.createElement('link'); + link.href = href + (config.debug ? '?v=' + new Date().getTime() : ''); + link.rel = 'stylesheet'; + link.id = id; + head.appendChild(link); + } + + // 若加载已完成,则直接执行回调函数 + if (link.__lay_readyState__ === 'complete') { + hasCallback && callback(link); + return that; + } + + // 初始加载 + onNodeLoad(link, function () { + link.__lay_readyState__ = 'complete'; + hasCallback && callback(link); + }, function () { + error(href + ' load error', 'error'); + head.removeChild(link); // 移除节点 + }); + return that; +}; + +/** + * CSS 内部加载器 + * @param {string} modName - 模块名 + */ +Class.prototype.addcss = function (modName, callback, id) { + return layui.link(config.dir + 'css/' + modName, callback, id); +}; + +/** + * 获取执行定义模块时的回调函数,factory 为向下兼容 + * @param {string} modName - 模块名 + * @returns {Function} + */ +Class.prototype.factory = function (modName) { + if (layui[modName]) { + return typeof config.callback[modName] === 'function' ? config.callback[modName] : null; + } +}; + +/** + * 图片预加载 + * @param {string} url - 图片路径 + * @param {Function} callback - 成功回调 + * @param {Function} error - 错误回调 + */ +Class.prototype.img = function (url, callback, error) { + var img = new Image(); + img.src = url; + if (img.complete) { + return callback(img); + } + img.onload = function () { + img.onload = null; + typeof callback === 'function' && callback(img); + }; + img.onerror = function (e) { + img.onerror = null; + typeof error === 'function' && error(e); + }; +}; + +/** + * location.hash 路由解析 + * @param {string} hash 值 + * @returns {Object} + */ +Class.prototype.router = Class.prototype.hash = function (hash) { + hash = hash || location.hash; + var that = this; + var data = { + path: [], + pathname: [], + search: {}, + hash: (hash.match(/[^#](#.*$)/) || [])[1] || '', + href: '' + }; + + // 禁止非 hash 路由规范 + if (!/^#/.test(hash)) { + return data; + } + hash = hash.replace(/^#/, ''); + data.href = hash; + hash = hash.replace(/([^#])(#.*$)/, '$1').split('/') || []; + + // 提取 Hash 结构 + that.each(hash, function (index, item) { + /^\w+=/.test(item) ? function () { + item = item.split('='); + data.search[item[0]] = item[1]; + }() : data.path.push(item); + }); + data.pathname = data.path; // path → pathname, 与 layui.url 一致 + return data; +}; + +/** + * URL 解析 + * @param {string} href - url 路径 + * @returns {Object} + */ +Class.prototype.url = function (href) { + var that = this; + var data = { + // 提取 url 路径 + pathname: function () { + var pathname = href ? function () { + var str = (href.match(/\.[^.]+?\/.+/) || [])[0] || ''; + return str.replace(/^[^/]+/, '').replace(/\?.+/, ''); + }() : location.pathname; + return pathname.replace(/^\//, '').split('/'); + }(), + // 提取 url 参数 + search: function () { + var obj = {}; + var search = (href ? function () { + var str = (href.match(/\?.+/) || [])[0] || ''; + return str.replace(/#.+/, ''); + }() : location.search).replace(/^\?+/, '').split('&'); // 去除 ?,按 & 分割参数 + + // 遍历分割后的参数 + that.each(search, function (index, item) { + var _index = item.indexOf('='); + var key = function () { + // 提取 key + if (_index < 0) { + return item.substr(0, item.length); + } else if (_index === 0) { + return false; + } else { + return item.substr(0, _index); + } + }(); + // 提取 value + if (key) { + obj[key] = _index > 0 ? item.substr(_index + 1) : null; + } + }); + return obj; + }(), + // 提取 Hash + hash: that.router(function () { + return href ? (href.match(/#.+/) || [])[0] || '/' : location.hash; + }()) + }; + return data; +}; + +/** + * 本地持久存储 + * @param {string} table - 表名 + * @param {Object} settings - 设置项 + * @param {Storage} storage - 存储对象,localStorage 或 sessionStorage + * @returns {Object} + */ +Class.prototype.data = function (table, settings, storage) { + table = table || 'layui'; + storage = storage || localStorage; + + // 如果 settings 为 null,则删除表 + if (settings === null) { + return delete storage[table]; + } + settings = typeof settings === 'object' ? settings : { + key: settings + }; + var data; + try { + data = JSON.parse(storage[table]); + } catch { + data = {}; + } + if ('value' in settings) data[settings.key] = settings.value; + if (settings.remove) delete data[settings.key]; + storage[table] = JSON.stringify(data); + return settings.key ? data[settings.key] : data; +}; + +/** + * 本地临时存储 + * @param {string} table - 表名 + * @param {Object} settings - 设置项 + * @returns {Object} + */ +Class.prototype.sessionData = function (table, settings) { + return this.data(table, settings, sessionStorage); +}; + +/** + * 设备信息 + * @param {string} key - 任意 key + * @returns {Object} + */ +Class.prototype.device = function (key) { + var agent = navigator.userAgent.toLowerCase(); + + // 获取版本号 + var getVersion = function (label) { + var exp = new RegExp(label + '/([^\\s\\_\\-]+)'); + label = (agent.match(exp) || [])[1]; + return label || false; + }; + + // 返回结果集 + var result = { + os: function () { + // 底层操作系统 + if (/windows/.test(agent)) { + return 'windows'; + } else if (/linux/.test(agent)) { + return 'linux'; + } else if (/iphone|ipod|ipad|ios/.test(agent)) { + return 'ios'; + } else if (/mac/.test(agent)) { + return 'mac'; + } + }(), + ie: function () { + // ie 版本 + return !!window.ActiveXObject || 'ActiveXObject' in window ? (agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识 + : false; + }(), + weixin: getVersion('micromessenger') // 是否微信 + }; + + // 任意的 key + if (key && !result[key]) { + result[key] = getVersion(key); + } + + // 移动设备 + result.android = /android/.test(agent); + result.ios = result.os === 'ios'; + result.mobile = result.android || result.ios; + return result; +}; + +// 提示 +Class.prototype.hint = function () { + return { + error: error, + errorOnce: errorOnce + }; +}; + +/** + * typeof 类型细分 -> string/number/boolean/undefined/null、object/array/function/… + * @param {*} operand - 任意值 + * @returns {string} + */ +Class.prototype._typeof = Class.prototype.type = function (operand) { + if (operand === null) return String(operand); + + // 细分引用类型 + return typeof operand === 'object' || typeof operand === 'function' ? function () { + var type = Object.prototype.toString.call(operand).match(/\s(.+)\]$/) || []; // 匹配类型字符 + var classType = 'Function|Array|Date|RegExp|Object|Error|Symbol'; // 常见类型字符 + + type = type[1] || 'Object'; + + // 除匹配到的类型外,其他对象均返回 object + return new RegExp('\\b(' + classType + ')\\b').test(type) ? type.toLowerCase() : 'object'; + }() : typeof operand; +}; + +/** + * 对象是否具备数组结构(此处为兼容 jQuery 对象) + * @param {Object} obj - 任意对象 + * @returns {boolean} + */ +Class.prototype._isArray = Class.prototype.isArray = function (obj) { + var that = this; + var len; + var type = that.type(obj); + if (!obj || typeof obj !== 'object' || obj === window) return false; + len = 'length' in obj && obj.length; // 兼容 ie + return type === 'array' || len === 0 || typeof len === 'number' && len > 0 && len - 1 in obj // 兼容 jQuery 对象 +; +}; + +/** + * 遍历 + * @param {Object} obj - 任意对象 + * @param {Function} fn - 遍历回调 + */ +Class.prototype.each = function (obj, fn) { + var key; + var that = this; + var callback = function (key, obj) { + return fn.call(obj[key], key, obj[key]); + }; + if (typeof fn !== 'function') { + return that; + } + obj = obj || []; + + // 优先处理数组结构 + if (that.isArray(obj)) { + for (key = 0; key < obj.length; key++) { + if (callback(key, obj)) break; + } + } else { + for (key in obj) { + if (callback(key, obj)) break; + } + } + return that; +}; + +/** + * 将数组中的成员对象按照某个 key 的 value 值进行排序 + * @param {Object[]} arr - 任意数组 + * @param {string} key - 任意 key + * @param {boolean} desc - 是否降序 + * @param {boolean} notClone - 是否不对 arr 进行克隆 + * @returns {Object[]} + */ +Class.prototype.sort = function (arr, key, desc, notClone) { + var that = this; + var clone = notClone ? arr || [] : JSON.parse(JSON.stringify(arr || [])); + + // 若未传入 key,则直接返回原对象 + if (that.type(arr) === 'object' && !key) { + return clone; + } else if (typeof arr !== 'object') { + // 若 arr 非对象 + return [clone]; + } + + // 开始排序 + clone.sort(function (o1, o2) { + var v1 = o1[key]; + var v2 = o2[key]; + + /* + * 特殊数据 + * 若比较的成员均非对象 + */ + + // 若比较的成员均为数字 + if (!isNaN(o1) && !isNaN(o2)) return o1 - o2; + + // 若比较的成员只存在某一个非对象 + if (!isNaN(o1) && isNaN(o2)) { + if (key && typeof o2 === 'object') { + v1 = o1; + } else { + return -1; + } + } else if (isNaN(o1) && !isNaN(o2)) { + if (key && typeof o1 === 'object') { + v2 = o2; + } else { + return 1; + } + } + + /* + * 正常数据 + * 即成员均为对象,也传入了对比依据: key + * 若 value 为数字,按「大小」排序;若 value 非数字,则按「字典序」排序 + */ + + // value 是否为数字 + var isNum = [!isNaN(v1), !isNaN(v2)]; + + // 若为数字比较 + if (isNum[0] && isNum[1]) { + if (v1 && !v2 && v2 !== 0) { + // 数字 vs 空 + return 1; + } else if (!v1 && v1 !== 0 && v2) { + // 空 vs 数字 + return -1; + } else { + // 数字 vs 数字 + return v1 - v2; + } + } + + /** + * 字典序排序 + */ + + // 若为非数字比较 + if (!isNum[0] && !isNum[1]) { + // 字典序比较 + if (v1 > v2) { + return 1; + } else if (v1 < v2) { + return -1; + } else { + return 0; + } + } + + // 若为混合比较 + if (isNum[0] || !isNum[1]) { + // 数字 vs 非数字 + return -1; + } else if (!isNum[0] || isNum[1]) { + // 非数字 vs 数字 + return 1; + } + }); + desc && clone.reverse(); // 倒序 + return clone; +}; + +/** + * 阻止事件冒泡 + * @param {Event} thisEvent - 事件对象 + */ +Class.prototype.stope = function (thisEvent) { + try { + thisEvent.stopPropagation(); + } catch { + thisEvent.cancelBubble = true; + } +}; + +// 字符常理 +var EV_REMOVE = 'LAYUI-EVENT-REMOVE'; + +/** + * 自定义模块事件 + * @param {string} modName - 模块名 + * @param {string} events - 事件名 + * @param {Function} callback - 回调 + * @returns {Object} + */ +Class.prototype.onevent = function (modName, events, callback) { + if (typeof modName !== 'string' || typeof callback !== 'function') { + return this; + } + return Class.event(modName, events, null, callback); +}; + +/** + * 执行自定义模块事件 + * @param {string} modName - 模块名 + * @param {string} events - 事件名 + * @param {Object} params - 参数 + * @param {Function} fn - 回调 + */ +Class.prototype.event = Class.event = function (modName, events, params, fn) { + var that = this; + var result = null; + var filter = (events || '').match(/\((.*)\)$/) || []; // 提取事件过滤器字符结构,如:select(xxx) + var eventName = (modName + '.' + events).replace(filter[0], ''); // 获取事件名称,如:form.select + var filterName = filter[1] || ''; // 获取过滤器名称, 如:xxx + var callback = function (_, item) { + var res = item && item.call(that, params); + res === false && result === null && (result = false); + }; + + // 如果参数传入特定字符,则执行移除事件 + if (params === EV_REMOVE) { + delete (that.cache.event[eventName] || {})[filterName]; + return that; + } + + // 添加事件 + if (fn) { + cache.event[eventName] = cache.event[eventName] || {}; + if (filterName) { + // 带 filter 不支持重复事件 + cache.event[eventName][filterName] = [fn]; + } else { + // 不带 filter 处理的是所有的同类事件,应该支持重复事件 + cache.event[eventName][filterName] = cache.event[eventName][filterName] || []; + cache.event[eventName][filterName].push(fn); + } + return this; + } + + // 执行事件回调 + layui.each(cache.event[eventName], function (key, item) { + // 执行当前模块的全部事件 + if (filterName === '{*}') { + layui.each(item, callback); + return; + } + + // 执行指定事件 + key === '' && layui.each(item, callback); + filterName && key === filterName && layui.each(item, callback); + }); + return result; +}; + +/** + * 新增模块事件 + * @param {string} events - 事件名 + * @param {string} modName - 模块名 + * @param {Function} callback - 回调 + * @returns {Object} + */ +Class.prototype.on = function (events, modName, callback) { + var that = this; + return that.onevent.call(that, modName, events, callback); +}; + +/** + * 移除模块事件 + * @param {string} events - 事件名 + * @param {string} modName - 模块名 + * @returns {Object} + */ +Class.prototype.off = function (events, modName) { + var that = this; + return that.event.call(that, modName, events, EV_REMOVE); +}; + +/** + * 防抖 + * @param {Function} func - 回调 + * @param {number} wait - 延时执行的毫秒数 + * @returns {Function} + */ +Class.prototype.debounce = function (func, wait) { + var timeout; + return function () { + var context = this; + var args = arguments; + clearTimeout(timeout); + timeout = setTimeout(function () { + func.apply(context, args); + }, wait); + }; +}; + +/** + * 节流 + * @param {Function} func - 回调 + * @param {number} wait - 不重复执行的毫秒数 + */ +Class.prototype.throttle = function (func, wait) { + var cooldown = false; + return function () { + var context = this; + var args = arguments; + if (!cooldown) { + func.apply(context, args); + cooldown = true; + setTimeout(function () { + cooldown = false; + }, wait); + } + }; +}; +const layui = new Class(); + +// 阻止 layui.use 加载内部模块 +layui.all = true; +layui['layui.all'] = 'layui.all'; + +export { layui }; diff --git a/dist/css/layui.css b/dist/css/layui.css new file mode 100644 index 000000000..26c8a59d8 --- /dev/null +++ b/dist/css/layui.css @@ -0,0 +1,2 @@ +.light,:root{--lay-color-primary:#16baaa;--lay-color-accent:#16b777;--lay-color-red:#ff5722;--lay-color-orange:#ffb800;--lay-color-green:#16baaa;--lay-color-blue:#1e9fff;--lay-color-purple:#a233c6;--lay-color-black:#2f363c;--lay-color-gray:#fafafa;--lay-gray-100:#fafafa;--lay-gray-200:#f7f7f7;--lay-gray-300:#eee;--lay-gray-400:#d1d1d1;--lay-gray-500:#c8c8c8;--lay-gray-600:#b7b7b7;--lay-gray-700:#959595;--lay-gray-800:#777;--lay-gray-900:#5a5a5a;--lay-border-color:var(--lay-gray-300);--lay-border-color-accent:var(--lay-gray-400);--lay-border-radius:2px;--lay-box-shadow:0 1px 2px rgba(0,0,0,.15);--lay-box-shadow-sm:0 0.5px 1px rgba(0,0,0,.08);--lay-box-shadow-lg:0 3px 6px rgba(0,0,0,.3);--lay-font-family:system-ui,-apple-system,"Segoe UI",Roboto,"PingFang SC","Microsoft YaHei","Helvetica Neue",Arial,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji";--lay-font-monospace:"Courier New",Consolas,"Lucida Console",monospace;--lay-spacing:16px;--lay-spacing-xs:5px;--lay-spacing-sm:8px;--lay-spacing-lg:24px;--lay-spacing-xl:32px}blockquote,body,button,dd,div,dl,dt,form,h1,h2,h3,h4,h5,h6,input,li,ol,p,pre,td,textarea,th,ul{margin:0;padding:0;-webkit-tap-highlight-color:rgba(0,0,0,0)}a:active,a:hover{outline:0}img{border:none;display:inline-block;vertical-align:middle}li{list-style:none}table{border-collapse:collapse;border-spacing:0}h1,h2,h3,h4,h5,h6{font-weight:700}button,h5,h6,input,select,textarea{font-size:100%}button,input,optgroup,option,select,textarea{font-family:inherit;font-size:inherit;font-style:inherit;font-weight:inherit;outline:0}pre{white-space:pre-wrap;word-wrap:break-word}body{color:rgba(0,0,0,.85);font-family:var(--lay-font-family);font-size:14px;line-height:1.6}hr{background:none;border:none;border-bottom:1px solid var(--lay-border-color);clear:both;height:0;line-height:0;margin:10px 0;overflow:hidden;padding:0}a{color:#333;text-decoration:none}a cite{font-style:normal}.layui-border-box,.layui-border-box *{box-sizing:border-box}.layui-box,.layui-box *{box-sizing:content-box}.layui-clear{clear:both}.layui-clear:after{clear:both;content:"\20";display:block;height:0}.layui-clear-space{word-spacing:-5px}.layui-edge,.layui-inline{display:inline-block;position:relative;vertical-align:middle}.layui-edge{border:6px dashed transparent;height:0;overflow:hidden;width:0}.layui-edge-top{border-bottom-color:#999;border-bottom-style:solid;top:-4px}.layui-edge-right{border-left-color:#999;border-left-style:solid}.layui-edge-bottom{border-top-color:#999;border-top-style:solid;top:2px}.layui-edge-left{border-right-color:#999;border-right-style:solid}.layui-ellip{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.layui-disabled,.layui-icon,.layui-unselect{-webkit-user-select:none;-moz-user-select:none;user-select:none}.layui-disabled,.layui-disabled:hover{color:var(--lay-gray-400)!important;cursor:not-allowed!important}.layui-circle{border-radius:100%}.layui-show{display:block!important}.layui-hide{display:none!important}.layui-show-v{visibility:visible!important}.layui-hide-v{visibility:hidden!important}@font-face{font-family:layui-icon;src:url("data:font/woff2;base64,d09GMgABAAAAAHU0AAsAAAAA1TwAAHTgAAEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAHFQGYACZfAqC7nCCqB8BNgIkA4YQC4MKAAQgBYR/B49GG52vB5TbJwXoDgDnrxoVPOHG0HsciD4ERwaCjUPggexU9v9/ToKSMfYbcBugIZmVIUSK7Ao0ZjeJiTwOTeXBaV6KzlrkujS26QrQ3qS2MLuJVXG4i2Z5F4CTBDhQdBs+USuVMEwozGMoCKCg2x6TOjinobkH73ubLL2Eh2jlKTh/Y6bdLaYzSxLvX57VTk1eNDrh6Rv7352Z3f1qGjUp4pFDpIlHSLT+LQX0WSYPBECnXiFo5rejlGSgkwGgAORALyLblHZKOOA2fAAMwTY7qiTFwAAERFBUSgWDNBJBRLAQBazNnBVLt9albu3SxU8X+T9dfM3/ucj/1e9j6a9++9henvAPdt37gbUEE2kLNA5TCAjbEQ3vHiogG6iMeG3TWY0PESRkYwNigYshfgip/va72FVflHGbaj+NDItLypT12153EBKQF4ZIwr6k+bn69O/U/nWSh0dJu3fmgKG4a0jiwkLaFNNlEKTJQsKXFugu+Ef6lX8PGAILtiXbbVJIA1gGSX6QAwT7A/McFOuqxJOHObMZKS7MGDaF5JBAsEBZKJM/0lf6JvZC2yPm7Pfu1b1Kq7SG2xB8CAB+IkEJwG43+2UrzR02mIDgdAc2OEKPwwCvBSxvBAxsN/aOxOC80Ecegm/L8puKAW+d5J8uXA9q82yrWkYeIbJdqZrtQcEW5SS/U9K4opxCn0PpqlpQ4j+OVAD4ifxIij8eUp8I8gMgOkV+jpVjLu8UbIByOHwEPgKOlCPlkKsQQ+mmcle7Kf+75M515ap20Zv6jxvnES6AZX9OnnhWv9fZX32KUDdovA+Xo1w2j2Y36Yo56Ko0iZAMQiEkthXNeJRjXlXtV1GJr7WpTL0NS10HASBtASDjAJRiQXSTXCnFfiHlFFJJ3Oq12kXKKVQqJedKK8NYt+vD9qct441/XZuqhYvd8UKaErfnu/UyDRD+M6bmw6Rjar8UqSJySszc1axxXZazppz5hIlxlNEsy2U5RuV/ooNs6/9jXrS+E5OWAUNqxCKBfyuCAKVMiyaf+DrlHGO7fO65zUyKeDMKRCNKl+/1Vxr+2JWQMaJQjJBs71PR5HuGgI7rucA38dbL6/gHDUpUwFusk3PsNXbrxhcP69mXsHvpaN350LICETBgvMe62ansqEqiIPG48Jea5IryP4Jt//kzBKrn9x/XnHMuS09IT0vPSe9J30r/yPSP6x/3zIHMm7JcWZ6sVtbXbKuFskcvVJ++X4688aXX3j6q6/cU5s4e9jgnR/t22WHvwrZj0sX1HLaDG3k0xv4DENwgRsKR3RzauX3LNkXu37tn99odO3dt99+2Zeumze4b3TasX7dm9aqVK5YGLPNa7ukwafKYoVOmTps+Y+as2XPmzpu/YOGixUt69ho7cfyEcaMHjuoYMXL4YGHYkEHtffrm9e6W39Ja19apobG0rLywKDc7MyUjLjU9Ps03KapHc2x0cnhEZGhYcEhnP29Hpy7ONrb25hYDLK0U5poWGJkk9mBAgxo6VNPknjFUUsT9mfw/wnvgaJcZyanzbaJGj37uN5h9l1un1umuMlWTfXU1WZYZ5BniqrvDKZGohSjjDV8OUBIIV/4bqC76ohrjCg3APHtBALsIgt0gKHYQDDsJju2EwBZCYhuhsJXQ+J8w+I+w+Jdw+J7w+IsI+Js88A8R8SeRsJHI+IMo+I2o+J1o+IU88SvRsZK88DN5YwX54CfyxY/EwA/kh+/IH99SAL6hQHxNTHxFLHxObOxDQfiCOFhDXHxJPKym4FMkPvAKheBVEuA5EmIzheI1CsPrJMIbFI43KQJvUSTeJjHeIQneJSneIxneJzk+oCh8SNH4iGLwMSnwCSnxKcXiM4rDnRSPuygBz5MKL5MaL5IGL5EWL5AOz5IeD1IinqEkPEnJeIpS8DSl4jFKw8OUjscpA49SJh6hLDxEBjxB2biHjLiXTCerHOBuMuM2yj1uFuB6ysMNZMWVZMONlI+bqABXUyGuoSJcQMWnVdlxUAlwDjlwLpXiDCrDaeTEKeTC8eTGyVSOI6kCJ1AlTqIqHEXVOJFmYT3NxrFUg0Op9vFWh+uoHkdQAw6jRhxHc3AQNeFgasYh1IIDqBUHUhv2o3bsTx24mTqxgbqwlrqxmHqwhHpxC83FUpqHeTQf82kBFtJCzKRFmEV9eIAWYzYtwRxaikFahrm0HNNpBc6mlZhCqzCN+rGKBjCJVmOU1mACrcU4rcN4Wo/R2oCLaRBjNISx2ohh2oRLaDMGaA+G6wtcSqM4msZwGZ3HSF3CefQ1zqfvsIkmMUI/YwG9wn2U2x94TUYOAmTkYZ+MEjwiYwhTyBjBYzLGcEwmaDxFqTiyKsZ4gUox5lEPjJdoLI5OtBnjEB3AaEE3cPRejwBDyKqOYVEJ4BW59bCF/OERkRiQoOAt4ffUArgFkLFhrbF2FQ6rT8P4J+ERijCEhaEUc40QfCYC9hShdPsNkqm6x7cwEkVMVQTNOE+PubCEIrwUo6Ghiq90SOeGZlHmR3k8ahC9/AYJ1xjpLWIgA8VIKWLoTYoSNiRwHKgmSMVrNnC7QWBjj0rrxQYhFCXRFCosiyll0oESeVmpjEy40qjxeIYDNIWNXT5QydyKatrZGUJtktQCTwUFKBsdYLNtxOFG2508tm25kZl3IRZaoo3UIi1OBEdTiVWqI9RO+1yIYmPyVCzOJsYI94gumOedi/VchHj+SA8EQZJlrqU3SyFoiLou2dmuJiBVty4iawpDANpeomfKlhaF1gwOZLNa2FqOnyFRMuX9YWcB1MoA2ZpjnsjgAbXxMUoMAgp6iHLKlObufqExYqqBoqrfqmq8mwixR9dZvRTpGpVma1PrveSIt1XKzh4wTzUPTVivb3mipadL4eMCNxuYzTg1caw1BswRa2QjFTLVua8/tQ4gCH3/KZxGviUPBkHVKnVp7taLSd3fDn1dUMm0JoqW2hho18j6RcSWAbsxfhSQ7e3qGO7oGu7s6pcK49l+8FKC5sqBX8QZKI71YDGUc2q4vu7o6vLQlEFRpXuIeeDXUyksqmhUYm1d5KrJa1qE9cXqw2ijwiG/UXYRcaSD1NmcOb7MrF3a3truMuppKxujzIof6qGTrZNQa0EYFCQrIzJNUGaYv4HuyXEONK42BcoDV0lugai21BQBSKMAcGB4BJUvol0fuNP76q4qCSF0JnMZt7TAlyrypisK4jqEvLU9JwZ0CVFikIfuKe/nZ61bi0K1Qm1oZEwdFDumJIowXCKHKe+IySUcoRQw2YQYhYmssxOhQQoRY3Ss04CW1cHCwLuxbBj8WolwXbVYq7JiNq2/aKUrcfHjF6/ae4EAA0kSEYC1i5TpzHgJWDQ1WxSsonksS0ck4pha4vOjd5ytSNkiLZUEn1yBBTIMQx1I31B5us5xrixzjP29pZPMsKSdgYgivUI+LokSlWrEl5wHC8zw6nPefn5jvIID5jRWzubWFZdHShZrSsN5ME+US4xmWBUB+s2xLY3CRK6AxSAF8RGS6rqnYsHJI2rew5a4bq05G/Zmu62RfUA6pwelRzpgzs8DiHBwISVsamQO+Jcvm1D01bSbR1VJPvOjBEMTwiz3TZI/zCSa9wfOfAm/9DV/xTmy8LgvtH+8cDoIaiJn0lpyxFBWpCxqfqmLvppU3O6pvWc1czwngTebVnC1KZHdFjD4au3FYuyPZ+x4s/LAfSHlv698E6YFEWVWwJXkLV1R4x10mW0zFUyDpzRcrYD6DZD4+q/tEettAQFb/lJcbqAmKX5ZKaq/UoG+Hh6Tu85BJ4oPyOKvquBqFsoCW4IX6XvTf+mLrdOBlRhyjIcmt7NNreugyK3ClNnZFpgCFle5AerW8CYQLA8wbzb/DzDhwKbvvH7izGRzehDXxZzmgyqTqJ9BrEia03eGr3D/cSk+s6/aXe4oKz87ydTLqYXEqe2F6EPmXjr91rLubZs/eH2omBLlgAFzDCp7995TByo9LgW6QywVQgjLFKxLbJOCYS47pci9GBed0rajluLAByyJCan6VcRKyp4bXWYbi3iFRFVN/ILTS8WvwH1z+ceHYP/1INOUMTDPnH8xKEysOkUITf10c2/87iSvP27DZyLEioz6KDYKM+uV7N6HTTq3mEMMjTnCpqYhbJnDuilzNQv9JN1KAXUS0JiPs1hysX4S5BQDaAjwz3SvVcs17LrjmbCq05krsc24nCkSsQDDQ9bznDp4okky3orUzkYmI94xL5LPe7DzJwBiSITd1/WC+nt+J6hglTdDPHr5F/x4s1GhwLDSRRImyWb94Zkn9LdRod1d9It9wbn7xnv7M/z93n/3y+QCzS3kQ4BG2LRJ1tE8qzNYtw27Kzxolu++sR/yvFcm7y43/9Mx/wIZD3xy20TZwCN9ol8W2dAcA2EVwXgx0LmYgf2dWOv4wesC9cxPjQlHYCPTlLmCVcZMDWtuN3pJUIExvS2sEKNox83SKsRrPWLCPTzDrC5kNIDsZrOjNmQoW/aWepwkdKiDHFizvC8dI6w0sCZy/Qw8X66SxyjW9S0IhC5UnF98CFsHTjrQDvr7GEs423vzAmKDPqPXSs07e5VxTGvHrX7CZB1/4FwYZO8OnFEyWlsvd/IcbRxtpvgAnj/3/v29CObZJB8xAPCc2wkXBwuBboW+8ctFfoQ5pLf6bnWcW/+y4l/rh6BjzKnb9ITM/WCZX1sepNWjNFSOtZ+tzysLGz/HVWjJRwt4Xb9Gy6WZeAnItR91nt5e2DYZYQwxXInLOJ2L/7ljel+9d4XUY/UHRDAaLiSIl+P2hxCg9N4UujzY0+qFU8ZZl8JmapW+VxeBN5ptf/TWQ1CiQTxAXZl/kGHHfPVd4CLrZtPWT3my8FU/wL5ZgPaJJD0bB2rBwGVM36FL9RA2l/PhuENIqiAqaPJG9Vwz4fn1/AJ+jcMdaimhG/mp2oW0mz7qJiu1CGKsl+/UKX9tOSD6v2EuxOjyvcYmmiDY7/7XpUXZQn401y0RIqqIJW6K+noj7LDfk1+C9H7I0QsBKTCmwEpq4SCslkOdW1Ud/YFW44nNpj/qpu+35f8IfqFPv8Of7urwiJS2IMPCU4Spyl4BDymTLF9TIzVbHOY5+laxKPoHQU1a/03WBAztb2/XqBUvP/lnk3Lt5JXK2IxRsAl8iGPtbR8FzEXye/p4C3ePOu+vvAyGvwRUzDk9sDRSXmgAtlOolw+vHi1XeYjNwg7Hj1Lh7EeXSvdcSIUny0+Gm4kGiKAtdTBHpFYO3r5qvcPSSKC/EY5NIXtY8FzuXlh4QD7m74tRFjTCQLAjmwlzv8Msrtrpwco6pePOxoZ/2ULzlMuGA9iHktM/OZb7ZsYQUnKs3wlTpt3G0cl4ltz6SK5JR9RrGIOtscVuFiYNlo+QnHcGaB39dsHaxCqlQJBcK7g7BXAJL5r93tRMrPq4Lv3jD3uT9gn+ksnH+6J9xC0vC2tamplNVbuvZu/GBZk9cn+tuhTJT0U5hk5HeqZ1OtliIaKHmsXFxgyQNU35Q/EbmuIYagMcjTvjssLzKJ+AjWHp4guHlzthPSbEMOcEqgQYkiygY0PwsILzJlqm5GxJ5UGrdNmvNI6ql1k5uNBdLoHKDoEvXEhV4b+90Oxfnr4UWe9x0zLtUjeX5Mu4on6QcTOl/XMvlOIUVlMr+y6b/rmdMzvm/T8bT22/cHR1f9bxFFFK60tf10U5X8BsR1L5dBz20gJZKlaRz5E1DNKIRDvOboQBzDBrcHJyutoM3SSXq6Qw6ajOmCd90oZmL70r3Q1ZvvYodOu5TXvDWcuC7jKhAE5IJ+5g6HozOlDQPQr/+/+CP1e3TJB/85Es4pNt8vE2FhjWcWERa4oaHC5Sdoir3N9AIaYNERDqQCM+6/p9sZz8mluCsCUgL26xf8CwpjTc+iq3CRK/kZFGDDdmy6Jh8Kza6ZYNu963Hleca5SS8B7BzCnv+i3KU8Fq4LQ6f+tzaViuf6m7jkPJVE+BXYeE3rxSaIb63mLAAFYeUnqZyNwjD/fB+Sacqu0a8N3HTWDmyaj65eGHYxDwB48ax1NVkUpymQFCkEFWqLi00RzPuUADvu2LUKSQCZYZptWq1svQy/K+UAhnIcWhg7qZWhkIim0zVj+7QY8DLKbuDoU37mYa8cKdO4NKwqOPR9qcspePKvT8r1URhx+NqkrzSRmA0ONJc+v04xOigds/BLRtjF2XQodD570EBP7xM3lYcFGnrdFgTae3wKqefLnmjKiwKyRWy4EPbXETdCs/k2zZwQFiQbD19s4/j67qijWU/ps3B04Fi9jVEryoXlh+5DM2YjYwly2sQJBgMkOOZMsj7TJ9NBPpepHJwVRmO/DgkJ3YbTULrM8IbC0QNALz51zVilk8Rwc14AFW7YpxChDGhpWAxuJNjsbONqqYog0sasW65jCkgNrL9irgPpuTFNgCqophjyjvpXshbWJ838qw/viMCgcmFJYp8EzZfELwzqYMI6mc6u8bHOobGerXWrXW9GwWYmpYPJmob9BhrcGl97ECr1ATlCiR/g6Poi/S85ppmGaczJawdAprktOl41qdA8v97Mo/q1008oSPgd2OYfGZGYaOA4HiRKfD2OfCGyHCgOg5+D5B6xNXxpv2iEYzEujshUuNQcvn6iEbTNAxyxhqcbc/cmHmTuVJb7Sb6R1AFEncQoHGRlmZMHK+0q1gfUReqE2iCdTuq7ilYkZKWVMYVwHcX0dZC/5Dnb/74durh/G55mhl/ffPnU6PyCbs7vJakWL2nts4Y2WzSRE+FWGhqA1+ubdxxjG40FlT3LE1zRcLPetVBJgoSupeWI9SVK4WqW4DtBmYSW/pCHv1lihYDHJOV7NqF2NdVIfnI5gfghA7IlFOpaqMwCVOPMeAxTImRqWFKeXoJeBMSjgD8Jn9wM3puKQA2qI33Fzy2uwjnQwvRPbxaL1gwEJ5VH4epP/+bLOAOnENdAg5iIhm9rb2GTttxva8oHJM4mTy8Ef43OfysRdCJbrfRR3lhIhjurFBZP/UwSO9zxs7L88c7emRTwOTBw4ff273MEPQ5Rar6jFtV4cHRLhZotqQ08wz99zZ94gL43mXRFylORhHR9wn3vRE/Y23B7DfBtgnLIPq/n4M1gMWI/19WKPCCt23vzAH/MbYFi6jvN9UixfWFeHWvnOYqC2KKN3SAs4g69aenwV+88ZL5k4lFOcZCWjqGvM6vbAxHGVA+5kmZe7IHODVhFWVXP58rj60AOZlHxsR5FHIwjf9JGdZVsa3bs1q7XJ95SA5yMFzlE5Im1wXjk4Mw8lnFXSPle1Wp+q+03zN2da62Ncn+F31yLbQtE533lJmQDJABoarTquWbTsgsYp4z5l+Dew6qbeWp4zajKXXRPFnDUSiCO/MVX55KpQPIAh6LVT0Gy0dRn2zAVq/Y+gvGPN5ZZiL12a+rWnA3qQAgTmmFWO8qhvPam231TVjV8z7nNXeMk1FHbfZkKaN2N5mPSQhLdsBRe6+k5YHccCX8A2U42IhMTi/tq0vP4XHarnMRMP+cJQ5ZFz5giVVL8Bj3PrO6+XR/58DaM/pEtNzq7nl05PfG+C/xM+pL6TdeAn4rnrYsbTNoDUt0Uba7WlOLu89vas3v7Y3bxrmQdOqUDlRjuQjk521ILa6U0dd5CUqaB6GENv/PPEksXig0llJ7DoKfSqBW+0nowX/FZ+kaKIovG0U/BSwION1ORBKrY9oZbHqoaholQwdX8Ey2V28RRmxxFK3b+6b62vMoEAsj48RE/faP3jjxmqQC/S1xGKPS6UEiRefznfPv349HZoFGBK3tXXxwLXVIJVVyztuBheoTNbjFaoCiFcKVFNnfGEGDAvpww5hNEHMrK/W/OIrD6BodtoikwbT1jh83HNoz8EpJ61mQFBFpmDpm2nqgTtBLCSz9YSjWfm2JgxYODbXSciHOtJ0taep1cg/k+CdKu6lt8n7qIqESfhv2bu/Fw7SBAxrKRcBT0xpn3yq+mgT53BBvl9jfC5e2qlObst3eF+pR6KFvdGbMxtd9dj0wPpbpyK/7Qz884W5IfBCWvbQqejUdk2QKopSQD0cyW/TMbXAvtIMWRuaWUny5MX7Z4Rm9WiwVXk2wRIoNh0r7jBt8F6yklToiZ0lY6V38+idhG+V57n3kiR+Pj6X0a+5WVSuosR0b7337UCf1zQ+rXcV9+2gLhwqrIdHdxR35OAJytBLvWfHFUoNLO05wzGozNa2Tjmz9lzu9EjVeNkbfdaZJWflnH2+s/Cz/+gV/qXGYgUX8gm2gMof0ZsSbqVSQKxMRFFvYAg+X48ZtiApwZDGFsjHYpqaUhJAkzJCECMoA0qNtPMgGpd2Q8zQT+QivrPQnpwE1tuuVmpR3eKcKIhnXsAf8alkBMPbnVj3zihzXuL6YBRhDj6JPixDDIlYBepmTFEBzMjdyWsYQMIEADPAoelknDpXMdJPgI+KpzNHuWgG2MoVjuUkBqtNPrYhhezwfBF4nRSFakAZSny6DNKFj3gAgzSeggBB0qwAhgxHoYnhh1j4I1vlSE3XJFDqFsldJl22k4DgCpasbB1Ru89WeOiq1wSk1MFj43tho8e6MVQ7SouS664+7dXh/+jYp88APZBa1/x0+N87YFo0grXqoV5jGmNEwiALmhfbjXCgYTrfXK+0vwkx226XkuunhirJSlpSOkKjBl8kw1UY0CDLWxyPOWRYU2YZGpGVQv51Rs0x8gozFpCDlggrk1hg5zw40Td5w6M91Uonxrhbyoqx8sAXK8OVnsW3bpTv5FjXULdPWWmOSmrqdsSFTE+Lsf+n4THXNOGmi4MQi94fiv1f2WwmckHknmvxr0KmiURkrvtSHx+5LdB+Fe6fn91nEnXY9af9tcbE1d2nZedXIm+82l+cTQmY41g3Qi1WoaLyuUgLfN6YYXykFya9+YWYAUOqeg5IHy/d6dx6bRpPTmmMnLsEyzK1VvaQIoa0DnLKeTVZSF6hW3PUnYsPvPa6jFXh6aTG5Shj6eyb9Fe2PHu7oZgMPt8Ev2aZVs3FxQu1qchfVUklgzqyucHYClHc5JCISG8ZaYY4luWxVLoEDkrxYTgx4KwMA5BG3jHr1FL7hcjCywoDu0qaRZ4VZiUhFVHZwmA+eiTY1vss96K6pDRtshNcSgyVdYAYAUY7f08WI4vT9biUMWVFqC+TO3XyeZ7xL7IFkDbABmxUQwN8/U79aw9FXzCsrJIyai4u+y7o96BRDZKN5it0gjC1WuvtNh4MBvUCFcvlBCmm7gfZcoQhfv6fUkqjYDQI7Wq8iSCvb9wN8vw9fGhSMOx9gKI9k06dDZCcc5HScGdvyWy99Odui7EztGns0kCxATuKlDlxtc5kW3VaND3MjNSzTtRQKNiRimioA51/8eHwJTu8gP3JE94nPNqcXXsoKLyLI+liamTJ7UWSXbKiyDV0IOCBBn0tdaAWq+ZS+l/vau5wBSfh/IaldbTrsRp1J7mVy003ZfyoEkX25W6JTB9RLdJOQPN54TBld1j0tqGogsr0W5RHK46Xj4Rq91KO30sIJJEOqesc5VgZm/qQu56pJ6uvbStdAKOZfiKjToKVPKGU1uvUchnayDQVVg0aFsRiP1OtM3pCkHpXyJUpdQY/0srroHVtAzNAb2/IeLSRm5YgGhvMRVKf05cmndF77uvcVN2YBn5mNX2ysnxacZPeUgL0ffCAuJ+u11cEvS8KVGq1KYX99OzKQQDh3aVTk3nFnV1fTirPr8xOx+Hk76dvjSpcDgsB8zVdhvKaFtnY0D0VKqVIwQfUOglVMrQ2c4sOT+CT9/a3W6vDMg/E9VUAQ0xxeIznGjYZ3/rvUvWJcaThgpc4CgOVhwNA64cMarQWN6vOhuaPZyR94U2Gyh1r2uS2yd0FJCXGsdWcM0JbonT/q+WOuwsXld+Sj5geUIBn/ekieGKn+SF6sSPyRGBEZeBr12R8o5kpZ67NjzfzI7cNzR8E2fP746VM/Mi2yW1WdCp4GpOl+J87Z8zzJ65kJKX78tvuLnU2yRtxGZuOz+z88czSTcdSUjlm28ZPB9DDCtylc0082geXqcABNUFx3GP6+WiOsGWOW8yxxjjLF7g63U6LKYkEvhYgZ4KUHMUqj/W4GulWvUc+Hy7U1jHKwxbq0/FqpmcaadMsNXI1rOuV2tQk0miKPjChc957dOw2HdILro3xclRFve/E+G0cB2Ppaw6OYemN8hYUwR9Y2AtgjqHlF1nL3TojrZ+FwPjDEX86xLMMw0qKq12gH+iBsw/2FhujCqkQKb0ToZ1rkkstB43NlIRUYwDxi2BEvdTA16YbTcLobJhkgs88T+yrd62EMLHmi8Z+re8h7vmR00FCHZzTqPx9y2Zh/pXcVVjD0R3wS7msCTuEONUkFQ8ymqi3Ry+sbvGSB1kWYikOMqufKldjk7Rah+NbeHXJhLc8WaCov1c1sKloaPGg8pJ4MpFbzaYTX88OC44GsT4JPDT6gtgfNjgsTff9kxWw/vAyHr9jmiHKdPfVbLYu/hjRUrYI/JXf42ZSFTQBp/EfxyHOSN9KtUrObQAJSBFxM0PQFdwGlexi1SnnR9aRAZWPpFgN6CquXc0FUp/IeEnlpRUr7SSO1xIRGeudhurvKI5HIojeiq5HbzduGx0BSWhCoB16PUbd1azL+JC8GJkSiNd8/RhwOkI9qAXEEg95G+D2iCu4tp1HdpmSSuAM8603Yh4Mghi7HZrskJ7gVAyzOhsjrUSXlRpRgtrtkyYw0w7csqaLymvyeRCLtuAjnbVkRc3WRuqK6k5J3+OYqzHd/QHsJiluwCBN/UuAdyvyx5F6SsAZ1EaZBpLEeha0yymHo1NRtbijCIZ/KNQ+YkQt7SztoBn6UaCUTa8HntGD85xhAwR07AV9XBWcj95h2SSP1QeMvp8EGoSMt8SVsabmv5n+nQcIWBzXjut4AorqwWQUIsO0dXEEOkJI6iIPTtkuiS9cYuz8noaJF79DvQBawNpgCfs23bvxdihIsHdMsMr0oPm5nejz9X+ntn8YDRYD3TZEMvtXF5PzBwcgkmBkYEn6nw0ZqWNus5qt2qKgKZuFikzDJsaz/qWheMO6B60JGpZxUJXRp/2nDOAu/UIWs+2xQ+p+8p8V1LzWNgH1sdbiE//dWBUOnl3cX0Yx0c2LU4hTgDJiX8JkeYU5Tfs6pE5AnatSlhZvPS+q3VYVkgp1mdAEsy4cDGF0I6R5U56sHGqMXZGDw6ZuNpRFRo/GFqnNpsulMAPyE3q6KtGCsnYNyutiCRT854kVdwJBS5mGuW3mSkNXm4SHbuZXmwiN6u/rHoflgHcIpVnihHOPkSqmrnlngr9fIShqzNmzMcPUEalAW3tzacAIpE9STxU1A+p5qB7R8x9F9CEDvNyFBQj8mrJ8rJ5W5CKQAHD1Ge3hQrKWvJDrMQImqJpPsMKe2sg9D8PbK/uKBPBSPVLFEZJ3TcTsbGA5YACKNomxV+GI0NTtXlN+HiPS4RYHhQGX0LeGHp7ElC3WhTW85vLzYi6/WsOizkXPy4KUJhjAtIPqEFYgY5PL8wy4tPsihEsb4fM2sgodYEiRS8LNpDlVGdUatel0Gk+v67MZprCTJN0+lwzdM9pRWzYlLbJc/Rk6cJKxLIY8zlWZXTUSe7nKWegCR3NLrho2ctemrzp+j1GyY2YtkDHuKg4P1m8LTvced2JDTBHezNJ8InM6mg1ZaNSY0L8x9a/byMPibIZx3UITtGRIFknYV/y4LgUC5gGNQO/FHDEWcYSmaXgSAJlJvT4vuMIERF58gOf4yPsjwv2GAS38l6PvechXLx26zVcKYZ8Xj9wemnf3PRwaiLxU7+9/sGlfPnpr0wKG//RXDt8S6A/2KrL22kq8QkJMgQRBBgSMhOMZpIMmrs3ahU5lZKFptRDq+5y0IFrzKednj5IOfIbXijVQyrLRAR2v1Ql6qYkRY/jfimQGGVJAHNlJdCQw0DRGL7zlIGVhyrBcP7LyunHD5lT+moXu+UOTdLyO1K93LO+t7b6MKyrq2CdO9PDN6a9dwJXOUPkQd3vcA0+IW6s230C/9qztObN77kTjxGqmkfF152fR09vxg00re5H8LhXms0RUsybFHUPEfBiRn3K1tQxpQclNKqPUyVESBpLzCWFAAxN3BPNaC0nVO0xBQZhrTGENrthRW6o2OvgFAYkL2HQvbYbBoqYM3USSS4s83F5Zg9hFNCm/2XO6es3jL1kdBrhhBDRAN/brMeOE1r0lZ6XLxrWRc3Rw/v5bR793M/j2SrvpyJw4fmzNOl7RHMTTe0vg43NehBge+7H4xyf0h9Qs/Yn+Df0Fd5mj5mHFAHmSDfuEuVd51vq1mJFEZrfU5qTb5/7VVpkPsqQRw1aD/RANPQVNSHd2H5DVMjoTDHKVt7bbMKyQ36y0s634w2z7DZiX9kCk4CmCNDpQG8Oo++6cA4dI8k6XD6bFGa7baxe5gjIG5d1RFWt738k9qqk48bcbQ/OHvI68X8UgTiyBZO4RYHh3qWOXqcyrb8sXmU01JnlSJYq/lCTOZeR+MJdp9OinRizYR6cDY4HqqCOkQWuKBWW4/diPm+B4zZV568xNYT0wKq+o7XclZjgh+v0muPhCoPfwacsHX4LwEpJR+6N9HF+aELQh/8oAuPxSkBhEbw5biaFsB1N2LLAmk4UOODYydB4wQsb6nR55L9SsNZfJ8/s00Wgmn+ayKGmQL+fn2LD6d12KTdUWKZWSWyj/W+3GhuMF4p6L1NxhDVPSxp/nJnr49MA+I8pIG+vUIFbXX1pcnjo1vzId1wrrSe19XRs35VhXM0fZGTH54BdvJCZDlll8xNyeKWUJbGl13av2CrSPag9L1vK0fuUHUhQPVYzgzZO0w5QjL75cTF3HuZV954Bvzj+gcOKX3TH37KlsG3kgDbIQKotN4skTIe5qj/feNm6ZufL7skQ0v0jD/XccC8yTYoMks7JVm2iHFHbzbV64H/yoa/uP5vLB+V1hFUh+19s2987ftiQZfOhvbJ8Op0B7mQFfg6ZbKdlIVmOda44AOJ1bKmqVBhg3z45mB7bMlnYd9InhCBITVO0a71WhgzTEyEEukNSX7UhjqMwEE+T9svX8kBXwS5wzhBjzhJS94EDlNZXzARsf3qtBY4XacZWtwpQ4yXlhNzykXx0vPQOkpGkZpuE97tIPFObyl4mwaVyGqy+BbiteqIwiwAM6n6UpEaLNkRKJjLtGtPmsMiKeFkXilNBSTgz2CvpKIxYrpgwBgKfmYjxe6noZGOWElPi9WjotS0CruIyAzmfu+Nz8SMd5GoE81rLxrxMow2rWK/StfN9zHN6JLReq+Z0k7MdIXmHuwl4jWJtUeggYm4Tf8DXceVKTGinUv9iq5LMQoGDXZvPpadTcMQh2TWYxAATToZvnZVdgm5lDHXpkBXWImg3+K1XPkGBgjr7xo7ne5kK4tQnKk3hKdw/jY3v5oSoiswBhdDOFSNF04y7VVomgZAkznDKX5tKEXeiYlCGGVwlFiLjxGzXFdJNIAD+NgnZKJ6i720OkdztISPcFJWgJc2TgBiWojLaf3RZJTz9P6JpGkIe3rxICPfylpAhnCENIHCGi4cQbSDnx2pJNWaVEwI49GKkuvj2eD+USMrGMozwaURlWJndVOpXubRYUEDxBISLXYxAsmjzuYk2RUSnUAfMKXaQ2PVhkyn6VIaYsAoog6MXBPHop5SAFJ3M9lARZhgbwBzQH4LvIUd75rSOSnHkGpBT3DZVSeDPXY8nAuzCuoAgxEJ9XkOWLGAjS3XWKA8oSO91pCPVQBqFP0+4lgrI4cjGlycnjiqsCej6JZYmUMNi/FFaIBloZzfcWY6Gp1ZRhhgvZNENExuASYhg8qCt2mePKalxSeLVD57hBY6wDczVDPBTllLpUkDJ0QGIXCFJGSUyppICR56OFJL1ikBhiqVO7Aa6EcyDBEirN4RIV0MO60nb3s0P0QUySu5ghE1OZia+C27BCG4AEU5C+SiSBh/LYR2BYDqVBCUMlGvNQv8MQKyRnCBBwyCn6uYVwUI4rmk0EIVaUY4bQdBp5d852LNVI9IEdxCKN1/SFlEA2iNzo1HBYDxVQyp6q4lTFJWeC9spfyCtPSKpHDA/ZgMBXNCjHbQiPc6M4lfpjxzQhImXHOGIIytjs2791INVRPOikhINgGSGmlRMKJCNkrJHSRfOKhVkxYJ4nzTjmktIpLmkvxCVtzHR9BYUcAGNNS7fNxIqx2uELQTMzOT8I470EVGhTEYPb2+LafEfjiuIFRPNoC1JE4tstrTURBEhA5W/S1jVMYQo2bRJzKildTSuI5bNtFrTs8oQCB8L2tyNCfMCnl2wQ6IKW7bKS5lxtcZATChQxmUvKzW2k+ZNNGjDPH+WJ8h50OOO741wXbqBdWYMEW6sdXvf1XhEThEBN28GiX5uhdEDdZs/TYqZa+FtDdrV53Yir+jFGh/5iWecwkGRUzCFA2FQ9ky4BaRwD7+TYTzpxXQglBEjpIqJQN9nacHF1DvhZo6qTYqxIX5FF0iWq6N1x9Eum6pSJeHNO0MvBHSzfV0As4q1yNazz2jyuLaEXWQF38gr9QLqYJ72gRFpETdmgbtolSGUyskReFkUq4wsorU4bJAfMgGNJIvf9/OoOOV/O7FURzlpUTN7qsNOyIgiw1eAvHbgONFTm+JIfHP9palfktwLGhW15xMqw4/zBGzElic/iA5W33uolZZQFRncHirXNZ0pp2ePSd+4E98gXaHoyRvWGVSUiVtwBRIlK8sczfzbTd3puHO5MUjj+S+yrRFdXKvV6ykgBGofvjGNqjcdjhKD4bwyYnEjKiiQiSIqccDdEKBrFmO4PinZqKxzAONmJa+/odh5FC9IOhPwalm/T1/tsj4LlqToVlOhO0A5fFlF8ePIvkY1YbAdEdV3nH6+LSZAnajCr3UnpANJTla9+wLEQa29MuyY0ULFxYuP+WTP1qyWaPTri4V0s1VNrNsVsGxY6gwpbBUNn/ACHhGAMI2m3lWJY/dykZMfg8qnkLwf+kjy1E4bHHP0TKWKvzMB6aJxT2hBptaoNuOO89Z16PDO77TyzUxsZnX2M8lDLTxe1cdNmR9fQyhDBmIpMbykfwJrskWMAKtcbsOO4pv3E7eHhW23M0CwlRgbMnYOHn0kdfDqlcBgDk/93GGgseOgFkx3Nq8l5TtKVf4n+41MGpy45M+jk6h/8Hvf/11JJxP//GcOs8HYxRlhITKgEBGXvjvFjs3TtTyuvL8hMOZ8xLsygYWl3hB/XWHLBEgnMBITtWFGmsvibPEFLmaOrtEGvcP/XhYfw1/2nf1sNkJ2gNDBZFglWi/2hyujad9cOL+easVT+0JJzZCWWHR78x6em3v+pAlkH2Fztj0V7PR0nB5QS8rw+qg/zGQ8S2IggvjHa/PjY6McTP308OvbJ+JdOytDK1589jptG/Y/zm6NUePURgHXY+tnfOlxnEt5wDuv8DzTEYLdFqShs8AxGMSCPHROaUQzZU1aovHM5rslOq+2a2yY95wQ1/+oBQk4UwqqaSVcTk6PleS554WRHx2/0sVG1uz4xpgvQxye8R014Ltv/MhjhV5325Tyq4G2GqU/o/9q+fOTx1d/aIHWL0Hf5yU/WR+4bMOmbTjRAd36Toc/mDQ99/dqV6Bq5iF1wIr1Ny23p5jRJ2tNOLMBSDi0VLFkrXHpgS343ynFpKH1Bc1n60A0jCsuIZqiT0/y1yTgQ+K6IoWOQ/7tjkXgUdkHbJ8JILLf/I0MYOp23mWwe2QbXwSXQZpBisWGrTwvXwaSYab+az9H6sCP9ZLd3iMEV9/95DvQEqUFdES83aGYfMzVAnyhim1RqU5BINeJDvExbBIFOhaW8+jmDncUpqgKF4kCtOoGVDwHALwdqZGWFZL3JJiYLEwVVvdFbciL0hsZwHdMRsKLkT3Phsi/qV0FgT/e4RQvlN+OGVSE6RBbitkiVkSOzM0hWA4/l6N+IhCUD5XWuG0e/bYWtRObRKrxvaKJ97WsjlX99fywsyTstwFaEmaROYhYn9kbY0tKyDPmiBRlegZhJyg+YtAlnTs6I+p+lj5AhnV6mbbOK6SbKEkQu7GrwjQFSpSJHVIZQwU58+LuRtjKywTfqWy0CQi3LCa9WZsy3bhL+5wuUmr0Ha2pm6Hz6n/Rx+jS9ijhLQXVbiSaZ+Qh2dvZchCoNYY7acRnuhFfBzXAVwixoTgSIH31aUYlXz2kk1gVnz6p2zf+FW/SnXFLNWqtMUj4O/N8o64KbEXP2PEmZQUWzxGyPnrUmGE1FWOCz1vIEGcwUz61RV8fHV6tr4ALDhp4Z/iyvpZEx9zGxpN6NvY/F+w/6PxbcYy4dK9EoPUjtS/ZVB6lrrKLAvZOLmYsx94EtrMGVz7NyFy/mWnn5rmphiaBoaKmDCV3vxi1mbVjwUo3c0TIebMuIbvAW+NFi+95ugYz3jG992xfK8RN4N0Rn2IKvtO5QIdfbAqGwiaNxd+BzEQGHkvaAZObWTPD1uedjqreAAlzzeqiDObRUUCQsqXbx8rnWxYut3ALe1CTtYpSRpdKSETqDGA5k28goeYkGlej4luRlrpWgnLWzoPr6ek99XZ0AVtZjQjpuVkhprw6hpQeB1zWt7tgypbIs1v1W7kpnmcId+zbqVCic2o6KMqfSKmp1elWBLE8qtcoLqpIi5t4K4ZN7xA8WiPgr/9H5ppg5K5Lld6JsETi5J1WUu8lWHJ4dlpkZZggvzt9kEaUi5s5WVSXEV6lm90IzK36Nqo0ulhUWyoqja6OKvCwNSww8U3BRrT26QCYvjCquKww2cQ1LGsGMstUVWxYTUxbrekvwtZfFuGLfumTUanWlVWqRSCxS6w2GJRaL5Jn5BlNq5s+Z0+w149Xs885pavae8W5umgOxqflCgADWoFsGAkNaLr+l26L5sxaFvBlmVj57Vnv5MBLLP+jWK8vKlOWxHzRiG7+mKKpAJiuIKnoA8LUXyIqiHjAVuL6FZA40Mynn3HTYOAzfa7uo/3oW9dyZ+8WewU18PMuXRcCGJCWFCFn33NJEAumux+SGw9d8SHjqEvdy5SBkpWJWtWLFRuVyWkryMwWN4TblOdfRR6NHVAmka23lsU6l0hlb/r6bXE5n5vfubIMZdZ6yuHKFXFEehxourO12l1yOHiE5kmd+xBYyZCkxk9b+JgVyMw6eiMOcQX2LOoMRCXs3IhK9FmVBdganfQfkxn1zZGaZXqb7Imi7r953R+KAQC/o5xTYLzrd5WaKecFVP37BWf4MBLZYnHD30eO+xL7Hj0cf15YDtC9sbX1tR770Bgkrm/5+SzSbcZNYszcDkzvZzm+RvtOCAsaT+h4kSe4nix+YpY/0plxn/LQ71mh2UpxtaOyyp+v9XucLnFZaGxK/J7mA00UkOs3A5bRuLniCQz8rZpoPHuzzfu3d7ASH8X2PSLM38AK7OaLm2Z7xaXr2w69+exc5MfHHeAl9OtgVfGjqvFVSMEFf/folZZqoJx5yzjVN+RIwYaq2hYt7X1ZWpsz8XpMN/gHTwSJYDUkMDNxDO8P34wAE5KSvOxLr6wNSmOn7JAakbujm0pk5jlyBKSQmpS0ka0dr4KrE7OLs8EyRKDM8+yuGRVmZYciP4lKDMDMkNEWUVkhg+7IJpvj+XWvWRQdHYsqOVVTuD6tcWF2efyA06ikO1/TD4PqYvwb2TA7uiWnbtLcNu3C3ovV7auvqzBjpO+om8J9yJVH7roczv9NU8tTJhQsXLZwkWDx4SVgIwlajExtUv/4K2lIT89TxuBJ1ucS0IUmMy446+NboYXx7MDuqsefnSEzq8pK446eYJjCTZE4SJPL5iYKkEYGvPZGfJBjRFDkJ2jqNpm4hgXULZYrmBIFNkAwqz2cA18nxD2TE9jH6JBsYbMZiSR9DJayVBifBVLMYGySLGYL4DSLUxyDrMCb48nkLZoyYIrS+XYPeqVJbW+5tyE0bTmp1fVWgQlzqjnG8u+sHixz8dIX9etfSTtM5aAfUMyj+7eKzwcLiwekTTzi7/KeXPCVMH8o46w5NZ6dmx5jAM+7QjCkJp6ealis2sXz2bMXyTcALsAXQfsHEz3gR8WLMptL/fQhkwtSywzb8FIEMnsQ88PSdLS/2TfERSlyF2A5fvf8jUnEOPzu4Ybln3ou/lffTHoNBUSyz+Fl8jZDey0NpsCRYQZgltNSaFZTBru9iGB625UhcWnNWWkQAVPuFp6YL8zOEotTQPYkuYIrilBh2/1cCC2vA3SfM4WV4aWyzL+oCXEgAE628v07W7qfGjATtSFsbj1iW25uX1xS9arfaHXYh5/CRurwJyplvjqKK9KwFazd2auZ3rPVhXp2MpEDKd0nGH+Twf8vM88wipnKM3xXCnKxc45j3BVRO8kFd1Hze6u8hm4mCHsOs6tylEWmAGaRqdceVKRRlseVvA2zSqXDHtaXrvRNtc1K5NvdOsuctrdsqNYvFZkneFABpZrFVciVPkqs9keVISiL2qY0KIfELM0+hm3vRBFSdGRs4exmRCZPblHInpE3stsYbYOE5Eac5thQAlZwK4s9KgLV2iCtT4H4WsdPPJp1dNfkit0A6dT9yUHy4YTNlRUP9g48TZNZPJ9f3Qn3Ww+66odfW8+FEXNPPYwzy0zKSo/5h4wrIFmulx1Y6HB76gAt7ELg+AE1ayUluqU33zwrMLS8ItQrjMtYhI6NMeeGksLRQYZpNq5wmDAvWMmeRASNawEtSh81fFt4uyhUHnlsgOZv4yKNtLZ6Lttyv/JS0Q2hwRicP7tbViO0RhYc6KonrkfVgBhayrjgp2WAMz5E5ctUJ1dUJ3SrGDgs7HkL3bT6hWp0rc4TnGIxJyeuK/z0XaYyIMIrjWYn3a/7YkVYQxZfzaTv+qLnPSowXRxiNEZFqHVesbaLfT0eGUYFEnGEOSeLrlhuM5sQQPd+wfKdhmX7xFUbAKwzLjOK/9f11mvoFmjn1q5eMrdK92tDNGTiiD/RWHVQFJoyr/L2B0eswZym1/4UGvy6vJXv/5UOOJPv85U2Zg+30lfoKe9Uwy6c383SxIkwJfHW+nYt+/zG5VkvWptT+GJxKoRuzKfzU3LbcNTIl20in/FFSHA4SmJkhi6KiimK2xXD6oqj6SJFbE8xTq3mZAo8fvI2Rfw4nsH2YuC/S3fWK+QS2+QWO6cMmIPApOW3d6anIHasHYcel2Z1masOlgF+4R46eOHz0iGtM6WzVdo7h/wM8Bmf+3Ocv8R/6X6sd9Nf6D2o0Ws1gYgNvUKOdHvKXgMjzecgK6+1QMXpzadloz6eKlquntje8fbtzu/J2SiuM1XA8SOLzrJVBeXOaQB4jEU4/pvj9djaJJWGfIWZIULNqQf5nytEa3NzHNHnzVxPFizo0Iir10dx/XcsXfbxjC4tZj36G/Zj/b88kWu6m3406iXVe9zwX9ZCOzwFHk/U5InpOQ6qZIYXoF1+MT714fPmlLCDJtoPM+K1wSLnKp6cfWmFe2ToAp9MGWvG0294qUKfDCFJc1sBiP4tIs/n77yciZGPWoScLo5quvztipoPzK7a8O3HZsc8NIMFxlQvgQNPTMXHnpaIkR1DzByF5YE3D2K9qlMAmbBu1PDe4mXW0de+eozq/qgo/fUBiVrnEKs7NnctLp6zKXIm1PCsg0U//14ev8zu6Z2/r0WxWRzvLEGQsaFsnJ7QVBBlZBiSCa9SdVfwmEXexkBQF2c4imAILQtOfbCcrKIj6FZooY0BOwMkAa2mjyEi2gmxgrUr0SfbdAoDmKpaBrGAj65YVpNXwG0L+QdLs4IJUCqIlWchGbWmQm/PQzS3jGLW50ijIc6Mqhk7utycQH1bNFTeF148erotoipxrrnUJS0MGB0McAlfdTXNjjCPaXhxVqmjILcgKSw8LTRdlzqDMQeREchIdEEjZ+3t4eu4eF6+HvIerBxBSDrGHqCPtCV4sfw7RJCPtJ+5fmzOmX+t/tBQNQZsCjq7Vn88BM6p8EztrtETZxhPsUXCbs1imoGMgLSU/u7pAbt0qEO4KPMgqLZDd2RY4n5YuX78HjZ2mTWO5CsTMjPuafXvIKyI+W/GSOQBYo2JpM4EqD7Ifi8DHTz8Xm6L6hGL6QEZ+CoPnh2WGpqWFZoadyFxRiqFpPef5CPh/8ZkQKlxvSGaktrozPJCbMr+bHT/7u8xNy6xJ8wI9Iv3fEk0eEfB0rjrzvYo3qOb9mslTp8Mjp7Qe7zymniqgcd+cAKo4PnPlAfyM92/uM+9NfDIeaqjnUunzs0MXVCPn2YXfCEvmIz1ciUfSmo4OI0off1sYuLEkPD5ay9C4uxKDanFEL4AzFEeAwBmV3f7VDIgkF7CJugAdkVsCv+7XztFOYDXnNccx2hNaoYUg8VjgwZ5aMCUWSNJbQyPIAGGh8f0SJAT5Ne157QRN2629nf7k3EJCkIdQo5mjAdLzBeGtnnXqheT/mq9AWqNJn5rPUfQ0ena0lKvjLiSKNDzb6an3rLM2tZy6kLSd1HrtaijJTFqI3vuJuUK93Bs0k8I1XK01kKKJfhMdqPOQPNpuaaxbyIuwYCzw4N4tm3sKBT2bt/QKEAljuxrRES6sKwKtysXmgmjII9oZ2l1GNn3Nsfuy0s5ZILP27yxHq7IhhQxWgHdNrc5KO0vTOGh+pZl3SqtoBWQuCw5XbsovraZ9GYB9hVVWb3/jfhYG3SM9WTIDpO6EUEpIqA88163qUQV1M/idgd6ZycugF3oQRUCtR4FjqEE7ZgSgh1B49F50LZj83kW7T3NBxycvNyJH7Nk77Qeoka1Ootr4H3oQuR6Frx1CgYbJy8nI5e9rQDN08agh1FFgX4zG7DtcC1An3wpGWhtEHUftQRHsQ6jG3KTJ70Hy1yrxCzKZrYYX4kjWX99+ldYMLAglEtvt4o/fgQEkqP92BSxLXZbm8ie9zC6SnipzhqIniVfN392j7FoZeRNEXH0V/BPWx7OKxv+H+g8fsNkxLwxq550JLdu75Bmz8fWmPzc1Up+XeGvZnwSnGijfPJeIlvAGHAkPnki1tA0APA4PK640Bj8fO/YmsPyh++Fr1uGjnOfAj9rD9ntxiCFlHHrhJ5VxWraHxGOxazF6BcFa3svcLvfCBujY2BX/UP5ZQV35N+XvleLzI6hBj0EUVADSHbcpNzGxqrKuYY4oguQFkK/STKjMQKO3Knq1BrpdJzUwjd65eOQoGdGP7ifURzpCLXrt5xRWIhN2/aLHnhR1sW9uUAFqxxWsHyQz1BScqtW+Wphu3/+58QU/M8yKL0e4IYXEIAju7Vg+Ic/XHJSs2D1OKuN7bxjbM2f7iFtf9r9W716wHPfpDLkc8j2YH3jp2T+Vm/79t/KP7J3WkNVHbCHM1rX5YWIdKvVpKaMOWyCK1KFS7pb6Ck/sg31fh8w+Sc0OWvK1bq7f7PKi4Hze8uW8/OCiKYFv+/Ll+byi4ClDXmFhjDQ1XUdftD86TFZGHimQpWLZlwWtCgzCCIAzB5D8+Oa5QJBzmhPWsUXnlxZ4YLZADskdBb3/iLf2lz2AbXHx0dxa/gIBSAuCmMTVIWAbQQfXeHptZ+hHd4B/ivw1qVT7mnCs9fRSfpb/0sHzrFl5dKJhddNe2ywinC7L23Vb0vjauIY3coh+aIS3xvi6UXJ7V56MDifOsu1tWt3gPdOtAO9gYyIPIuj5/NtLUPlNlQNAS4Kjt3wt+npLdPBedHGOPDWAxd+wf/n1NadTAdFDNAZ7B2Bqu4xbhvgcv3BZ7VWDF1V4/YxhIcAjr3XcE9c/eqc0MosfkHX7wBWibXO07UQG5xmZCCOSJ4J2//p2KC5vymvVqu0wuEfMUH8nru/D/zSNLnjdAhq2Z6fwbtkFTMamC9P7O5FTRAgOrPG9t/7CCNOInaHOYD0CYQHdckEIgbSAzSeJdX51/mQ/8k5iiV9JrT0AUxKT1Jyob01W3/mGpvErr2To/BMzIcDJdAIILJOjY6s7ctKQdYdRSU2JiS2rElstfV+VjUVTmQ6QHVFqjAg3lYHDaT0QkIuR4a/300nBCMvFOgNaQ2fFwVrTDEDmBo4E0kv5xnIM3chvoAee9lzTzTAz9lGv7m25InH2U99p3xwGhBBIjJyIjjF5sD2yY0rpgZenJhu1FJPtwSb8HzAS4FnKh5gIZB8ywQThl3oSRsxH59AnEIrYG+uwJpfOiy3KFGWEhWbkYT0khFWY6KzulJSEGllG8X2gxQYSzanvM5gGZl6LW1mqiCmNdb3ZwWa2NMYd2+K0CXNDOtZ5FzXV5Dt++i/Rlh6aIhSmhqYfEVhMEXQtm/rE+p9OHF+xAmjHJv2XkfXbwS3SD6Tj83msyYBvzgYsIyFuT6xeTg+m77xHYWaVUarNi1OHZXC9c73cSD7FqlBrnESjMsEso+3bFN9As7MMk2XRh1W+ekZKaEH08sQ0ePKKurl1HSB2PgGCjyUAwnw8iRCLJ8dAHj2SEv6RUQLgsXcM6bWFCw9xkfEacPGf68KA4h0sHQdw0aGLS8e/xkfjXst6z5/Hz+CjldB5HBDJRFnt43QcUfLZHqOZGXjgo+UM8CghoV2nnayrOTrq5G8c9y7MifigNop88Bv5h52jziE+vsg7We5TNBWyyYYf6urO6vWlCQ6d7uf6uh82WflD57yLKuM+VMQW+HwaDNlkDThinwq9K+NhJs6rcJw/tNF2rK72jF4HYuu1HEtfXx43n/fdADe5qI9r4eV/z7Nx8xYZEBdxW+rr4+TxbN+/8m9xTSyX83WSo1ThUv6pHVThULpeK52KUr2mRhF1hDfEHeKNpK8nkEddXzLhnWABcaM99+6d9WNmUiGTJGomdOJyJ7ck9TkcfUkfS0ubfZqD1oenZGFntmVRxvvMCu8fbX1kDVk7BVJhNiqjVzG5eZ9epZ9Z6pssysMuBVeCJnsry9T1qU8opFpv2/HnAtaxeSnIK5AGvUiR3j76STX4b7YacnlxlhAlmZVaNv/KEdEA9eHyscePIpBRozfCYyqSdMirlJuG8PYtPwZlDnwXyo3MjuHnlziXRi0//eDZcMISKzv29FzGjX7ARIZvhEigSySQwBcPz3WDbXWwYmVRjJL54XE0zFGURZeURJcp5jQ4oorlMYVKO6xOBbOLDZFZhrCc8JIys2j7U4g0l5WEm8KysyKzxcUwoIAJPSiEXcqyHxqb9Hir1lbvkBZL4mzxBbha/PsdKjzGLsuSZhiFOWEl5WJH7ZQgoroy6pZYNhBYrKyEw/W15ZE/CWigOvuwyNg6/iz1QCJ5+ePR4ZKJ7VO4mO77xxYsp5RaNfg3ek4ibkNTYyxvV2kXmobZKvbB5dxAnf4qmZfhcSKUSh5rO7p6NBunIvobIy1Rpv8eA1sYkxp8P+U6YauxsDKytVGmI5e0VAXG6GZ/f11PlitXxZfThFXS2jDvh91fLBwK1ncmKpJGCoXhomyeOiWoLLpVw137Vucta2XxNOuOyyt+mU733r0Oqxg5Mp1MLzN7SVuXYau4xY6KSXb+oqxmQ3PWIsCGBapVajsiMTQ5jJvNz2lmqpjFSavmZpmtvZm6VfY4+YjZYSyi3xAKUlIEuQKHhCp+g3nED0zoUfWAgHJhpWudglWIcqCKCvalK5oYuwc35QZaYT74klurGkIyCtPyaY2eLYL60DVNVmGAOR/k+RuhQY7ENF3ysZxSeCSBoi65U4IcAUZr/uOQPu99uwE1Zl8A/xjC8A7t/I3cO78MPwn8eL4BBCJWrd7z+SfnN7+tR2mWY/oDbpzb6rln3x7Mcg1qveSqy3PruRtl4n43Pr8Bt9f/ZqJrsOnR2ndK9b/WEq/g86SIf56Ujnf0I9vUT3yMF/eYTv28LlPrIm0gvTm4brbnrtqg0fVH+Kak+Ax4GcmgbX8blFxB7RgvffJP9sgvqnZEwDigALb7dVO/V4nVs/Taqn0nhXlabUPK+fGcX5476hffbXmeAR+skG64l7AWG/yLd9LI9mx9SJnj+S85454T/tPzRWOKRxHfXpP67lowvx/bUPUpL/REyXeH47LnVLa4YktjFKXLiSKX//WSo4vGEOOKBb91O/K4OUHz53PMnLzzAsOGHszjXhghc9A8A+JyXBjYjF5I6tadTz7lPrnad0eRfO+mnCRFWZz7Xdx+M35akv9fTH8teh1GA9VMOgjzKQuz/dWhIaFqpYq/MVXkXC8vY9fuQdohZemMpDdyB/WNWnNpDL5KpIuqXnhC+650HbjaBSHfY5OdMDfzJeswOUf5rOenmYdeXyhNFAwZ2IsgAOpkukjsg1Ab7SDbSWI2QX+gYilK0xdeX858fvybowTjQAvmhpGd7Hssm7o1Z8Z6Eblt9qZgTa0Y5EEH1LuPJUxXiYvFfPUJ6fjpX5eHk1wQMbAAwIaQXMxNcOBI6636O3aeW8jbNgmBA2XOZm7N6azbUCcJiKG5gExykijfqvZ18jYrcwACTAI5KIbkKO+U/tGqACm3NtDJ3Px+6OlQTCZkEgCFnVDmnTPY281V4k4zdfUabX2fwHV9UqEdl+fLZLZqAuuqmW3g/gFTLDfmHyouNjtWiSj2+UfmGTuvjhv9TxbNFDCUaPX6x+rdjppewt/f8Q6DtKMjS6dUea81tjXA/3VLbEtAiR3Jb3MNcXOtmvyPrKEFpeExZ0zpr7Ws0Y5N5yT7yz+cnBcUrgAMmKQF4ULMYnfMFZrPD87ElJ3XrzspzlXqopZQXAPMVJ7SrsoVW+EosPX3t7UmfU1MCrV92g5muq/f3XBYkU2Gnt85b8tBygdP3MSqwcOLfSjvDx+bu422ueF6G5r8+615pQ756p+uVmy13FE6770PGbUuLVYnn//TFYqro4DmThqzLqeNQNLDz8oVw0cjV3N50dTl3gORowHl/qdomcrNc/49IyFJ/ph1Uphx8qcydqCTGUIQUcoMmdwfadRzk3nCZKEamYlIU6zc8fZsy6Vbh0HnTWT77rOtFTv4An7s09uHMfNNsoqdp1ov/TVO3rp0tuL0nrMdMzNSdkGbgoVJ4clQM9TITeOlc+yUiph4to461qCoEwXKA6sUo2wdZazszbw/RAWihpmv+wdcQxRiLnnZ2NjW1yy5JUWYHBKSLEw5JPCQ5JAU4SHNnEVOIf4zNraM7GTmkV/DPAadO36ZVlclJFT1JlQDz5WoGlXlHMimDlqt9Ek9JHjjRkeWttfnDsX37Zez5KHeFuLdA6jxkIEzie/rRi8K0U1IzT+Ybupf/z/94fWm86t9Zg79Gmg5/kz6KuNXX0pq7DmXcWvN4/me4pkLigsg6JpJgNSgm4QXR+veJw6cCRlHHbhLtKCzpLMOXvMlP43p4TizNm5UloaSrK9f0+ddO5evdRnPpcZSfB9nPJ/xsQT+eujYuwH2qk3nX//w9P+/qCndiguKraYIct7PvUexC+IFqMBiVXzPDH0eWNJ3IfFCVd7Y2jVXKytmrcvf/+fIn1XrZlVUrr261iN1gMf5xPMidQGBzaAQFuRVgYeBvqc2Sjdu43v46CFjBBClWXz03q7my/Qi/9y8+9tjPlKfp74Sn5+nju9THymCiz6D/hm9H/3UoV8JzurWIS4jyT387B9N5FZanCtW6WxTulzKVolK10vD6YqNAwOR2eHh2SXhRuMSICPKflIiPwyEWcPA84tLZP7CnnM5Rz/Q8bgHng9weHJW24E6H0K/8kpljI98bohXqZxx6J783iE5f9PW+npOhvws+DlkcjvNxOtYYL5hIBbSU76Zypy3I1ora6KORzY9HJBkdVXGl8fGlsdXfhJ4SHlsZfwnzUKXmt3OS9ZipXn5vMWHTL46qVYqkUr7faVQaKW69Eld1A/jXyvlq2gTn5tCzT2M79jXgT+cS03h8k3Rr3qkDK+Tl8hjjRhDeMlUyzlC+752wjkLNZkXYnTs8grK9l/kn1uzbADp49/n/8zd5fWM+T6TyR7aag/8rYgpSyd2dbpcM/VNQQFLr2fxs7s5usBNmwPonml0MHO80es0vSEfzHR6le/jGAKFAKqxcP5tJXus+QyB0rVzPJ1aOg1a6YRrUFBtxtTZCBacK3bSzBou3Iu//hsRvKsbvhoCMr+xQc5erpHBkSeRweJ3CRP/bzoqnFpdydSXo06GcizjnzO0EKkZaGNwBM45iuz8WTaU87dz4x8pFjL5e38O5STcPj1SAzIhDyhSv8tk6aLwzvRQe9G18Gt5nBQZvzT5TU1afN3sPMl3lUyoJBr5ADftOY07CakFI9N2+EkKx/97MtmS8sfGOU85FMrZ8zLKOQ4Bp4nJBTANJOPzuJsTexJVrmdWrp4SHt30/0QWTByFPImAcWsun7VBaD88QEZLoMzK7/Iks+vS1NlvU+r58hiO9Xr4pSJ7emhn+CIp+bKflNJOk+BCiVwp/5MTlZAmTYkx8BLT+wpmyQoltjxpvvy2wKLE1h2cVZC+mKePMUhTEtKiOI9YuiVBvPhUaXJUBler78qyi7LDsjJEhvAvsw7JwwZas2fpO7naqExpcnxKcNDDXJD7ZPoGPzam1KGY49hswy2yKaVC/my+sZc7XyvYqS9mFgjsy3dbFQUe4NfTvaMBQtW6mVfgKijN/EZbFtS8baU2bi5n4QKOhWv9mmvj5C5cmMuxcb+2GsoXcnK5tnIrx7JwwdrXym0+NhL5kcr4V3CUQxlctjjA8/hsiP0+UDr6O1Ml9F4Xf9ITFTP8IOdmQD1J5HNo3/8WMVfOfjr6WyyGyeK8Oj09xpfX0COo9/+frVFzQbyD+A2FswvhHaFeL/vXMtfUue0c1hlZNg5mk8zMDTvneDZZqO6S6sFd/9Gk5NWc+x+LH9tyHpOSjoxvvr1k69KBM5LksNTdTXvPg3DIjo9SaYsP2afP5WJRLVjCovKKvo9oi0z2d4U8feYh90lGSsaTVE7giCMMYaKsIlHmF7ZLlImy0nMRR0inXadJ37P4EebPTB+q9hAdAoRstwemI/U1XwuCfb9bvWCLfglNf0IWCUHDEbfrmfK82UsJ3cQVXtWSLEWWKHFi3vN5/hp2xku9LN5fodOtYkUm+VaH1lZQLKIq+Ac54j2LoQoyUTYRjcHfLE3+owKdyUZl4SrnO3rl8z8mY48HJt3+uHaztZ1s80glr2Cmb/z05D337SovHCw+wRag72Ne3stz79znrzpQPC/g2c3VU/UNPo2kdYQ2L1XB8w92pjeeIIrc4Qt70N26oAkG3TqNTERlsk2hKCe9YKWF+l+k+xZjFroJzNQEHNQejGUVA7YFHNIciu0ZoNJTwKwc/0GFX8HPhj5DOj2zM2M2LO8IaX9j1LZx6kvs6dABc0r0J4QnFI6dxr6UbA2+W5swr6SHXbIFf4eBMaOUjiTsWfRl+B3wXuDx8Yr7qvtvzaVrLMHD4Q2Ta4ZPsH4NcV6pfcd5X+O68iSYfWJ43uTOIf5D8dU/QHT37j33+ZdD7jscpWWv+JP8+83g3kSVLnq1Z1nZff7ZlentBUp198aN94PPBN+35tls94P3839wgaamtnphHh+acUGamwCQvHkASGL4NOp0KS1p/6f5haYIQqRLbj6eZUyQSvIsYtn4eDfEY+0en4BH5cWLi+XR8uK8ODD0ZbvjZMDe9Vr6RCMGS77rQJD7glrIiI67QVFE2lcsVUmYLBdSGZ1XGNFPMDO1s3O1c/zbPBgnxWkZafiRgRu/+7rxs7aEN8emoq56KrOvfnjwnpeENVIyqi7YKP0qhIfEA17kwLzNKcbme/qM+lRQdLCUdovQmwJLQyFqrDqHsRbuIWFAJ9TAYU6Ja9VmpM/7oA7eqOb9VczTZOjjupINzLYu7e4C1BmUgZalkJ3DMnV0raqEm1I23Po7y1vTjE1Tr0hs12tOi+m482u1KJ9F+ub+NR6IZk2md2dtyiDULIjYvrMrrFCiTak7Xfc+PtNBiyuOkkgte1cT4S0aFdWRJ2vWoc94nEFD3PX7QaR9bHFT88XkBvhVDy3xx+6QUsWpUFCQ2eMS/XUVUQtijMu3vmqkNG6bbliJuY9ZCY/CJyuRqPil817XvRMCGxrSVVUef7XIw0Pip/UgvOo73nbnuAo1Vb/eXSprnT/DS/hD/cX66pj7PwT+pCvu318VoGG45EwNZt5/BmxQbFBSymS/3q8vGsb4/glk/BXWFTzZVyfR7RTLvf4Mm3EY/zQtDcdfKvApOOZzLN8n/1J2EdtD7BdIwrDT0xt7n/qK9op6X/6GjMVgaIoC1rBq1o+U5YpNO4CDkbllHdF162McUUXFUSUxQJ7pNeMFqMYhJvbPP4kr0QFmukuiY/zoxFY5ZMST0kdRkVdk+qxeuocO+jycV1PZFWuQ8mDmNSqkpjHv599NF81mmA62BC4Bl77logQCY3PgACgHLECminfWUCCcStxO+6+kNw4H6bXu7VUhiP0J3uTNFH5CLQl9Y2GPFRIQ1mPAw/qJn5i/JR9TQL7E+iHur//LiCGp9t2e6WLPdJc9gqOwoOTwcLlx3TxhoMc5RKlA+amC/+oR9cmCOp+vBIQXd4/eIPnV9HTFeW2mx3X+4o/tp/mD5zjBYZ+6tb/QlOc2b8ocIreCUghguBkbfSe7O0+IpmARCLHGhEKFUaulBWJrrjRPdk1gE2KrtKCaGoZEmzRiBALn0xVbpSh3xrnj3wPQhKI8tgr8OA+4qMf5guGNPSROumj3qS4dQ+erXhXAVAwDiBqteYZEo1FYFeL+hVFhpdFkT7fmiRrDat+TMshircSji0Hq29VN0F/XoAZReOJW2fCJRH45tXz7Emu6aTwIQKSn1B8ndmmRcOYa3C3cGv67huf14viuJfhTChy5UFhVsg4rx64rqQo9bk/5FDxHq637IhKOjZbFGoUxJQ0KB8MYm3/B8YW2TgsUkPFVcFPHR+dQn8oveUp1bkXTqt+TL3vl/fLBVw8zrkw6lIVU9bCSNcQBuQbRlmZNtKHSEE0yTe8bTA+Y2Op0ifCiFmcLN2nkpP4h+iOVe77omOhYKl50I+x6tOgmuC7Cpx76/Y9o5QsuINT1+fbduRNEyL595735F/s8vBKvDD2vLa0MBkcq074LS9tzAfmm3APwDYbSSjfJECUvUMRryhcb6Ll1GXFRdSW6JNTFERA+9uuPTRVzb+pyLlzc0e0qebmnZE1TcDjfneLdBtbOHPkmNjinra1ybaG1UmaKtP2Q/+IHRnHdA91GtweFAIuIj5/4K6Z4oj35oSnOTbxONY22E3gMf48FF8ftZgHvVrWMAO8d5un9Tuu8HUXWWXIXM9i+gxZLM0kdGJBRUrPFMujLZmzItZzW+2mDCSxGn8XSlxpQQf7liQESfRdbcnUOnwonp/iUOOe6XMsG8MmFrhV/tJ3/GITBC1SbzvFtzEfsD7axj1CAjatkD37YqorobzxWvpT0nZdPVOW6E5TYWikM7h2Vv2DbM7Cu9PsfNwxOgXOScUiZJLZWNtDT23DUupTyDVBqjSjgmSnseSSTFy7Iy1uwsC+QrCK/0bL2jY2x48MDricmWPP0ejKnoJKXnz02Bqc+GUrUJ7CsBXb3kb8nWlZWFGuILe/UgT6SitiXmAhmut2n01etSj/9o8T+VVv4Ae79/bxiTsG3YCB0yQ28zF+eHJk4nZMT0OhXW+0a0JBjnt6hsQJwLDk36bFo509FOStwvxaRp1F1pWvyKslDX31ybIak7A9P2zR/fCofjeYp5qwjAmaEr5QJOsR9AdD4Ciwhn0+HovGQ8fGxWcm7Ts5EfhXGn+k2zlbENVX9uJPn5gfxQFWfyvhzselDr/ewC+u5GWKvAuV4Uz1Tfg00/ekEkaNZo2B9vAUReba7qrq93tkwf7/ZhozXxJuRspOjhzdfcm+UjtH9nPYTkXkIEB2kUfXSqPAe1XnRGpDhThMo+DN4CsFJY9zdCMewMcNUSKnQLHoc+Hgjt5+bc6C4b0kdBDJhJNCxTJbtx7MKOvBpcGPceeQlgeuBRJgPX2NOD/Azl//dIhm6quLL4+LK46s+CXzt5XFV8Z+0s1BP7LPOUiq+N3H5PegD0D0uE1ssknJgEUssFZIfoUJ/GbFF9tVUO5gjWGKehln4d0dZeNPH9iItO1iYFCJIzgVYyk2WTQkxaPhc3cJAYZIgTUiijpDVZ4b2+uKEgqRkQS78SZZUIYigwDs7p2dCZ8jEfmB/Z0euqbMz5nT6ZEcHuKHZS91H7aOMUM/gCKXvpp4+CRND+iBi2F4YG62yYbkgj7qXrCDvpTrquhAyIg9BjqFwKmUBbJi2h4Il76UNZ5CxlD1nQ6DIYSQUS0ageQjhth/ShQAIF9IP4RY/RwiuqW9Th7/qxaKAXeUvRS+76Mxgc6Y5mEnvsu64qiScJyu4JbDpPGmBrCpdz9D4VjkCVU6F+7okKz0yrCnOJCiAJ4mSlq5JENcUlx4pzbruvi7IgeenAODyXbc6w4zIuK0zIiUdz6kIVFU5NL56RjqIVR0J0vz6MrEi8fljTtDo8vygu0G25Tt4rCAWqFiR/KIt4eDWrvyC1rmzB+YVA2V/7L7ytq8NR5zOYvfdZZfQ9X0rYaPYcp2Avcn3vOqGXNfpFWQmqb9uWmaVN23NKspRnwW4V/Rp4GvZu3tB14UI22Pb5NzeU71CRzppCQSRg70HTsI12YMPxKT5t+r4h/B/YEFsJAyffuLTWjLR4N2qhvpFcQ+ZaCPcJv8ncxan13+zcYE7YQBaJDgx92NQpQ9sYRldi/+P/n6Q1Mmd5acjV+sQX4nVo4dJZD+jLpmINZ1cuw6t/tEsMf+RBb6P8VpgdbdyfxvYgXb5OL0Lo0oWLYsJ54UtreF7CsMMfr9h0+xvyp+XwjyRPdr1wIPly/J44CJ0tXYfaKUHd9sFErpvMnQMCtsEwFzOPruJuYwRAAFmcgaNOYsRAiHmDOb5czOHzBEIBZQ+isBOt9/cb7buDyIHGSTUyENIuF/I1c/2cchBIIjMoVCQUJhMIOfmeuYKK5RyIycrZM4186zAp0uikIASB9AqtUw1qKhpUF2rpwZWvB5Yrl46fynQgdUOsEq0CqwePIB01SKldmAQOGD+75M5fKXrhHrPdJumrWkIjJDtFGJ/eD9xCAAIGOGB6Zp95DUgOxtyn7c/+D4k2zh3S7goHPIk3wbgAJZ58M+0w+9mAtH2GXIJ+e3osemDkpjmVWIQY3ALKM2U0+QVC1gZYq2yTlXuqdoTkklpDmoJ6gtaVE2uQwnNwItUHk182wH2CvaCwOuxR6bPd9VWl6szuinKtMoru8io1abZhfJ8mdQWVfizwMR8WaH8pyK5TSazyQcQyGyTFcmr/4v1aFBmIjvPpJVcTxW5uzq65lfVCIqsdnm6Az6yCOK3rbpB7aSokF5k7+VePB9IHHWQcgNC2UeNQ3gnDfnewdJV5HU0+WGE6pbqxgziNaKHGgSIg3Bj2E6VNNWLCSjkDkIUTGS9VL1Sv1K9DGwgu5hOlpPpWqA4FXWk81GIeuR/MvCKupge2XWzxTfi3MHWCPoUWsQeQxLmPy8PJK3hmD/FazgWsuXDvikmc9GrhaAx58UXgBnUVV7Ez+cuW86znV5UsMx/5aSjTZZxtjRuER/ZcLW7eqYNJlR/lntcRXlsdcJncLe4Co2fjVmr46+ffuMOO5d1LiPsjdNjilPRxknQhr1ZO5cV9sYtALJHbH/8ecWdrMXgUsFmALmjOI8PiJstxLi6you5nqzNys0sz4HXl0NTwoQZBYktN4C/GDRdhUDk+YKMlLDQqpcQUDVePdETE0fistQbdKsJyR7/2SlQfGKyvr05abnATMlJfhOZ4MMH8H8iHfJbZ2yFO74ddGVF500QbvywJ4YdM06EuzGsmL2YScx5bAgZp4g9D4PQ2zA2LAMqhp2HiaF7o1nRd6PZ0eMO3mOS/9TdW9T7X2FQ8Hiy7xviZkDx9QOqA8Lup+ueggjSpbwGXSphkX/GzR7x+vrqPnm6e+TrKyHPBx4e0E3t9ZA+ct7NeKSb2kCQMDuG8/nAlZFvGk9eHF72zzuzhLMWttOqokHusYZX7J1Y0rn81rrbLSuHGPt83r95G5/w7m1m+Btpsm314YtfC46/Uhv6bbpM6dTJss+IiaAD8SV/WaPT5SmFQntoXf5O5bGl262i2SUmroHzmZgWkT4Sqsl2CJ1en4WfRQQh4UEoNXsFHjx69+l19tBCoTwlOt1qFieFqjJDU/hGfGxmW8ASZaYJn8zPDA1TiZPM7TBZErr1Y4lblOe4WpJ91VHuEpVk6SaiZZLiD1ELhKslBiM3VRY9YQZhF3pOhhvCgbcFfCieiAAWKQUeTvwuOBG0LZkyTknexn3H4cRd4JzkXIjjhJ0Xnueet//qOS145TeaBmFHlwUsyycb0YFoXkJxVXJVsYBGp03qKVwfh9zhE4XCFEmLMGd337iNopdKtK3LWgdDKR0FouotYTj/Zj+Xv9t/wu/Uv3Vj8fHjricZ2B8wPwxSR6hrSghc9Eb3gy33Dm71AJzbI46RUhBhsDb+9lN1NVCy1pGQV80eiPXQL9M2hWvL/Qb3L5S6GAuTxNn1Rn+J3JuQ7WcgpOE1vgQTRscm/VS/Y8/zb8f62IMemxdXKBU13OBd19Lx15AkdZCrFAXtXcfjyb2gfExrmKotNoisHZm4oxJ9+1teg1W3CRluIMUHF7G+gHrlGvc3lEQ2fv52bIR4hoS/2UeRetBOpk6YPH55T1LBc5nZhImsmJEYdG5kotU1I8GY5iSH1QzmfeioZOH0WLwaWUaP7fD/veH05eL/zq3dRp5ubl+cvndy/sV0wiheg5tIxtMWjez1/kGG1k2LV4k/1y4ZuXg+HJcBdcETYY1wD7P3+/qXjjpNmnRO34w5KVzT5pO2INU9NGoiHMZ37jpSvu0sWX5p/qyArPr6nMJUQ7ZUYWiaLTQ1NRTs2NTdTdQF5BC/O+kDdJ3MAXpOxza8vb0i3qmMdcZVfIwrj3U5lRVxH+Q5OqcTV/4xrkLpdCkr4ttzqsqSSLKzrOC2DEl8tzUsKV2i234JOnY1AKfTE5tZEet9Dqd4kcPJXnE+cewZdm/gWeYvPr943o/cHuETMU5TVaWGtrK7S43zMTUaacuVFco0syB8fkyhOrgyoDYvuQFdohRV7umTqNO4frVbfbbqdGSHx0oGMeL1xDD7PPemYHcwsIkSVKKaMNUi/Cp61bVirrvGv7nI/07T/1x7q8a/xV/7j/ZY1wZCoRo+mP6elmpxUp/4Bv+FnQeFEyKLhm9fiaDuFWyiJ4VeNP10MAVKhxRD/GFICNgJEUGGY3hUdOIw9M9w6go+RjIXgoiHFsMTIKSBGhIUtq2GDFkIib/HnA1n2lHq9jjoPchoFH13ETM6jRop3AzZQILMo3u0thyOHdmfAUXNlh3lC0l/I29E13Chn2LSuUISfPa/xQ8dJGhiKJSq5zJiaOk4AlGRgrHxsrIhVPz0gxQ4lOuZ/mV6KU+BjPTKhNVzSCr1nAY47E8c+SAzFv4vDR3aiYZCkuH4nrqbcDjC4nw0xd62cin0IhZKg2AxNDhtPRomgbZBy+E/Ydm/LYFtQCVFoqFTv0ErYedeQ69BBgDpPp4kx8JgQalQ6BkPKAR6krmCclnaC3VNDug7qI4IxVOhOzjQIVwkEoOAMTFUCBWB00VheRZ4vgEKm+f3EMmXw7FvaMZTA0rF++A/IKHQtlBPOSG0fNHB+NZVKG8oCi6Efgd5bBwCG60VjtpMGkK8RGZ5fP2CSc5JlHqN/vPvbQm1WM0JnbXI/gqK8oRGIXxysmHvfKDefBjSk5R0AeIPD4OuGP0lHVrxHuRGIb42RPbu6xKhdmUtsO8sZ0Z41Hm23IS+hEY0fIXoRXj9kAh5NBpxB7p9HVWva4vQELRCo8Ewd9maegiUmemljghniaHfPemB01UQ6Cg04iZ5OmnTPCYPlhQfEYwcnE1yR0KbIfDn0ZiI7yHQUPggE2pf7i2AQcP0EEiicPUIlAi72CEctI+rxHc5zxGovXTBdQ6MANSIgUAohINCn8UgxLgZ3CgJ1VE+1IJTxXGTYpXzFzibkQf+QN8pYRsK5UE+9lEFhX3hkXvr2hSABIN+a6d/Cvkv7EXISy+7573ge0JipRuIWoYmwMgwER9Lctxmdomk34lpifvDSs5ovV6GvAj7L+QT3U7PW+RZQcPQEt8EHUZs59LLADKLMr4oQBuERnyNYy1k72EiRb5wEESln/Q/65oPIR7RtfjeM0AyT+pCaA0G3ABkVxDwgS1jrmctYuKOwZywktfDseFQSLWnLzvFng6Vp29gljbNwcEc8NcwCiym7mob4tcVoT1d5LLARgosnINsryu7XWnRWLwCauOtIN03RNVU3pbfE2/vYcIg5EUBI898KWXEc2GtzYffERh/UAvdJrnRCYn9+PpYd0/IX0TcdXQEDBKNbYh2UzkwX0pJ/BxudGL7o8N/N8riICwt9IvtJDuE1+2H0KgFEFhknV34O6wUho0A4ANnPpTuwVoB4RA9aUcRUhQClMzqtW0VcZebl8WVf/BcgB6piPurfFlXrdCwArybfMQyq1Buk1ZMi37iq6pcYbVUQ1Ikzfks50M6xU2hTXlSWkpoyvsnCzxTArCECHF159SI4DKvm0PiBKYK5uybBhFvGXcHnTHRy73tf9lVbZOrkjkxZZHo3mJVUWoCBc5hexdt5QPqygaTfEuNaGvNzZNzk09Q4VoA0QAa9ZukU3N/21oj2lIjB9KxrCH/IbDPf19p2WDAIBhsJZEjvAgNlpUFFsBQwFBpKQCobEOLF/BaVOKQ3EKQzG73IiWpBTCpCW2XrXLK6nfnVlZegdb5hDnvhaz9UMOJtzYQbdfFI0Fsld2wyVwt1rCYkWzSivl5Bflbt+af1ICCracKpGP5W0FM9pd67NV5CoNXXOuGtoDB6cHHexbvfbfrQ0ADA6v3L/UI9Sj1r6mjhxF119cv3vM4kxLQtmFpvK3mcdRoY1iOScivFj9ZJ58cf0lCw46n4Vmi47JCluuKZDOigxV+h3HRuMPRnACOt6RqGSpGWdmK+GnX+kXNlJWpGFq/tRo/tQExChmaaoaGkTqckxySGMLXC5L3CQwburBvuPQhUvK+N0mvD2yhv8sMat60Qb95Q4sPxKd5w+acDZua9WBe8wwr28YyzJiJdEtt2AOw9fMCtLeOnhe9pzulQ5rKs6KhqiUWThRunqfjbuX+fS3zeIw7s91QiM5nmQ/QQZtn38HxVrcMnqm8a+RyvOUcfZ8XMgNCJX1bw2IT4L00L+8fy1Qhqmc02olX5IsLVkbTgYlECK5e+vMlmupcSkGLgZufOdQ1ay+JadcmCRg8GIgxRXBDUFCyoWbVV/ewNo7DYMoN/vfzw2vzLIQatJ7BCA9PXmOICS+uRYLM+h24+cOd9pHUcwN/q5u9gYeyoPkW+9JgJSGqQfb6xm4rQOoxiX4BYlbKTkNsRMlcb8ud/wkHkt3znK1Vca4PxxcN9XlS2ZvuMoNvna4iwkJqN/95W+54XPFVnzWk07xxVc0ZNtNusgr8+QiIoiwiOBYDZxtrh6+8iG2Tzvee15zMAIEXdAVgeMNEcwcoAJb4jTVNazNy0Q7O1bD4VyXGxezPK02rgESrNkAsoEA/3NI2nMSZYEjlOXCTAl9GbhQyC59fgv4Q5LjBesCEaW5iIa9595L98kVrEK8YYj9lNzKBue1+BJVbu7XvLoG+3Lt7mVTbbmqxe35U8cNdHhZH5Sc+jCqW5+fLu7JMWnLTy+ZO6RY5jXfrxiy6T2KbZX1brlX0woM3Kfu4g37/fdQUyQKUr3M6uzpl14ri4uN4HlAOmzM5FkemU7grvV7ToV4zXlA60WEH9LAOJ4Vu/vM9Gu1Eoeude0acS9bt3m3WAYDk/Nk/hzVHFqizS7vDpuZ0cCvXZORVTgdWRpdLTyNHEuEqwLCTpdar0jyx5cTyrOXV+fLdCy/l7UqYw4y3DmsbFI5KY5mU5CIxA4wk8IjkZg7VqXckF6i4v3zHKe4iLlEP/OR/ctd4D8IMT4SbEV0ioW3iFpQXlcM6+VpfrbNUIkZBGQ7Wn0+PKkDcuzg14egC8NWjsw9Dvr7p+dUArwDyOStiYt2RV+O8q5hXnq8w4AeMQ3qV2N0BgwWYIdy/08x1KNozaZRnznY0zI8eBj7Htk6aw5bVvF3+eTUAS2xrRaMjxh4VZVc4nipKo4rt0U/8lAnRW1SUotwRZbdHna2RPMC5fYtz66uD3waR0J7JwBmE92VuoisXjP7WSbgcV7juR0F59hAOw+BuuYVNV0S8rRb6DXwRVrRd/e3FjyWzMDhiB8qN8E3YenOZ70vHMlN8FcOj1gHN1hkgdohRCuZvcYktkTl/zClJrg1/45HiHInFlcdND0qdX2mkNohDHEij1CAWXUxvR0RJRYQtPG9vo4uAUSFPZ+b6LJnDNQSbCutiSqKL7PLSmKcDDBu6UfAv8cZfc4pDAs58VPWW9Br+Af7jg8IDvlv+h6APKz7m9O3SmC5Sl4hYRbSS+FEiiTybB5B+88PYhyyHtIdC6V4vk3qWq70hYpJPeLSe5/0d2XMJORIwri5ZsSyutiQrGzxhZl+ZvFPH3efc7cYvVSmcR9t3sEchtcM/M4u/PvGz/OcTBsSGayGj7B/t4jxKURX1YL9AmX6YvcaAq/cJng4YPHDApXF86n/BflztvJnsS/dNplj9uMf6Pzk0rj+UgwHB0z71OMOa/z9Cpggbosm3AtmvWscoNyxEOgUVhkH/mPm04WGFZ+xSnh0EvottPc9cinVfaBRQlCHwxn0uOirr9Ebpxu5zmeptdfbo284Eo+2PJcoLEbRHPYZYKN/BKPtjiPICsNujgzs7KnS4GfoMTt9Z2UyfoTfv29bi07I8r3EQ8fZLDy+12fN/epMHMSzwdBGbcLMRgOgagAmTV+XL8iSSPFn+LYkS64buv/VcZC3IUxl5ZvIZsnmbd/HCJgAsPt/ENrDaO64zj50IMrGyNvSoiX3CaIiws9imS6kDbAPASYgLiRU26bGGoNR6XVVr9czXtPs71fv4UVZWf79EkpU55LD5e6vq/Qvi+y7+kG1/CPtDf2KUNbjMA0XhSz3iCF/rmDDwv57jgy8x5XZZ7otGOepL8XvPbKKn5lE8TAIVubY6tAjsWreWx55a1t3hIhPUjjyynY0cc1aifHeOmhwkouIBThRCFiS+Eo1LEJdcoMCwUiRKJPoRylL9s6if4oJA6w1fb4a0DsqMeOIUa8POfeFqbgOHOReq3KDyUdzvbdtDJ7i4GySuiym6Mf390k+ACYB2sOw8P63vg1+3X1N5aJ4QfwUnhQA2PAVy2SHessFXpX0x9ZI1aTFcix4p5bn7hEMJJV9c0issBp0poMiZWBekKshTt4X6ewzAfOUWmeG9Op9AfXxOgB1O2dyX2pp61RhqTMw1cTlgdrmRidaWp58FtVbw81Rl/N3f5mKfXusWy3ZbQzZPNl6+GcQehZ+yWWEONLexfXqqUx0LMInaoj9c2gkw4fLIYoeWnOVHzFA4ctLNcKr7EuVRQP9xtHYXp3srwa+ZPCx++4qG4Q0QrpgXIx+aisSTvpMS14wTcMR4yhrXHDvnI6jpT2j+IM8Xokpq2XOo3RrCMg3ntHeESGyuWE5NWvtsI4SDCcDXCAYSzjwiUuP4raR/m1r81OUiAQJ6qHh406i8tvT+ZTP4f6OPgn3U5AbF3AUHrR9KYUrQ9vGe4VtdZiiHX23L5XZur7Yreh7HuA3FbrRt9uoXHNsX+r69oTdeGggNPpeoe9tKOii999rX1QRvuKSzpn2Qz87SXt+WcOFOiT/aOodbpqFfsrmv38E+HwKgl3vXcFBV0n8+wgx8uxMSAGxMjvKbo7kV+1yW26ekk9zTkT6JY1oOwxHN7MPyBJ52IuVx0Y9MOdH8mo27rwF9TRxwlF7L8ujedePMmLeu9E1djfBgGe+M9pkrfRQO5j5AHzA8bJPm//XUD/HP/Q3BynpS5pePOyMKwCL1UoEJHF3ELen/kOFX/Lb8ei1OYv8TuAAsj24f62en/9+G8b84LyhGIdhi9GcLxSW1zxP5O9Lto8OtIoDBTHLLuwVMGOY/MZL+YQWCA1wR/++a4z/37jCYVQ17QtbHlILL8L+wO/E/LzniotFugv1vFNfpGwoBbhUeJBNAgdLHbnAe2mo9aENaXbAJQumSfHasUkTHsUYp/VKomzw2UsbysYlS9o4tZUzWtsuoM8AgRLEEGDShOFaot+1YpZI7bK66qzhAnezYSKPf8YT9Qz62lNNwd66MwbQ/30TQG0YXnq5A20h2Y/8cZVo69AvTmCKXQ6a9fyhacAt3mtcN/Z+4odQVoHs6m5EjadV9YO4aMjfXpd0RbM5m/bYs5Ao9Q6svr4LeMLrwHJ29QNvINPYgjcbJffIvTGN28Y66fuI/FIVA3b+JnH0Nkj7pFjgiM6fu6WyPgtzAlFan2gdXjOeF3Fx3l7sj2JwjzH5bHmeiUDrTarVTp8DxOOrDlk3jtkl5CpSvAhWqSOE3bjtYaWVUov4M1/cbQIQJZVxIpY11PsQkzfKirOqm7fphnOZl3fbjvO7n/f63MP5/TNEMy/GCKMmKqumGadmO6/lBGMVJmuVFWdVN2/XDOM3Luu32h+PpfLne7o/n6/35/v4ACMEIiuEESdEMy/GCKMmKqumGadmO6/lBGMVJmuVFWdVN2/XDOM3Luu3Hed3P+/2///z99x/2AFS11zIE9YDlQGDQnkilwNaxZ243akzsQDp5D87+nCI3egpKqKo1opnaqH3b0Nr06BHgrDWwbq8Bf/E+sOZSv7hxeMg50PZqN22Yje+WiUWCnTgiCMiWPKTu+PAj83F6rL3xFowvvBWMxIZdf968z0E6XNXPBKfphbid1/CP39HXYsr79v3gF0LtjpB49/HgWvS7DUVbYj20ezh450Fai3gRy7ug9A0Z2DbBZEa17ZDlB/viDZMvhYvMqv35DNnmH1NS4QKL3bh6wp9bzQOotFU3A2qmLvJR1CBoroZZyJEzyb5MmWo8CddvdQaI3KdWjDts04KV9eCaD/BTJ9P6+P+x4YPdTvJpNFilC1On1r7VyizYDe3MF8/3v4eexvWVRctqV70NVDJj91mrfu9CL4Q0bDJs6kiKymrRyVM4xaHSmY5oJy6kb4Q3jKC1qWA88Gzs+CDakLXbbdxQBoVPhusWcgz+vpd7M58gax12wkWCMOTRGFWfuhE3DHI9Q1VDArpgtEI+MOVIHdMOOsF+FyLzYkGiy37hN2yfn1g3SskCo4qQjZHp0lqSwLvVFU0+5nLEhncKn7zDnDeScL58Vifzbr0bvsKGH0/jFqWyjm05Gh3hkONUpQbkMINet1ZUn4lr2ZKM911cj9kelE8+LiPWKarK0IV+484FOmZQafC4q6IL0Bv0gs2k1VuOkGXamv06PQa04FGlumk90qjC9TV23rwbwvmUx8HZag4PL3zUDKgOWwHlgrpcwSt1RNOGHViC0bOldvD6o1BhjXqSIWBhTxECR8J6cMUDNiY8ZziNCzhGriMIZsC7YnI9dD0GVJz6D2cZmX61e1uVrm93biDT3iCrTGWDIx7ksBBHOIaj3gkdih0IyKbIJHp0fDSfkJm4IpDaFYgFixlTPWCKzNwxKTzrtaRF3gX+uLHzlaN+131W/y3K/CHGfMN1nfH9U7uvm1GDICG0823cSw1gW+5TvSA4lCQF2XaOZIxaWkymlfKCW359+bmi9uupn68YZK49kokW/oSB9QjMzUeBgBo+9xg9W8Nbe4UMuQOc5IPpHdO7scDYPaiTfb6gejXjAKNhGcksku21mf8HAAAAAA==") format("woff2")}.layui-icon{font-family:layui-icon!important;font-size:16px;font-style:normal;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-icon-sound:before{content:"\e69d"}.layui-icon-bot:before{content:"\e7d6"}.layui-icon-leaf:before{content:"\e701"}.layui-icon-folder:before{content:"\eabe"}.layui-icon-folder-open:before{content:"\eac1"}.layui-icon-gitee:before{content:"\e69b"}.layui-icon-github:before{content:"\e6a7"}.layui-icon-disabled:before{content:"\e6cc"}.layui-icon-moon:before{content:"\e6c2"}.layui-icon-error:before{content:"\e693"}.layui-icon-success:before{content:"\e697"}.layui-icon-question:before{content:"\e699"}.layui-icon-lock:before{content:"\e69a"}.layui-icon-eye:before{content:"\e695"}.layui-icon-eye-invisible:before{content:"\e696"}.layui-icon-backspace:before{content:"\e694"}.layui-icon-tips-fill:before{content:"\eb2e"}.layui-icon-test:before{content:"\e692"}.layui-icon-clear:before{content:"\e788"}.layui-icon-heart-fill:before{content:"\e68f"}.layui-icon-light:before{content:"\e748"}.layui-icon-music:before{content:"\e690"}.layui-icon-time:before{content:"\e68d"}.layui-icon-ie:before{content:"\e7bb"}.layui-icon-firefox:before{content:"\e686"}.layui-icon-at:before{content:"\e687"}.layui-icon-bluetooth:before{content:"\e689"}.layui-icon-chrome:before{content:"\e68a"}.layui-icon-edge:before{content:"\e68b"}.layui-icon-heart:before{content:"\e68c"}.layui-icon-key:before{content:"\e683"}.layui-icon-android:before{content:"\e684"}.layui-icon-mike:before{content:"\e6dc"}.layui-icon-mute:before{content:"\e685"}.layui-icon-gift:before{content:"\e627"}.layui-icon-windows:before{content:"\e67f"}.layui-icon-ios:before{content:"\e680"}.layui-icon-logout:before{content:"\e682"}.layui-icon-wifi:before{content:"\e7e0"}.layui-icon-rss:before{content:"\e808"}.layui-icon-email:before{content:"\e618"}.layui-icon-reduce-circle:before{content:"\e616"}.layui-icon-transfer:before{content:"\e691"}.layui-icon-service:before{content:"\e626"}.layui-icon-addition:before{content:"\e624"}.layui-icon-subtraction:before{content:"\e67e"}.layui-icon-slider:before{content:"\e714"}.layui-icon-print:before{content:"\e66d"}.layui-icon-export:before{content:"\e67d"}.layui-icon-cols:before{content:"\e610"}.layui-icon-screen-full:before{content:"\e622"}.layui-icon-screen-restore:before{content:"\e758"}.layui-icon-rate-half:before{content:"\e6c9"}.layui-icon-rate-solid:before{content:"\e67a"}.layui-icon-rate:before{content:"\e67b"}.layui-icon-cellphone:before{content:"\e678"}.layui-icon-vercode:before{content:"\e679"}.layui-icon-login-weibo:before{content:"\e675"}.layui-icon-login-qq:before{content:"\e676"}.layui-icon-login-wechat:before{content:"\e677"}.layui-icon-username:before{content:"\e66f"}.layui-icon-password:before{content:"\e673"}.layui-icon-refresh-3:before{content:"\e9aa"}.layui-icon-auz:before{content:"\e672"}.layui-icon-shrink-right:before{content:"\e668"}.layui-icon-spread-left:before{content:"\e66b"}.layui-icon-snowflake:before{content:"\e6b1"}.layui-icon-tips:before{content:"\e702"}.layui-icon-note:before{content:"\e66e"}.layui-icon-senior:before{content:"\e674"}.layui-icon-refresh-1:before{content:"\e666"}.layui-icon-refresh:before{content:"\e669"}.layui-icon-flag:before{content:"\e66c"}.layui-icon-theme:before{content:"\e66a"}.layui-icon-notice:before{content:"\e667"}.layui-icon-console:before{content:"\e665"}.layui-icon-website:before{content:"\e7ae"}.layui-icon-face-surprised:before{content:"\e664"}.layui-icon-set:before{content:"\e716"}.layui-icon-template:before{content:"\e663"}.layui-icon-app:before{content:"\e653"}.layui-icon-template-1:before{content:"\e656"}.layui-icon-home:before{content:"\e68e"}.layui-icon-female:before{content:"\e661"}.layui-icon-male:before{content:"\e662"}.layui-icon-tread:before{content:"\e6c5"}.layui-icon-praise:before{content:"\e6c6"}.layui-icon-rmb:before{content:"\e65e"}.layui-icon-more:before{content:"\e65f"}.layui-icon-camera:before{content:"\e660"}.layui-icon-cart-simple:before{content:"\e698"}.layui-icon-face-cry:before{content:"\e69c"}.layui-icon-face-smile:before{content:"\e6af"}.layui-icon-survey:before{content:"\e6b2"}.layui-icon-read:before{content:"\e705"}.layui-icon-location:before{content:"\e715"}.layui-icon-dollar:before{content:"\e659"}.layui-icon-diamond:before{content:"\e735"}.layui-icon-return:before{content:"\e65c"}.layui-icon-camera-fill:before{content:"\e65d"}.layui-icon-fire:before{content:"\e756"}.layui-icon-more-vertical:before{content:"\e671"}.layui-icon-cart:before{content:"\e657"}.layui-icon-star-fill:before{content:"\e658"}.layui-icon-prev:before{content:"\e65a"}.layui-icon-next:before{content:"\e65b"}.layui-icon-upload:before{content:"\e67c"}.layui-icon-upload-drag:before{content:"\e681"}.layui-icon-user:before{content:"\e770"}.layui-icon-file-b:before{content:"\e655"}.layui-icon-component:before{content:"\e857"}.layui-icon-find-fill:before{content:"\e670"}.layui-icon-loading:before{content:"\e63d"}.layui-icon-loading-1:before{content:"\e63e"}.layui-icon-add-1:before{content:"\e654"}.layui-icon-pause:before{content:"\e651"}.layui-icon-play:before{content:"\e652"}.layui-icon-video:before{content:"\e6ed"}.layui-icon-headset:before{content:"\e6fc"}.layui-icon-voice:before{content:"\e688"}.layui-icon-speaker:before{content:"\e645"}.layui-icon-fonts-del:before{content:"\e64f"}.layui-icon-fonts-html:before{content:"\e64b"}.layui-icon-fonts-code:before{content:"\e64e"}.layui-icon-fonts-strong:before{content:"\e62b"}.layui-icon-unlink:before{content:"\e64d"}.layui-icon-picture:before{content:"\e64a"}.layui-icon-link:before{content:"\e64c"}.layui-icon-face-smile-b:before{content:"\e650"}.layui-icon-align-center:before{content:"\e647"}.layui-icon-align-right:before{content:"\e648"}.layui-icon-align-left:before{content:"\e649"}.layui-icon-fonts-u:before{content:"\e646"}.layui-icon-fonts-i:before{content:"\e644"}.layui-icon-tabs:before{content:"\e62a"}.layui-icon-circle:before{content:"\e63f"}.layui-icon-radio:before{content:"\e643"}.layui-icon-share:before{content:"\e641"}.layui-icon-edit:before{content:"\e642"}.layui-icon-delete:before{content:"\e640"}.layui-icon-engine:before{content:"\e628"}.layui-icon-chart-screen:before{content:"\e629"}.layui-icon-chart:before{content:"\e62c"}.layui-icon-table:before{content:"\e62d"}.layui-icon-tree:before{content:"\e62e"}.layui-icon-upload-circle:before{content:"\e62f"}.layui-icon-templeate-1:before{content:"\e630"}.layui-icon-util:before{content:"\e631"}.layui-icon-layouts:before{content:"\e632"}.layui-icon-prev-circle:before{content:"\e633"}.layui-icon-carousel:before{content:"\e634"}.layui-icon-code-circle:before{content:"\e635"}.layui-icon-water:before{content:"\e636"}.layui-icon-date:before{content:"\e637"}.layui-icon-layer:before{content:"\e638"}.layui-icon-fonts-clear:before{content:"\e639"}.layui-icon-dialogue:before{content:"\e63a"}.layui-icon-cellphone-fine:before{content:"\e63b"}.layui-icon-form:before{content:"\e63c"}.layui-icon-file:before{content:"\e621"}.layui-icon-triangle-r:before{content:"\e623"}.layui-icon-triangle-d:before{content:"\e625"}.layui-icon-set-sm:before{content:"\e620"}.layui-icon-add-circle:before{content:"\e61f"}.layui-icon-layim-download:before{content:"\e61e"}.layui-icon-layim-uploadfile:before{content:"\e61d"}.layui-icon-404:before{content:"\e61c"}.layui-icon-about:before{content:"\e60b"}.layui-icon-layim-theme:before{content:"\e61b"}.layui-icon-down:before{content:"\e61a"}.layui-icon-up:before{content:"\e619"}.layui-icon-circle-dot:before{content:"\e617"}.layui-icon-set-fill:before{content:"\e614"}.layui-icon-search:before{content:"\e615"}.layui-icon-friends:before{content:"\e612"}.layui-icon-group:before{content:"\e613"}.layui-icon-reply-fill:before{content:"\e611"}.layui-icon-menu-fill:before{content:"\e60f"}.layui-icon-face-smile-fine:before{content:"\e60c"}.layui-icon-picture-fine:before{content:"\e60d"}.layui-icon-log:before{content:"\e60e"}.layui-icon-list:before{content:"\e60a"}.layui-icon-release:before{content:"\e609"}.layui-icon-add-circle-fine:before{content:"\e608"}.layui-icon-ok:before{content:"\e605"}.layui-icon-help:before{content:"\e607"}.layui-icon-chat:before{content:"\e606"}.layui-icon-top:before{content:"\e604"}.layui-icon-right:before{content:"\e602"}.layui-icon-left:before{content:"\e603"}.layui-icon-star:before{content:"\e600"}.layui-icon-download-circle:before{content:"\e601"}.layui-icon-close:before{content:"\1006"}.layui-icon-close-fill:before{content:"\1007"}.layui-icon-ok-circle:before{content:"\1005"}.layui-main{margin:0 auto;position:relative;width:1160px}.layui-header{height:60px;position:relative;z-index:1000}.layui-header a:hover{transition:all .5s}.layui-side{bottom:0;left:0;overflow-x:hidden;position:fixed;top:0;width:200px;z-index:999}.layui-side-scroll{height:100%;overflow-x:hidden;position:relative;width:220px}.layui-body{bottom:0;box-sizing:border-box;left:200px;position:relative;right:0;top:0;width:auto}.layui-layout-body{overflow-x:hidden}.layui-layout-admin .layui-header{background-color:#23292e;left:0;position:fixed;right:0;top:0}.layui-layout-admin .layui-side{overflow-x:hidden;top:60px;width:200px}.layui-layout-admin .layui-body{padding-bottom:44px;position:absolute;top:60px}.layui-layout-admin .layui-main{margin:0 15px;width:auto}.layui-layout-admin .layui-footer{background-color:var(--lay-color-gray);bottom:0;box-shadow:-1px 0 4px rgba(0,0,0,.12);height:44px;left:200px;line-height:44px;padding:0 15px;position:fixed;right:0;z-index:990}.layui-layout-admin .layui-logo{box-shadow:0 1px 2px 0 rgba(0,0,0,.15);color:var(--lay-color-primary);font-size:16px;height:100%;left:0;line-height:60px;position:absolute;text-align:center;top:0;width:200px}.layui-layout-admin .layui-header .layui-nav{background:none}.layui-layout-left{left:200px;position:absolute!important;top:0}.layui-layout-right{position:absolute!important;right:0;top:0}.layui-container{box-sizing:border-box}.layui-container,.layui-fluid{margin:0 auto;position:relative}.layui-fluid{padding:0 15px}.layui-row:after,.layui-row:before{clear:both;content:"";display:block}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9,.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9,.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9,.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9,.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{box-sizing:border-box;display:block;position:relative}.layui-col-xs1,.layui-col-xs10,.layui-col-xs11,.layui-col-xs12,.layui-col-xs2,.layui-col-xs3,.layui-col-xs4,.layui-col-xs5,.layui-col-xs6,.layui-col-xs7,.layui-col-xs8,.layui-col-xs9{float:left}.layui-col-xs1{width:8.33333333%}.layui-col-xs2{width:16.66666667%}.layui-col-xs3{width:25%}.layui-col-xs4{width:33.33333333%}.layui-col-xs5{width:41.66666667%}.layui-col-xs6{width:50%}.layui-col-xs7{width:58.33333333%}.layui-col-xs8{width:66.66666667%}.layui-col-xs9{width:75%}.layui-col-xs10{width:83.33333333%}.layui-col-xs11{width:91.66666667%}.layui-col-xs12{width:100%}.layui-col-xs-offset1{margin-left:8.33333333%}.layui-col-xs-offset2{margin-left:16.66666667%}.layui-col-xs-offset3{margin-left:25%}.layui-col-xs-offset4{margin-left:33.33333333%}.layui-col-xs-offset5{margin-left:41.66666667%}.layui-col-xs-offset6{margin-left:50%}.layui-col-xs-offset7{margin-left:58.33333333%}.layui-col-xs-offset8{margin-left:66.66666667%}.layui-col-xs-offset9{margin-left:75%}.layui-col-xs-offset10{margin-left:83.33333333%}.layui-col-xs-offset11{margin-left:91.66666667%}.layui-col-xs-offset12{margin-left:100%}@media screen and (max-width:767.98px){.layui-container{padding:0 15px}.layui-hide-xs{display:none!important}.layui-show-xs-block{display:block!important}.layui-show-xs-inline{display:inline!important}.layui-show-xs-inline-block{display:inline-block!important}}@media screen and (min-width:768px){.layui-container{width:720px}.layui-hide-sm{display:none!important}.layui-show-sm-block{display:block!important}.layui-show-sm-inline{display:inline!important}.layui-show-sm-inline-block{display:inline-block!important}.layui-col-sm1,.layui-col-sm10,.layui-col-sm11,.layui-col-sm12,.layui-col-sm2,.layui-col-sm3,.layui-col-sm4,.layui-col-sm5,.layui-col-sm6,.layui-col-sm7,.layui-col-sm8,.layui-col-sm9{float:left}.layui-col-sm1{width:8.33333333%}.layui-col-sm2{width:16.66666667%}.layui-col-sm3{width:25%}.layui-col-sm4{width:33.33333333%}.layui-col-sm5{width:41.66666667%}.layui-col-sm6{width:50%}.layui-col-sm7{width:58.33333333%}.layui-col-sm8{width:66.66666667%}.layui-col-sm9{width:75%}.layui-col-sm10{width:83.33333333%}.layui-col-sm11{width:91.66666667%}.layui-col-sm12{width:100%}.layui-col-sm-offset1{margin-left:8.33333333%}.layui-col-sm-offset2{margin-left:16.66666667%}.layui-col-sm-offset3{margin-left:25%}.layui-col-sm-offset4{margin-left:33.33333333%}.layui-col-sm-offset5{margin-left:41.66666667%}.layui-col-sm-offset6{margin-left:50%}.layui-col-sm-offset7{margin-left:58.33333333%}.layui-col-sm-offset8{margin-left:66.66666667%}.layui-col-sm-offset9{margin-left:75%}.layui-col-sm-offset10{margin-left:83.33333333%}.layui-col-sm-offset11{margin-left:91.66666667%}.layui-col-sm-offset12{margin-left:100%}}@media screen and (min-width:992px){.layui-container{width:960px}.layui-hide-md{display:none!important}.layui-show-md-block{display:block!important}.layui-show-md-inline{display:inline!important}.layui-show-md-inline-block{display:inline-block!important}.layui-col-md1,.layui-col-md10,.layui-col-md11,.layui-col-md12,.layui-col-md2,.layui-col-md3,.layui-col-md4,.layui-col-md5,.layui-col-md6,.layui-col-md7,.layui-col-md8,.layui-col-md9{float:left}.layui-col-md1{width:8.33333333%}.layui-col-md2{width:16.66666667%}.layui-col-md3{width:25%}.layui-col-md4{width:33.33333333%}.layui-col-md5{width:41.66666667%}.layui-col-md6{width:50%}.layui-col-md7{width:58.33333333%}.layui-col-md8{width:66.66666667%}.layui-col-md9{width:75%}.layui-col-md10{width:83.33333333%}.layui-col-md11{width:91.66666667%}.layui-col-md12{width:100%}.layui-col-md-offset1{margin-left:8.33333333%}.layui-col-md-offset2{margin-left:16.66666667%}.layui-col-md-offset3{margin-left:25%}.layui-col-md-offset4{margin-left:33.33333333%}.layui-col-md-offset5{margin-left:41.66666667%}.layui-col-md-offset6{margin-left:50%}.layui-col-md-offset7{margin-left:58.33333333%}.layui-col-md-offset8{margin-left:66.66666667%}.layui-col-md-offset9{margin-left:75%}.layui-col-md-offset10{margin-left:83.33333333%}.layui-col-md-offset11{margin-left:91.66666667%}.layui-col-md-offset12{margin-left:100%}}@media screen and (min-width:1200px){.layui-container{width:1150px}.layui-hide-lg{display:none!important}.layui-show-lg-block{display:block!important}.layui-show-lg-inline{display:inline!important}.layui-show-lg-inline-block{display:inline-block!important}.layui-col-lg1,.layui-col-lg10,.layui-col-lg11,.layui-col-lg12,.layui-col-lg2,.layui-col-lg3,.layui-col-lg4,.layui-col-lg5,.layui-col-lg6,.layui-col-lg7,.layui-col-lg8,.layui-col-lg9{float:left}.layui-col-lg1{width:8.33333333%}.layui-col-lg2{width:16.66666667%}.layui-col-lg3{width:25%}.layui-col-lg4{width:33.33333333%}.layui-col-lg5{width:41.66666667%}.layui-col-lg6{width:50%}.layui-col-lg7{width:58.33333333%}.layui-col-lg8{width:66.66666667%}.layui-col-lg9{width:75%}.layui-col-lg10{width:83.33333333%}.layui-col-lg11{width:91.66666667%}.layui-col-lg12{width:100%}.layui-col-lg-offset1{margin-left:8.33333333%}.layui-col-lg-offset2{margin-left:16.66666667%}.layui-col-lg-offset3{margin-left:25%}.layui-col-lg-offset4{margin-left:33.33333333%}.layui-col-lg-offset5{margin-left:41.66666667%}.layui-col-lg-offset6{margin-left:50%}.layui-col-lg-offset7{margin-left:58.33333333%}.layui-col-lg-offset8{margin-left:66.66666667%}.layui-col-lg-offset9{margin-left:75%}.layui-col-lg-offset10{margin-left:83.33333333%}.layui-col-lg-offset11{margin-left:91.66666667%}.layui-col-lg-offset12{margin-left:100%}}@media screen and (min-width:1400px){.layui-container{width:1330px}.layui-hide-xl{display:none!important}.layui-show-xl-block{display:block!important}.layui-show-xl-inline{display:inline!important}.layui-show-xl-inline-block{display:inline-block!important}.layui-col-xl1,.layui-col-xl10,.layui-col-xl11,.layui-col-xl12,.layui-col-xl2,.layui-col-xl3,.layui-col-xl4,.layui-col-xl5,.layui-col-xl6,.layui-col-xl7,.layui-col-xl8,.layui-col-xl9{float:left}.layui-col-xl1{width:8.33333333%}.layui-col-xl2{width:16.66666667%}.layui-col-xl3{width:25%}.layui-col-xl4{width:33.33333333%}.layui-col-xl5{width:41.66666667%}.layui-col-xl6{width:50%}.layui-col-xl7{width:58.33333333%}.layui-col-xl8{width:66.66666667%}.layui-col-xl9{width:75%}.layui-col-xl10{width:83.33333333%}.layui-col-xl11{width:91.66666667%}.layui-col-xl12{width:100%}.layui-col-xl-offset1{margin-left:8.33333333%}.layui-col-xl-offset2{margin-left:16.66666667%}.layui-col-xl-offset3{margin-left:25%}.layui-col-xl-offset4{margin-left:33.33333333%}.layui-col-xl-offset5{margin-left:41.66666667%}.layui-col-xl-offset6{margin-left:50%}.layui-col-xl-offset7{margin-left:58.33333333%}.layui-col-xl-offset8{margin-left:66.66666667%}.layui-col-xl-offset9{margin-left:75%}.layui-col-xl-offset10{margin-left:83.33333333%}.layui-col-xl-offset11{margin-left:91.66666667%}.layui-col-xl-offset12{margin-left:100%}}.layui-col-space1{margin:-.5px}.layui-col-space1>*{padding:.5px}.layui-col-space2{margin:-1px}.layui-col-space2>*{padding:1px}.layui-col-space4{margin:-2px}.layui-col-space4>*{padding:2px}.layui-col-space5{margin:-2.5px}.layui-col-space5>*{padding:2.5px}.layui-col-space6{margin:-3px}.layui-col-space6>*{padding:3px}.layui-col-space8{margin:-4px}.layui-col-space8>*{padding:4px}.layui-col-space10{margin:-5px}.layui-col-space10>*{padding:5px}.layui-col-space12{margin:-6px}.layui-col-space12>*{padding:6px}.layui-col-space14{margin:-7px}.layui-col-space14>*{padding:7px}.layui-col-space15{margin:-7.5px}.layui-col-space15>*{padding:7.5px}.layui-col-space16{margin:-8px}.layui-col-space16>*{padding:8px}.layui-col-space18{margin:-9px}.layui-col-space18>*{padding:9px}.layui-col-space20{margin:-10px}.layui-col-space20>*{padding:10px}.layui-col-space22{margin:-11px}.layui-col-space22>*{padding:11px}.layui-col-space24{margin:-12px}.layui-col-space24>*{padding:12px}.layui-col-space25{margin:-12.5px}.layui-col-space25>*{padding:12.5px}.layui-col-space26{margin:-13px}.layui-col-space26>*{padding:13px}.layui-col-space28{margin:-14px}.layui-col-space28>*{padding:14px}.layui-col-space30{margin:-15px}.layui-col-space30>*{padding:15px}.layui-col-space32{margin:-16px}.layui-col-space32>*{padding:16px}.layui-padding-1{padding:var(--lay-spacing-xs)!important}.layui-padding-2{padding:var(--lay-spacing-sm)!important}.layui-padding-3{padding:var(--lay-spacing)!important}.layui-padding-4{padding:var(--lay-spacing-lg)!important}.layui-padding-5{padding:var(--lay-spacing-xl)!important}.layui-margin-1{margin:var(--lay-spacing-xs)!important}.layui-margin-2{margin:var(--lay-spacing-sm)!important}.layui-margin-3{margin:var(--lay-spacing)!important}.layui-margin-4{margin:var(--lay-spacing-lg)!important}.layui-margin-5{margin:var(--lay-spacing-xl)!important}.layui-btn,.layui-input,.layui-select,.layui-textarea,.layui-upload-button{-webkit-appearance:none;-moz-appearance:none;appearance:none;box-sizing:border-box;outline:none;transition:all .3s}.layui-elem-quote{background-color:var(--lay-color-gray);border-left:5px solid var(--lay-color-accent);border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0;line-height:1.8;margin-bottom:10px;padding:var(--lay-spacing)}.layui-quote-nm{background:none;border-style:solid;border-width:1px 1px 1px 5px}.layui-elem-field{border-style:solid;border-width:1px;margin-bottom:10px;padding:0}.layui-elem-field legend{font-size:20px;margin-left:20px;padding:0 10px}.layui-field-title{border-width:1px 0 0;margin:var(--lay-spacing) 0}.layui-field-box{padding:var(--lay-spacing)}.layui-field-title .layui-field-box{padding:10px 0}.layui-auxiliar-moving{background:none;bottom:0;height:100%;left:0;position:fixed;right:0;top:0;-moz-user-select:none;-webkit-user-select:none;user-select:none;width:100%;z-index:9999999999}.layui-scrollbar-hide{overflow:hidden!important}.layui-progress{background-color:var(--lay-gray-300);border-radius:20px;height:6px;position:relative}.layui-progress-bar{background-color:var(--lay-color-accent);border-radius:20px;height:6px;left:0;max-width:100%;position:absolute;text-align:right;top:0;transition:all .3s;width:0}.layui-progress-big,.layui-progress-big .layui-progress-bar{height:18px;line-height:18px}.layui-progress-text{color:#5f5f5f;font-size:12px;line-height:18px;position:relative;top:-20px}.layui-progress-big .layui-progress-text{color:#fff;padding:0 10px;position:static}.layui-collapse{border-radius:var(--lay-border-radius);border-style:solid;border-width:1px}.layui-colla-content,.layui-colla-item{border-top-style:solid;border-top-width:1px}.layui-colla-item:first-child{border-top:none}.layui-colla-title{background-color:var(--lay-color-gray);color:#333;cursor:pointer;font-size:14px;height:42px;line-height:42px;overflow:hidden;padding:0 15px 0 35px;position:relative}.layui-colla-content{color:#5f5f5f;display:none;line-height:1.6;padding:10px 15px}.layui-colla-icon{font-size:14px;left:15px;line-height:normal;margin-top:-7px;position:absolute;top:50%;transition:all .2s}.layui-colla-item.layui-show>.layui-colla-title .layui-colla-icon{transform:rotate(90deg)}.layui-colla-item.layui-show>.layui-colla-content{display:block}.layui-card{background-color:#fff;border-radius:var(--lay-border-radius);box-shadow:0 1px 2px 0 rgba(0,0,0,.05);margin-bottom:15px}.layui-card:last-child{margin-bottom:0}.layui-card-body,.layui-card-header{padding:10px 15px;position:relative}.layui-card-header{border-bottom:1px solid #f8f8f8;border-radius:var(--lay-border-radius) 2px 0 0;color:#333;font-size:14px}.layui-card-body .layui-table{margin:5px 0}.layui-card .layui-tab{margin:0}.layui-panel{border-radius:var(--lay-border-radius);border-style:solid;border-width:1px;box-shadow:1px 1px 4px rgb(0 0 0/8%);color:#5f5f5f}.layui-panel,.layui-panel-window{background-color:#fff;position:relative}.layui-panel-window{border-radius:0;border-top:5px solid var(--lay-border-color);padding:15px}.layui-bg-red{background-color:var(--lay-color-red)!important;color:#fff!important}.layui-bg-orange{background-color:var(--lay-color-orange)!important;color:#fff!important}.layui-bg-green{background-color:var(--lay-color-primary)!important;color:#fff!important}.layui-bg-cyan{background-color:#2f4056!important;color:#fff!important}.layui-bg-blue{background-color:var(--lay-color-blue)!important;color:#fff!important}.layui-bg-purple{background-color:var(--lay-color-purple)!important;color:#fff!important}.layui-bg-black{background-color:var(--lay-color-black)!important;color:#fff!important}.layui-bg-gray{background-color:var(--lay-color-gray)!important;color:#5f5f5f!important}.layui-badge-rim,.layui-border,.layui-colla-content,.layui-colla-item,.layui-collapse,.layui-elem-field,.layui-form-pane .layui-form-item[pane],.layui-form-pane .layui-form-label,.layui-input,.layui-input-split,.layui-panel,.layui-quote-nm,.layui-select,.layui-tab-bar,.layui-tab-card,.layui-tab-title,.layui-tab-title .layui-this:after,.layui-textarea{border-color:var(--lay-border-color)}.layui-border{color:#5f5f5f!important}.layui-border,.layui-border-red{border-style:solid;border-width:1px}.layui-border-red{border-color:var(--lay-color-red)!important;color:var(--lay-color-red)!important}.layui-border-orange{border-color:var(--lay-color-orange)!important;border-style:solid;border-width:1px;color:var(--lay-color-orange)!important}.layui-border-green{border-color:var(--lay-color-primary)!important;border-style:solid;border-width:1px;color:var(--lay-color-primary)!important}.layui-border-cyan{border-color:#2f4056!important;border-style:solid;border-width:1px;color:#2f4056!important}.layui-border-blue{border-color:var(--lay-color-blue)!important;border-style:solid;border-width:1px;color:var(--lay-color-blue)!important}.layui-border-purple{border-color:var(--lay-color-purple)!important;border-style:solid;border-width:1px;color:var(--lay-color-purple)!important}.layui-border-black{border-color:var(--lay-color-black)!important;border-style:solid;border-width:1px;color:var(--lay-color-black)!important}hr.layui-border-black,hr.layui-border-blue,hr.layui-border-cyan,hr.layui-border-green,hr.layui-border-orange,hr.layui-border-purple,hr.layui-border-red{border-width:0 0 1px}.layui-timeline-item:before{background-color:var(--lay-gray-300)}.layui-text{font-size:14px;line-height:1.8}.layui-text h1{font-size:32px;margin:32px 0}.layui-text h2{font-size:24px;margin:24px 0}.layui-text h3{font-size:18px;margin:16px 0}.layui-text h4{font-size:16px;margin:11px 0}.layui-text h5{font-size:14px;margin:11px 0}.layui-text h6{font-size:13px;margin:11px 0}.layui-text p{margin:15px 0}.layui-text p:first-child{margin-top:0}.layui-text p:last-child{margin-bottom:0}.layui-text hr{margin:15px 0}.layui-text ol,.layui-text ul{padding-left:15px}.layui-text ul li{list-style-type:disc;margin-top:5px}.layui-text ol li{list-style-type:decimal;margin-top:5px}.layui-text ol ul>li,.layui-text ul ul>li{list-style-type:disc}.layui-text ol li>p:first-child,.layui-text ul li>p:first-child{margin-bottom:0;margin-top:0}.layui-text :where(a:not(.layui-btn)){color:#01aaed}.layui-text :where(a:not(.layui-btn):hover){text-decoration:underline}.layui-text blockquote:not(.layui-elem-quote){border-left:5px solid var(--lay-border-color);margin:15px 0;padding:5px 15px}.layui-text pre>code:not(.layui-code){display:block;font-family:Courier New,Consolas,Lucida Console,monospace;padding:15px}.layui-text-em,.layui-word-aux{color:#999!important;padding-left:5px!important;padding-right:5px!important}.layui-font-12{font-size:12px!important}.layui-font-13{font-size:13px!important}.layui-font-14{font-size:14px!important}.layui-font-16{font-size:16px!important}.layui-font-18{font-size:18px!important}.layui-font-20{font-size:20px!important}.layui-font-22{font-size:22px!important}.layui-font-24{font-size:24px!important}.layui-font-26{font-size:26px!important}.layui-font-28{font-size:28px!important}.layui-font-30{font-size:30px!important}.layui-font-32{font-size:32px!important}.layui-font-red{color:var(--lay-color-red)!important}.layui-font-orange{color:var(--lay-color-orange)!important}.layui-font-green{color:var(--lay-color-primary)!important}.layui-font-cyan{color:#2f4056!important}.layui-font-blue{color:#01aaed!important}.layui-font-purple{color:var(--lay-color-purple)!important}.layui-font-black{color:#000!important}.layui-font-gray{color:#c2c2c2!important}.layui-btn{background-color:var(--lay-color-primary);border:1px solid transparent;border-radius:var(--lay-border-radius);color:#fff;cursor:pointer;display:inline-block;font-size:14px;height:38px;line-height:36px;padding:0 18px;text-align:center;-webkit-user-select:none;-moz-user-select:none;user-select:none;vertical-align:middle;white-space:nowrap}.layui-btn:hover{color:#fff;filter:alpha(opacity=80);opacity:.8}.layui-btn:active{filter:alpha(opacity=100);opacity:1}.layui-btn+.layui-btn{margin-left:10px}.layui-btn-container{word-spacing:-5px}.layui-btn-container .layui-btn{margin-bottom:10px;margin-right:10px;word-spacing:normal}.layui-btn-container .layui-btn+.layui-btn{margin-left:0}.layui-table .layui-btn-container .layui-btn{margin-bottom:9px}.layui-btn-radius{border-radius:100px}.layui-btn .layui-icon{padding:0 2px;vertical-align:middle\0;vertical-align:bottom}.layui-btn-primary{background:none;border-color:var(--lay-border-color-accent);color:#5f5f5f}.layui-btn-primary:hover{border-color:var(--lay-color-primary);color:#333}.layui-btn-normal{background-color:var(--lay-color-blue)}.layui-btn-warm{background-color:var(--lay-color-orange)}.layui-btn-danger{background-color:var(--lay-color-red)}.layui-btn-checked{background-color:var(--lay-color-accent)}.layui-btn-disabled,.layui-btn-disabled:active,.layui-btn-disabled:hover{background-color:#fbfbfb!important;border-color:var(--lay-border-color)!important;color:var(--lay-gray-400)!important;cursor:not-allowed!important;opacity:1}.layui-btn-lg{font-size:16px;height:44px;line-height:44px;padding:0 25px}.layui-btn-sm{font-size:12px;height:30px;line-height:30px;padding:0 10px}.layui-btn-xs{font-size:12px;height:22px;line-height:22px;padding:0 5px}.layui-btn-xs i{font-size:12px!important}.layui-btn-group{display:inline-block;font-size:0;vertical-align:middle}.layui-btn-group .layui-btn{border-left:1px solid hsla(0,0%,100%,.5);border-radius:0;margin-left:0!important;margin-right:0!important}.layui-btn-group .layui-btn-primary{border-left:none}.layui-btn-group .layui-btn-primary:hover{border-color:var(--lay-border-color-accent);color:var(--lay-color-primary)}.layui-btn-group .layui-btn:first-child{border-left:none;border-radius:var(--lay-border-radius) 0 0 var(--lay-border-radius)}.layui-btn-group .layui-btn-primary:first-child{border-left:1px solid var(--lay-gray-400)}.layui-btn-group .layui-btn:last-child{border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0}.layui-btn-group .layui-btn+.layui-btn{margin-left:0}.layui-btn-group+.layui-btn-group{margin-left:10px}.layui-btn-fluid{width:100%}.layui-input,.layui-select,.layui-textarea{background-color:#fff;border-radius:var(--lay-border-radius);border-style:solid;border-width:1px;color:rgba(0,0,0,.85);height:38px;line-height:1.3;line-height:38px\9}.layui-input::-webkit-input-placeholder,.layui-select::-webkit-input-placeholder,.layui-textarea::-webkit-input-placeholder{line-height:1.3}.layui-input,.layui-textarea{display:block;padding-left:10px;width:100%}.layui-input:hover,.layui-textarea:hover{border-color:var(--lay-border-color-accent)!important}.layui-input:focus,.layui-textarea:focus{border-color:var(--lay-color-accent)!important;box-shadow:0 0 0 3px rgba(22,183,119,.08)}.layui-textarea{height:auto;line-height:20px;min-height:100px;padding:6px 10px;position:relative;resize:vertical}.layui-input[disabled],.layui-textarea[disabled]{background-color:var(--lay-color-gray)}.layui-select{padding:0 10px}.layui-form input[type=checkbox],.layui-form input[type=radio],.layui-form select{display:none}.layui-form [lay-ignore]{display:initial}.layui-form-item{clear:both;margin-bottom:15px;position:relative}.layui-form-item:after{clear:both;content:"\20";display:block;height:0}.layui-form-label{display:block;float:left;font-weight:400;line-height:20px;padding:9px 15px;position:relative;text-align:right;width:80px}.layui-form-label-col{display:block;float:none;line-height:20px;padding:9px 0;text-align:left}.layui-form-item .layui-inline{margin-bottom:5px;margin-right:10px}.layui-input-block,.layui-input-inline{position:relative}.layui-input-block{margin-left:110px;min-height:36px}.layui-input-inline{display:inline-block;vertical-align:middle}.layui-form-item .layui-input-inline{float:left;margin-right:10px;width:190px}.layui-form-text .layui-input-inline{width:auto}.layui-form-mid{display:block;float:left;line-height:20px;margin-right:10px;padding:9px 0!important;position:relative}.layui-form-danger+.layui-form-select .layui-input,.layui-form-danger:focus{border-color:var(--lay-color-red)!important;box-shadow:0 0 0 3px rgba(255,87,34,.08)}.layui-input-prefix,.layui-input-split,.layui-input-suffix,.layui-input-suffix .layui-input-affix{box-sizing:border-box;height:100%;padding:0 10px;position:absolute;right:0;text-align:center;top:0;transition:all .3s;width:35px}.layui-input-prefix{border-radius:var(--lay-border-radius) 0 0 var(--lay-border-radius);left:0}.layui-input-suffix{border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0;right:0}.layui-input-split{border-style:solid;border-width:1px}.layui-input-prefix .layui-icon,.layui-input-split .layui-icon,.layui-input-suffix .layui-icon{color:#5f5f5f;font-size:16px;position:relative;transition:all .3s}.layui-input-group{box-sizing:border-box;display:table;position:relative}.layui-input-group>*{display:table-cell;position:relative;vertical-align:middle}.layui-input-group .layui-input{padding-right:15px}.layui-input-group>.layui-input-prefix{border-right:0;width:auto}.layui-input-group>.layui-input-suffix{border-left:0;width:auto}.layui-input-group .layui-input-split{white-space:nowrap}.layui-input-wrap{line-height:38px;position:relative}.layui-input-wrap .layui-input{padding-right:35px}.layui-input-wrap .layui-input::-ms-clear,.layui-input-wrap .layui-input::-ms-reveal{display:none}.layui-input-wrap .layui-input-prefix+.layui-input,.layui-input-wrap .layui-input-prefix~* .layui-input{padding-left:35px}.layui-input-wrap .layui-input-split+.layui-input,.layui-input-wrap .layui-input-split~* .layui-input{padding-left:45px}.layui-input-wrap .layui-input-prefix~.layui-form-select{position:static}.layui-input-wrap .layui-input-prefix,.layui-input-wrap .layui-input-split,.layui-input-wrap .layui-input-suffix{pointer-events:none}.layui-input-wrap .layui-input:hover+.layui-input-split{border-color:var(--lay-border-color-accent)}.layui-input-wrap .layui-input:focus+.layui-input-split{border-color:var(--lay-color-accent)}.layui-input-wrap .layui-input.layui-form-danger:focus+.layui-input-split{border-color:var(--lay-color-red)}.layui-input-wrap .layui-input-prefix.layui-input-split{border-width:0 1px 0 0}.layui-input-wrap .layui-input-suffix.layui-input-split{border-width:0 0 0 1px}.layui-input-affix{line-height:38px}.layui-input-suffix .layui-input-affix{left:-35px;right:auto}.layui-input-affix .layui-icon{color:rgba(0,0,0,.8);cursor:pointer;pointer-events:auto!important}.layui-input-affix .layui-icon-clear{color:rgba(0,0,0,.3)}.layui-input-affix .layui-icon:hover{color:rgba(0,0,0,.6)}.layui-input-wrap .layui-input-number{padding:0;width:24px}.layui-input-wrap .layui-input-number .layui-icon{font-size:12px;height:50%;line-height:normal;position:absolute;right:0;width:100%}.layui-input-wrap .layui-input-number .layui-icon:before{left:50%;margin-left:-6px;margin-top:-6px;position:absolute;top:50%}.layui-input-wrap .layui-input-number .layui-icon-up{border-bottom:1px solid var(--lay-border-color);top:0}.layui-input-wrap .layui-input-number .layui-icon-down{bottom:0}.layui-input-wrap .layui-input-number .layui-icon:hover{font-weight:700}.layui-input-wrap .layui-input[type=number]::-webkit-inner-spin-button,.layui-input-wrap .layui-input[type=number]::-webkit-outer-spin-button{-webkit-appearance:none!important}.layui-input-wrap .layui-input[type=number]{-moz-appearance:textfield;-webkit-appearance:textfield;appearance:textfield}.layui-input-wrap .layui-input.layui-input-number-invalid,.layui-input-wrap .layui-input.layui-input-number-out-of-range{color:var(--lay-color-red)}.layui-form-select{color:#5f5f5f;position:relative}.layui-form-select .layui-input{cursor:pointer;padding-right:30px}.layui-form-select .layui-edge{border-top:solid #c2c2c2;border-width:6px;cursor:pointer;margin-top:-3px;position:absolute;right:10px;top:50%;transition:all .3s}.layui-form-select dl{background-color:#fff;border:1px solid var(--lay-border-color);border-radius:var(--lay-border-radius);box-shadow:1px 1px 4px rgb(0 0 0/8%);box-sizing:border-box;display:none;left:0;max-height:300px;min-width:100%;overflow-y:auto;padding:5px 0;position:absolute;top:42px;z-index:899}.layui-form-select dl dd,.layui-form-select dl dt{line-height:36px;overflow:hidden;padding:0 10px;text-overflow:ellipsis;white-space:nowrap}.layui-form-select dl dt{color:#999;font-size:12px}.layui-form-select dl dd{cursor:pointer}.layui-form-select dl dd:hover{background-color:#f8f8f8;transition:all .5s}.layui-form-select .layui-select-group dd{padding-left:20px}.layui-form-select dl dd.layui-select-tips{color:#999;padding-left:10px!important}.layui-form-select dl dd.layui-this{background-color:#f8f8f8;color:var(--lay-color-accent);font-weight:700}.layui-form-select dl dd.layui-disabled{background-color:#fff}.layui-form-selected dl{display:block}.layui-form-selected .layui-edge{margin-top:-9px;margin-top:-3px\0;transform:rotate(180deg)}:root .layui-form-selected .layui-edge{margin-top:-9px\0/IE9}.layui-form-selectup dl{bottom:42px;top:auto}.layui-select-none{color:#999;margin:5px 0;text-align:center}.layui-select-panel-wrap{position:absolute;z-index:99999999}.layui-select-panel-wrap dl{display:block;position:relative;top:0}.layui-select-disabled .layui-disabled{border-color:var(--lay-border-color)!important}.layui-select-disabled .layui-edge{border-top-color:var(--lay-border-color-accent)}.layui-form-checkbox{background-color:#fff;box-sizing:border-box;cursor:pointer;font-size:0;height:30px;line-height:30px;margin-right:10px;padding-right:30px;position:relative;transition:.1s linear}.layui-form-checkbox,.layui-form-checkbox>*{display:inline-block;vertical-align:middle}.layui-form-checkbox>div{background-color:var(--lay-gray-400);border-radius:var(--lay-border-radius) 0 0 var(--lay-border-radius);color:#fff;font-size:14px;overflow:hidden;padding:0 11px;text-overflow:ellipsis;white-space:nowrap}.layui-form-checkbox>div>.layui-icon{line-height:normal}.layui-form-checkbox:hover>div{background-color:#c2c2c2}.layui-form-checkbox>i{border:1px solid var(--lay-border-color-accent);border-left:none;border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0;box-sizing:border-box;color:#fff;color:hsla(0,0%,100%,0);font-size:20px;height:100%;position:absolute;right:0;text-align:center;top:0;width:30px}.layui-form-checkbox:hover>i{border-color:#c2c2c2;color:#c2c2c2}.layui-form-checked,.layui-form-checked:hover{border-color:var(--lay-color-accent)}.layui-form-checked:hover>div,.layui-form-checked>div{background-color:var(--lay-color-accent)}.layui-form-checked:hover>i,.layui-form-checked>i{color:var(--lay-color-accent)}.layui-form-item .layui-form-checkbox{margin-top:4px}.layui-form-checkbox.layui-checkbox-disabled>div{background-color:var(--lay-gray-300)!important}.layui-form [lay-checkbox]{display:none}.layui-form-checkbox[lay-skin=primary]{background:none;border:none!important;height:auto!important;line-height:normal!important;margin-right:0;min-height:18px;min-width:18px;padding-left:24px;padding-right:0}.layui-form-checkbox[lay-skin=primary]>div{background:none;color:#5f5f5f;line-height:18px;margin-top:-1px;padding-left:0;padding-right:15px}.layui-form-checkbox[lay-skin=primary]>i{background-color:#fff;border:1px solid #d2d2d2;border-radius:var(--lay-border-radius);font-size:12px;height:16px;left:0;line-height:14px;right:auto;transition:.1s linear;width:16px}.layui-form-checkbox[lay-skin=primary]:hover>i{border-color:var(--lay-color-accent);color:#fff}.layui-form-checked[lay-skin=primary]>i{background-color:var(--lay-color-accent);border-color:var(--lay-color-accent)!important;color:#fff}.layui-checkbox-disabled[lay-skin=primary]>div{background:none!important}.layui-form-checked.layui-checkbox-disabled[lay-skin=primary]>i{background:var(--lay-gray-300)!important;border-color:var(--lay-gray-300)!important}.layui-checkbox-disabled[lay-skin=primary]:hover>i{border-color:var(--lay-border-color-accent)}.layui-form-item .layui-form-checkbox[lay-skin=primary]{margin-top:10px}.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate{background-color:#fff;border-color:var(--lay-color-accent)}.layui-form-checkbox[lay-skin=primary]>.layui-icon-indeterminate:before{background-color:var(--lay-color-accent);content:"";display:inline-block;height:1px;margin:-1px auto 0;position:relative;vertical-align:middle;width:50%}.layui-form-switch{background-color:#fff;border:1px solid #d2d2d2;box-sizing:border-box;cursor:pointer;display:inline-block;height:24px;line-height:22px;margin-top:8px;min-width:44px;padding:0 5px;position:relative;vertical-align:middle}.layui-form-switch,.layui-form-switch>i{border-radius:20px;transition:.1s linear}.layui-form-switch>i{background-color:var(--lay-gray-400);height:16px;left:5px;position:absolute;top:3px;width:16px}.layui-form-switch>div{color:#999!important;font-size:12px;font-style:normal!important;margin-left:21px;padding:0!important;position:relative;text-align:center!important;top:0}.layui-form-onswitch{background-color:var(--lay-color-accent);border-color:var(--lay-color-accent)}.layui-form-onswitch>i{background-color:#fff;left:100%;margin-left:-21px}.layui-form-onswitch>div{color:#fff!important;margin-left:0;margin-right:21px}.layui-form-checkbox[lay-skin=none] *,.layui-form-radio[lay-skin=none] *{box-sizing:border-box}.layui-form-checkbox[lay-skin=none],.layui-form-radio[lay-skin=none]{height:auto;line-height:normal;margin:0;min-height:20px;padding:0;position:relative}.layui-form-checkbox[lay-skin=none]>div,.layui-form-radio[lay-skin=none]>div{background-color:inherit;color:inherit;cursor:pointer;left:0;position:relative;top:0;z-index:10}.layui-form-checkbox[lay-skin=none]>i,.layui-form-radio[lay-skin=none]>i{display:none}.layui-form-checkbox[lay-skin=none].layui-checkbox-disabled>div,.layui-form-radio[lay-skin=none].layui-radio-disabled>div{cursor:not-allowed}.layui-checkbox-disabled{border-color:var(--lay-border-color)!important}.layui-checkbox-disabled>div{color:#c2c2c2!important}.layui-checkbox-disabled>i{border-color:var(--lay-border-color)!important}.layui-checkbox-disabled:hover>i{color:#fff!important}.layui-form-checkbox[lay-skin=tag].layui-form-checked.layui-checkbox-disabled>i{color:#c2c2c2}.layui-form-checkbox[lay-skin=tag].layui-form-checked.layui-checkbox-disabled:hover>i{color:#c2c2c2!important}.layui-form-radio{cursor:pointer;font-size:0;line-height:28px;margin:6px 10px 0 0;padding-right:10px}.layui-form-radio,.layui-form-radio>*{display:inline-block;vertical-align:middle}.layui-form-radio>*{font-size:14px}.layui-form-radio>i{color:#c2c2c2;font-size:22px;margin-right:8px}.layui-form-radio:hover>*,.layui-form-radioed,.layui-form-radioed>i{color:var(--lay-color-accent)}.layui-radio-disabled>i{color:var(--lay-gray-300)!important}.layui-radio-disabled>*{color:#c2c2c2!important}.layui-form [lay-radio]{display:none}.layui-form-pane .layui-form-label{background-color:var(--lay-color-gray);border-radius:var(--lay-border-radius) 0 0 var(--lay-border-radius);border-style:solid;border-width:1px;box-sizing:border-box;height:38px;line-height:20px;overflow:hidden;padding:8px 15px;text-align:center;text-overflow:ellipsis;white-space:nowrap;width:110px}.layui-form-pane .layui-input-inline{margin-left:-1px}.layui-form-pane .layui-input-block{left:-1px;margin-left:110px}.layui-form-pane .layui-input{border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0}.layui-form-pane .layui-form-text .layui-form-label{border-radius:var(--lay-border-radius);box-sizing:border-box;float:none;text-align:left;width:100%}.layui-form-pane .layui-form-text .layui-input-inline{clear:both;display:block;margin:0;top:-1px}.layui-form-pane .layui-form-text .layui-input-block{left:0;margin:0;top:-1px}.layui-form-pane .layui-form-text .layui-textarea{border-radius:0 0 var(--lay-border-radius) var(--lay-border-radius);min-height:100px}.layui-form-pane .layui-form-checkbox{margin:4px 0 4px 10px}.layui-form-pane .layui-form-radio,.layui-form-pane .layui-form-switch{margin-left:10px;margin-top:6px}.layui-form-pane .layui-form-item[pane]{border-style:solid;border-width:1px;position:relative}.layui-form-pane .layui-form-item[pane] .layui-form-label{border-width:0 1px 0 0;height:100%;left:0;position:absolute;top:0}.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left:110px}@media screen and (max-width:450px){.layui-form-item .layui-form-label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.layui-form-item .layui-inline{clear:both;display:block;margin-bottom:20px;margin-right:0}.layui-form-item .layui-inline:after{clear:both;content:"\20";display:block;height:0}.layui-form-item .layui-input-inline{display:block;float:none;left:-3px;margin:0 0 10px 112px;width:auto!important}.layui-form-item .layui-input-inline+.layui-form-mid{margin-left:110px;padding:0;top:-5px}.layui-form-item .layui-form-checkbox{margin-bottom:5px;margin-right:5px}}.layui-laypage{display:inline-block;font-size:0;margin:10px 0;vertical-align:middle}.layui-laypage>a:first-child,.layui-laypage>a:first-child em{border-radius:var(--lay-border-radius) 0 0 var(--lay-border-radius)}.layui-laypage>a:last-child,.layui-laypage>a:last-child em{border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0}.layui-laypage>:first-child{margin-left:0!important}.layui-laypage>:last-child{margin-right:0!important}.layui-laypage a,.layui-laypage button,.layui-laypage input,.layui-laypage select,.layui-laypage span{border:1px solid var(--lay-border-color)}.layui-laypage a,.layui-laypage span{background-color:#fff;color:#333;display:inline-block;font-size:12px;height:28px;line-height:28px;margin:0 -1px 5px 0;padding:0 15px;vertical-align:middle}.layui-laypage a[data-page]{color:#333}.layui-laypage a{cursor:pointer;text-decoration:none!important}.layui-laypage a:hover{color:var(--lay-color-primary)}.layui-laypage em{font-style:normal}.layui-laypage .layui-laypage-spr{color:#999;font-weight:700}.layui-laypage .layui-laypage-curr{position:relative}.layui-laypage .layui-laypage-curr em{color:#fff;position:relative}.layui-laypage .layui-laypage-curr .layui-laypage-em{background-color:var(--lay-color-primary);height:100%;left:-1px;padding:1px;position:absolute;top:-1px;width:100%}.layui-laypage-em{border-radius:var(--lay-border-radius)}.layui-laypage-next em,.layui-laypage-prev em{font-family:Sim sun;font-size:16px}.layui-laypage .layui-laypage-count,.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh,.layui-laypage .layui-laypage-skip{border:none;margin-left:10px;margin-right:10px;padding:0}.layui-laypage .layui-laypage-limits,.layui-laypage .layui-laypage-refresh{vertical-align:top}.layui-laypage .layui-laypage-refresh i{cursor:pointer;font-size:18px}.layui-laypage select{border-radius:var(--lay-border-radius);cursor:pointer;height:22px;padding:3px}.layui-laypage .layui-laypage-skip{color:#999;height:30px;line-height:30px}.layui-laypage button,.layui-laypage input{background-color:#fff;border-radius:var(--lay-border-radius);box-sizing:border-box;height:30px;line-height:30px;vertical-align:top}.layui-laypage input{display:inline-block;margin:0 10px;padding:0 3px;text-align:center;transition:none;width:40px}.layui-laypage input:focus,.layui-laypage select:focus{border-color:var(--lay-color-primary)!important}.layui-laypage button{cursor:pointer;margin-left:10px;padding:0 10px}.layui-flow-more{clear:both;color:#999;font-size:14px;margin:10px 0;text-align:center}.layui-flow-more a{height:32px;line-height:32px}.layui-flow-more a *{display:inline-block;vertical-align:top}.layui-flow-more a cite{background-color:var(--lay-gray-300);border-radius:var(--lay-border-radius);color:#333;font-style:normal;padding:0 20px}.layui-flow-more a cite:hover{opacity:.8}.layui-flow-more a i{color:#737383;font-size:30px}.layui-table{background-color:#fff;color:#5f5f5f;margin:10px 0;width:100%}.layui-table tr{transition:all .3s}.layui-table th{font-weight:600;text-align:left}.layui-table-mend{background-color:#fff}.layui-table-click,.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(2n){background-color:#f8f8f8}.layui-table-checked{background-color:#dbfbf0}.layui-table-checked.layui-table-click,.layui-table-checked.layui-table-hover,.layui-table[lay-even] tbody tr:nth-child(2n).layui-table-checked{background-color:#abf8dd}.layui-table-disabled-transition *,.layui-table-disabled-transition :after,.layui-table-disabled-transition :before{transition:none!important}.layui-table td,.layui-table th,.layui-table-col-set,.layui-table-fixed-r,.layui-table-grid-down,.layui-table-header,.layui-table-mend,.layui-table-page,.layui-table-tips-main,.layui-table-tool,.layui-table-total,.layui-table-view,.layui-table[lay-skin=line],.layui-table[lay-skin=row]{border-color:var(--lay-border-color);border-style:solid;border-width:1px}.layui-table td,.layui-table th{font-size:14px;line-height:20px;min-height:20px;padding:9px 15px;position:relative}.layui-table[lay-skin=line] td,.layui-table[lay-skin=line] th{border-width:0 0 1px}.layui-table[lay-skin=row] td,.layui-table[lay-skin=row] th{border-width:0 1px 0 0}.layui-table[lay-skin=nob] td,.layui-table[lay-skin=nob] th{border:none}.layui-table img{max-width:100px}.layui-table[lay-size=lg] td,.layui-table[lay-size=lg] th{padding:15px 30px}.layui-table-view .layui-table[lay-size=lg] .layui-table-cell{height:50px;line-height:40px}.layui-table[lay-size=sm] td,.layui-table[lay-size=sm] th{font-size:12px;padding:5px 10px}.layui-table-view .layui-table[lay-size=sm] .layui-table-cell{height:30px;line-height:20px;padding-left:11px;padding-right:11px;padding-top:5px}.layui-table[lay-data],.layui-table[lay-options]{display:none}.layui-table-box{overflow:hidden;position:relative}.layui-table-view{border-right:none;clear:both;position:relative}.layui-table-view:after{background-color:var(--lay-gray-300);content:"";height:100%;position:absolute;right:0;top:0;width:1px;z-index:101}.layui-table-view .layui-table{border:0;border-collapse:separate;margin:0;position:relative;width:auto}.layui-table-view .layui-table[lay-skin=line]{border-width:0 1px 0 0}.layui-table-view .layui-table[lay-skin=row]{border-width:0 0 1px}.layui-table-view .layui-table td,.layui-table-view .layui-table th{border-left:none;border-top:none;padding:0}.layui-table-view .layui-table th [lay-event],.layui-table-view .layui-table th.layui-unselect .layui-table-cell span{cursor:pointer}.layui-table-view .layui-table td,.layui-table-view .layui-table th span{cursor:default}.layui-table-view .layui-table td[data-edit]{cursor:text}.layui-table-view .layui-table td[data-edit]:hover:after{border:1px solid #16b777;box-sizing:border-box;content:"";height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%}.layui-table-view .layui-form-checkbox[lay-skin=primary] i{height:18px;line-height:16px;width:18px}.layui-table-view .layui-form-radio{line-height:0;padding:0}.layui-table-view .layui-form-radio>i{font-size:20px;margin:0}.layui-table-init{bottom:0;left:0;margin:0;position:absolute;right:0;top:0;transition:opacity .1s;-webkit-user-select:none;-moz-user-select:none;user-select:none;z-index:199}.layui-table-loading-icon{left:50%;left:auto\0;margin-top:-15px\0;position:absolute;text-align:center;top:50%;transform:translate(-50%,-50%);transform:none\0;width:100%\0}.layui-table-loading-icon .layui-icon{color:#c2c2c2;font-size:30px}.layui-table-header{border-width:0 0 1px;overflow:hidden}.layui-table-header .layui-table{margin-bottom:-1px}.layui-table-column{border-width:0 0 1px;min-height:41px;padding:8px 16px;position:relative;width:100%}.layui-table-column .layui-btn-container{margin-bottom:-8px}.layui-table-column .layui-btn-container .layui-btn{margin-bottom:8px;margin-right:8px}.layui-table-tool .layui-inline[lay-event]{border:1px solid #ccc;color:#333;cursor:pointer;height:26px;line-height:16px;margin-right:10px;padding:5px;position:relative;text-align:center;transition:all .5s;width:26px}.layui-table-tool .layui-inline[lay-event]:hover{border:1px solid #999}.layui-table-tool-temp{padding-right:120px}.layui-table-tool-self{position:absolute;right:17px;top:10px}.layui-table-tool .layui-table-tool-self .layui-inline[lay-event]{margin:0 0 0 10px}.layui-table-tool-panel{background-color:#fff;border:1px solid var(--lay-border-color-accent);box-shadow:0 2px 4px rgba(0,0,0,.12);left:-1px;min-height:40px;min-width:150px;overflow-y:auto;padding:5px 0!important;position:absolute;text-align:left;top:29px;z-index:399}.layui-table-tool-panel li{line-height:30px;list-style-type:none!important;margin:0!important;overflow:hidden;padding:0 10px;text-overflow:ellipsis;transition:all .5s;white-space:nowrap}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{width:100%}.layui-table-tool-panel li:hover{background-color:#f8f8f8}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary]{padding-left:28px}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] i{left:0;position:absolute;top:0}.layui-table-tool-panel li .layui-form-checkbox[lay-skin=primary] span{padding:0}.layui-table-tool .layui-table-tool-self .layui-table-tool-panel{left:auto;right:-1px}.layui-table-col-set{background-color:#fff;border-width:0 0 0 1px;height:100%;position:absolute;right:0;top:0;width:20px}.layui-table-sort{cursor:pointer!important;height:20px;margin-left:5px;width:10px}.layui-table-sort .layui-edge{border-width:5px;left:5px;position:absolute}.layui-table-sort .layui-table-sort-asc{border-bottom-color:#b2b2b2;border-bottom-style:solid;border-top:none;top:3px}.layui-table-sort .layui-table-sort-asc:hover{border-bottom-color:#5f5f5f}.layui-table-sort .layui-table-sort-desc{border-bottom:none;border-top-color:#b2b2b2;border-top-style:solid;bottom:5px}.layui-table-sort .layui-table-sort-desc:hover{border-top-color:#5f5f5f}.layui-table-sort[lay-sort=asc] .layui-table-sort-asc{border-bottom-color:#000}.layui-table-sort[lay-sort=desc] .layui-table-sort-desc{border-top-color:#000}.layui-table-cell{box-sizing:border-box;height:38px;line-height:28px;overflow:hidden;padding:6px 15px;position:relative;text-overflow:ellipsis;white-space:nowrap}.layui-table-cell .layui-form-checkbox[lay-skin=primary]{padding:0;top:-1px}.layui-table-cell .layui-form-checkbox[lay-skin=primary]>div{padding-left:24px}.layui-table-cell .layui-table-link{color:#01aaed}.layui-table-cell .layui-btn{vertical-align:inherit}.layui-table-cell[align=center]{-webkit-box-pack:center}.layui-table-cell[align=right]{-webkit-box-pack:end}.laytable-cell-checkbox,.laytable-cell-numbers,.laytable-cell-radio,.laytable-cell-space{text-align:center;-webkit-box-pack:center}.layui-table-body{margin-bottom:-1px;overflow:auto;position:relative}.layui-table-body .layui-none{color:#999;line-height:26px;padding:30px 15px;text-align:center}.layui-table-fixed{left:0;position:absolute;top:0;z-index:101}.layui-table-fixed .layui-table-body{overflow:hidden}.layui-table-fixed-l{box-shadow:1px 0 8px rgba(0,0,0,.08)}.layui-table-fixed-r{border-width:0 0 0 1px;box-shadow:-1px 0 8px rgba(0,0,0,.08);left:auto;right:0}.layui-table-fixed-r .layui-table-header{overflow:visible;position:relative}.layui-table-mend{border-width:0 0 0 1px;height:100%;position:absolute;right:-49px;top:0;width:50px}.layui-table-tool{border-width:0 0 1px;line-height:30px;min-height:50px;padding:10px 15px;position:relative;width:100%}.layui-table-tool .layui-btn-container{margin-bottom:-10px}.layui-table-page,.layui-table-total{border-width:1px 0 0;margin-bottom:-1px;overflow:hidden}.layui-table-page{white-space:nowrap}.layui-table-page>div{height:26px}.layui-table-page .layui-laypage{margin:0}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span{background:none;border:none;height:26px;line-height:26px;margin-bottom:10px}.layui-table-page .layui-laypage a,.layui-table-page .layui-laypage span.layui-laypage-curr{padding:0 12px}.layui-table-page .layui-laypage span{margin-left:0;padding:0}.layui-table-page .layui-laypage .layui-laypage-prev{margin-left:-11px!important}.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em{left:0;padding:0;top:0}.layui-table-page .layui-laypage button,.layui-table-page .layui-laypage input{height:26px;line-height:26px}.layui-table-page .layui-laypage input{width:40px}.layui-table-page .layui-laypage button{padding:0 10px}.layui-table-page select{height:18px}.layui-table-pagebar{float:right;line-height:23px}.layui-table-pagebar .layui-btn-sm{margin-top:-1px}.layui-table-pagebar .layui-btn-xs{margin-top:2px}.layui-table-view select[lay-ignore]{display:inline-block}.layui-table-patch .layui-table-cell{padding:0;width:30px}.layui-table-edit{background-color:#fff;border-radius:0;box-shadow:1px 1px 20px rgba(0,0,0,.15);left:0;min-height:100%;min-width:100%;padding:5px 14px;position:absolute;top:0;z-index:189}.layui-table-edit:focus{border-color:var(--lay-color-accent)!important}input.layui-input.layui-table-edit{height:100%}select.layui-table-edit{border-color:var(--lay-border-color-accent);padding:0 0 0 10px}.layui-table-view .layui-form-checkbox,.layui-table-view .layui-form-radio,.layui-table-view .layui-form-switch{margin:0;top:0}.layui-table-view .layui-form-checkbox{height:26px;line-height:26px;top:-1px}.layui-table-view .layui-form-checkbox i{height:26px}.layui-table-grid .layui-table-cell{overflow:visible}.layui-table-grid-down{background-color:#fff;border-width:0 0 0 1px;color:#999;cursor:pointer;height:100%;padding:5px 0;position:absolute;right:0;text-align:center;top:0;width:24px}.layui-table-grid-down .layui-icon{font-size:14px;left:50%;margin:-8px 0 0 -8px;position:absolute;top:50%}.layui-table-grid-down:hover{background-color:#fbfbfb}.layui-table-expanded{height:95px}.layui-table-expanded .layui-table-cell,.layui-table-view .layui-table[lay-size=lg] .layui-table-expanded .layui-table-cell,.layui-table-view .layui-table[lay-size=sm] .layui-table-expanded .layui-table-cell{height:auto;max-height:94px;text-overflow:clip;white-space:normal}.layui-table-cell-c{background-color:#fff;border:1px solid var(--lay-border-color);border-radius:50%;bottom:-10px;cursor:pointer;font-size:14px;height:20px;line-height:18px;margin-right:-9px;position:absolute;right:50%;text-align:center;transition:all .3s;width:20px;z-index:1000}.layui-table-cell-c:hover{border-color:var(--lay-color-accent)}.layui-table-expanded td:hover .layui-table-cell{overflow:auto}.layui-table-main>.layui-table>tbody>tr:last-child>td>.layui-table-cell-c{bottom:0}body .layui-table-tips .layui-layer-content{background:none;box-shadow:0 1px 6px rgba(0,0,0,.12);padding:0}.layui-table-tips-main{background-color:#fff;color:#5f5f5f;font-size:14px;margin:-49px 0 0 -1px;max-height:150px;overflow-y:scroll;padding:8px 15px}.layui-table-tips-c{background-color:#5f5f5f;border-radius:50%;color:#fff;cursor:pointer;height:20px;padding:3px;position:absolute;right:-3px;top:-13px;width:20px}.layui-table-tips-c:hover{background-color:#777}.layui-table-tips-c:before{position:relative;right:-2px}.layui-table-tree-nodeIcon{max-width:20px}.layui-table-tree-nodeIcon>*{width:100%}.layui-table-tree-flexIcon,.layui-table-tree-nodeIcon{margin-right:2px}.layui-table-tree-flexIcon{cursor:pointer}.layui-upload-file{display:none!important;filter:Alpha(opacity=1);opacity:.01}.layui-upload-list{margin:11px 0}.layui-upload-choose{color:#999;font-size:14px;max-width:200px;overflow:hidden;padding:0 10px;text-overflow:ellipsis;white-space:nowrap}.layui-upload-drag{background-color:#fff;border:1px dashed #e2e2e2;color:#999;cursor:pointer;display:inline-block;padding:30px;position:relative;text-align:center}.layui-upload-drag .layui-icon{color:var(--lay-color-primary);font-size:50px}.layui-upload-drag[lay-over]{border-color:var(--lay-color-primary)}.layui-upload-form{display:inline-block}.layui-upload-iframe{border:0;height:0;position:absolute;visibility:hidden;width:0}.layui-upload-wrap{display:inline-block;position:relative;vertical-align:middle}.layui-upload-wrap .layui-upload-file{cursor:pointer;display:block!important;filter:Alpha(opacity=1);font-size:100px;height:100%;left:0;opacity:.01;position:absolute;top:0;width:100%;z-index:10}.layui-btn-container .layui-upload-choose{padding-left:0}.layui-menu{background-color:#fff;margin:5px 0;position:relative}.layui-menu,.layui-menu *{box-sizing:border-box}.layui-menu li,.layui-menu-body-title,.layui-menu-body-title a{color:initial;padding:5px 15px}.layui-menu li{color:rgba(0,0,0,.8);cursor:pointer;font-size:14px;line-height:26px;margin:0 0 1px;position:relative;transition:all .3s;white-space:nowrap}.layui-menu li:hover{background-color:#f8f8f8}.layui-menu li.layui-disabled,.layui-menu li.layui-disabled *{background:none!important;color:#d2d2d2!important;cursor:not-allowed!important}.layui-menu-item-parent:hover>.layui-menu-body-panel{animation-delay:.2s;animation-duration:.3s;animation-fill-mode:both;animation-name:layui-fadein;display:block}.layui-menu-item-group>.layui-menu-body-title,.layui-menu-item-parent>.layui-menu-body-title{padding-right:38px}.layui-menu .layui-menu-item-divider:hover,.layui-menu .layui-menu-item-group:hover,.layui-menu .layui-menu-item-none:hover{background:none;cursor:default}.layui-menu .layui-menu-item-group>ul{margin:5px 0 -5px}.layui-menu .layui-menu-item-group>.layui-menu-body-title{color:rgba(0,0,0,.35);-webkit-user-select:none;-moz-user-select:none;user-select:none}.layui-menu .layui-menu-item-none{color:rgba(0,0,0,.35);cursor:default;text-align:center}.layui-menu .layui-menu-item-divider{border-bottom:1px solid var(--lay-border-color);height:0;line-height:0;margin:5px 0;overflow:hidden;padding:0}.layui-menu .layui-menu-item-down:hover,.layui-menu .layui-menu-item-up:hover{cursor:pointer}.layui-menu .layui-menu-item-up>.layui-menu-body-title{color:rgba(0,0,0,.8)}.layui-menu .layui-menu-item-up>ul{height:0;overflow:hidden;visibility:hidden}.layui-menu .layui-menu-item-down>.layui-menu-body-title>.layui-icon-down{transform:rotate(180deg)}.layui-menu .layui-menu-item-up>.layui-menu-body-title>.layui-icon-up{transform:rotate(-180deg)}.layui-menu .layui-menu-item-down:hover>.layui-menu-body-title>.layui-icon,.layui-menu .layui-menu-item-up>.layui-menu-body-title:hover>.layui-icon{color:#000}.layui-menu .layui-menu-item-down>ul{height:auto;visibility:visible}.layui-menu .layui-menu-item-checked,.layui-menu .layui-menu-item-checked2{background-color:#f8f8f8!important;color:var(--lay-color-accent)}.layui-menu .layui-menu-item-checked a,.layui-menu .layui-menu-item-checked2 a{color:var(--lay-color-accent)}.layui-menu .layui-menu-item-checked:after{border-right:3px solid var(--lay-color-accent);bottom:0;content:"";position:absolute;right:-1px;top:0}.layui-menu-body-title{position:relative}.layui-menu-body-title,.layui-menu-body-title a{margin:-5px -15px;overflow:hidden;text-overflow:ellipsis}.layui-menu-body-title a{color:rgba(0,0,0,.8);display:block}.layui-menu-body-title a:hover{transition:all .3s}.layui-menu-body-title>.layui-icon{font-size:14px;line-height:normal;margin-top:-6px;position:absolute;right:15px;top:50%;transition:all .2s}.layui-menu-body-title>.layui-icon:hover{transition:all .3s}.layui-menu-body-title>.layui-icon-right{right:14px}.layui-menu-body-panel{display:none;left:100%;margin-left:13px;padding:5px 0;position:absolute;top:-7px;z-index:1000}.layui-menu-body-panel:before{bottom:0;content:"";left:-16px;position:absolute;top:0;width:20px}.layui-menu-body-panel-left{left:auto;margin:0 13px;right:100%}.layui-menu-body-panel-left:before{left:auto;right:-16px}.layui-menu-lg li{line-height:32px}.layui-menu-lg .layui-menu-body-title a:hover,.layui-menu-lg li:hover{background:none;color:var(--lay-color-accent)}.layui-menu-lg li .layui-menu-body-panel{margin-left:14px}.layui-menu-lg li .layui-menu-body-panel-left{margin:0 15px}.layui-dropdown{left:-999999px;margin:5px 0;min-width:100px;position:absolute;top:-999999px;z-index:77777777}.layui-dropdown:before{content:"";height:6px;left:0;position:absolute;top:-6px;width:100%}.layui-dropdown-shade{height:100%;left:0;pointer-events:auto;position:fixed;top:0;width:100%}.layui-tabs{position:relative}.layui-tabs.layui-hide-v{overflow:hidden}.layui-tabs-header{font-size:0;height:40px;left:0;padding:0!important;position:relative;transition:all .16s;white-space:nowrap}.layui-tabs-header:after,.layui-tabs-scroll:after{border-bottom:1px solid var(--lay-border-color);bottom:0;content:"";left:0;position:absolute;width:100%;z-index:0}.layui-tabs-header li{cursor:pointer;display:inline-block;font-size:14px;line-height:40px;margin:0!important;padding:0 16px;position:relative;text-align:center;transition:all .16s;vertical-align:middle}.layui-tabs-header li:first-child{margin-left:0}.layui-tabs-header li a{color:inherit;display:block;margin:0 calc(var(--lay-spacing)*-1);padding:0 var(--lay-spacing)}.layui-tabs-header li a:hover{text-decoration:none}.layui-tabs-header .layui-this,.layui-tabs-header li:hover{color:var(--lay-color-primary)}.layui-tabs-header .layui-this:after{border-bottom:3px solid var(--lay-color-primary);box-sizing:border-box;content:"";height:100%;left:0;pointer-events:none;position:absolute;top:0;width:100%;z-index:1}.layui-tabs-header .layui-badge,.layui-tabs-header .layui-badge-dot{left:5px;top:-1px}.layui-tabs-scroll{overflow:hidden;padding:0 40px;position:relative}.layui-tabs-scroll .layui-tabs-header:after{border:0;content:none;display:none}.layui-tabs-bar .layui-icon{background-color:#fff;border:1px solid var(--lay-border-color);box-shadow:2px 0 5px 0 rgb(0 0 0/6%);box-sizing:border-box;cursor:pointer;height:100%;left:0;line-height:40px;position:absolute;text-align:center;top:0;width:40px;z-index:3}.layui-tabs-bar .layui-icon-next{box-shadow:-2px 0 5px 0 rgb(0 0 0/6%);left:auto;right:0}.layui-tabs-header li .layui-tabs-close{border-radius:50%;color:#959595;display:inline-block;font-size:12px;font-weight:700;height:16px;line-height:18px;margin-left:8px;position:relative;text-align:center;top:0;transition:all .16s;width:16px}.layui-tabs-header li .layui-tabs-close:hover{background-color:var(--lay-color-red);color:#fff}.layui-tabs-header li[lay-closable=false] .layui-tabs-close{display:none}.layui-tabs-body{padding:var(--lay-spacing) 0}.layui-tabs-item{display:none}.layui-tabs-card>.layui-tabs-header .layui-this{background-color:#fff}.layui-tabs-card>.layui-tabs-header .layui-this:after{border:1px solid var(--lay-border-color);border-bottom:1px solid #fff;border-radius:var(--lay-border-radius) var(--lay-border-radius) 0 0}.layui-tabs-card>.layui-tabs-header li:first-child.layui-this:after{margin-left:-1px}.layui-tabs-card>.layui-tabs-header li:last-child.layui-this:after{margin-right:-1px}.layui-tabs-card.layui-panel>.layui-tabs-header .layui-this:after{border-radius:0;border-top:0}.layui-tabs-card.layui-panel>.layui-tabs-body{padding:var(--lay-spacing)}.layui-tab{margin:10px 0;text-align:left!important}.layui-tab[overflow]>.layui-tab-title{overflow:hidden}.layui-tab .layui-tab-title{font-size:0;height:40px;left:0;position:relative;transition:all .2s;white-space:nowrap}.layui-tab .layui-tab-title:after{border-bottom:1px solid var(--lay-border-color);border-left-style:none;border-right-style:none;border-top-style:none;bottom:0;content:"";left:0;pointer-events:none;position:absolute;right:auto;top:auto;width:100%;z-index:8}.layui-tab .layui-tab-title li{cursor:pointer;display:inline-block;font-size:14px;line-height:40px;margin:0;min-width:65px;padding:0 15px;position:relative;text-align:center;transition:all .2s;vertical-align:middle}.layui-tab .layui-tab-title li a{display:block;margin:0 -15px;padding:0 15px}.layui-tab-title .layui-this{color:#000}.layui-tab-title .layui-this:after{border-width:1px;border-bottom:1px #fff;border-radius:var(--lay-border-radius) var(--lay-border-radius) 0 0;border-style:solid;content:"";left:0;pointer-events:none;width:100%;z-index:9}.layui-tab-bar,.layui-tab-title .layui-this:after{box-sizing:border-box;height:40px;position:absolute;top:0}.layui-tab-bar{background-color:#fff;border-radius:var(--lay-border-radius);border-style:solid;border-width:1px;cursor:pointer;line-height:40px;right:0;text-align:center;width:30px;z-index:10}.layui-tab-bar .layui-icon{display:inline-block;position:relative;top:3px;transition:all .3s}.layui-tab-item{display:none}.layui-tab-more{height:auto!important;padding-right:30px;white-space:normal!important}.layui-tab-more li.layui-this:after{border-bottom-color:var(--lay-border-color);border-radius:var(--lay-border-radius)}.layui-tab-more .layui-tab-bar .layui-icon{top:-2px;top:3px\0;transform:rotate(180deg)}:root .layui-tab-more .layui-tab-bar .layui-icon{top:-2px\0/IE9}.layui-tab-content{padding:15px 0}.layui-tab-title li .layui-tab-close{color:#c2c2c2;display:inline-block;font-size:14px;height:18px;line-height:20px;margin-left:8px;position:relative;text-align:center;top:1px;transition:all .2s;width:18px}.layui-tab-title li .layui-tab-close:hover{background-color:var(--lay-color-red);border-radius:var(--lay-border-radius);color:#fff}.layui-tab-brief>.layui-tab-title .layui-this{color:var(--lay-color-primary)}.layui-tab-brief>.layui-tab-more li.layui-this:after,.layui-tab-brief>.layui-tab-title .layui-this:after{border:none;border-bottom:2px solid var(--lay-color-accent);border-radius:0}.layui-tab-card{border-radius:var(--lay-border-radius);border-style:solid;border-width:1px;box-shadow:0 2px 5px 0 rgba(0,0,0,.1)}.layui-tab-card>.layui-tab-title{background-color:var(--lay-color-gray)}.layui-tab-card>.layui-tab-title li{margin-left:-1px;margin-right:-1px}.layui-tab-card>.layui-tab-title .layui-this{background-color:#fff}.layui-tab-card>.layui-tab-title .layui-this:after{border-bottom-color:#fff;border-width:medium 1px 1px;border-top:1px}.layui-tab-card>.layui-tab-title .layui-tab-bar{border-radius:0;border-right:none;border-top:none;height:40px;line-height:40px}.layui-tab-card>.layui-tab-more .layui-this{background:none;color:var(--lay-color-accent)}.layui-tab-card>.layui-tab-more .layui-this:after{border:none}.layui-nav{background-color:var(--lay-color-black);border-radius:var(--lay-border-radius);box-sizing:border-box;color:#fff;font-size:0;padding:0 15px;position:relative}.layui-nav *{font-size:14px}.layui-nav .layui-nav-item{display:inline-block;line-height:60px;list-style:none;margin-top:0;position:relative;vertical-align:middle}.layui-nav .layui-nav-item a{color:#fff;color:hsla(0,0%,100%,.7);display:block;padding:0 20px;transition:all .3s}.layui-nav .layui-this:after,.layui-nav-bar{background-color:var(--lay-color-accent);content:"";height:3px;left:0;pointer-events:none;position:absolute;top:0;transition:all .2s;width:0}.layui-nav-bar{z-index:1000}.layui-nav[lay-bar=disabled] .layui-nav-bar{display:none}.layui-nav .layui-nav-item a:hover,.layui-nav .layui-this a{color:#fff;text-decoration:none}.layui-nav .layui-this:after{bottom:0;top:auto;width:100%}.layui-nav-img{border-radius:50%;height:30px;margin-right:10px;width:30px}.layui-nav .layui-nav-more{cursor:pointer;font-size:12px;left:auto!important;margin-top:0;position:absolute;right:3px;top:0;transition:all .2s}.layui-nav .layui-nav-mored,.layui-nav-itemed>a .layui-nav-more{transform:rotate(180deg)}.layui-nav-child{background-color:#fff;border:1px solid var(--lay-border-color);border-radius:var(--lay-border-radius);box-shadow:0 2px 4px rgba(0,0,0,.12);box-sizing:border-box;display:none;left:0;line-height:36px;min-width:100%;padding:5px 0;position:absolute;top:65px;white-space:nowrap;z-index:100}.layui-nav .layui-nav-child a{color:#5f5f5f;color:rgba(0,0,0,.8)}.layui-nav .layui-nav-child a:hover{background-color:#f8f8f8;color:rgba(0,0,0,.8)}.layui-nav-child dd{margin:1px 0;position:relative}.layui-nav-child dd.layui-this{background-color:#f8f8f8;color:#000}.layui-nav-child dd.layui-this:after{display:none}.layui-nav-child-r{left:auto;right:0}.layui-nav-child-c{text-align:center}.layui-nav.layui-nav-tree{padding:0;width:200px}.layui-nav-tree .layui-nav-item{display:block;line-height:40px;width:100%}.layui-nav-tree .layui-nav-item a{height:40px;line-height:40px;overflow:hidden;position:relative;text-overflow:ellipsis;white-space:nowrap}.layui-nav-tree .layui-nav-item>a{padding-bottom:5px;padding-top:5px}.layui-nav-tree .layui-nav-more{right:15px}.layui-nav-tree .layui-nav-item>a .layui-nav-more{padding:5px 0}.layui-nav-tree .layui-nav-bar{height:0;width:5px}.layui-side .layui-nav-tree .layui-nav-bar{width:2px}.layui-nav-tree .layui-nav-child dd.layui-this,.layui-nav-tree .layui-nav-child dd.layui-this a,.layui-nav-tree .layui-this,.layui-nav-tree .layui-this>a,.layui-nav-tree .layui-this>a:hover{background-color:var(--lay-color-primary);color:#fff}.layui-nav-tree .layui-this:after{display:none}.layui-nav-itemed>a,.layui-nav-tree .layui-nav-title a,.layui-nav-tree .layui-nav-title a:hover{color:#fff!important}.layui-nav-tree .layui-nav-bar{background-color:var(--lay-color-primary)}.layui-nav-tree .layui-nav-child{background:none;background-color:rgba(0,0,0,.3);border:none;box-shadow:none;position:relative;top:0;z-index:0}.layui-nav-tree .layui-nav-child dd{margin:0}.layui-nav-tree .layui-nav-child a{color:#fff;color:hsla(0,0%,100%,.7)}.layui-nav-tree .layui-nav-child a:hover{background:none;color:#fff}.layui-nav-itemed>.layui-nav-child,.layui-nav-itemed>.layui-nav-child>.layui-this>.layui-nav-child{display:block}.layui-nav-side{bottom:0;left:0;overflow-x:hidden;position:fixed;top:0;z-index:999}.layui-nav-tree.layui-bg-gray a,.layui-nav.layui-bg-gray .layui-nav-item a{color:#373737;color:rgba(0,0,0,.8)}.layui-nav-tree.layui-bg-gray .layui-nav-itemed>a{color:#000!important}.layui-nav.layui-bg-gray .layui-this a{color:var(--lay-color-accent)}.layui-nav-tree.layui-bg-gray .layui-nav-child{background:none;padding-left:11px}.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a,.layui-nav-tree.layui-bg-gray .layui-this,.layui-nav-tree.layui-bg-gray .layui-this>a{background:none!important;color:var(--lay-color-accent)!important;font-weight:700}.layui-nav-tree.layui-bg-gray .layui-nav-bar{background-color:var(--lay-color-accent)}.layui-breadcrumb{font-size:0;visibility:hidden}.layui-breadcrumb>*{font-size:14px}.layui-breadcrumb a{color:#999!important}.layui-breadcrumb a:hover{color:var(--lay-color-accent)!important}.layui-breadcrumb a cite{color:#5f5f5f;font-style:normal}.layui-breadcrumb span[lay-separator]{color:#999;margin:0 10px}.layui-timeline{padding-left:5px}.layui-timeline-item{padding-bottom:20px;position:relative}.layui-timeline-axis{background-color:#fff;border-radius:50%;color:var(--lay-color-accent);cursor:pointer;height:20px;left:-5px;line-height:20px;position:absolute;text-align:center;top:0;width:20px;z-index:10}.layui-timeline-axis:hover{color:var(--lay-color-red)}.layui-timeline-item:before{content:"";height:100%;left:5px;position:absolute;top:0;width:1px;z-index:0}.layui-timeline-item:first-child:before{display:block}.layui-timeline-item:last-child:before{display:none}.layui-timeline-content{padding-left:25px}.layui-timeline-title{line-height:22px;margin-bottom:10px;position:relative}.layui-badge,.layui-badge-dot,.layui-badge-rim{background-color:var(--lay-color-red);border-radius:var(--lay-border-radius);color:#fff;display:inline-block;font-size:12px;padding:0 6px;position:relative;text-align:center}.layui-badge{height:18px;line-height:18px}.layui-badge-dot{border-radius:50%;height:8px;padding:0;width:8px}.layui-badge-rim{background-color:#fff;border-style:solid;border-width:1px;color:#5f5f5f;height:18px;line-height:18px}.layui-btn .layui-badge,.layui-btn .layui-badge-dot{margin-left:5px}.layui-nav .layui-badge,.layui-nav .layui-badge-dot{margin:-5px 6px 0;position:absolute;top:50%}.layui-nav .layui-badge{margin-top:-10px}.layui-tab-title .layui-badge,.layui-tab-title .layui-badge-dot{left:5px;top:-2px}.layui-carousel{background-color:#f8f8f8;left:0;position:relative;top:0}.layui-carousel>[carousel-item]{height:100%;overflow:hidden;position:relative;width:100%}.layui-carousel>[carousel-item]:before{color:#c2c2c2;content:"\e63d";font-family:layui-icon!important;font-size:30px;font-style:normal;left:50%;line-height:20px;margin:-10px 0 0 -50px;position:absolute;text-align:center;top:50%;width:100px;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.layui-carousel>[carousel-item]>*{background-color:#f8f8f8;display:none;height:100%;left:0;position:absolute;top:0;transition-duration:.3s;width:100%}.layui-carousel-updown>*{transition:up .3s ease-in-out}.layui-carousel-arrow{background-color:rgba(0,0,0,.2);border:0;border-radius:50%;color:#fff;cursor:pointer;display:none\0;font-size:20px;height:36px;left:10px;line-height:36px;margin-top:-18px;opacity:0;position:absolute;text-align:center;top:50%;transition-duration:.3s;width:36px}.layui-carousel-arrow[lay-type=add]{left:auto!important;right:10px}.layui-carousel[lay-arrow=always] .layui-carousel-arrow{left:20px;opacity:1}.layui-carousel[lay-arrow=always] .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel[lay-arrow=none] .layui-carousel-arrow{display:none}.layui-carousel-arrow:hover,.layui-carousel-ind ul:hover{background-color:rgba(0,0,0,.35)}.layui-carousel:hover .layui-carousel-arrow{display:block\0;left:20px;opacity:1}.layui-carousel:hover .layui-carousel-arrow[lay-type=add]{right:20px}.layui-carousel-ind{font-size:0;line-height:0!important;position:relative;text-align:center;top:-35px;width:100%}.layui-carousel[lay-indicator=outside]{margin-bottom:30px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind{top:10px}.layui-carousel[lay-indicator=outside] .layui-carousel-ind ul{background-color:rgba(0,0,0,.5)}.layui-carousel[lay-indicator=none] .layui-carousel-ind{display:none}.layui-carousel-ind ul{background-color:rgba(0,0,0,.2);border-radius:10px;display:inline-block;padding:5px;transition-duration:.3s}.layui-carousel-ind ul li{background-color:var(--lay-gray-300);background-color:hsla(0,0%,100%,.5);border-radius:50%;cursor:pointer;display:inline-block;font-size:14px;height:10px;margin:0 3px;transition-duration:.3s;width:10px}.layui-carousel-ind ul li:hover{background-color:hsla(0,0%,100%,.7)}.layui-carousel-ind ul li.layui-this{background-color:#fff}.layui-carousel>[carousel-item]>.layui-carousel-next,.layui-carousel>[carousel-item]>.layui-carousel-prev,.layui-carousel>[carousel-item]>.layui-this{display:block}.layui-carousel>[carousel-item]>.layui-this{transform:translateX(0)}.layui-carousel>[carousel-item]>.layui-carousel-prev{transform:translateX(-100%)}.layui-carousel>[carousel-item]>.layui-carousel-next{transform:translateX(100%)}.layui-carousel>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel>[carousel-item]>.layui-carousel-prev.layui-carousel-right{transform:translateX(0)}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-left{transform:translateX(-100%)}.layui-carousel>[carousel-item]>.layui-this.layui-carousel-right{transform:translateX(100%)}.layui-carousel[lay-anim=updown] .layui-carousel-arrow{left:50%!important;margin:0 0 0 -18px;top:20px}.layui-carousel[lay-anim=updown] .layui-carousel-arrow[lay-type=add]{bottom:20px;top:auto!important}.layui-carousel[lay-anim=updown] .layui-carousel-ind{height:auto;position:absolute;right:20px;top:50%;width:auto}.layui-carousel[lay-anim=updown] .layui-carousel-ind ul{padding:3px 5px}.layui-carousel[lay-anim=updown] .layui-carousel-ind li{display:block;margin:6px 0}.layui-carousel[lay-anim=updown]>[carousel-item]>*{left:0!important}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this{transform:translateY(0)}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev{transform:translateY(-100%)}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next{transform:translateY(100%)}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{transform:translateY(0)}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-left{transform:translateY(-100%)}.layui-carousel[lay-anim=updown]>[carousel-item]>.layui-this.layui-carousel-right{transform:translateY(100%)}.layui-carousel[lay-anim=fade]>[carousel-item]>*{transform:translateX(0)!important}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev{opacity:0}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-next.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-carousel-prev.layui-carousel-right{opacity:1}.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-left,.layui-carousel[lay-anim=fade]>[carousel-item]>.layui-this.layui-carousel-right{opacity:0}.layui-fixbar{bottom:16px;position:fixed;right:16px;z-index:999999}.layui-fixbar li{background-color:#9f9f9f;border-radius:var(--lay-border-radius);color:#fff;cursor:pointer;font-size:30px;height:50px;line-height:50px;margin-bottom:1px;opacity:.95;text-align:center;width:50px}.layui-fixbar li:hover{opacity:.85}.layui-fixbar li:active{opacity:1}.layui-fixbar .layui-fixbar-top{display:none;font-size:40px}.layui-transfer-box,.layui-transfer-header,.layui-transfer-search{border-color:var(--lay-border-color);border-style:solid;border-width:0}.layui-transfer-box{background-color:#fff;border-radius:var(--lay-border-radius);border-width:1px;display:inline-block;height:360px;position:relative;vertical-align:middle;width:200px}.layui-transfer-box .layui-form-checkbox{margin:0!important;width:100%}.layui-transfer-header{border-bottom-width:1px;height:38px;line-height:38px;padding:0 11px}.layui-transfer-search{border-bottom-width:1px;padding:11px;position:relative}.layui-transfer-search .layui-input{font-size:12px;height:32px;padding-left:30px}.layui-transfer-search .layui-icon-search{color:#5f5f5f;left:20px;line-height:normal;margin-top:-8px;position:absolute;top:50%}.layui-transfer-active{display:inline-block;margin:0 15px;vertical-align:middle}.layui-transfer-active .layui-btn{background-color:var(--lay-color-accent);border-color:var(--lay-color-accent);color:#fff;display:block;margin:0;padding:0 15px}.layui-transfer-active .layui-btn-disabled{background-color:#fbfbfb;border-color:var(--lay-border-color);color:var(--lay-gray-400)}.layui-transfer-active .layui-btn:first-child{margin-bottom:15px}.layui-transfer-active .layui-btn .layui-icon{font-size:14px!important;margin:0}.layui-transfer-data{overflow:auto;padding:5px 0}.layui-transfer-data li{height:32px;line-height:32px;list-style-type:none!important;margin-top:0!important;padding:0 11px}.layui-transfer-data li:hover{background-color:#f8f8f8;transition:all .5s}.layui-transfer-data .layui-none{color:#999;padding:15px 11px;text-align:center}.layui-rate,.layui-rate *{display:inline-block;vertical-align:middle}.layui-rate{font-size:0;padding:11px 6px 11px 0}.layui-rate li{margin-top:0!important}.layui-rate li i.layui-icon{color:var(--lay-color-orange);font-size:20px;margin-right:5px;transition:all .3s}.layui-rate li i:hover,.layui-rate-hover{cursor:pointer;transform:scale(1.12)}.layui-rate[readonly] li i:hover{cursor:default;transform:scale(1)}.layui-colorpicker{border:1px solid var(--lay-border-color);border-radius:var(--lay-border-radius);box-sizing:border-box;cursor:pointer;display:inline-block;height:38px;line-height:24px;padding:5px;transition:all .3s;width:38px}.layui-colorpicker:hover{border-color:var(--lay-gray-400)}.layui-colorpicker.layui-colorpicker-lg{height:44px;line-height:30px;width:44px}.layui-colorpicker.layui-colorpicker-sm{height:30px;line-height:20px;padding:3px;width:30px}.layui-colorpicker.layui-colorpicker-xs{height:22px;line-height:16px;padding:1px;width:22px}.layui-colorpicker-trigger-bgcolor{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);border-radius:var(--lay-border-radius);display:block}.layui-colorpicker-trigger-span{border:1px solid rgba(0,0,0,.15);border-radius:var(--lay-border-radius);box-sizing:border-box;display:block;height:100%;text-align:center}.layui-colorpicker-trigger-i{color:#fff;display:inline-block;font-size:12px}.layui-colorpicker-trigger-i.layui-icon-close{color:#999}.layui-colorpicker-main{background:#fff;border:1px solid var(--lay-border-color);border-radius:var(--lay-border-radius);box-shadow:0 2px 4px rgba(0,0,0,.12);left:-999999px;margin:5px 0;padding:7px;position:absolute;top:-999999px;width:280px;z-index:77777777}.layui-colorpicker-main-wrapper{height:180px;position:relative}.layui-colorpicker-basis{height:100%;overflow:hidden;position:relative;width:260px}.layui-colorpicker-basis-white{background:linear-gradient(90deg,#fff,hsla(0,0%,100%,0));height:100%;left:0;position:absolute;top:0;width:100%}.layui-colorpicker-basis-black{background:linear-gradient(0deg,#000,transparent);height:100%;left:0;position:absolute;top:0;width:100%}.layui-colorpicker-basis-cursor{border:1px solid #fff;border-radius:50%;cursor:pointer;height:10px;position:absolute;right:100%;top:0;transform:translate(-50%,-50%);width:10px}.layui-colorpicker-side{background:linear-gradient(red,#ff0,#0f0,#0ff,#00f,#f0f,red);height:100%;position:absolute;right:0;top:0;width:12px}.layui-colorpicker-side-slider{background:#fff;border:1px solid #f0f0f0;border-radius:1px;box-shadow:0 0 1px #888;box-sizing:border-box;cursor:pointer;height:5px;left:0;position:absolute;width:100%}.layui-colorpicker-main-alpha{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);display:none;height:12px;margin-top:7px}.layui-colorpicker-alpha-bgcolor{height:100%;position:relative}.layui-colorpicker-alpha-slider{background:#fff;border:1px solid #f0f0f0;border-radius:1px;box-shadow:0 0 1px #888;box-sizing:border-box;cursor:pointer;height:100%;position:absolute;top:0;width:5px}.layui-colorpicker-main-pre{font-size:0;padding-top:7px}.layui-colorpicker-pre{border-radius:var(--lay-border-radius);cursor:pointer;display:inline-block;height:20px;margin-bottom:7px;margin-left:6px;width:20px}.layui-colorpicker-pre:nth-child(11n+1){margin-left:0}.layui-colorpicker-pre-isalpha{background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.layui-colorpicker-pre.layui-this{box-shadow:0 0 3px 2px rgba(0,0,0,.15)}.layui-colorpicker-pre>div{border-radius:var(--lay-border-radius);height:100%}.layui-colorpicker-main-input{padding-top:7px;text-align:right}.layui-colorpicker-main-input .layui-btn-container .layui-btn{margin:0 0 0 10px}.layui-colorpicker-main-input div.layui-inline{float:left;font-size:14px}.layui-colorpicker-main-input input.layui-input{color:#5f5f5f;height:30px;padding-left:5px;width:168px}.layui-slider{background:var(--lay-gray-300);cursor:pointer;height:4px;position:relative}.layui-slider,.layui-slider-bar{border-radius:var(--lay-border-radius)}.layui-slider-bar{height:100%;position:absolute}.layui-slider-step{background:#fff;border-radius:50%;height:4px;top:0;width:4px}.layui-slider-step,.layui-slider-wrap{position:absolute;transform:translateX(-50%)}.layui-slider-wrap{height:36px;text-align:center;top:-16px;width:36px;z-index:10}.layui-slider-wrap-btn{background:#fff;border-radius:50%;cursor:pointer;display:inline-block;height:12px;transition:.3s;vertical-align:middle;width:12px}.layui-slider-wrap:after{content:"";display:inline-block;height:100%;vertical-align:middle}.layui-slider-wrap-btn.layui-slider-hover,.layui-slider-wrap-btn:hover{transform:scale(1.2)}.layui-slider-wrap-btn.layui-disabled:hover{transform:scale(1)!important}.layui-slider-tips{background:#000;border-radius:var(--lay-border-radius);color:#fff;height:25px;line-height:25px;padding:0 10px;position:absolute;top:-42px;transform:translateX(-50%);white-space:nowrap;z-index:77777777}.layui-slider-tips:after{border:6px solid transparent;border-top-color:#000;bottom:-11px;content:"";height:0;left:50%;margin-left:-6px;position:absolute;width:0}.layui-slider-input{border:1px solid var(--lay-border-color);border-radius:var(--lay-border-radius);box-sizing:border-box;font-size:16px;height:32px;line-height:32px;position:absolute;right:0;top:-14px;width:70px}.layui-slider-input-btn{border-left:1px solid var(--lay-border-color);height:100%;position:absolute;right:0;top:0;width:20px}.layui-slider-input-btn i{bottom:0;color:#999;cursor:pointer;font-size:12px;height:50%;line-height:16px;position:absolute;right:0;text-align:center;width:20px}.layui-slider-input-btn i:first-child{border-bottom:1px solid var(--lay-border-color);top:0}.layui-slider-input-txt{font-size:14px;height:100%}.layui-slider-input-txt input{border:none;height:100%;padding-right:21px}.layui-slider-input-btn i:hover{color:var(--lay-color-primary)}.layui-slider-vertical{margin-left:33px;width:4px}.layui-slider-vertical .layui-slider-bar{width:4px}.layui-slider-vertical .layui-slider-step{left:0;top:auto;transform:translateY(50%)}.layui-slider-vertical .layui-slider-wrap{left:-16px;top:auto;transform:translateY(50%)}.layui-slider-vertical .layui-slider-tips{left:2px;top:auto}@media \0screen{.layui-slider-wrap-btn{margin-left:-20px}.layui-slider-vertical .layui-slider-wrap-btn{margin-bottom:-20px;margin-left:0}.layui-slider-vertical .layui-slider-tips{margin-left:-8px}.layui-slider>span{margin-left:8px}}.layui-tree{line-height:22px}.layui-tree .layui-form-checkbox{margin:0!important}.layui-tree-set{position:relative;width:100%}.layui-tree-pack{display:none;padding-left:20px;position:relative}.layui-tree-line .layui-tree-pack{padding-left:27px}.layui-tree-line .layui-tree-set .layui-tree-set:after{border-top:1px dotted #c0c4cc;content:"";height:0;left:-9px;position:absolute;top:14px;width:17px}.layui-tree-entry{height:26px;padding:3px 0;position:relative;white-space:nowrap}.layui-tree-entry:hover{background-color:var(--lay-gray-300)}.layui-tree-line .layui-tree-entry:hover{background-color:transparent}.layui-tree-line .layui-tree-entry:hover .layui-tree-txt{color:#999;text-decoration:underline;transition:.3s}.layui-tree-main{cursor:pointer;display:inline-block;padding-right:10px;vertical-align:middle}.layui-tree-line .layui-tree-set:before{border-left:1px dotted #c0c4cc;content:"";height:100%;left:-9px;position:absolute;top:0;width:0}.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before{height:13px}.layui-tree-line .layui-tree-set.layui-tree-setHide:before{height:0}.layui-tree-iconClick{color:#c0c4cc;display:inline-block;height:20px;line-height:20px;margin:0 10px;position:relative;vertical-align:middle}.layui-tree-icon{border:1px solid #c0c4cc;height:14px;line-height:10px;margin:0 11px;text-align:center;width:14px}.layui-tree-icon .layui-icon{color:#5f5f5f;font-size:12px}.layui-tree-iconArrow{padding:0 5px}.layui-tree-iconArrow:after{border:5px solid transparent;border-left-color:#c0c4cc;content:"";height:0;left:4px;position:absolute;top:3px;transition:.5s;width:0;z-index:100}.layui-tree-spread>.layui-tree-entry .layui-tree-iconClick>.layui-tree-iconArrow:after{transform:rotate(90deg) translate(3px,4px)}.layui-tree-txt{color:#555;display:inline-block;vertical-align:middle}.layui-tree-search{color:#5f5f5f;margin-bottom:15px}.layui-tree-btnGroup{display:inline-block;position:relative;vertical-align:middle;visibility:hidden}.layui-tree-btnGroup .layui-icon{cursor:pointer;display:inline-block;padding:0 2px;vertical-align:middle}.layui-tree-btnGroup .layui-icon:hover{color:#999;transition:.3s}.layui-tree-entry:hover .layui-tree-btnGroup{visibility:visible}.layui-tree-editInput{background-color:rgba(0,0,0,.05);border:none;display:inline-block;height:20px;line-height:20px;padding:0;position:relative;vertical-align:middle}.layui-tree-emptyText{color:#999;text-align:center}.layui-anim{-webkit-animation-duration:.3s;animation-duration:.3s;-webkit-animation-fill-mode:both;animation-fill-mode:both}.layui-anim.layui-icon{display:inline-block}.layui-anim-loop{animation-iteration-count:infinite}.layui-trans,.layui-trans a{transition:all .2s}@keyframes layui-rotate{0%{transform:rotate(0deg)}to{transform:rotate(1turn)}}.layui-anim-rotate{animation-duration:1s;animation-name:layui-rotate;animation-timing-function:linear}@keyframes layui-up{0%{opacity:.3;transform:translate3d(0,100%,0)}to{opacity:1;transform:translateZ(0)}}.layui-anim-up{animation-name:layui-up}@keyframes layui-upbit{0%{opacity:.3;transform:translate3d(0,15px,0)}to{opacity:1;transform:translateZ(0)}}.layui-anim-upbit{animation-name:layui-upbit}@keyframes layui-down{0%{opacity:.3;transform:translate3d(0,-100%,0)}to{opacity:1;transform:translateZ(0)}}.layui-anim-down{animation-name:layui-down}@keyframes layui-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}to{opacity:1;transform:translateZ(0)}}.layui-anim-downbit{animation-name:layui-downbit}@keyframes layui-scale{0%{opacity:.3;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.layui-anim-scale{animation-name:layui-scale}@keyframes layui-scale-spring{0%{opacity:.5;transform:scale(.5)}80%{opacity:.8;transform:scale(1.1)}to{opacity:1;transform:scale(1)}}.layui-anim-scaleSpring{animation-name:layui-scale-spring}@keyframes layui-scalesmall{0%{opacity:.3;transform:scale(1.5)}to{opacity:1;transform:scale(1)}}.layui-anim-scalesmall{animation-name:layui-scalesmall}@keyframes layui-scalesmall-spring{0%{opacity:.3;transform:scale(1.5)}80%{opacity:.8;transform:scale(.9)}to{opacity:1;transform:scale(1)}}.layui-anim-scalesmall-spring{animation-name:layui-scalesmall-spring}@keyframes layui-fadein{0%{opacity:0}to{opacity:1}}.layui-anim-fadein{animation-name:layui-fadein}@keyframes layui-fadeout{0%{opacity:1}to{opacity:0}}.layui-anim-fadeout{animation-name:layui-fadeout}.layui-code{background-color:#fff;border:1px solid var(--lay-border-color);border-left-width:6px;color:#333;display:block;font-size:12px;line-height:20px;padding:15px;position:relative}.layui-code,.layui-code-wrap{font-family:var(--lay-font-monospace)}.layui-code-wrap{font-size:13px}.layui-code-view{background-color:#fff;border:1px solid var(--lay-border-color);border-left-width:6px;color:#333;display:block;padding:0!important;position:relative}.layui-code-view pre{margin:0!important}.layui-code-header{background-color:var(--lay-color-gray);border-bottom:1px solid var(--lay-border-color);font-size:12px;height:40px;line-height:40px;padding:0 11px;position:relative;z-index:3}.layui-code-header>.layui-code-header-about{color:#b7b7b7;position:absolute;right:11px;top:0}.layui-code-header-about>a{padding-left:10px}.layui-code-wrap{display:block;overflow-x:hidden;overflow-y:auto;padding:11px 0!important;z-index:1}.layui-code-line,.layui-code-wrap{margin:0!important;position:relative}.layui-code-line{line-height:19px}.layui-code-line-number{height:100%;left:0;min-width:45px;overflow:hidden;padding:0 8px;position:absolute;text-align:right;top:0;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.layui-code-line-content{padding:0 11px;word-wrap:break-word;white-space:pre-wrap}.layui-code-ln-mode>.layui-code-wrap>.layui-code-line{padding-left:45px}.layui-code-ln-side{background-color:var(--lay-color-gray);border-right:1px solid;border-color:hsla(0,2%,49%,.15);bottom:0;left:0;pointer-events:none;position:absolute;top:0;width:45px;z-index:0}.layui-code-nowrap>.layui-code-wrap{overflow:auto}.layui-code-nowrap>.layui-code-wrap>.layui-code-line>.layui-code-line-content{white-space:pre;word-wrap:normal}.layui-code-nowrap>.layui-code-ln-side{background:none!important;border-right-width:0!important}.layui-code-fixbar{padding-right:45px;position:absolute;right:11px;top:8px;z-index:5}.layui-code-fixbar>span{color:#777;padding:0 8px;position:absolute;right:0;top:0;transition:all .3s}.layui-code-fixbar>span:hover{color:var(--lay-color-accent)}.layui-code-copy{cursor:pointer;display:none}.layui-code-preview>.layui-code-view>.layui-code-fixbar .layui-code-copy{display:none!important}.layui-code-view:hover>.layui-code-fixbar .layui-code-copy{display:block}.layui-code-view:hover>.layui-code-fixbar .layui-code-lang-marker{display:none}.layui-code-theme-dark,.layui-code-theme-dark>.layui-code-header{background-color:#1f1f1f;border-color:hsla(0,2%,49%,.15)}.layui-code-theme-dark{border-width:1px;color:#ccc}.layui-code-theme-dark>.layui-code-ln-side{background:none;border-right-color:#2a2a2a;color:#6e7681}.layui-code textarea{display:none}.layui-code-preview>.layui-code,.layui-code-preview>.layui-code-view{margin:0}.layui-code-preview>.layui-tab{margin-bottom:0;position:relative;z-index:1}.layui-code-preview .layui-code-item{border-top-width:0;display:none}.layui-code-item-preview{padding:var(--lay-spacing);position:relative}.layui-code-item-preview>iframe{border:none;height:100%;left:0;position:absolute;top:0;width:100%}.layui-code-tools{line-height:normal;position:absolute;right:11px;top:8px}.layui-code-tools>i{cursor:pointer;display:inline-block;margin-left:6px;padding:3px}.layui-code-tools>i.layui-icon-file-b{color:#999}.layui-code-tools>i:hover{color:var(--lay-color-accent)}.layui-code-full{background-color:#fff;height:100%;left:0;position:fixed;top:0;width:100%;z-index:1111111}.layui-code-full .layui-code-item{border-width:0!important;width:100%!important}.layui-code-full .layui-code-item,.layui-code-full .layui-code-view,.layui-code-full .layui-code-wrap{box-sizing:border-box;height:calc(100vh - 51px)!important}.layui-code-full .layui-code-item-preview{overflow:auto}.layui-code-view.layui-code-hl{border-left-width:1px;line-height:20px!important}.layui-code-view.layui-code-hl>.layui-code-ln-side{background-color:transparent}.layui-code-theme-dark.layui-code-hl,.layui-code-theme-dark.layui-code-hl>.layui-code-ln-side{border-color:hsla(0,2%,49%,.15)}.layui-code-line-highlighted{background-color:rgba(142,150,170,.14)}.layui-code-line-diff-add{background-color:rgba(16,185,129,.14)}.layui-code-line-diff-remove{background-color:rgba(244,63,94,.14)}.layui-code-line-diff-add:before{color:#18794e;content:"+";position:absolute}.layui-code-line-diff-remove:before{color:#b8272c;content:"-";position:absolute}.layui-code-has-focused-lines .layui-code-line:not(.layui-code-line-has-focus){filter:blur(.095rem);opacity:.7;transition:filter .35s,opacity .35s}.layui-code-has-focused-lines:hover .layui-code-line:not(.layui-code-line-has-focus){filter:blur();opacity:1}.layui-laydate *{margin:0;padding:0}.layui-laydate,.layui-laydate *{box-sizing:border-box}.layui-laydate{animation-duration:.2s;animation-fill-mode:both;border-radius:var(--lay-border-radius);font-size:14px;line-height:normal;margin:5px 0;position:absolute;z-index:99999999}.layui-laydate-main{width:272px}.layui-laydate-content td,.layui-laydate-header *,.layui-laydate-list li{transition-duration:.3s}.layui-laydate-shade{height:100%;left:0;pointer-events:auto;position:fixed;top:0;width:100%}@keyframes laydate-downbit{0%{opacity:.3;transform:translate3d(0,-5px,0)}to{opacity:1;transform:translateZ(0)}}.layui-laydate{animation-name:laydate-downbit}.layui-laydate-static{animation:none;display:inline-block;margin:0;position:relative;z-index:0}.laydate-ym-show .laydate-next-m,.laydate-ym-show .laydate-prev-m{display:none!important}.laydate-ym-show .laydate-next-y,.laydate-ym-show .laydate-prev-y{display:inline-block!important}.laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-time-show .layui-laydate-header .layui-icon,.laydate-ym-show .laydate-set-ym span[lay-type=month]{display:none!important}.layui-laydate-header{line-height:30px;padding:10px 70px 5px;position:relative}.layui-laydate-header *{display:inline-block;vertical-align:bottom}.layui-laydate-header i{color:#999;cursor:pointer;font-size:18px;padding:0 5px;position:absolute;top:10px}.layui-laydate-header i.laydate-prev-y{left:15px}.layui-laydate-header i.laydate-prev-m{left:45px}.layui-laydate-header i.laydate-next-y{right:15px}.layui-laydate-header i.laydate-next-m{right:45px}.laydate-time-show .layui-laydate-header{padding-left:10px;padding-right:10px}.laydate-set-ym{box-sizing:border-box;overflow:hidden;text-align:center;text-overflow:ellipsis;white-space:nowrap;width:100%}.laydate-set-ym span{cursor:pointer;padding:0 10px}.laydate-time-text{cursor:default!important}.layui-laydate-content{padding:10px;position:relative;-moz-user-select:none;-webkit-user-select:none;user-select:none}.layui-laydate-content table{border-collapse:collapse;border-spacing:0}.layui-laydate-content td,.layui-laydate-content th{height:30px;padding:0;text-align:center;width:36px}.layui-laydate-content th{font-weight:400}.layui-laydate-content td{cursor:pointer;position:relative}.laydate-day-mark{font-size:12px;left:0;line-height:30px;overflow:hidden;position:absolute;top:0;width:100%}.laydate-day-mark:after{border-radius:50%;content:"";height:5px;position:absolute;right:2px;top:2px;width:5px}.laydate-day-holidays:before{color:#ff5722;content:"\4F11";font-size:12px;left:0;position:absolute;top:0;transform:scale(.7)}.laydate-day-holidays[type=workdays]:before{color:inherit;content:"\73ED"}.layui-laydate .layui-this .laydate-day-holidays:before{color:#fff}.layui-laydate-footer{height:46px;line-height:26px;padding:10px;position:relative}.layui-laydate-footer span{background-color:#fff;border:1px solid #c9c9c9;border-radius:var(--lay-border-radius);cursor:pointer;display:inline-block;font-size:12px;height:26px;line-height:24px;padding:0 10px;transition:all .3s;vertical-align:top;white-space:nowrap}.layui-laydate-footer span:hover{color:var(--lay-color-accent)}.layui-laydate-footer span.layui-laydate-preview{border-color:transparent!important;cursor:default}.layui-laydate-footer span.layui-laydate-preview:hover{color:#777}.layui-laydate-footer span:first-child.layui-laydate-preview{padding-left:0}.laydate-footer-btns{position:absolute;right:10px;top:10px}.laydate-footer-btns span{border-radius:0;margin:0 0 0 -1px}.laydate-footer-btns span:first-child{border-radius:var(--lay-border-radius) 0 0 var(--lay-border-radius)}.laydate-footer-btns span:last-child{border-radius:0 var(--lay-border-radius) var(--lay-border-radius) 0}.layui-laydate-shortcut{display:inline-block;max-height:276px;overflow:auto;padding:6px 0;text-align:center;vertical-align:top;width:80px}.layui-laydate-shortcut+.layui-laydate-main{border-left:1px solid #e2e2e2;display:inline-block}.layui-laydate-shortcut>li{cursor:pointer;line-height:18px;padding:5px 8px}.layui-laydate .layui-laydate-list{background-color:#fff;box-sizing:border-box;height:100%;left:0;padding:10px;position:absolute;top:0;width:100%}.layui-laydate .layui-laydate-list>li{cursor:pointer;display:inline-block;height:36px;line-height:36px;list-style:none;margin:3px 0;position:relative;text-align:center;vertical-align:middle;width:33.3%}.layui-laydate .laydate-month-list>li{margin:17px 0;width:25%}.laydate-time-list{display:table}.layui-laydate .laydate-time-list>li{cursor:default;display:table-cell;height:100%;line-height:normal;margin:0}.layui-laydate .laydate-time-list p{line-height:29px;margin:0;position:relative;top:-4px}.layui-laydate .laydate-time-list ol{height:181px;overflow:hidden}.layui-laydate .laydate-time-list>li:hover ol{overflow-y:auto}.layui-laydate .laydate-time-list ol li{cursor:pointer;height:30px;line-height:30px;padding-left:33px;text-align:left;width:130%}.layui-laydate .laydate-time-list-hide-1 ol li{padding-left:53px}.layui-laydate .laydate-time-list-hide-2 ol li{padding-left:117px}.layui-laydate-hint{font-size:12px;left:50%;line-height:20px;margin-left:-125px;padding:15px;position:absolute;text-align:center;top:115px;white-space:pre-line;width:250px}.layui-laydate-range{width:546px}.layui-laydate-range .layui-laydate-main{display:inline-block;max-width:50%;vertical-align:middle}.layui-laydate-range .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range .laydate-main-list-1 .layui-laydate-header{border-left:1px solid #e2e2e2}.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-y,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-m,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-y{display:none}.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .layui-laydate-content,.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .layui-laydate-header{border-left-style:dashed}.layui-laydate,.layui-laydate-hint{background-color:#fff;border:1px solid var(--lay-border-color-accent);box-shadow:0 2px 4px rgba(0,0,0,.12);color:#777}.layui-laydate-header{border-bottom:1px solid #e2e2e2}.layui-laydate-header i:hover,.layui-laydate-header span:hover{color:var(--lay-color-accent)}.layui-laydate-content{border-bottom:0;border-top:0}.layui-laydate-content th{color:#333}.layui-laydate-content td{color:#777}.layui-laydate-content td.laydate-day-now{color:var(--lay-color-accent)}.layui-laydate-content td.laydate-day-now:after{border:1px solid var(--lay-color-accent);box-sizing:border-box;content:"";height:30px;left:0;position:absolute;top:0;width:100%}.layui-laydate-linkage .layui-laydate-content td.laydate-selected>div{background-color:#cffae9;transition:all .3s}.layui-laydate-linkage .laydate-selected:hover>div{background-color:#cffae9!important}.layui-laydate-content td.laydate-selected:after,.layui-laydate-content td:hover:after{content:none}.layui-laydate-content td>div:hover,.layui-laydate-list li:hover,.layui-laydate-shortcut>li:hover{background-color:var(--lay-gray-300);color:#333;transition:all .3s}.laydate-time-list li ol{border:1px solid #e2e2e2;border-left-width:0;margin:0;padding:0}.laydate-time-list li:first-child ol{border-left-width:1px}.laydate-time-list>li:hover{background:none}.layui-laydate-content .laydate-day-next,.layui-laydate-content .laydate-day-prev{color:var(--lay-gray-400)}.layui-laydate-linkage .laydate-selected.laydate-day-next>div,.layui-laydate-linkage .laydate-selected.laydate-day-prev>div{background:none!important}.layui-laydate-footer{border-top:1px solid #e2e2e2}.layui-laydate-hint{color:#ff5722}.laydate-day-mark:after{background-color:var(--lay-color-accent)}.layui-laydate-content td.layui-this .laydate-day-mark:after{display:none}.layui-laydate-footer span[lay-type=date]{color:var(--lay-color-accent)}.layui-laydate .layui-this,.layui-laydate .layui-this>div{background-color:var(--lay-color-accent)!important;color:#fff!important}.layui-laydate .laydate-disabled,.layui-laydate .laydate-disabled:hover{background:none!important;color:var(--lay-gray-400)!important;cursor:not-allowed!important;-moz-user-select:none;-webkit-user-select:none;user-select:none}.layui-laydate .layui-this.laydate-disabled,.layui-laydate .layui-this.laydate-disabled>div{background-color:var(--lay-gray-300)!important}.layui-laydate-content td>div{height:100%;padding:7px 0}.laydate-theme-molv{border:none}.laydate-theme-molv.layui-laydate-range{width:548px}.laydate-theme-molv .layui-laydate-main{width:274px}.laydate-theme-molv .layui-laydate-header{background-color:var(--lay-color-primary);border:none}.laydate-theme-molv .layui-laydate-header i,.laydate-theme-molv .layui-laydate-header span{color:#f6f6f6}.laydate-theme-molv .layui-laydate-header i:hover,.laydate-theme-molv .layui-laydate-header span:hover{color:#fff}.laydate-theme-molv .layui-laydate-content{border:1px solid #e2e2e2;border-bottom:none;border-top:none}.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content{border-left:none}.laydate-theme-molv .layui-this,.laydate-theme-molv .layui-this>div{background-color:var(--lay-color-primary)!important}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li,.laydate-theme-grid .layui-laydate-content td,.laydate-theme-grid .layui-laydate-content thead,.laydate-theme-molv .layui-laydate-footer{border:1px solid #e2e2e2}.layui-laydate-linkage.laydate-theme-grid .laydate-selected,.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover{background-color:#f2f2f2!important;color:var(--lay-color-primary)!important}.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next,.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev{color:var(--lay-gray-400)!important}.laydate-theme-grid .laydate-month-list,.laydate-theme-grid .laydate-year-list{margin:1px 0 0 1px}.laydate-theme-grid .laydate-month-list>li,.laydate-theme-grid .laydate-year-list>li{margin:0 -1px -1px 0}.laydate-theme-grid .laydate-year-list>li{height:43px;line-height:43px}.laydate-theme-grid .laydate-month-list>li{height:71px;line-height:71px}.laydate-theme-grid .layui-laydate-content td>div{height:29px;margin-top:-1px}.laydate-theme-circle .layui-laydate-content td.layui-this>div,.laydate-theme-circle .layui-laydate-content td>div{border-radius:14px;height:28px;line-height:28px;margin:0 4px;padding:0;width:28px}.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this{background-color:transparent!important}.laydate-theme-grid.laydate-theme-circle .layui-laydate-content td>div{margin:0 3.5px}.laydate-theme-fullpanel .layui-laydate-main{width:526px}.laydate-theme-fullpanel .layui-laydate-list{left:272px;width:252px}.laydate-theme-fullpanel .laydate-set-ym span{display:none}.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=month],.laydate-theme-fullpanel .laydate-time-show .laydate-set-ym span[lay-type=year],.laydate-theme-fullpanel .laydate-time-show .layui-laydate-header .layui-icon{display:inline-block!important}.laydate-theme-fullpanel .laydate-btns-time{display:none}.laydate-theme-fullpanel .laydate-time-list-hide-1 ol li{padding-left:49px}.laydate-theme-fullpanel .laydate-time-list-hide-2 ol li{padding-left:107px}.layui-layer,.layui-layer-shade{pointer-events:auto;position:fixed;_position:absolute}.layui-layer-shade{height:100%;left:0;opacity:0;top:0;transition:opacity .35s cubic-bezier(.34,.69,.1,1);width:100%}.layui-layer{-webkit-background-clip:content;background-clip:content;background-color:#fff;border-radius:var(--lay-border-radius);box-shadow:1px 1px 50px rgba(0,0,0,.3);left:0;margin:0;padding:0;top:150px}.layui-layer-close{position:absolute}.layui-layer-content{position:relative}.layui-layer-border{border:1px solid #b2b2b2;border:1px solid rgba(0,0,0,.1);box-shadow:1px 1px 5px rgba(0,0,0,.2)}.layui-layer-load{background:url("data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=") #fff 50% no-repeat}.layui-layer-btn a,.layui-layer-setwin span{display:inline-block;vertical-align:middle}.layui-layer-move{background-color:#fff;cursor:move;display:none;filter:alpha(opacity=0);height:100%;left:0;opacity:0;position:fixed;top:0;width:100%;z-index:2147483647}.layui-layer-resize{bottom:0;cursor:se-resize;height:15px;position:absolute;right:0;width:15px}.layer-anim{animation-duration:.3s;animation-fill-mode:both}@keyframes layer-bounceIn{0%{opacity:0;transform:scale(.5)}to{opacity:1;transform:scale(1)}}.layer-anim-00{animation-name:layer-bounceIn}@keyframes layer-zoomInDown{0%{animation-timing-function:ease-in-out;opacity:0;transform:scale(.1) translateY(-2000px)}60%{animation-timing-function:ease-out;opacity:1;transform:scale(.475) translateY(60px)}}.layer-anim-01{animation-name:layer-zoomInDown}@keyframes layer-fadeInUpBig{0%{opacity:0;transform:translateY(2000px)}to{opacity:1;transform:translateY(0)}}.layer-anim-02{animation-name:layer-fadeInUpBig}@keyframes layer-zoomInLeft{0%{animation-timing-function:ease-in-out;opacity:0;transform:scale(.1) translateX(-2000px)}60%{animation-timing-function:ease-out;opacity:1;transform:scale(.475) translateX(48px)}}.layer-anim-03{animation-name:layer-zoomInLeft}@keyframes layer-rollIn{0%{opacity:0;transform:translateX(-100%) rotate(-120deg)}to{opacity:1;transform:translateX(0) rotate(0deg)}}.layer-anim-04{animation-name:layer-rollIn}@keyframes layer-fadeIn{0%{opacity:0}to{opacity:1}}.layer-anim-05{animation-name:layer-fadeIn}@keyframes layer-shake{0%,to{transform:translateX(0)}10%,30%,50%,70%,90%{transform:translateX(-10px)}20%,40%,60%,80%{transform:translateX(10px)}}.layer-anim-06{animation-name:layer-shake}@keyframes layer-slide-down{0%{transform:translate3d(0,-100%,0)}to{transform:translateZ(0)}}@keyframes layer-slide-down-out{0%{transform:translateZ(0)}to{transform:translate3d(0,-100%,0)}}.layer-anim-slide-down{animation-name:layer-slide-down}.layer-anim-slide-down-out{animation-name:layer-slide-down-out}@keyframes layer-slide-left{0%{transform:translate3d(100%,0,0)}to{transform:translateZ(0)}}@keyframes layer-slide-left-out{0%{transform:translateZ(0)}to{transform:translate3d(100%,0,0)}}.layer-anim-slide-left{animation-name:layer-slide-left}.layer-anim-slide-left-out{animation-name:layer-slide-left-out}@keyframes layer-slide-up{0%{transform:translate3d(0,100%,0)}to{transform:translateZ(0)}}@keyframes layer-slide-up-out{0%{transform:translateZ(0)}to{transform:translate3d(0,100%,0)}}.layer-anim-slide-up{animation-name:layer-slide-up}.layer-anim-slide-up-out{animation-name:layer-slide-up-out}@keyframes layer-slide-right{0%{transform:translate3d(-100%,0,0)}to{transform:translateZ(0)}}@keyframes layer-slide-right-out{0%{transform:translateZ(0)}to{transform:translate3d(-100%,0,0)}}.layer-anim-slide-right{animation-name:layer-slide-right}.layer-anim-slide-right-out{animation-name:layer-slide-right-out}.layui-layer-title{border-bottom:1px solid #f0f0f0;border-radius:var(--lay-border-radius) var(--lay-border-radius) 0 0;color:#333;font-size:14px;height:50px;line-height:50px;overflow:hidden;padding:0 81px 0 16px;text-overflow:ellipsis;white-space:nowrap}.layui-layer-setwin{font-size:0;line-height:normal;position:absolute;right:15px;top:16px}.layui-layer-setwin span{box-sizing:border-box;color:#000;cursor:pointer;font-size:16px;height:16px;line-height:18px;margin-left:10px;_overflow:hidden;position:relative;text-align:center;width:16px}.layui-layer-setwin .layui-layer-min:before{border-bottom:1px solid #2e2d3c;content:"";cursor:pointer;left:50%;margin:-.5px 0 0 -6px;_overflow:hidden;position:absolute;top:50%;width:12px}.layui-layer-setwin .layui-layer-max:after,.layui-layer-setwin .layui-layer-max:before{border:1px solid #2e2d3c;content:"";height:9px;left:50%;margin:-5px 0 0 -5px;position:absolute;top:50%;width:9px;z-index:1}.layui-layer-setwin .layui-layer-max:hover:after,.layui-layer-setwin .layui-layer-max:hover:before{border-color:#2d93ca}.layui-layer-setwin .layui-layer-min:hover:before{background-color:#2d93ca}.layui-layer-setwin .layui-layer-maxmin:after,.layui-layer-setwin .layui-layer-maxmin:before{background-color:#fff;height:7px;margin:-3px 0 0 -3px;width:7px}.layui-layer-setwin .layui-layer-maxmin:after{margin:-5px 0 0 -1px;z-index:0}.layui-layer-setwin .layui-layer-close{cursor:pointer}.layui-layer-setwin .layui-layer-close:hover{opacity:.7}.layui-layer-setwin .layui-layer-close2{background-color:#787878;border:3px solid;border-radius:50%;color:#fff;font-size:16px;font-weight:bolder;height:28px;margin-left:0;padding:3px;position:absolute;right:-28px;top:-28px;width:28px}.layui-layer-setwin .layui-layer-close2:hover{background-color:#3888f6;opacity:unset}.layui-layer-btn{padding:0 15px 12px;pointer-events:auto;text-align:right;-webkit-user-select:none;-moz-user-select:none;user-select:none}.layui-layer-btn a{background-color:#fff;border:1px solid #dedede;border-radius:var(--lay-border-radius);box-sizing:border-box;color:#333;cursor:pointer;font-weight:400;height:30px;line-height:30px;margin:5px 5px 0;padding:0 var(--lay-spacing);text-decoration:none}.layui-layer-btn a:hover{opacity:.9;text-decoration:none}.layui-layer-btn a:active{opacity:.8}.layui-layer-btn .layui-layer-btn0{background-color:#1e9fff;border-color:transparent;color:#fff}.layui-layer-btn-l{text-align:left}.layui-layer-btn-c{text-align:center}.layui-layer-btn-is-loading{cursor:not-allowed!important;cursor:wait!important;opacity:.5!important;overflow:hidden;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.layui-layer-btn-is-loading .layui-layer-btn-loading-icon{font-size:14px;margin-right:8px}.layui-layer-dialog{min-width:240px}.layui-layer-dialog .layui-layer-content{font-size:14px;line-height:24px;overflow:hidden;overflow-x:hidden;overflow-y:auto;padding:16px;position:relative;word-break:break-all}.layui-layer-dialog .layui-layer-content .layui-layer-face{color:#959595;font-size:32px;left:16px;_left:-40px;position:absolute;top:18px}.layui-layer-dialog .layui-layer-content .layui-icon-tips{color:#f39b12}.layui-layer-dialog .layui-layer-content .layui-icon-success{color:var(--lay-color-accent)}.layui-layer-dialog .layui-layer-content .layui-icon-error{color:#ff5722;top:19px}.layui-layer-dialog .layui-layer-content .layui-icon-question{color:#ffb800}.layui-layer-dialog .layui-layer-content .layui-icon-lock{color:#787878}.layui-layer-dialog .layui-layer-content .layui-icon-face-cry{color:#ff5722}.layui-layer-dialog .layui-layer-content .layui-icon-face-smile{color:var(--lay-color-accent)}.layui-layer-rim{border:6px solid #8d8d8d;border:6px solid rgba(0,0,0,.3);border-radius:5px;box-shadow:none}.layui-layer-msg{border:1px solid #d3d4d3;box-shadow:none;min-width:180px}.layui-layer-hui{background-color:#000;background-color:rgba(0,0,0,.6);border:none;color:#fff;filter:alpha(opacity=60);min-width:100px}.layui-layer-hui .layui-layer-close{color:#fff}.layui-layer-hui .layui-layer-content{padding:11px 24px;text-align:center}.layui-layer-dialog .layui-layer-padding{padding:18px 24px 18px 58px;text-align:left}.layui-layer-page .layui-layer-content{overflow:auto;position:relative}.layui-layer-iframe .layui-layer-btn,.layui-layer-page .layui-layer-btn{padding-top:10px}.layui-layer-nobg{background:none}.layui-layer-iframe iframe{display:block;width:100%}.layui-layer-loading{background:none;border:none;border-radius:100%;box-shadow:none}.layui-layer-loading .layui-layer-content{height:38px;line-height:38px;text-align:center;width:76px}.layui-layer-loading-icon{color:#959595;font-size:38px}.layui-layer-loading2{text-align:center}.layui-layer-loading-2{height:38px;position:relative}.layui-layer-loading-2:after,.layui-layer-loading-2:before{border:3px solid var(--lay-border-color-accent);border-radius:50%;box-sizing:border-box;content:"";height:38px;left:50%;margin:-19px 0 0 -19px;position:absolute;top:50%;width:38px}.layui-layer-loading-2:after{border-color:transparent transparent transparent #1e9fff}.layui-layer-tips{background:none;border:none;box-shadow:none}.layui-layer-tips .layui-layer-content{background-color:#000;border-radius:var(--lay-border-radius);box-shadow:1px 1px 3px rgba(0,0,0,.2);color:#fff;_float:left;font-size:12px;line-height:22px;min-width:12px;padding:8px 15px;position:relative}.layui-layer-tips .layui-layer-close{right:-2px;top:-1px}.layui-layer-tips i.layui-layer-TipsG{border:8px dashed transparent;height:0;position:absolute;width:0}.layui-layer-tips i.layui-layer-TipsB,.layui-layer-tips i.layui-layer-TipsT{border-right-color:#000;border-right-style:solid;left:5px}.layui-layer-tips i.layui-layer-TipsT{bottom:-8px}.layui-layer-tips i.layui-layer-TipsB{top:-8px}.layui-layer-tips i.layui-layer-TipsL,.layui-layer-tips i.layui-layer-TipsR{border-bottom-color:#000;border-bottom-style:solid;top:5px}.layui-layer-tips i.layui-layer-TipsR{left:-8px}.layui-layer-tips i.layui-layer-TipsL{right:-8px}.layui-layer-lan .layui-layer-title{background:#4476a7;border:none;color:#fff}.layui-layer-lan .layui-layer-btn{border-top:1px solid #e9e7e7;padding:5px 10px 10px}.layui-layer-lan .layui-layer-btn a{background:#fff;border-color:#e9e7e7;color:#333}.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#c9c5c5}.layui-layer-molv .layui-layer-title{background:#009f95;border:none;color:#fff}.layui-layer-molv .layui-layer-btn a{background:#009f95;border-color:#009f95}.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92b8b1}.layui-layer-lan .layui-layer-setwin .layui-icon,.layui-layer-molv .layui-layer-setwin .layui-icon{color:#fff}.layui-layer-win10{border:1px solid #aaa;border-radius:none;box-shadow:1px 1px 6px rgba(0,0,0,.3)}.layui-layer-win10 .layui-layer-title{border-bottom:none;font-size:12px;height:32px;line-height:32px;padding-left:8px}.layui-layer-win10 .layui-layer-setwin{right:0;top:0}.layui-layer-win10 .layui-layer-setwin span{height:32px;margin-left:0;padding:8px;width:32px}.layui-layer-win10.layui-layer-page .layui-layer-setwin span{width:38px}.layui-layer-win10 .layui-layer-setwin span:hover{background-color:#e5e5e5}.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover{background-color:#e81123;color:#fff}.layui-layer-win10.layui-layer-dialog .layui-layer-content{color:#0033bc;padding:var(--lay-spacing-sm) var(--lay-spacing) var(--lay-spacing-lg)}.layui-layer-win10.layui-layer-dialog .layui-layer-padding{padding-left:58px;padding-top:18px}.layui-layer-win10 .layui-layer-btn{background-color:#f0f0f0;border-top:1px solid #dfdfdf;padding:5px 5px 10px}.layui-layer-win10 .layui-layer-btn a{background-color:#e1e1e1;border-color:#adadad;color:#000;font-size:12px;height:20px;line-height:18px;transition:all .3s}.layui-layer-win10 .layui-layer-btn a:hover{background-color:#e5f1fb;border-color:#2a8edd}.layui-layer-win10 .layui-layer-btn .layui-layer-btn0{border-color:#0078d7}.layui-layer-prompt .layui-layer-input{border:1px solid #e6e6e6;color:#333;display:block;height:36px;line-height:30px;margin:0 auto;padding-left:10px;width:260px}.layui-layer-prompt textarea.layui-layer-input{height:100px;line-height:20px;padding:6px 10px;width:300px}.layui-layer-prompt .layui-layer-content{padding:var(--lay-spacing)}.layui-layer-prompt .layui-layer-btn{padding-top:0}.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4)}.layui-layer-tab .layui-layer-title{overflow:visible;padding-left:0}.layui-layer-tab .layui-layer-title span{border-left:1px solid transparent;border-right:1px solid transparent;cursor:default;cursor:pointer;display:inline-block;max-width:300px;min-width:80px;overflow:hidden;padding:0 var(--lay-spacing);position:relative;text-align:center;text-overflow:ellipsis;vertical-align:top;white-space:nowrap}.layui-layer-tab .layui-layer-title span.layui-this{background-color:#fff;border-left-color:var(--lay-border-color);border-right-color:var(--lay-border-color);height:51px;z-index:10}.layui-layer-tab .layui-layer-title span:first-child{border-left-color:transparent}.layui-layer-tabmain{clear:both;line-height:24px}.layui-layer-tabmain .layui-layer-tabli{display:none}.layui-layer-tabmain .layui-layer-tabli.layui-this{display:block}.layui-layer-photos{background:none;box-shadow:none}.layui-layer-photos .layui-layer-content{overflow:visible;text-align:center}.layui-layer-photos .layer-layer-photos-main img{display:inline-block;position:relative;vertical-align:top;width:100%}.layui-layer-photos-next,.layui-layer-photos-prev{color:#717171;cursor:pointer;font-size:52px;height:52px;line-height:52px;margin-top:-26px;position:fixed;top:50%;width:52px}.layui-layer-photos-prev{left:32px}.layui-layer-photos-next{right:32px}.layui-layer-photos-next:hover,.layui-layer-photos-prev:hover{color:#959595}.layui-layer-photos-toolbar{background-color:rgba(0,0,0,.32);bottom:0;color:#fff;font-size:0;height:52px;left:0;line-height:52px;overflow:hidden;position:fixed;right:0;text-overflow:ellipsis;white-space:nowrap;width:100%}.layui-layer-photos-toolbar>*{color:#fff;display:inline-block;font-size:12px;padding:0 var(--lay-spacing);vertical-align:top}.layui-layer-photos-toolbar *{font-size:12px}.layui-layer-photos-header{bottom:auto;top:0}.layui-layer-photos-header>span{cursor:pointer}.layui-layer-photos-header>span:hover{background-color:rgba(51,51,51,.32)}.layui-layer-photos-header .layui-icon{font-size:18px}.layui-layer-photos-footer>h3{max-width:65%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.layui-layer-photos-footer a:hover{text-decoration:underline}.layui-layer-photos-footer em{font-style:normal}@keyframes layer-bounceOut{to{opacity:0;transform:scale(.7)}30%{transform:scale(1.05)}0%{transform:scale(1)}}.layer-anim-close{animation-duration:.2s;animation-fill-mode:both;animation-name:layer-bounceOut} +/*# sourceMappingURL=layui.css.map */ \ No newline at end of file diff --git a/dist/css/layui.css.map b/dist/css/layui.css.map new file mode 100644 index 000000000..878f1d302 --- /dev/null +++ b/dist/css/layui.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["../../src/css/var.css","../../src/css/base.css","../../src/css/modules/icon.css","../../src/css/modules/layout.css","../../src/css/modules/auxiliary.css","../../src/css/modules/progress.css","../../src/css/modules/panel.css","../../src/css/modules/theme.css","../../src/css/modules/text.css","../../src/css/modules/button.css","../../src/css/modules/form.css","../../src/css/modules/laypage.css","../../src/css/modules/flow.css","../../src/css/modules/table.css","../../src/css/modules/upload.css","../../src/css/modules/menu.css","../../src/css/modules/tabs.css","../../src/css/modules/tab.css","../../src/css/modules/nav.css","../../src/css/modules/timeline.css","../../src/css/modules/badge.css","../../src/css/modules/carousel.css","../../src/css/modules/util.css","../../src/css/modules/transfer.css","../../src/css/modules/rate.css","../../src/css/modules/colorpicker.css","../../src/css/modules/slider.css","../../src/css/modules/tree.css","../../src/css/modules/anim.css","../../src/css/modules/code.css","../../src/css/modules/laydate.css","../../src/css/modules/layer.css"],"names":[],"mappings":"AAIA,aAGE,2BAA4B,CAC5B,0BAA2B,CAG3B,uBAAwB,CACxB,0BAA2B,CAC3B,yBAA0B,CAC1B,wBAAyB,CACzB,0BAA2B,CAC3B,yBAA0B,CAC1B,wBAAyB,CAGzB,sBAAuB,CACvB,sBAAuB,CACvB,mBAAuB,CACvB,sBAAuB,CACvB,sBAAuB,CACvB,sBAAuB,CACvB,sBAAuB,CACvB,mBAAuB,CACvB,sBAAuB,CAGvB,sCAAuC,CACvC,6CAA8C,CAC9C,uBAAwB,CACxB,0CAA+C,CAC/C,+CAAoD,CACpD,4CAAiD,CAGjD,uMAGyD,CACzD,sEAA0E,CAG1E,kBAAmB,CACnB,oBAAqB,CACrB,oBAAqB,CACrB,qBAAsB,CACtB,qBACF,CClDA,+FAuBE,QAAS,CACT,SAAU,CACV,yCACF,CACA,iBAEE,SACF,CACA,IAEE,WAAY,CADZ,oBAAqB,CAErB,qBACF,CACA,GACE,eACF,CACA,MACE,wBAAyB,CACzB,gBACF,CACA,kBAME,eACF,CAKA,mCAIE,cACF,CACA,6CAME,mBAAoB,CACpB,iBAAkB,CAClB,kBAAmB,CACnB,mBAAoB,CACpB,SACF,CACA,IACE,oBAAqB,CACrB,oBACF,CAGA,KAEE,qBAA0B,CAE1B,kCAAmC,CADnC,cAAe,CAFf,eAIF,CACA,GASE,eAAgB,CAJhB,WAAY,CACZ,+CAAgD,CAChD,UAAW,CANX,QAAS,CACT,aAAc,CACd,aAAc,CAKd,eAAgB,CAJhB,SAMF,CACA,EACE,UAAW,CACX,oBACF,CACA,OACE,iBACF,CAGA,sCAEE,qBACF,CAEA,wBAEE,sBACF,CACA,aACE,UACF,CACA,mBAEE,UAAW,CADX,aAAc,CAEd,aAAc,CACd,QACF,CACA,mBACE,iBACF,CAOA,0BAJE,oBAAqB,CADrB,iBAAkB,CAElB,qBAaF,CAVA,YAQE,6BAAyB,CAHzB,QAAS,CAIT,eAAgB,CALhB,OAMF,CACA,gBAEE,wBAAyB,CACzB,yBAA0B,CAF1B,QAGF,CACA,kBACE,sBAAuB,CACvB,uBACF,CACA,mBAEE,qBAAsB,CACtB,sBAAuB,CAFvB,OAGF,CACA,iBACE,uBAAwB,CACxB,wBACF,CAEA,aAEE,eAAgB,CADhB,sBAAuB,CAEvB,kBACF,CAEA,4CAGE,wBAAyB,CACzB,qBAAsB,CAEtB,gBACF,CAEA,sCAEE,mCAAqC,CACrC,4BACF,CAEA,cACE,kBACF,CACA,YACE,uBACF,CACA,YACE,sBACF,CACA,cACE,4BACF,CACA,cACE,2BACF,CCrMA,WACE,sBAAyB,CACzB,0nuCACF,CAEA,YACE,gCAAoC,CACpC,cAAe,CACf,iBAAkB,CAClB,kCAAmC,CACnC,iCACF,CAGA,yBACE,eACF,CACA,uBACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,+BACE,eACF,CACA,yBACE,eACF,CACA,0BACE,eACF,CACA,4BACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,2BACE,eACF,CACA,4BACE,eACF,CACA,wBACE,eACF,CACA,uBACE,eACF,CACA,iCACE,eACF,CACA,6BACE,eACF,CACA,6BACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,8BACE,eACF,CACA,yBACE,eACF,CACA,yBACE,eACF,CACA,wBACE,eACF,CACA,sBACE,eACF,CACA,2BACE,eACF,CACA,sBACE,eACF,CACA,6BACE,eACF,CACA,0BACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,uBACE,eACF,CACA,2BACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,2BACE,eACF,CACA,uBACE,eACF,CACA,0BACE,eACF,CACA,wBACE,eACF,CACA,uBACE,eACF,CACA,yBACE,eACF,CACA,iCACE,eACF,CACA,4BACE,eACF,CACA,2BACE,eACF,CACA,4BACE,eACF,CACA,+BACE,eACF,CACA,0BACE,eACF,CACA,yBACE,eACF,CACA,0BACE,eACF,CACA,wBACE,eACF,CACA,+BACE,eACF,CACA,kCACE,eACF,CACA,6BACE,eACF,CACA,8BACE,eACF,CACA,wBACE,eACF,CACA,6BACE,eACF,CACA,2BACE,eACF,CACA,+BACE,eACF,CACA,4BACE,eACF,CACA,gCACE,eACF,CACA,4BACE,eACF,CACA,4BACE,eACF,CACA,6BACE,eACF,CACA,uBACE,eACF,CACA,gCACE,eACF,CACA,+BACE,eACF,CACA,6BACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,6BACE,eACF,CACA,2BACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,0BACE,eACF,CACA,2BACE,eACF,CACA,2BACE,eACF,CACA,kCACE,eACF,CACA,uBACE,eACF,CACA,4BACE,eACF,CACA,uBACE,eACF,CACA,8BACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,0BACE,eACF,CACA,uBACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,+BACE,eACF,CACA,4BACE,eACF,CACA,8BACE,eACF,CACA,0BACE,eACF,CACA,wBACE,eACF,CACA,4BACE,eACF,CACA,0BACE,eACF,CACA,2BACE,eACF,CACA,0BACE,eACF,CACA,+BACE,eACF,CACA,wBACE,eACF,CACA,iCACE,eACF,CACA,wBACE,eACF,CACA,6BACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,+BACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,6BACE,eACF,CACA,6BACE,eACF,CACA,2BACE,eACF,CACA,6BACE,eACF,CACA,yBACE,eACF,CACA,yBACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,2BACE,eACF,CACA,yBACE,eACF,CACA,2BACE,eACF,CACA,6BACE,eACF,CACA,8BACE,eACF,CACA,8BACE,eACF,CACA,gCACE,eACF,CACA,0BACE,eACF,CACA,2BACE,eACF,CACA,wBACE,eACF,CACA,gCACE,eACF,CACA,gCACE,eACF,CACA,+BACE,eACF,CACA,8BACE,eACF,CACA,2BACE,eACF,CACA,2BACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,yBACE,eACF,CACA,yBACE,eACF,CACA,wBACE,eACF,CACA,0BACE,eACF,CACA,0BACE,eACF,CACA,gCACE,eACF,CACA,yBACE,eACF,CACA,yBACE,eACF,CACA,wBACE,eACF,CACA,iCACE,eACF,CACA,+BACE,eACF,CACA,wBACE,eACF,CACA,2BACE,eACF,CACA,+BACE,eACF,CACA,4BACE,eACF,CACA,+BACE,eACF,CACA,yBACE,eACF,CACA,wBACE,eACF,CACA,yBACE,eACF,CACA,+BACE,eACF,CACA,4BACE,eACF,CACA,kCACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,8BACE,eACF,CACA,8BACE,eACF,CACA,0BACE,eACF,CACA,8BACE,eACF,CACA,kCACE,eACF,CACA,oCACE,eACF,CACA,uBACE,eACF,CACA,yBACE,eACF,CACA,+BACE,eACF,CACA,wBACE,eACF,CACA,sBACE,eACF,CACA,8BACE,eACF,CACA,4BACE,eACF,CACA,0BACE,eACF,CACA,2BACE,eACF,CACA,yBACE,eACF,CACA,8BACE,eACF,CACA,6BACE,eACF,CACA,mCACE,eACF,CACA,gCACE,eACF,CACA,uBACE,eACF,CACA,wBACE,eACF,CACA,2BACE,eACF,CACA,mCACE,eACF,CACA,sBACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,uBACE,eACF,CACA,yBACE,eACF,CACA,wBACE,eACF,CACA,wBACE,eACF,CACA,mCACE,eACF,CACA,yBACE,eACF,CACA,8BACE,eACF,CACA,6BACE,eACF,CCtlBA,YAGE,aAAc,CAFd,iBAAkB,CAClB,YAEF,CACA,cAGE,WAAY,CAFZ,iBAAkB,CAClB,YAEF,CACA,sBAEE,kBACF,CACA,YAIE,QAAS,CAFT,MAAO,CAKP,iBAAkB,CANlB,cAAe,CAEf,KAAM,CAGN,WAAY,CADZ,WAGF,CACA,mBAGE,WAAY,CACZ,iBAAkB,CAHlB,iBAAkB,CAClB,WAGF,CACA,YAKE,QAAS,CAET,qBAAsB,CALtB,UAAW,CADX,iBAAkB,CAElB,OAAQ,CACR,KAAM,CAEN,UAEF,CAGA,mBACE,iBACF,CACA,kCAKE,wBAAyB,CAFzB,MAAO,CAFP,cAAe,CAGf,OAAQ,CAFR,KAIF,CACA,gCAGE,iBAAkB,CAFlB,QAAS,CACT,WAEF,CACA,gCAGE,mBAAoB,CAFpB,iBAAkB,CAClB,QAEF,CACA,gCAEE,aAAc,CADd,UAEF,CACA,kCAUE,sCAAuC,CANvC,QAAS,CAKT,qCAAuC,CAHvC,WAAY,CAJZ,UAAW,CAKX,gBAAiB,CACjB,cAAe,CAPf,cAAe,CAEf,OAAQ,CAER,WAMF,CACA,gCAUE,sCAAwC,CAFxC,8BAA+B,CAC/B,cAAe,CAJf,WAAY,CAHZ,MAAO,CAIP,gBAAiB,CALjB,iBAAkB,CAMlB,iBAAkB,CAJlB,KAAM,CACN,WAOF,CACA,6CACE,eACF,CACA,mBAEE,UAAW,CADX,2BAA6B,CAE7B,KACF,CACA,oBACE,2BAA6B,CAC7B,OAAQ,CACR,KACF,CAGA,iBAGE,qBACF,CACA,8BAHE,aAAc,CADd,iBAQF,CAJA,aAGE,cACF,CAEA,mCAIE,UAAW,CAFX,UAAW,CACX,aAEF,CACA,m5BA8DE,qBAAsB,CADtB,aAAc,CADd,iBAGF,CAEA,uLAYE,UACF,CACA,eACE,iBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,gBACE,kBACF,CACA,gBACE,kBACF,CACA,gBACE,UACF,CAEA,sBACE,uBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,uBACE,wBACF,CACA,uBACE,wBACF,CACA,uBACE,gBACF,CAGA,uCACE,iBACE,cACF,CACA,eACE,sBACF,CACA,qBACE,uBACF,CACA,sBACE,wBACF,CACA,4BACE,8BACF,CACF,CAGA,oCACE,iBACE,WACF,CACA,eACE,sBACF,CACA,qBACE,uBACF,CACA,sBACE,wBACF,CACA,4BACE,8BACF,CAEA,uLAYE,UACF,CACA,eACE,iBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,gBACE,kBACF,CACA,gBACE,kBACF,CACA,gBACE,UACF,CAEA,sBACE,uBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,uBACE,wBACF,CACA,uBACE,wBACF,CACA,uBACE,gBACF,CACF,CAEA,oCACE,iBACE,WACF,CACA,eACE,sBACF,CACA,qBACE,uBACF,CACA,sBACE,wBACF,CACA,4BACE,8BACF,CAEA,uLAYE,UACF,CACA,eACE,iBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,gBACE,kBACF,CACA,gBACE,kBACF,CACA,gBACE,UACF,CAEA,sBACE,uBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,uBACE,wBACF,CACA,uBACE,wBACF,CACA,uBACE,gBACF,CACF,CAEA,qCACE,iBACE,YACF,CACA,eACE,sBACF,CACA,qBACE,uBACF,CACA,sBACE,wBACF,CACA,4BACE,8BACF,CAEA,uLAYE,UACF,CACA,eACE,iBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,gBACE,kBACF,CACA,gBACE,kBACF,CACA,gBACE,UACF,CAEA,sBACE,uBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,uBACE,wBACF,CACA,uBACE,wBACF,CACA,uBACE,gBACF,CACF,CAEA,qCACE,iBACE,YACF,CACA,eACE,sBACF,CACA,qBACE,uBACF,CACA,sBACE,wBACF,CACA,4BACE,8BACF,CAEA,uLAYE,UACF,CACA,eACE,iBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,eACE,kBACF,CACA,eACE,kBACF,CACA,eACE,SACF,CACA,gBACE,kBACF,CACA,gBACE,kBACF,CACA,gBACE,UACF,CAEA,sBACE,uBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,sBACE,wBACF,CACA,sBACE,wBACF,CACA,sBACE,eACF,CACA,uBACE,wBACF,CACA,uBACE,wBACF,CACA,uBACE,gBACF,CACF,CAGA,kBACE,YACF,CACA,oBACE,YACF,CACA,kBACE,WACF,CACA,oBACE,WACF,CACA,kBACE,WACF,CACA,oBACE,WACF,CACA,kBACE,aACF,CACA,oBACE,aACF,CACA,kBACE,WACF,CACA,oBACE,WACF,CACA,kBACE,WACF,CACA,oBACE,WACF,CACA,mBACE,WACF,CACA,qBACE,WACF,CACA,mBACE,WACF,CACA,qBACE,WACF,CACA,mBACE,WACF,CACA,qBACE,WACF,CACA,mBACE,aACF,CACA,qBACE,aACF,CACA,mBACE,WACF,CACA,qBACE,WACF,CACA,mBACE,WACF,CACA,qBACE,WACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CACA,mBACE,cACF,CACA,qBACE,cACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CACA,mBACE,YACF,CACA,qBACE,YACF,CAKA,iBACE,uCACF,CACA,iBACE,uCACF,CACA,iBACE,oCACF,CACA,iBACE,uCACF,CACA,iBACE,uCACF,CAKA,gBACE,sCACF,CACA,gBACE,sCACF,CACA,gBACE,mCACF,CACA,gBACE,sCACF,CACA,gBACE,sCACF,CCx2BA,2EAME,uBAAwB,CACxB,oBAAqB,CACrB,eAAgB,CAGhB,qBAAsB,CANtB,YAAa,CAKb,kBAEF,CAGA,kBAME,sCAAuC,CAFvC,6CAA8C,CAC9C,mEAAoE,CAFpE,eAAgB,CAFhB,kBAAmB,CACnB,0BAKF,CACA,gBAIE,eAAgB,CAHhB,kBAAmB,CAEnB,4BAEF,CAGA,kBAIE,kBAAmB,CADnB,gBAAiB,CAFjB,kBAAmB,CACnB,SAGF,CACA,yBAGE,cAAe,CAFf,gBAAiB,CACjB,cAEF,CACA,mBAGE,oBAAqB,CAFrB,2BAGF,CACA,iBACE,0BACF,CACA,oCACE,cACF,CAGA,uBAQE,eAAgB,CAHhB,QAAS,CAET,WAAY,CALZ,MAAO,CADP,cAAe,CAEf,OAAQ,CACR,KAAM,CAMN,qBAAsB,CACtB,wBAAyB,CAEzB,gBAAiB,CAPjB,UAAW,CAGX,kBAKF,CACA,sBACE,yBACF,CC3EA,gBAIE,oCAAqC,CADrC,kBAAmB,CADnB,UAAW,CADX,iBAIF,CACA,oBASE,wCAAyC,CAFzC,kBAAmB,CADnB,UAAW,CAJX,MAAO,CAGP,cAAe,CAJf,iBAAkB,CAOlB,gBAAiB,CALjB,KAAM,CAQN,kBAAoB,CAPpB,OAQF,CACA,4DAEE,WAAY,CACZ,gBACF,CACA,qBAKE,aAAc,CADd,cAAe,CADf,gBAAiB,CAFjB,iBAAkB,CAClB,SAIF,CACA,yCAGE,UAAW,CADX,cAAe,CADf,eAGF,CC/BA,gBAGE,sCAAuC,CADvC,kBAAmB,CADnB,gBAGF,CACA,uCAGE,sBAAuB,CADvB,oBAEF,CACA,8BACE,eACF,CACA,mBAME,sCAAuC,CADvC,UAAW,CAEX,cAAe,CACf,cAAe,CANf,WAAY,CACZ,gBAAiB,CAMjB,eAAgB,CALhB,qBAAsB,CAHtB,iBASF,CACA,qBAIE,aAAc,CAHd,YAAa,CAEb,eAAgB,CADhB,iBAGF,CACA,kBAKE,cAAe,CAHf,SAAU,CAIV,kBAAmB,CAFnB,eAAgB,CAHhB,iBAAkB,CAElB,OAAQ,CAIR,kBACF,CACA,kEACE,uBACF,CACA,kDACE,aACF,CAGA,YAGE,qBAAsB,CADtB,sCAAuC,CAEvC,sCAA2C,CAH3C,kBAIF,CACA,uBACE,eACF,CACA,oCAGE,iBAAkB,CADlB,iBAEF,CACA,mBACE,+BAAgC,CAEhC,8CAA+C,CAD/C,UAAW,CAEX,cACF,CACA,8BACE,YACF,CACA,uBACE,QACF,CAGA,aAIE,sCAAuC,CADvC,kBAAmB,CADnB,gBAAiB,CAGjB,oCAAuC,CAEvC,aACF,CAGA,iCALE,qBAAsB,CALtB,iBAgBF,CANA,oBAGE,eAAgB,CAChB,4CAA6C,CAF7C,YAIF,CC5FA,cACE,+CAAiD,CACjD,oBACF,CACA,iBACE,kDAAoD,CACpD,oBACF,CACA,gBACE,mDAAqD,CACrD,oBACF,CACA,eACE,kCAAoC,CACpC,oBACF,CACA,eACE,gDAAkD,CAClD,oBACF,CACA,iBACE,kDAAoD,CACpD,oBACF,CACA,gBACE,iDAAmD,CACnD,oBACF,CACA,eACE,gDAAkD,CAClD,uBACF,CAGA,iWAkBE,oCACF,CAEA,cAGE,uBACF,CACA,gCAHE,kBAAmB,CADnB,gBASF,CALA,kBAGE,2CAA6C,CAC7C,oCACF,CACA,qBAGE,8CAAgD,CADhD,kBAAmB,CADnB,gBAAiB,CAGjB,uCACF,CACA,oBAGE,+CAAiD,CADjD,kBAAmB,CADnB,gBAAiB,CAGjB,wCACF,CACA,mBAGE,8BAAgC,CADhC,kBAAmB,CADnB,gBAAiB,CAGjB,uBACF,CACA,mBAGE,4CAA8C,CAD9C,kBAAmB,CADnB,gBAAiB,CAGjB,qCACF,CACA,qBAGE,8CAAgD,CADhD,kBAAmB,CADnB,gBAAiB,CAGjB,uCACF,CACA,oBAGE,6CAA+C,CAD/C,kBAAmB,CADnB,gBAAiB,CAGjB,sCACF,CAGA,wJAOE,oBACF,CAGA,4BACE,oCACF,CCzHA,YAEE,cAAe,CADf,eAEF,CACA,eAEE,cAAe,CADf,aAEF,CACA,eAEE,cAAe,CADf,aAEF,CACA,eAEE,cAAe,CADf,aAEF,CACA,eAEE,cAAe,CADf,aAEF,CACA,eAEE,cAAe,CADf,aAEF,CACA,eAEE,cAAe,CADf,aAEF,CACA,cACE,aACF,CACA,0BACE,YACF,CACA,yBACE,eACF,CACA,eACE,aACF,CACA,8BAEE,iBACF,CACA,kBAEE,oBAAqB,CADrB,cAEF,CACA,kBAEE,uBAAwB,CADxB,cAEF,CACA,0CAEE,oBACF,CACA,gEAGE,eAAgB,CADhB,YAEF,CACA,sCACE,aACF,CACA,4CACE,yBACF,CACA,8CAGE,6CAA8C,CAF9C,aAAc,CACd,gBAEF,CACA,sCACE,aAAc,CAEd,yDAAiE,CADjE,YAEF,CAGA,+BAEE,oBAAsB,CACtB,0BAA4B,CAC5B,2BACF,CAGA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CACA,eACE,wBACF,CAGA,gBACE,oCACF,CACA,mBACE,uCACF,CACA,kBACE,wCACF,CACA,iBACE,uBACF,CACA,iBACE,uBACF,CACA,mBACE,uCACF,CACA,kBACE,oBACF,CACA,iBACE,uBACF,CCjJA,WAOE,yCAA0C,CAF1C,4BAA6B,CAO7B,sCAAuC,CAJvC,UAAW,CAKX,cAAe,CAZf,oBAAqB,CAUrB,cAAe,CARf,WAAY,CACZ,gBAAiB,CAEjB,cAAe,CAIf,iBAAkB,CAIlB,wBAAyB,CACzB,qBAAsB,CAEtB,gBAAiB,CAfjB,qBAAsB,CAOtB,kBASF,CACA,iBAGE,UAAW,CADX,wBAAyB,CADzB,UAGF,CACA,kBAEE,yBAA0B,CAD1B,SAEF,CACA,sBACE,gBACF,CAGA,qBACE,iBACF,CACA,gCAEE,kBAAmB,CADnB,iBAAkB,CAElB,mBACF,CACA,2CACE,aACF,CACA,6CACE,iBACF,CAGA,kBACE,mBACF,CACA,uBACE,aAAc,CACd,uBAAwB,CACxB,qBACF,CAGA,mBAEE,eAAgB,CADhB,2CAA4C,CAE5C,aACF,CACA,yBACE,qCAAsC,CACtC,UACF,CAEA,kBACE,sCACF,CAEA,gBACE,wCACF,CAEA,kBACE,qCACF,CAEA,mBACE,wCACF,CAEA,yEAIE,kCAAoC,CADpC,8CAAgD,CAEhD,mCAAqC,CACrC,4BAA8B,CAC9B,SACF,CAGA,cAIE,cAAe,CAHf,WAAY,CACZ,gBAAiB,CACjB,cAEF,CAEA,cAIE,cAAe,CAHf,WAAY,CACZ,gBAAiB,CACjB,cAEF,CAEA,cAIE,cAAe,CAHf,WAAY,CACZ,gBAAiB,CACjB,aAEF,CACA,gBACE,wBACF,CAEA,iBACE,oBAAqB,CAErB,WAAY,CADZ,qBAEF,CACA,4BAGE,wCAA+C,CAC/C,eAAgB,CAHhB,uBAAyB,CACzB,wBAGF,CACA,oCACE,gBACF,CACA,0CACE,2CAA4C,CAC5C,8BACF,CACA,wCACE,gBAAiB,CACjB,mEACF,CACA,gDACE,yCACF,CACA,uCACE,mEACF,CACA,uCACE,aACF,CACA,kCACE,gBACF,CAEA,iBACE,UACF,CChKA,2CAQE,qBAAsB,CAEtB,sCAAuC,CAHvC,kBAAmB,CADnB,gBAAiB,CAGjB,qBAA0B,CAN1B,WAAY,CACZ,eAAgB,CAChB,kBAMF,CACA,4HAGE,eACF,CACA,6BAEE,aAAc,CAEd,iBAAkB,CADlB,UAEF,CACA,yCAEE,qDACF,CACA,yCAEE,8CAAgD,CAChD,yCACF,CACA,gBAGE,WAAY,CACZ,gBAAiB,CAFjB,gBAAiB,CAGjB,gBAAiB,CAJjB,iBAAkB,CAKlB,eACF,CACA,iDAEE,sCACF,CACA,cACE,cACF,CACA,kFAGE,YACF,CACA,yBACE,eACF,CAEA,iBAGE,UAAW,CADX,kBAAmB,CADnB,iBAGF,CACA,uBAEE,UAAW,CADX,aAAc,CAEd,aAAc,CACd,QACF,CACA,kBAGE,aAAc,CADd,UAAW,CAIX,eAAgB,CAChB,gBAAiB,CAHjB,gBAAiB,CAHjB,iBAAkB,CAOlB,gBAAiB,CAHjB,UAIF,CACA,sBACE,aAAc,CACd,UAAW,CAEX,gBAAiB,CADjB,aAAc,CAEd,eACF,CACA,+BACE,iBAAkB,CAClB,iBACF,CACA,uCAEE,iBACF,CACA,mBACE,iBAAkB,CAClB,eACF,CACA,oBACE,oBAAqB,CACrB,qBACF,CACA,qCACE,UAAW,CAEX,iBAAkB,CADlB,WAEF,CACA,qCACE,UACF,CAGA,gBAGE,aAAc,CADd,UAAW,CAGX,gBAAiB,CACjB,iBAAkB,CAFlB,uBAAyB,CAHzB,iBAMF,CAGA,4EAEE,2CAA6C,CAC7C,wCACF,CAGA,kGAYE,qBAAsB,CAHtB,WAAY,CAFZ,cAAe,CAHf,iBAAkB,CAClB,OAAQ,CAKR,iBAAkB,CAJlB,KAAM,CAKN,kBAAoB,CAHpB,UAKF,CACA,oBAEE,mEAAoE,CADpE,MAEF,CACA,oBAEE,mEAAoE,CADpE,OAEF,CACA,mBAEE,kBAAmB,CADnB,gBAEF,CACA,+FAKE,aAAc,CADd,cAAe,CADf,iBAAkB,CAGlB,kBACF,CAGA,mBAGE,qBAAsB,CADtB,aAAc,CADd,iBAGF,CACA,qBACE,kBAAmB,CAEnB,iBAAkB,CADlB,qBAEF,CACA,gCACE,kBACF,CACA,uCAEE,cAAe,CADf,UAEF,CACA,uCAEE,aAAc,CADd,UAEF,CACA,sCACE,kBACF,CAGA,kBAEE,gBAAiB,CADjB,iBAEF,CACA,+BACE,kBACF,CACA,qFAEE,YACF,CACA,wGAEE,iBACF,CACA,sGAEE,iBACF,CACA,yDACE,eACF,CACA,iHAGE,mBACF,CACA,wDACE,2CACF,CACA,wDACE,oCACF,CACA,0EACE,iCACF,CACA,wDAEE,sBACF,CACA,wDAEE,sBACF,CAGA,mBACE,gBACF,CACA,uCAEE,UAAW,CADX,UAEF,CACA,+BACE,oBAAyB,CAEzB,cAAe,CADf,6BAEF,CACA,qCACE,oBACF,CACA,qCACE,oBACF,CAGA,sCAEE,SAAU,CADV,UAEF,CACA,kDAME,cAAe,CAFf,UAAW,CACX,kBAAmB,CAJnB,iBAAkB,CAClB,OAAQ,CACR,UAIF,CACA,yDAEE,QAAS,CAGT,gBAAiB,CADjB,eAAgB,CAHhB,iBAAkB,CAElB,OAGF,CACA,qDAEE,+CAAgD,CADhD,KAEF,CACA,uDACE,QACF,CACA,wDACE,eACF,CACA,8IAEE,iCACF,CACA,4CACE,yBAA0B,CAC1B,4BAA6B,CAC7B,oBACF,CACA,yHAEE,0BACF,CAGA,mBAEE,aAAc,CADd,iBAEF,CACA,gCAEE,cAAe,CADf,kBAEF,CACA,+BAQE,wBAAuB,CAAvB,gBAAuB,CAHvB,cAAe,CADf,eAAgB,CAHhB,iBAAkB,CAClB,UAAW,CACX,OAAQ,CAOR,kBACF,CACA,sBAWE,qBAAsB,CAHtB,wCAAyC,CAIzC,sCAAuC,CACvC,oCAAuC,CACvC,qBAAsB,CAbtB,YAAa,CAEb,MAAO,CAMP,gBAAiB,CAFjB,cAAe,CAGf,eAAgB,CALhB,aAAc,CAHd,iBAAkB,CAElB,QAAS,CAET,WASF,CACA,kDAGE,gBAAiB,CAEjB,eAAgB,CAHhB,cAAe,CAIf,sBAAuB,CAFvB,kBAGF,CACA,yBAEE,UAAW,CADX,cAEF,CACA,yBACE,cACF,CACA,+BACE,wBAAyB,CAEzB,kBACF,CACA,0CACE,iBACF,CACA,2CAEE,UAAW,CADX,2BAEF,CACA,oCACE,wBAAyB,CACzB,6BAA8B,CAC9B,eACF,CAEA,wCACE,qBACF,CACA,wBACE,aACF,CACA,iCACE,eAAgB,CAKhB,iBAAkB,CAHlB,wBACF,CAIA,uCACE,qBACF,CACA,wBAEE,WAAY,CADZ,QAEF,CACA,mBAGE,UAAW,CAFX,YAAa,CACb,iBAEF,CACA,yBACE,iBAAkB,CAClB,gBACF,CACA,4BAEE,aAAc,CADd,iBAAkB,CAElB,KACF,CAEA,uCACE,8CACF,CACA,mCACE,+CACF,CAGA,qBAQE,qBAAsB,CAKtB,qBAAsB,CAJtB,cAAe,CACf,WAAY,CANZ,WAAY,CACZ,gBAAiB,CACjB,iBAAkB,CAClB,kBAAmB,CANnB,iBAAkB,CAWlB,qBAEF,CACA,4CAbE,oBAAqB,CACrB,qBAeF,CACA,yBAIE,oCAAqC,CADrC,mEAAoE,CAEpE,UAAW,CAHX,cAAe,CAIf,eAAgB,CALhB,cAAe,CAOf,sBAAuB,CADvB,kBAEF,CACA,qCACE,kBACF,CACA,+BACE,wBACF,CACA,uBAOE,+CAAiB,CAAjB,gBAAiB,CACjB,mEAAoE,CAKpE,qBAAsB,CAJtB,UAAW,CACX,uBAA6B,CAC7B,cAAe,CANf,WAAY,CAJZ,iBAAkB,CAClB,OAAQ,CAUR,iBAAkB,CATlB,KAAM,CACN,UAUF,CACA,6BACE,oBAAqB,CACrB,aACF,CACA,8CAEE,oCACF,CACA,sDAEE,wCACF,CACA,kDAEE,6BACF,CACA,sCACE,cACF,CACA,iDACE,8CACF,CACA,2BACE,YACF,CAGA,uCASE,eAAgB,CAJhB,qBAAuB,CAJvB,qBAAuB,CACvB,4BAA8B,CAI9B,cAAe,CAFf,eAAgB,CADhB,cAAe,CAIf,iBAAkB,CAClB,eAEF,CACA,2CAKE,eAAgB,CAChB,aAAc,CAFd,gBAAiB,CAHjB,eAAgB,CAChB,cAAe,CACf,kBAIF,CACA,yCASE,qBAAsB,CAHtB,wBAAyB,CAEzB,sCAAuC,CADvC,cAAe,CAHf,WAAY,CAFZ,MAAO,CAGP,gBAAiB,CAJjB,UAAW,CAUX,qBAAuB,CARvB,UASF,CACA,+CACE,oCAAqC,CACrC,UACF,CACA,wCAEE,wCAAyC,CADzC,8CAAgD,CAEhD,UACF,CACA,+CACE,yBACF,CACA,gEACE,wCAA0C,CAC1C,0CACF,CACA,mDACE,2CACF,CACA,wDACE,eACF,CACA,iEAEE,qBAAsB,CADtB,oCAEF,CACA,wEAQE,wCAAyC,CAPzC,UAAW,CACX,oBAAqB,CAIrB,UAAW,CACX,kBAAmB,CAHnB,iBAAkB,CADlB,qBAAsB,CAEtB,SAIF,CAGA,mBAaE,qBAAsB,CAJtB,wBAAyB,CAGzB,qBAAsB,CADtB,cAAe,CATf,oBAAqB,CAErB,WAAY,CACZ,gBAAiB,CAGjB,cAAe,CAFf,cAAe,CACf,aAAc,CANd,iBAAkB,CAElB,qBAaF,CACA,wCAPE,kBAAmB,CAKnB,qBAYF,CAVA,qBAOE,oCAAqC,CAFrC,WAAY,CAHZ,QAAS,CADT,iBAAkB,CAElB,OAAQ,CACR,UAMF,CACA,uBAME,oBAAsB,CAEtB,cAAe,CADf,2BAA6B,CAJ7B,gBAAiB,CACjB,mBAAqB,CAHrB,iBAAkB,CAIlB,2BAA6B,CAH7B,KAOF,CACA,qBAEE,wCAAyC,CADzC,oCAEF,CACA,uBAGE,qBAAsB,CAFtB,SAAU,CACV,iBAEF,CACA,yBAGE,oBAAsB,CAFtB,aAAc,CACd,iBAEF,CAGA,yEAEE,qBACF,CACA,qEAME,WAAY,CACZ,kBAAmB,CAHnB,QAAS,CADT,eAAgB,CAEhB,SAAU,CAHV,iBAMF,CACA,6EAQE,wBAAyB,CADzB,aAAc,CAFd,cAAe,CADf,MAAO,CAFP,iBAAkB,CAClB,KAAM,CAGN,UAGF,CACA,yEAEE,YACF,CACA,0HAEE,kBACF,CAEA,yBACE,8CACF,CACA,6BACE,uBACF,CACA,2BACE,8CACF,CACA,iCACE,oBACF,CACA,gFAEE,aACF,CACA,sFAEE,uBACF,CAGA,kBAME,cAAe,CACf,WAAY,CAJZ,gBAAiB,CACjB,mBAAoB,CACpB,kBAGF,CACA,sCARE,oBAAqB,CACrB,qBAWF,CAJA,oBAGE,cACF,CACA,oBAGE,aAAc,CADd,cAAe,CADf,gBAGF,CACA,oEAGE,6BACF,CACA,wBACE,mCACF,CACA,wBACE,uBACF,CACA,wBACE,YACF,CAGA,mCASE,sCAAuC,CAFvC,mEAAoE,CADpE,kBAAmB,CADnB,gBAAiB,CAQjB,qBAAsB,CAVtB,WAAY,CACZ,gBAAiB,CAMjB,eAAgB,CARhB,gBAAiB,CAMjB,iBAAkB,CAIlB,sBAAuB,CADvB,kBAAmB,CAVnB,WAaF,CACA,qCACE,gBACF,CACA,oCAEE,SAAU,CADV,iBAEF,CACA,8BACE,mEACF,CACA,oDAGE,sCAAuC,CACvC,qBAAsB,CAHtB,UAAW,CAIX,eAAgB,CAHhB,UAIF,CACA,sDAIE,UAAW,CAHX,aAAc,CACd,QAAS,CACT,QAEF,CACA,qDAEE,MAAO,CADP,QAAS,CAET,QACF,CACA,kDAEE,mEAAoE,CADpE,gBAEF,CACA,sCACE,qBACF,CACA,uEAGE,gBAAiB,CADjB,cAEF,CACA,wCAGE,kBAAmB,CADnB,gBAAiB,CADjB,iBAGF,CACA,0DAME,sBAAuB,CAFvB,WAAY,CAFZ,MAAO,CADP,iBAAkB,CAElB,KAIF,CACA,4DACE,iBACF,CAGA,oCACE,mCAEE,eAAgB,CADhB,sBAAuB,CAEvB,kBACF,CACA,+BAIE,UAAW,CAHX,aAAc,CAEd,kBAAmB,CADnB,cAGF,CACA,qCAEE,UAAW,CADX,aAAc,CAEd,aAAc,CACd,QACF,CACA,qCACE,aAAc,CACd,UAAW,CACX,SAAU,CAEV,qBAAsB,CADtB,oBAEF,CACA,qDACE,iBAAkB,CAElB,SAAU,CADV,QAEF,CACA,sCAEE,iBAAkB,CADlB,gBAEF,CACF,CCzyBA,eACE,oBAAqB,CAGrB,WAAY,CADZ,aAAc,CADd,qBAGF,CACA,6DAEE,mEACF,CACA,2DAEE,mEACF,CACA,4BACE,uBACF,CACA,2BACE,wBACF,CACA,sGAKE,wCACF,CACA,qCAQE,qBAAsB,CACtB,UAAW,CAPX,oBAAqB,CAQrB,cAAe,CALf,WAAY,CACZ,gBAAiB,CACjB,mBAAoB,CAHpB,cAAe,CADf,qBAQF,CACA,4BACE,UACF,CACA,iBAEE,cAAe,CADf,8BAEF,CACA,uBACE,8BACF,CACA,kBACE,iBACF,CACA,kCACE,UAAW,CACX,eACF,CACA,mCACE,iBACF,CACA,sCAEE,UAAW,CADX,iBAEF,CACA,qDAOE,yCAA0C,CAD1C,WAAY,CAJZ,SAAU,CAEV,WAAY,CAHZ,iBAAkB,CAElB,QAAS,CAET,UAGF,CACA,kBACE,sCACF,CACA,8CAEE,mBAAoB,CACpB,cACF,CAEA,kJAOE,WAAY,CAHZ,gBAAiB,CACjB,iBAAkB,CAClB,SAEF,CACA,2EAEE,kBACF,CACA,wCAEE,cAAe,CADf,cAEF,CACA,sBAGE,sCAAuC,CACvC,cAAe,CAHf,WAAY,CACZ,WAGF,CACA,mCAGE,UAAW,CAFX,WAAY,CACZ,gBAEF,CACA,2CAME,qBAAsB,CAFtB,sCAAuC,CAGvC,qBAAsB,CALtB,WAAY,CACZ,gBAAiB,CAEjB,kBAGF,CACA,qBACE,oBAAqB,CAErB,aAAc,CACd,aAAc,CACd,iBAAkB,CAClB,eAAgB,CAJhB,UAKF,CACA,uDAEE,+CACF,CACA,sBAGE,cAAe,CAFf,gBAAiB,CACjB,cAEF,CCtIA,iBAKE,UAAW,CAFX,UAAW,CACX,cAAe,CAHf,aAAc,CACd,iBAIF,CACA,mBACE,WAAY,CACZ,gBACF,CACA,qBACE,oBAAqB,CACrB,kBACF,CACA,wBAGE,oCAAqC,CADrC,sCAAuC,CAEvC,UAAW,CACX,iBAAkB,CAJlB,cAKF,CACA,8BACE,UACF,CACA,qBAEE,aAAc,CADd,cAEF,CC5BA,aAGE,qBAAsB,CACtB,aAAc,CAFd,aAAc,CADd,UAIF,CACA,gBAEE,kBACF,CACA,gBAEE,eAAgB,CADhB,eAEF,CAEA,kBACE,qBACF,CACA,oFAGE,wBACF,CACA,qBACE,wBACF,CACA,gJAGE,wBACF,CACA,oHAOE,yBACF,CAEA,8RAgBE,oCAAqC,CADrC,kBAAmB,CADnB,gBAGF,CAEA,gCAME,cAAe,CADf,gBAAiB,CADjB,eAAgB,CADhB,gBAAiB,CADjB,iBAKF,CAEA,8DAGE,oBACF,CACA,4DAGE,sBACF,CACA,4DAEE,WACF,CAEA,iBACE,eACF,CAGA,0DAKE,iBACF,CACA,8DACE,WAAY,CACZ,gBACF,CAGA,0DAME,cAAe,CADf,gBAEF,CACA,8DACE,WAAY,CACZ,gBAAiB,CAEjB,iBAAkB,CAClB,kBAAmB,CAFnB,eAGF,CAGA,iDAEE,YACF,CACA,iBAEE,eAAgB,CADhB,iBAEF,CACA,kBAGE,iBAAkB,CAFlB,UAAW,CACX,iBAEF,CACA,wBAOE,oCAAqC,CANrC,UAAW,CAKX,WAAY,CAJZ,iBAAkB,CAElB,OAAQ,CADR,KAAM,CAEN,SAAU,CAGV,WACF,CACA,+BAIE,QAAS,CACT,wBAAyB,CAFzB,QAAS,CAFT,iBAAkB,CAClB,UAIF,CACA,8CAEE,sBACF,CACA,6CAEE,oBACF,CACA,oEAIE,gBAAiB,CADjB,eAAgB,CADhB,SAGF,CACA,sHAEE,cACF,CACA,yEAEE,cACF,CACA,6CACE,WACF,CACA,yDAOE,wBAAyB,CADzB,qBAAsB,CAGtB,UAAW,CAJX,WAAY,CAHZ,MAAO,CAMP,mBAAoB,CAPpB,iBAAkB,CAElB,KAAM,CACN,UAMF,CAEA,2DAEE,WAAY,CACZ,gBAAiB,CAFjB,UAGF,CACA,oCACE,aAAc,CACd,SACF,CACA,sCAEE,cAAe,CADf,QAEF,CACA,kBAKE,QAAS,CAHT,MAAO,CAIP,QAAS,CALT,iBAAkB,CAGlB,OAAQ,CADR,KAAM,CAKN,sBAAwB,CACxB,wBAAyB,CACzB,qBAAsB,CAEtB,gBAAiB,CALjB,WAMF,CACA,0BAGE,QAAS,CACT,WAAY,CAEZ,kBAAmB,CALnB,iBAAkB,CAQlB,iBAAkB,CAJlB,OAAQ,CAER,8BAAgC,CAChC,gBAAiB,CANjB,YAQF,CACA,sCAEE,aAAc,CADd,cAEF,CACA,oBAEE,oBAAwB,CACxB,eACF,CACA,iCACE,kBACF,CAEA,oBAME,oBAAwB,CAHxB,eAAgB,CAChB,gBAAiB,CAHjB,iBAAkB,CAClB,UAKF,CACA,yCACE,kBACF,CACA,oDAEE,iBAAkB,CADlB,gBAEF,CAEA,2CASE,qBAAsB,CADtB,UAAW,CAEX,cAAe,CAPf,WAAY,CAEZ,gBAAiB,CACjB,iBAAkB,CAFlB,WAAY,CAHZ,iBAAkB,CAMlB,iBAAkB,CAKlB,kBAAoB,CAVpB,UAWF,CACA,iDACE,qBACF,CACA,uBACE,mBACF,CACA,uBACE,iBAAkB,CAClB,UAAW,CACX,QACF,CACA,kEACE,iBACF,CACA,wBAWE,qBAAsB,CAHtB,+CAAgD,CAIhD,oCAAyC,CATzC,SAAU,CAIV,eAAgB,CADhB,eAAgB,CAIhB,eAAgB,CALhB,uBAAyB,CAJzB,iBAAkB,CAQlB,eAAgB,CAPhB,QAAS,CAET,WASF,CACA,2BAGE,gBAAiB,CACjB,8BAAgC,CAFhC,kBAAoB,CAIpB,eAAgB,CALhB,cAAe,CAMf,sBAAuB,CAEvB,kBAAoB,CAJpB,kBAKF,CACA,kEACE,UACF,CACA,iCACE,wBACF,CACA,kEACE,iBACF,CACA,oEAEE,MAAO,CADP,iBAAkB,CAElB,KACF,CACA,uEACE,SACF,CACA,iEACE,SAAU,CACV,UACF,CAEA,qBAQE,qBAAsB,CADtB,sBAAsB,CAFtB,WAAY,CAJZ,iBAAkB,CAClB,OAAQ,CACR,KAAM,CACN,UAKF,CAEA,kBAIE,wBAA0B,CAF1B,WAAY,CACZ,eAAgB,CAFhB,UAIF,CACA,8BAGE,gBAAiB,CADjB,QAAS,CADT,iBAGF,CACA,wCAIE,2BAA4B,CAD5B,yBAA0B,CAD1B,eAAgB,CADhB,OAIF,CACA,8CACE,2BACF,CACA,yCAEE,kBAAmB,CAEnB,wBAAyB,CADzB,sBAAuB,CAFvB,UAIF,CACA,+CACE,wBACF,CACA,sDACE,wBACF,CACA,wDACE,qBACF,CAEA,kBAQE,qBAAsB,CAPtB,WAAY,CACZ,gBAAiB,CAGjB,eAAgB,CAFhB,gBAAiB,CACjB,iBAAkB,CAElB,sBAAuB,CACvB,kBAEF,CACA,yDAEE,SAAU,CADV,QAEF,CACA,6DACE,iBACF,CACA,oCACE,aACF,CACA,6BACE,sBACF,CACA,gCACE,uBACF,CACA,+BACE,oBACF,CAEA,yFAIE,iBAAkB,CAClB,uBACF,CAEA,kBAGE,kBAAmB,CADnB,aAAc,CADd,iBAGF,CACA,8BAIE,UAAW,CAHX,gBAAiB,CACjB,iBAAkB,CAClB,iBAEF,CACA,mBAEE,MAAO,CADP,iBAAkB,CAElB,KAAM,CACN,WACF,CACA,qCACE,eACF,CACA,qBACE,oCACF,CACA,qBAIE,sBAAsB,CACtB,qCAA0C,CAJ1C,SAAU,CACV,OAIF,CACA,yCAEE,gBAAiB,CADjB,iBAEF,CACA,kBAOE,sBAAsB,CAHtB,WAAY,CAHZ,iBAAkB,CAClB,WAAY,CACZ,KAAM,CAEN,UAGF,CAEA,kBAOE,oBAAwB,CAHxB,gBAAiB,CADjB,eAAgB,CAEhB,iBAAkB,CAJlB,iBAAkB,CAClB,UAMF,CACA,uCACE,mBACF,CASA,qCAJE,oBAAqB,CAFrB,kBAAmB,CAGnB,eASF,CANA,kBAIE,kBAEF,CACA,sBACE,WACF,CACA,iCACE,QACF,CACA,yEAME,eAAgB,CADhB,WAAY,CAHZ,WAAY,CACZ,gBAAiB,CACjB,kBAGF,CACA,4FAEE,cACF,CACA,sCACE,aAAc,CACd,SACF,CACA,qDACE,2BACF,CACA,uEACE,MAAO,CAEP,SAAU,CADV,KAEF,CACA,+EAEE,WAAY,CACZ,gBACF,CACA,uCACE,UACF,CACA,wCACE,cACF,CACA,yBACE,WACF,CACA,qBACE,WAAY,CACZ,gBACF,CACA,mCACE,eACF,CACA,mCACE,cACF,CAEA,qCACE,oBACF,CACA,qCACE,SAAU,CACV,UACF,CAEA,kBAUE,qBAAsB,CAFtB,eAAgB,CAChB,uCAA4C,CAP5C,MAAO,CAIP,eAAgB,CADhB,cAAe,CAEf,gBAAiB,CANjB,iBAAkB,CAElB,KAAM,CACN,WAOF,CACA,wBACE,8CACF,CACA,mCACE,WACF,CACA,wBAEE,2CAA4C,CAD5C,kBAEF,CACA,gHAIE,QAAS,CADT,KAEF,CACA,uCAEE,WAAY,CACZ,gBAAiB,CAFjB,QAGF,CACA,yCACE,WACF,CAGA,oCACE,gBACF,CACA,uBAUE,qBAAsB,CAFtB,sBAAsB,CAGtB,UAAW,CACX,cAAe,CAPf,WAAY,CACZ,aAAc,CALd,iBAAkB,CAElB,OAAQ,CAMR,iBAAkB,CAPlB,KAAM,CAEN,UASF,CACA,mCAKE,cAAe,CAFf,QAAS,CACT,oBAAqB,CAHrB,iBAAkB,CAClB,OAIF,CACA,6BACE,wBACF,CAGA,sBACE,WACF,CACA,gNASE,WAAY,CACZ,eAAgB,CAEhB,kBAAmB,CADnB,kBAEF,CACA,oBAUE,qBAAsB,CACtB,wCAAyC,CACzC,iBAAkB,CAVlB,YAAa,CAMb,cAAe,CAOf,cAAe,CATf,WAAY,CACZ,gBAAiB,CAHjB,iBAAkB,CAHlB,iBAAkB,CAElB,SAAU,CAMV,iBAAkB,CAKlB,kBAAoB,CATpB,UAAW,CAQX,YAGF,CACA,0BACE,oCACF,CACA,iDACE,aACF,CACA,0EAME,QACF,CAGA,4CACE,eAAgB,CAEhB,oCAAyC,CADzC,SAEF,CACA,uBAME,qBAAsB,CACtB,aAAc,CAHd,cAAe,CAHf,qBAAsB,CACtB,gBAAiB,CAGjB,iBAAkB,CAFlB,gBAKF,CACA,oBAQE,wBAAyB,CACzB,iBAAkB,CAClB,UAAW,CAHX,cAAe,CAFf,WAAY,CACZ,WAAY,CALZ,iBAAkB,CAClB,UAAW,CACX,SAAU,CACV,UAOF,CACA,0BACE,qBACF,CACA,2BACE,iBAAkB,CAClB,UACF,CAGA,2BACE,cACF,CACA,6BACE,UACF,CACA,sDAEE,gBACF,CACA,2BACE,cACF,CCvsBA,mBACE,sBAAwB,CAExB,uBAAwB,CADxB,WAEF,CACA,mBACE,aACF,CACA,qBAGE,UAAW,CACX,cAAe,CAHf,eAAgB,CAKhB,eAAgB,CAJhB,cAAe,CAGf,sBAAuB,CAEvB,kBACF,CACA,mBAKE,qBAAsB,CADtB,yBAA0B,CAI1B,UAAW,CADX,cAAe,CALf,oBAAqB,CACrB,YAAa,CAFb,iBAAkB,CAKlB,iBAGF,CACA,+BAEE,8BAA+B,CAD/B,cAEF,CACA,6BACE,qCACF,CACA,mBACE,oBACF,CACA,qBAIE,QAAS,CADT,QAAS,CAFT,iBAAkB,CAIlB,iBAAkB,CAHlB,OAIF,CACA,mBAEE,oBAAqB,CADrB,iBAAkB,CAElB,qBACF,CACA,sCAWE,cAAe,CAVf,uBAAyB,CASzB,uBAAwB,CAJxB,eAAgB,CAEhB,WAAY,CALZ,MAAO,CAMP,WAAa,CAPb,iBAAkB,CAElB,KAAM,CAGN,UAAW,CAFX,UAOF,CACA,0CACE,cACF,CChEA,YAGE,qBAAsB,CADtB,YAAa,CADb,iBAIF,CACA,0BAFE,qBAIF,CACA,+DAIE,aAAc,CADd,gBAEF,CACA,eAIE,oBAAyB,CAGzB,cAAe,CAFf,cAAe,CAFf,gBAAiB,CADjB,cAAe,CADf,iBAAkB,CAOlB,kBAAoB,CAFpB,kBAGF,CACA,qBACE,wBACF,CACA,8DAEE,yBAA2B,CAC3B,uBAAyB,CACzB,4BACF,CAEA,qDAKE,mBAAqB,CAFrB,sBAAwB,CACxB,wBAAyB,CAFzB,2BAA4B,CAD5B,aAKF,CACA,6FAEE,kBACF,CAEA,4HAGE,eAAgB,CAChB,cACF,CACA,sCACE,iBACF,CACA,0DACE,qBAA0B,CAC1B,wBAAyB,CACzB,qBAAsB,CAEtB,gBACF,CACA,kCACE,qBAA0B,CAC1B,cAAe,CAIf,iBAHF,CAKA,qCAKE,+CAAgD,CAFhD,QAAS,CACT,aAAc,CAHd,YAAa,CAKb,eAAgB,CAJhB,SAKF,CAEA,8EAEE,cACF,CACA,uDACE,oBACF,CACA,mCAEE,QAAS,CACT,eAAgB,CAFhB,iBAGF,CACA,0EACE,wBACF,CACA,sEACE,yBACF,CACA,oJAEE,UACF,CACA,qCAEE,WAAY,CADZ,kBAEF,CAEA,2EAEE,kCAAoC,CACpC,6BACF,CACA,+EAEE,6BACF,CACA,2CAKE,8CAA+C,CAD/C,QAAS,CAET,UAAW,CALX,iBAAkB,CAClB,UAAW,CACX,KAIF,CAEA,uBACE,iBAIF,CACA,gDAJE,iBAAkB,CAClB,eAAgB,CAChB,sBAQF,CANA,yBAKE,oBAAyB,CAJzB,aAKF,CACA,+BACE,kBACF,CACA,mCAME,cAAe,CADf,kBAAmB,CADnB,eAAgB,CAHhB,iBAAkB,CAClB,UAAW,CACX,OAAQ,CAKR,kBACF,CACA,yCACE,kBACF,CACA,yCACE,UACF,CACA,uBACE,YAAa,CAGb,SAAU,CAEV,gBAAiB,CACjB,aAAc,CALd,iBAAkB,CAClB,QAAS,CAET,YAGF,CACA,8BAME,QAAS,CALT,UAAW,CAGX,UAAW,CAFX,iBAAkB,CAGlB,KAAM,CAFN,UAIF,CACA,4BACE,SAAU,CAEV,aAAgB,CADhB,UAEF,CACA,mCACE,SAAU,CACV,WACF,CAEA,kBACE,gBACF,CACA,sEAEE,eAAgB,CAChB,6BACF,CACA,yCACE,gBACF,CACA,8CACE,aACF,CAGA,gBAEE,cAAe,CAGf,YAAa,CACb,eAAgB,CALhB,iBAAkB,CAElB,aAAc,CACd,gBAGF,CACA,uBACE,UAAW,CAGX,UAAW,CACX,MAAO,CAHP,iBAAkB,CAIlB,QAAS,CAHT,UAIF,CACA,sBAIE,WAAY,CAFZ,MAAO,CAIP,mBAAoB,CADpB,cAAe,CAJf,KAAM,CAEN,UAIF,CC/NA,YACE,iBACF,CACA,yBACE,eACF,CACA,mBAME,WAAY,CAHZ,WAAY,CADZ,MAAO,CAEP,mBAAqB,CAHrB,iBAAkB,CAOlB,mBAAqB,CAHrB,kBAIF,CACA,kDAQE,+CAAgD,CAHhD,QAAS,CAHT,UAAW,CAEX,MAAO,CADP,iBAAkB,CAIlB,UAAW,CADX,SAGF,CACA,sBAQE,cAAe,CANf,oBAAqB,CAOrB,cAAe,CALf,gBAAiB,CACjB,kBAAoB,CACpB,cAAe,CALf,iBAAkB,CAMlB,iBAAkB,CAIlB,mBAAqB,CARrB,qBASF,CACA,kCACE,aACF,CACA,wBAIE,aAAc,CAHd,aAAc,CAEd,oCAAuC,CADvC,4BAGF,CACA,8BACE,oBACF,CACA,2DAEE,8BACF,CACA,qCAQE,gDAAiD,CACjD,qBAAsB,CARtB,UAAW,CAMX,WAAY,CAJZ,MAAO,CAOP,mBAAoB,CARpB,iBAAkB,CAElB,KAAM,CAEN,UAAW,CADX,SAMF,CACA,oEAEE,QAAS,CACT,QACF,CAEA,mBAEE,eAAgB,CAChB,cAAe,CAFf,iBAGF,CACA,4CAGE,QAAS,CADT,YAAa,CADb,YAGF,CACA,4BAYE,qBAAsB,CAJtB,wCAAyC,CAKzC,oCAAuC,CAFvC,qBAAsB,CADtB,cAAe,CAJf,WAAY,CAJZ,MAAO,CAKP,gBAAiB,CANjB,iBAAkB,CAQlB,iBAAkB,CANlB,KAAM,CAEN,UAAW,CADX,SAUF,CACA,iCAGE,qCAAwC,CAFxC,SAAU,CACV,OAEF,CAEA,wCAWE,iBAAkB,CADlB,aAAc,CARd,oBAAqB,CAOrB,cAAe,CAGf,eAAgB,CARhB,WAAY,CACZ,gBAAiB,CACjB,eAAgB,CALhB,iBAAkB,CAOlB,iBAAkB,CADlB,KAAQ,CAOR,mBAAqB,CAXrB,UAYF,CACA,8CACE,qCAAsC,CACtC,UACF,CACA,4DACE,YACF,CAEA,iBACE,4BACF,CACA,iBACE,YACF,CAGA,gDACE,qBACF,CACA,sDAEE,wCAAyB,CAAzB,4BAAyB,CACzB,mEACF,CACA,oEACE,gBACF,CACA,mEACE,iBACF,CACA,kEAEE,eAAgB,CADhB,YAEF,CACA,8CACE,0BACF,CC1JA,WACE,aAAc,CACd,yBACF,CACA,sCACE,eACF,CACA,4BAKE,WAAY,CAFZ,WAAY,CADZ,MAAO,CADP,iBAAkB,CAMlB,kBAAoB,CAHpB,kBAIF,CACA,kCAIE,+CAA6B,CAA7B,sBAA6B,CAA7B,uBAA6B,CAA7B,qBAA6B,CAC7B,QAAS,CAJT,UAAW,CAKX,MAAO,CAGP,mBAAoB,CACpB,iBAAkB,CAHlB,UAAW,CACX,QAAS,CAGT,UAAW,CACX,SACF,CACA,+BAcE,cAAe,CAbf,oBAAqB,CAErB,cAAe,CAMf,gBAAiB,CAEjB,QAAS,CADT,cAAe,CAEf,cAAe,CAJf,iBAAkB,CAKlB,iBAAkB,CARlB,kBAAoB,CAHpB,qBAIF,CAUA,iCACE,aAAc,CAEd,cAAe,CADf,cAEF,CACA,6BACE,UACF,CAEA,mCAOE,gBAAiB,CAGjB,sBAAyB,CACzB,mEAAoE,CADpE,kBAAyB,CANzB,UAAW,CAFX,MAAO,CAWP,mBAAoB,CARpB,UAAW,CASX,SACF,CACA,kDAJE,qBAAsB,CANtB,WAAY,CALZ,iBAAkB,CAElB,KA4BF,CAfA,eAaE,qBAAsB,CAFtB,sCAAuC,CADvC,kBAAmB,CADnB,gBAAiB,CAKjB,cAAe,CANf,gBAAiB,CALjB,OAAQ,CASR,iBAAkB,CANlB,UAAW,CADX,UAUF,CACA,2BAEE,oBAAqB,CADrB,iBAAkB,CAElB,OAAQ,CAER,kBACF,CACA,gBACE,YACF,CACA,gBAEE,qBAAuB,CADvB,kBAAmB,CAEnB,4BACF,CACA,oCACE,2CAA4C,CAC5C,sCACF,CACA,2CACE,QAAS,CACT,SAAU,CAEV,wBACF,CACA,iDACE,cACF,CAEA,mBACE,cACF,CAGA,qCAUE,aAAc,CARd,oBAAqB,CAOrB,cAAe,CALf,WAAY,CACZ,gBAAiB,CACjB,eAAgB,CALhB,iBAAkB,CAOlB,iBAAkB,CADlB,OAAQ,CAKR,kBAAoB,CATpB,UAUF,CACA,2CAEE,qCAAsC,CADtC,sCAAuC,CAEvC,UACF,CAGA,8CACE,8BACF,CACA,yGAEE,WAAY,CAEZ,+CAAgD,CADhD,eAEF,CAGA,gBAGE,sCAAuC,CADvC,kBAAmB,CADnB,gBAAiB,CAGjB,qCACF,CACA,iCACE,sCACF,CACA,oCAEE,gBAAiB,CADjB,iBAEF,CACA,6CACE,qBACF,CACA,mDAGE,wBAAyB,CADzB,2BAAiB,CAAjB,cAEF,CACA,gDAGE,eAAgB,CAEhB,iBAAkB,CADlB,eAAgB,CAHhB,WAAY,CACZ,gBAIF,CACA,4CACE,eAAgB,CAChB,6BACF,CACA,kDACE,WACF,CC7LA,WAGE,uCAAwC,CAExC,sCAAuC,CAEvC,qBAAsB,CAHtB,UAAW,CAEX,WAAY,CAJZ,cAAe,CADf,iBAOF,CACA,aACE,cACF,CACA,2BAEE,oBAAqB,CAIrB,gBAAiB,CAFjB,eAAgB,CADhB,YAAa,CAFb,iBAAkB,CAIlB,qBAEF,CACA,6BAGE,UAAW,CACX,wBAA+B,CAH/B,aAAc,CACd,cAAe,CAIf,kBACF,CACA,4CAQE,wCAAyC,CANzC,UAAW,CAKX,UAAW,CAHX,MAAO,CAOP,mBAAoB,CARpB,iBAAkB,CAElB,KAAM,CAKN,kBAAoB,CAJpB,OAMF,CACA,eACE,YACF,CACA,4CACE,YACF,CACA,4DAEE,UAAW,CACX,oBACF,CACA,6BAEE,QAAS,CADT,QAAS,CAET,UACF,CACA,eAIE,iBAAkB,CAFlB,WAAY,CACZ,iBAAkB,CAFlB,UAIF,CAEA,2BAOE,cAAe,CADf,cAAe,CAFf,mBAAqB,CACrB,YAAa,CAJb,iBAAkB,CAElB,SAAU,CADV,KAAM,CAON,kBACF,CACA,gEAEE,wBACF,CAEA,iBAUE,qBAAsB,CADtB,wCAAyC,CAGzC,sCAAuC,CAJvC,oCAAyC,CAMzC,qBAAsB,CAbtB,YAAa,CAEb,MAAO,CAGP,gBAAiB,CADjB,cAAe,CAEf,aAAc,CALd,iBAAkB,CAElB,QAAS,CAST,kBAAmB,CAFnB,WAIF,CACA,8BACE,aAAc,CACd,oBACF,CACA,oCACE,wBAAyB,CACzB,oBACF,CACA,oBACE,YAAa,CACb,iBACF,CACA,+BACE,wBAAyB,CACzB,UACF,CACA,qCACE,YACF,CACA,mBACE,SAAU,CACV,OACF,CACA,mBACE,iBACF,CAGA,0BAEE,SAAU,CADV,WAEF,CACA,gCACE,aAAc,CAEd,gBAAiB,CADjB,UAEF,CACA,kCAEE,WAAY,CACZ,gBAAiB,CAEjB,eAAgB,CAJhB,iBAAkB,CAGlB,sBAAuB,CAEvB,kBACF,CACA,kCAEE,kBAAmB,CADnB,eAEF,CACA,gCACE,UACF,CACA,kDACE,aACF,CACA,+BAEE,QAAS,CADT,SAEF,CACA,2CACE,SACF,CACA,8LAKE,yCAA0C,CAC1C,UACF,CACA,kCACE,YACF,CACA,gGAGE,oBACF,CACA,+BACE,yCACF,CAEA,iCAKE,eAAgB,CAChB,+BAAoC,CAFpC,WAAY,CAGZ,eAAgB,CANhB,iBAAkB,CAElB,KAAM,CADN,SAMF,CACA,oCACE,QACF,CACA,mCACE,UAAW,CACX,wBACF,CACA,yCACE,eAAgB,CAChB,UACF,CAGA,mGAEE,aACF,CAGA,gBAGE,QAAS,CACT,MAAO,CACP,iBAAkB,CAJlB,cAAe,CACf,KAAM,CAIN,WACF,CAGA,2EAEE,aAAc,CACd,oBACF,CACA,kDACE,oBACF,CACA,uCACE,6BACF,CACA,+CAEE,eAAgB,CADhB,iBAEF,CACA,kNAIE,yBAA2B,CAC3B,uCAAyC,CACzC,eACF,CACA,6CACE,wCACF,CAGA,kBAEE,WAAY,CADZ,iBAEF,CACA,oBACE,cACF,CACA,oBACE,oBACF,CACA,0BACE,uCACF,CACA,yBACE,aAAc,CACd,iBACF,CACA,sCAEE,UAAW,CADX,aAEF,CCxQA,gBACE,gBACF,CACA,qBAEE,mBAAoB,CADpB,iBAEF,CACA,qBAQE,qBAAsB,CAEtB,iBAAkB,CADlB,6BAA8B,CAG9B,cAAe,CANf,WAAY,CAJZ,SAAU,CAKV,gBAAiB,CANjB,iBAAkB,CAUlB,iBAAkB,CARlB,KAAM,CAEN,UAAW,CADX,UASF,CACA,2BACE,0BACF,CACA,4BACE,UAAW,CAMX,WAAY,CAJZ,QAAS,CADT,iBAAkB,CAElB,KAAM,CAEN,SAAU,CADV,SAGF,CAEA,wCACE,aACF,CACA,uCACE,YACF,CACA,wBACE,iBACF,CACA,sBAGE,gBAAiB,CADjB,kBAAmB,CADnB,iBAGF,CC/CA,+CAQE,qCAAsC,CAEtC,sCAAuC,CADvC,UAAW,CALX,oBAAqB,CAErB,cAAe,CADf,aAAc,CAFd,iBAAkB,CAIlB,iBAIF,CACA,aACE,WAAY,CACZ,gBACF,CACA,iBAIE,iBAAkB,CAFlB,UAAW,CACX,SAAU,CAFV,SAIF,CACA,iBAKE,qBAAsB,CADtB,kBAAmB,CADnB,gBAAiB,CAGjB,aAAc,CALd,WAAY,CACZ,gBAKF,CAEA,oDAEE,eACF,CACA,oDAIE,iBAAkB,CAFlB,iBAAkB,CAClB,OAEF,CACA,wBACE,gBACF,CACA,gEAEE,QAAS,CACT,QACF,CChDA,gBAIE,wBAAyB,CAFzB,MAAO,CADP,iBAAkB,CAElB,KAEF,CACA,gCAGE,WAAY,CACZ,eAAgB,CAHhB,iBAAkB,CAClB,UAGF,CACA,uCASE,aAAc,CAPd,eAAgB,CAQhB,gCAAoC,CACpC,cAAe,CACf,iBAAkB,CATlB,QAAS,CAGT,gBAAiB,CACjB,sBAAuB,CANvB,iBAAkB,CAOlB,iBAAkB,CAJlB,OAAQ,CACR,WAAY,CAQZ,kCAAmC,CACnC,iCACF,CACA,kCAOE,wBAAyB,CANzB,YAAa,CAKb,WAAY,CAHZ,MAAO,CADP,iBAAkB,CAElB,KAAM,CAKN,uBAAyB,CAJzB,UAKF,CACA,yBAEE,6BACF,CACA,sBAcE,+BAAoC,CAFpC,QAAc,CACd,iBAAkB,CAElB,UAAW,CAGX,cAAe,CAjBf,cAAe,CAUf,cAAe,CAHf,WAAY,CAJZ,SAAU,CAKV,gBAAiB,CAHjB,gBAAiB,CAJjB,SAAU,CACV,iBAAkB,CAOlB,iBAAkB,CALlB,OAAQ,CAYR,uBAAyB,CAVzB,UAYF,CACA,oCACE,mBAAqB,CACrB,UACF,CACA,wDAEE,SAAU,CADV,SAEF,CACA,sEACE,UACF,CACA,sDACE,YACF,CACA,yDAEE,gCACF,CACA,4CACE,eAAgB,CAEhB,SAAU,CADV,SAEF,CACA,0DACE,UACF,CACA,oBAME,WAAY,CAFZ,uBAAyB,CAHzB,iBAAkB,CAIlB,iBAAkB,CAHlB,SAAU,CACV,UAIF,CACA,uCACE,kBACF,CACA,2DACE,QACF,CACA,8DACE,+BACF,CACA,wDACE,YACF,CACA,uBAGE,+BAAoC,CACpC,kBAAmB,CAHnB,oBAAqB,CACrB,WAAY,CAIZ,uBACF,CACA,0BAME,oCAAqC,CACrC,mCAA0C,CAC1C,iBAAkB,CAClB,cAAe,CARf,oBAAqB,CAIrB,cAAe,CAFf,WAAY,CACZ,YAAa,CAOb,uBAAyB,CATzB,UAUF,CACA,gCACE,mCACF,CACA,qCACE,qBACF,CACA,sJAGE,aACF,CACA,4CAEE,uBACF,CACA,qDAEE,2BACF,CACA,qDAEE,0BACF,CACA,mJAGE,uBACF,CACA,gEAEE,2BACF,CACA,iEAEE,0BACF,CAGA,uDACE,kBAAoB,CAEpB,kBAAmB,CADnB,QAEF,CACA,qEAEE,WAAY,CADZ,kBAEF,CACA,qDAKE,WAAY,CAJZ,iBAAkB,CAElB,UAAW,CADX,OAAQ,CAER,UAEF,CACA,wDACE,eACF,CACA,wDACE,aAAc,CACd,YACF,CAEA,mDACE,gBACF,CACA,6DAEE,uBACF,CACA,sEAEE,2BACF,CACA,sEAEE,0BACF,CACA,qLAOE,uBACF,CACA,iFAIE,2BACF,CACA,kFAIE,0BACF,CAGA,iDAEE,iCACF,CACA,wIAEE,SACF,CACA,iLAME,SACF,CACA,+JAME,SACF,CC7PA,cAGE,WAAY,CAFZ,cAAe,CACf,UAAW,CAEX,cACF,CACA,iBAQE,wBAAyB,CAEzB,sCAAuC,CADvC,UAAW,CAHX,cAAe,CACf,cAAe,CALf,WAAY,CACZ,gBAAiB,CACjB,iBAAkB,CAOlB,WAAa,CANb,iBAAkB,CAJlB,UAWF,CACA,uBACE,WACF,CACA,wBACE,SACF,CACA,gCACE,YAAa,CACb,cACF,CC5BA,kEAKE,oCAAqC,CADrC,kBAAmB,CADnB,cAGF,CACA,oBAQE,qBAAsB,CADtB,sCAAuC,CAHvC,gBAAiB,CAFjB,oBAAqB,CAIrB,YAAa,CALb,iBAAkB,CAElB,qBAAsB,CAEtB,WAIF,CACA,yCAEE,kBAAoB,CADpB,UAEF,CACA,uBAIE,uBAAwB,CAHxB,WAAY,CACZ,gBAAiB,CACjB,cAEF,CACA,uBAGE,uBAAwB,CADxB,YAAa,CADb,iBAGF,CACA,oCAGE,cAAe,CAFf,WAAY,CACZ,iBAEF,CACA,0CAME,aAAc,CAJd,SAAU,CAEV,kBAAmB,CACnB,eAAgB,CAJhB,iBAAkB,CAElB,OAIF,CACA,uBAEE,oBAAqB,CADrB,aAAc,CAEd,qBACF,CACA,kCAIE,wCAAyC,CACzC,oCAAqC,CACrC,UAAW,CALX,aAAc,CACd,QAAS,CACT,cAIF,CACA,2CACE,wBAAyB,CACzB,oCAAqC,CACrC,yBACF,CACA,8CACE,kBACF,CACA,8CAEE,wBAA0B,CAD1B,QAEF,CACA,qBAEE,aAAc,CADd,aAEF,CACA,wBACE,WAAY,CACZ,gBAAiB,CAGjB,8BAAgC,CAFhC,sBAAwB,CACxB,cAEF,CACA,8BACE,wBAAyB,CACzB,kBACF,CACA,iCAGE,UAAW,CAFX,iBAAkB,CAClB,iBAEF,CCzFA,0BAEE,oBAAqB,CACrB,qBACF,CACA,YAEE,WAAY,CADZ,uBAEF,CACA,eACE,sBACF,CACA,4BAEE,6BAA8B,CAD9B,cAAe,CAIf,gBAAiB,CAEjB,kBAJF,CAMA,yCAEE,cAAe,CAEf,qBACF,CACA,iCACE,cAAe,CACf,kBACF,CC9BA,mBAGE,wCAAyC,CAEzC,sCAAuC,CAMvC,qBAAsB,CAHtB,cAAe,CADf,oBAAqB,CALrB,WAAY,CAIZ,gBAAiB,CAFjB,WAAY,CAMZ,kBAAoB,CATpB,UAWF,CACA,yBACE,gCACF,CACA,wCAEE,WAAY,CACZ,gBAAiB,CAFjB,UAGF,CACA,wCAEE,WAAY,CACZ,gBAAiB,CACjB,WAAY,CAHZ,UAIF,CACA,wCAEE,WAAY,CACZ,gBAAiB,CACjB,WAAY,CAHZ,UAIF,CAEA,mCAEE,sJAAuJ,CACvJ,sCAAuC,CAFvC,aAGF,CACA,gCAIE,gCAAqC,CACrC,sCAAuC,CAFvC,qBAAsB,CAFtB,aAAc,CACd,WAAY,CAIZ,iBACF,CACA,6BAEE,UAAW,CADX,oBAAqB,CAErB,cACF,CACA,8CACE,UACF,CAEA,wBAQE,eAAgB,CAChB,wCAAyC,CACzC,sCAAuC,CACvC,oCAAyC,CATzC,cAAe,CAIf,YAAa,CACb,WAAY,CANZ,iBAAkB,CAElB,aAAc,CAEd,WAAY,CADZ,gBAQF,CACA,gCACE,YAAa,CACb,iBACF,CACA,yBAEE,WAAY,CAEZ,eAAgB,CADhB,iBAAkB,CAFlB,WAIF,CACA,+BAME,wDAA8D,CAJ9D,WAAY,CAGZ,MAAO,CAFP,iBAAkB,CAClB,KAAM,CAHN,UAMF,CACA,+BAME,iDAAoD,CAJpD,WAAY,CAGZ,MAAO,CAFP,iBAAkB,CAClB,KAAM,CAHN,UAMF,CACA,gCAGE,qBAAsB,CACtB,iBAAkB,CAIlB,cAAe,CANf,WAAY,CAGZ,iBAAkB,CAElB,UAAW,CADX,KAAO,CAGP,8BAAgC,CARhC,UASF,CACA,wBAME,4DAAqE,CADrE,WAAY,CAJZ,iBAAkB,CAElB,OAAQ,CADR,KAAM,CAEN,UAGF,CACA,+BAKE,eAAgB,CAEhB,wBAAyB,CADzB,iBAAkB,CAHlB,uBAA2B,CAC3B,qBAAsB,CAItB,cAAe,CANf,UAAW,CAQX,MAAO,CADP,iBAAkB,CARlB,UAUF,CACA,8BAIE,sJAAuJ,CAHvJ,YAAa,CACb,WAAY,CACZ,cAEF,CACA,iCACE,WAAY,CACZ,iBACF,CACA,gCAKE,eAAgB,CAEhB,wBAAyB,CADzB,iBAAkB,CAHlB,uBAA2B,CAC3B,qBAAsB,CAItB,cAAe,CANf,WAAY,CAOZ,iBAAkB,CAClB,KAAM,CATN,SAUF,CACA,4BAEE,WAAY,CADZ,eAEF,CACA,uBAGE,sCAAuC,CAIvC,cAAe,CAHf,oBAAqB,CAFrB,WAAY,CAIZ,iBAAkB,CADlB,eAAgB,CAJhB,UAOF,CACA,wCACE,aACF,CACA,+BACE,sJACF,CACA,kCACE,sCACF,CACA,2BAEE,sCAAuC,CADvC,WAEF,CACA,8BAEE,eAAgB,CADhB,gBAEF,CACA,8DACE,iBACF,CACA,+CACE,UAAW,CACX,cACF,CACA,gDAGE,aAAc,CADd,WAAY,CAEZ,gBAAiB,CAHjB,WAIF,CC9LA,cAEE,8BAA+B,CAG/B,cAAe,CAJf,UAAW,CAGX,iBAEF,CACA,gCAJE,sCAQF,CAJA,kBAGE,WAAY,CADZ,iBAEF,CACA,mBAME,eAAgB,CADhB,iBAAkB,CADlB,UAAW,CAFX,KAAM,CACN,SAMF,CACA,sCATE,iBAAkB,CAOlB,0BAWF,CATA,mBAEE,WAAY,CAMZ,iBAAkB,CAJlB,SAAU,CAHV,UAAW,CAMX,UAEF,CACA,uBAIE,eAAgB,CADhB,iBAAkB,CAIlB,cAAe,CAFf,oBAAqB,CAHrB,WAAY,CAMZ,cAAgB,CAFhB,qBAAsB,CALtB,UAQF,CACA,yBACE,UAAW,CAEX,oBAAqB,CADrB,WAAY,CAEZ,qBACF,CACA,uEAEE,oBACF,CACA,4CACE,4BACF,CACA,mBAQE,eAAgB,CAChB,sCAAuC,CAFvC,UAAW,CAGX,WAAY,CACZ,gBAAiB,CACjB,cAAe,CAXf,iBAAkB,CAClB,SAAU,CAIV,0BAA2B,CAF3B,kBAAmB,CADnB,gBAUF,CACA,yBAUE,4BAAsD,CAAtD,qBAAsD,CAPtD,YAAa,CAFb,UAAW,CAMX,QAAS,CAHT,QAAS,CACT,gBAAiB,CAHjB,iBAAkB,CAIlB,OAKF,CACA,oBAGE,wCAAyC,CACzC,sCAAuC,CAMvC,qBAAsB,CALtB,cAAe,CAHf,WAAY,CAIZ,gBAAiB,CACjB,iBAAkB,CAClB,OAAQ,CACR,SAAU,CARV,UAUF,CACA,wBAME,6CAA8C,CAD9C,WAAY,CAJZ,iBAAkB,CAElB,OAAQ,CADR,KAAM,CAEN,UAGF,CACA,0BAIE,QAAS,CAMT,UAAW,CATX,cAAe,CAMf,cAAe,CADf,UAAW,CAEX,gBAAiB,CANjB,iBAAkB,CAClB,OAAQ,CAMR,iBAAkB,CAJlB,UAMF,CACA,sCAEE,+CAAgD,CADhD,KAEF,CACA,wBAEE,cAAe,CADf,WAEF,CACA,8BAEE,WAAY,CADZ,WAAY,CAEZ,kBACF,CACA,gCACE,8BACF,CAEA,uBAEE,gBAAiB,CADjB,SAEF,CACA,yCACE,SACF,CACA,0CAEE,MAAS,CADT,QAAS,CAGT,yBACF,CACA,0CAEE,UAAW,CADX,QAAS,CAGT,yBACF,CACA,0CAEE,QAAS,CADT,QAEF,CACA,gBACE,uBACE,iBACF,CACA,8CAEE,mBAAoB,CADpB,aAEF,CACA,0CACE,gBACF,CACA,mBACE,eACF,CACF,CCvKA,YACE,gBACF,CACA,iCACE,kBACF,CACA,gBAEE,iBAAkB,CADlB,UAEF,CACA,iBACE,YAAa,CACb,iBAAkB,CAClB,iBACF,CACA,kCACE,iBACF,CACA,uDAOE,6BAA8B,CAN9B,UAAW,CAKX,QAAS,CAFT,SAAU,CAFV,iBAAkB,CAClB,QAAS,CAET,UAGF,CACA,kBAGE,WAAY,CADZ,aAAc,CADd,iBAAkB,CAGlB,kBACF,CACA,wBACE,oCACF,CACA,yCACE,4BACF,CACA,yDACE,UAAW,CACX,yBAA0B,CAC1B,cACF,CACA,iBAGE,cAAe,CAFf,oBAAqB,CAGrB,kBAAmB,CAFnB,qBAGF,CACA,wCAOE,8BAA+B,CAN/B,UAAW,CAKX,WAAY,CAFZ,SAAU,CAFV,iBAAkB,CAClB,KAAM,CAEN,OAGF,CACA,gEACE,WACF,CACA,2DACE,QACF,CACA,sBAOE,aAAc,CANd,oBAAqB,CAGrB,WAAY,CACZ,gBAAiB,CACjB,aAAc,CAHd,iBAAkB,CADlB,qBAMF,CACA,iBAME,wBAAyB,CALzB,WAAY,CACZ,gBAAiB,CAEjB,aAAc,CACd,iBAAkB,CAFlB,UAIF,CACA,6BAEE,aAAc,CADd,cAEF,CACA,sBACE,aACF,CACA,4BAUE,4BAAyD,CAAzD,yBAAyD,CATzD,UAAW,CAMX,QAAS,CAJT,QAAS,CADT,iBAAkB,CAElB,OAAQ,CAOR,cAAgB,CALhB,OAAQ,CADR,WAOF,CACA,uFAIE,0CACF,CACA,gBAGE,UAAW,CAFX,oBAAqB,CACrB,qBAEF,CACA,mBAEE,aAAc,CADd,kBAEF,CACA,qBAEE,oBAAqB,CAErB,iBAAkB,CADlB,qBAAsB,CAFtB,iBAIF,CACA,iCAIE,cAAe,CAHf,oBAAqB,CAErB,aAAc,CADd,qBAGF,CACA,uCACE,UAAW,CACX,cACF,CACA,6CACE,kBACF,CACA,sBAQE,gCAAqC,CADrC,WAAY,CALZ,oBAAqB,CAErB,WAAY,CACZ,gBAAiB,CACjB,SAAU,CALV,iBAAkB,CAElB,qBAMF,CACA,sBAEE,UAAW,CADX,iBAEF,CCrJA,YACE,8BAAgC,CAEhC,sBAAwB,CADxB,gCAAiC,CAEjC,wBACF,CACA,uBACE,oBACF,CACA,iBAEE,kCACF,CACA,4BAGE,kBACF,CAWA,wBACE,GACE,sBACF,CACA,GACE,uBACF,CACF,CACA,mBAIE,qBAAsB,CAFtB,2BAA4B,CAI5B,gCACF,CAaA,oBACE,GAEE,UAAY,CADZ,+BAEF,CACA,GAEE,SAAU,CADV,uBAEF,CACF,CACA,eAEE,uBACF,CAaA,uBACE,GAEE,UAAY,CADZ,+BAEF,CACA,GAEE,SAAU,CADV,uBAEF,CACF,CACA,kBAEE,0BACF,CAGA,sBACE,GACE,UAAY,CACZ,gCACF,CACA,GACE,SAAU,CACV,uBACF,CACF,CACA,iBACE,yBACF,CAGA,yBACE,GACE,UAAY,CACZ,+BACF,CACA,GACE,SAAU,CACV,uBACF,CACF,CACA,oBACE,4BACF,CAaA,uBACE,GACE,UAAY,CAEZ,mBACF,CACA,GACE,SAAU,CAEV,kBACF,CACF,CACA,kBAEE,0BACF,CAiBA,8BACE,GACE,UAAY,CACZ,mBACF,CACA,IACE,UAAY,CACZ,oBACF,CACA,GACE,SAAU,CACV,kBACF,CACF,CACA,wBAEE,iCACF,CAGA,4BACE,GACE,UAAY,CACZ,oBACF,CACA,GACE,SAAU,CACV,kBACF,CACF,CACA,uBACE,+BACF,CAGA,mCACE,GACE,UAAY,CACZ,oBACF,CACA,IACE,UAAY,CACZ,mBACF,CACA,GACE,SAAU,CACV,kBACF,CACF,CACA,8BACE,sCACF,CAWA,wBACE,GACE,SACF,CACA,GACE,SACF,CACF,CACA,mBAEE,2BACF,CAWA,yBACE,GACE,SACF,CACA,GACE,SACF,CACF,CACA,oBAEE,4BACF,CCrQA,YAOE,qBAAsB,CADtB,wCAAsB,CAAtB,qBAAsB,CAEtB,UAAW,CAPX,aAAc,CASd,cAAe,CANf,gBAAiB,CADjB,YAAa,CADb,iBASF,CAGA,6BALE,qCAQF,CAHA,iBACE,cAEF,CAGA,iBAME,qBAAsB,CADtB,wCAAsB,CAAtB,qBAAsB,CAEtB,UAAW,CANX,aAAc,CAEd,mBAAqB,CADrB,iBAMF,CACA,qBACE,kBACF,CAEA,mBAOE,sCAAuC,CADvC,+CAAgD,CAEhD,cAAe,CAJf,WAAY,CACZ,gBAAiB,CAFjB,cAAe,CAFf,iBAAkB,CAClB,SAOF,CACA,4CAIE,aAAc,CAHd,iBAAkB,CAClB,UAAW,CACX,KAEF,CACA,2BACE,iBACF,CAEA,iBAEE,aAAc,CAId,iBAAkB,CAClB,eAAgB,CAFhB,wBAA0B,CAF1B,SAKF,CACA,kCALE,kBAAoB,CAHpB,iBAYF,CAJA,iBAEE,gBAEF,CACA,wBAME,WAAY,CAJZ,MAAO,CAGP,cAAe,CAQf,eAAgB,CAThB,aAAc,CAHd,iBAAkB,CAMlB,gBAAiB,CAJjB,KAAM,CAKN,wBAAyB,CACzB,qBAAsB,CAEtB,gBAAiB,CACjB,kBAEF,CACA,yBACE,cAAe,CACf,oBAAqB,CACrB,oBACF,CAEA,sDACE,iBACF,CACA,oBASE,sCAAuC,CADvC,sBAAoC,CAApC,+BAAoC,CAJpC,QAAS,CAFT,MAAO,CAQP,mBAAoB,CATpB,iBAAkB,CAElB,KAAM,CAGN,UAAW,CADX,SAMF,CAGA,oCACE,aACF,CACA,8EAIE,eAAgB,CAChB,gBACF,CACA,uCAEE,yBAA2B,CAD3B,8BAEF,CAEA,mBAIE,kBAAmB,CAHnB,iBAAkB,CAElB,UAAW,CADX,OAAQ,CAGR,SACF,CACA,wBAKE,UAAW,CADX,aAAc,CAHd,iBAAkB,CAClB,OAAQ,CACR,KAAM,CAGN,kBACF,CACA,8BACE,6BACF,CACA,iBAEE,cAAe,CADf,YAEF,CACA,yEACE,sBACF,CACA,2DACE,aACF,CACA,kEACE,YACF,CAGA,iEAGE,wBAAyB,CADzB,+BAEF,CACA,uBACE,gBAAiB,CACjB,UACF,CACA,2CAEE,eAAgB,CADhB,0BAA2B,CAE3B,aACF,CAGA,qBACE,YACF,CACA,qEAEE,QACF,CACA,+BAGE,eAAgB,CAFhB,iBAAkB,CAClB,SAEF,CACA,qCAEE,kBAAmB,CADnB,YAEF,CACA,yBAEE,0BAA2B,CAD3B,iBAEF,CACA,gCAME,WAAY,CADZ,WAAY,CAFZ,MAAO,CAFP,iBAAkB,CAClB,KAAM,CAEN,UAGF,CAGA,kBAIE,kBAAmB,CAHnB,iBAAkB,CAClB,UAAW,CACX,OAEF,CACA,oBAIE,cAAe,CAHf,oBAAqB,CACrB,eAAgB,CAChB,WAEF,CACA,sCACE,UACF,CACA,0BACE,6BACF,CAGA,iBAOE,qBAAsB,CADtB,WAAY,CAJZ,MAAO,CADP,cAAe,CAEf,KAAM,CAEN,UAAW,CADX,eAIF,CACA,kCAEE,wBAA0B,CAD1B,oBAEF,CACA,sGAIE,qBAAsB,CADtB,mCAEF,CACA,0CACE,aACF,CAGA,+BAEE,qBAAsB,CADtB,0BAEF,CACA,mDACE,4BACF,CACA,8FAEE,+BACF,CAGA,6BACE,sCACF,CACA,0BACE,qCACF,CACA,6BACE,oCACF,CACA,iCAGE,aAAc,CADd,WAAY,CADZ,iBAGF,CACA,oCAGE,aAAc,CADd,WAAY,CADZ,iBAGF,CACA,+EACE,oBAAsB,CACtB,UAAY,CAIZ,mCAGF,CACA,qFAEE,aAAc,CACd,SACF,CCjSA,iBACE,QAAS,CACT,SACF,CAGA,gCAEE,qBACF,CACA,eAQE,sBAAwB,CAExB,wBAAyB,CANzB,sCAAuC,CACvC,cAAe,CACf,kBAAmB,CAHnB,YAAa,CAFb,iBAAkB,CAClB,gBASF,CACA,oBACE,WACF,CACA,yEAIE,uBACF,CACA,qBAIE,WAAY,CAFZ,MAAO,CAIP,mBAAoB,CADpB,cAAe,CAJf,KAAM,CAEN,UAIF,CAGA,2BACE,GACE,UAAY,CACZ,+BACF,CACA,GACE,SAAU,CACV,uBACF,CACF,CAEA,eACE,8BACF,CACA,sBAME,cAAe,CAHf,oBAAqB,CACrB,QAAS,CAHT,iBAAkB,CAClB,SAKF,CAGA,kEAEE,sBACF,CACA,kEAEE,8BACF,CAMA,0NAGE,sBACF,CAGA,sBAEE,gBAAiB,CACjB,qBAAsB,CAFtB,iBAGF,CACA,wBACE,oBAAqB,CACrB,qBACF,CACA,wBAIE,UAAW,CAEX,cAAe,CADf,cAAe,CAFf,aAAc,CAFd,iBAAkB,CAClB,QAKF,CACA,uCACE,SACF,CACA,uCACE,SACF,CACA,uCACE,UACF,CACA,uCACE,UACF,CACA,yCACE,iBAAkB,CAClB,kBACF,CACA,gBAGE,qBAAsB,CAEtB,eAAgB,CAHhB,iBAAkB,CAElB,sBAAuB,CAEvB,kBAAmB,CALnB,UAMF,CACA,qBAEE,cAAe,CADf,cAEF,CACA,mBACE,wBACF,CAGA,uBAEE,YAAa,CADb,iBAAkB,CAElB,qBAAsB,CACtB,wBAAyB,CAEzB,gBACF,CACA,6BACE,wBAAyB,CACzB,gBACF,CACA,oDAGE,WAAY,CACZ,SAAU,CACV,iBAAkB,CAHlB,UAIF,CACA,0BACE,eACF,CACA,0BAEE,cAAe,CADf,iBAEF,CACA,kBAME,cAAe,CAJf,MAAO,CAGP,gBAAiB,CAEjB,eAAgB,CANhB,iBAAkB,CAElB,KAAM,CACN,UAIF,CACA,wBAOE,iBAAkB,CALlB,UAAW,CAIX,UAAW,CALX,iBAAkB,CAElB,SAAU,CACV,OAAQ,CACR,SAGF,CACA,6BASE,aAAc,CADd,eAAgB,CAJhB,cAAe,CAFf,MAAO,CADP,iBAAkB,CAElB,KAAM,CAEN,mBACF,CAKA,4CAEE,aAAc,CADd,eAEF,CACA,wDACE,UACF,CAGA,sBAEE,WAAY,CACZ,gBAAiB,CACjB,YAAa,CAHb,iBAIF,CACA,2BAQE,qBAAsB,CAFtB,wBAAyB,CACzB,sCAAuC,CAGvC,cAAe,CATf,oBAAqB,CAQrB,cAAe,CANf,WAAY,CACZ,gBAAiB,CACjB,cAAe,CAOf,kBAAoB,CAVpB,kBAAmB,CASnB,kBAEF,CACA,iCACE,6BACF,CACA,iDAEE,kCAAoC,CADpC,cAEF,CACA,uDACE,UACF,CACA,6DACE,cACF,CACA,qBACE,iBAAkB,CAClB,UAAW,CACX,QACF,CACA,0BAEE,eAAkB,CADlB,iBAEF,CACA,sCACE,mEACF,CACA,qCACE,mEACF,CAGA,wBAGE,oBAAqB,CAGrB,gBAAiB,CADjB,aAAc,CAHd,aAAc,CAKd,iBAAkB,CAHlB,kBAAmB,CAHnB,UAOF,CACA,4CAEE,6BAA8B,CAD9B,oBAEF,CACA,2BAEE,cAAe,CACf,gBAAiB,CAFjB,eAGF,CAGA,mCAQE,qBAAsB,CADtB,qBAAsB,CAFtB,WAAY,CAHZ,MAAO,CAIP,YAAa,CALb,iBAAkB,CAElB,KAAM,CACN,UAKF,CACA,sCASE,cAAe,CAPf,oBAAqB,CAErB,WAAY,CACZ,gBAAiB,CAKjB,eAAgB,CAJhB,YAAa,CALb,iBAAkB,CAOlB,iBAAkB,CADlB,qBAAsB,CAJtB,WAQF,CACA,sCAEE,aAAc,CADd,SAEF,CACA,mBACE,aACF,CACA,qCAKE,cAAe,CAJf,kBAAmB,CACnB,WAAY,CAEZ,kBAAmB,CADnB,QAGF,CACA,oCAIE,gBAAiB,CADjB,QAAS,CAFT,iBAAkB,CAClB,QAGF,CACA,qCACE,YAAa,CACb,eACF,CACA,8CACE,eACF,CACA,wCAME,cAAe,CAHf,WAAY,CACZ,gBAAiB,CAFjB,iBAAkB,CAGlB,eAAgB,CAJhB,UAMF,CACA,+CACE,iBACF,CACA,+CACE,kBACF,CAGA,oBASE,cAAe,CANf,QAAS,CAGT,gBAAiB,CADjB,kBAAmB,CAEnB,YAAa,CANb,iBAAkB,CAOlB,iBAAkB,CANlB,SAAU,CASV,oBAAqB,CAPrB,WAQF,CAGA,qBACE,WACF,CACA,yCACE,oBAAqB,CAErB,aAAc,CADd,qBAEF,CACA,iIAEE,6BACF,CACA,gUAME,YACF,CACA,6KAME,wBACF,CAGA,mCAIE,qBAAsB,CAFtB,+CAAgD,CAChD,oCAAyC,CAEzC,UACF,CACA,sBACE,+BACF,CACA,+DAEE,6BACF,CACA,uBAEE,eAAqB,CADrB,YAEF,CACA,0BACE,UACF,CACA,0BACE,UACF,CACA,0CACE,6BACF,CACA,gDAOE,wCAAyC,CACzC,qBAAsB,CAPtB,UAAW,CAGX,WAAY,CACZ,MAAO,CAHP,iBAAkB,CAIlB,KAAM,CAHN,UAMF,CACA,sEACE,wBAAyB,CACzB,kBACF,CACA,mDACE,kCACF,CACA,uFAEE,YACF,CACA,kGAGE,oCAAqC,CACrC,UAAW,CACX,kBACF,CACA,yBAIE,wBAAoB,CAApB,mBAAoB,CAHpB,QAAS,CACT,SAGF,CACA,qCACE,qBACF,CACA,4BACE,eACF,CACA,kFAEE,yBACF,CACA,4HAEE,yBACF,CACA,sBACE,4BACF,CACA,oBACE,aACF,CACA,wBACE,wCACF,CACA,6DACE,YACF,CACA,0CACE,6BACF,CACA,0DAEE,kDAAoD,CACpD,oBACF,CACA,wEAEE,yBAA2B,CAC3B,mCAAqC,CACrC,4BAA8B,CAC9B,qBAAsB,CACtB,wBAAyB,CAEzB,gBACF,CACA,4FAEE,8CACF,CACA,8BAEE,WAAY,CADZ,aAEF,CAGA,oBACE,WACF,CACA,wCACE,WACF,CACA,wCACE,WACF,CACA,0CAEE,yCAA0C,CAD1C,WAEF,CACA,2FAEE,aACF,CACA,uGAEE,UACF,CACA,2CAGE,wBAAmB,CAAnB,kBAAmB,CAAnB,eACF,CACA,gEACE,gBACF,CACA,oEAEE,mDACF,CAMA,8NAIE,wBACF,CACA,8HAEE,kCAAoC,CACpC,wCACF,CACA,0JAEE,mCACF,CACA,+EAEE,kBACF,CACA,qFAEE,oBACF,CACA,0CACE,WAAY,CACZ,gBACF,CACA,2CACE,WAAY,CACZ,gBACF,CACA,kDACE,WAAY,CACZ,eACF,CAGA,mHAKE,kBAAmB,CAFnB,WAAY,CACZ,gBAAiB,CAEjB,YAAa,CACb,SAAU,CALV,UAMF,CACA,+EACE,sCACF,CACA,uEACE,cACF,CAGA,6CACE,WACF,CACA,6CAEE,UAAW,CADX,WAEF,CACA,8CACE,YACF,CACA,+OASE,8BACF,CACA,4CACE,YACF,CACA,yDACE,iBACF,CACA,yDACE,kBACF,CCvmBA,gCAIE,mBAAoB,CAFpB,cAAe,EACf,iBAEF,CACA,mBAME,WAAY,CAFZ,MAAO,CAHP,SAAU,CAEV,KAAM,CADN,kDAA0D,CAG1D,UAEF,CACA,aAME,+BAAgC,CAChC,uBAAwB,CAFxB,qBAAsB,CAGtB,sCAAuC,CACvC,sCAA2C,CAP3C,MAAO,CACP,QAAS,CACT,SAAU,CAHV,SASF,CACA,mBACE,iBACF,CACA,qBACE,iBACF,CACA,oBACE,wBAAyB,CACzB,+BAAoC,CACpC,qCACF,CACA,kBACE,m+BAEF,CACA,4CAEE,oBAAqB,CACrB,qBACF,CAEA,kBAUE,qBAAsB,CAHtB,WAAY,CANZ,YAAa,CAQb,uBAAwB,CAHxB,WAAY,CAHZ,MAAS,CAKT,SAAU,CANV,cAAe,CAEf,KAAQ,CACR,UAAW,CAMX,kBACF,CACA,oBAKE,QAAS,CACT,gBAAiB,CAHjB,WAAY,CAFZ,iBAAkB,CAGlB,OAAQ,CAFR,UAKF,CAGA,YAIE,sBAAwB,CAFxB,wBAGF,CAeA,0BACE,GACE,SAAU,CAGV,mBACF,CACA,GACE,SAAU,CAGV,kBACF,CACF,CACA,eAEE,6BACF,CAkBA,4BACE,GAME,qCAAsC,CALtC,SAAU,CAGV,uCAGF,CACA,IAME,kCAAmC,CALnC,SAAU,CAGV,sCAGF,CACF,CACA,eAEE,+BACF,CAcA,6BACE,GACE,SAAU,CAGV,4BACF,CACA,GACE,SAAU,CAGV,uBACF,CACF,CACA,eAEE,gCACF,CAkBA,4BACE,GAME,qCAAsC,CALtC,SAAU,CAGV,uCAGF,CACA,IAME,kCAAmC,CALnC,SAAU,CAGV,sCAGF,CACF,CACA,eAEE,+BACF,CAcA,wBACE,GACE,SAAU,CAGV,2CACF,CACA,GACE,SAAU,CAGV,oCACF,CACF,CACA,eAEE,2BACF,CAUA,wBACE,GACE,SACF,CACA,GACE,SACF,CACF,CACA,eAEE,2BACF,CAwBA,uBACE,MAIE,uBACF,CACA,oBAOE,2BACF,CACA,gBAME,0BACF,CACF,CACA,eAEE,0BACF,CAGA,4BACE,GACE,gCACF,CACA,GACE,uBACF,CACF,CACA,gCACE,GACE,uBACF,CACA,GACE,gCACF,CACF,CACA,uBACE,+BACF,CACA,2BACE,mCACF,CAGA,4BACE,GACE,+BACF,CACA,GACE,uBACF,CACF,CACA,gCACE,GACE,uBACF,CACA,GACE,+BACF,CACF,CACA,uBACE,+BACF,CACA,2BACE,mCACF,CAGA,0BACE,GACE,+BACF,CACA,GACE,uBACF,CACF,CACA,8BACE,GACE,uBACF,CACA,GACE,+BACF,CACF,CACA,qBACE,6BACF,CACA,yBACE,iCACF,CAGA,6BACE,GACE,gCACF,CACA,GACE,uBACF,CACF,CACA,iCACE,GACE,uBACF,CACA,GACE,gCACF,CACF,CACA,wBACE,gCACF,CACA,4BACE,oCACF,CAGA,mBAIE,+BAAgC,CAMhC,mEAAoE,CAJpE,UAAW,CADX,cAAe,CAHf,WAAY,CACZ,gBAAiB,CAIjB,eAAgB,CANhB,qBAAsB,CAOtB,sBAAuB,CACvB,kBAEF,CACA,oBAIE,WAAY,CACZ,kBAAoB,CAJpB,iBAAkB,CAClB,UAAW,CACX,QAGF,CACA,yBAWE,qBAAsB,CAFtB,UAAW,CADX,cAAe,CADf,cAAe,CAJf,WAAY,CACZ,gBAAiB,CACjB,gBAAiB,EAKjB,eAAiB,CATjB,iBAAkB,CAKlB,iBAAkB,CAJlB,UAUF,CACA,4CAIE,+BAAgC,CAHhC,UAAW,CAOX,cAAe,CAHf,QAAS,CAET,qBAAuB,EAEvB,eAAiB,CAPjB,iBAAkB,CAIlB,OAAQ,CAHR,UAOF,CAIA,uFAUE,wBAAyB,CARzB,UAAW,CAMX,UAAW,CAJX,QAAS,CAKT,oBAAqB,CANrB,iBAAkB,CAElB,OAAQ,CAER,SAAU,CADV,SAKF,CACA,mGAEE,oBACF,CACA,kDACE,wBACF,CACA,6FAKE,qBAAsB,CAFtB,UAAW,CACX,oBAAqB,CAFrB,SAIF,CACA,8CAEE,oBAAqB,CADrB,SAEF,CACA,uCACE,cACF,CACA,6CACE,UACF,CACA,wCAKE,wBAAyB,CAEzB,gBAAiB,CAKjB,iBAAkB,CARlB,UAAW,CAMX,cAAe,CACf,kBAAmB,CAFnB,WAAY,CAIZ,aAAc,CAPd,WAAY,CALZ,iBAAkB,CAClB,WAAY,CACZ,SAAU,CAKV,UAMF,CACA,8CAEE,wBAAyB,CADzB,aAEF,CAGA,iBAEE,mBAAoB,CACpB,mBAAoB,CAFpB,gBAAiB,CAGjB,wBAAyB,CACzB,qBAAsB,CAEtB,gBACF,CACA,mBAME,qBAAsB,CADtB,wBAAyB,CAGzB,sCAAuC,CAIvC,qBAAsB,CALtB,UAAW,CAGX,cAAe,CADf,eAAgB,CARhB,WAAY,CACZ,gBAAiB,CACjB,gBAAiB,CACjB,4BAA6B,CAO7B,oBAEF,CACA,yBACE,UAAY,CACZ,oBACF,CACA,0BACE,UACF,CACA,mCAEE,wBAAyB,CADzB,wBAAyB,CAEzB,UACF,CACA,mBACE,eACF,CACA,mBACE,iBACF,CACA,4BAEE,4BAA8B,CAC9B,qBAAuB,CAFvB,oBAAuB,CAGvB,eAAgB,CAEhB,wBAAyB,CAEzB,qBAAiB,CAAjB,gBAAiB,CAHjB,kBAIF,CACA,0DAEE,cAAe,CADf,gBAEF,CAGA,oBACE,eACF,CACA,yCAME,cAAe,CAHf,gBAAiB,CAEjB,eAAgB,CAEhB,iBAAkB,CAClB,eAAgB,CANhB,YAAa,CADb,iBAAkB,CAGlB,oBAKF,CACA,2DAIE,aAAc,CACd,cAAe,CAFf,SAAU,EAGV,UAAY,CALZ,iBAAkB,CAClB,QAKF,CACA,0DACE,aACF,CACA,6DACE,6BACF,CACA,2DAEE,aAAc,CADd,QAEF,CACA,8DACE,aACF,CACA,0DACE,aACF,CACA,8DACE,aACF,CACA,gEACE,6BACF,CAEA,iBACE,wBAAyB,CACzB,+BAAoC,CACpC,iBAAkB,CAClB,eACF,CACA,iBAEE,wBAAyB,CACzB,eAAgB,CAFhB,eAGF,CACA,iBAEE,qBAAsB,CAEtB,+BAAoC,CAEpC,WAAY,CADZ,UAAW,CAFX,wBAAyB,CAFzB,eAMF,CACA,oCACE,UACF,CACA,sCACE,iBAAkB,CAClB,iBACF,CACA,yCACE,2BAA4B,CAC5B,eACF,CACA,uCAEE,aAAc,CADd,iBAEF,CACA,wEAEE,gBACF,CACA,kBACE,eACF,CACA,2BACE,aAAc,CACd,UACF,CAEA,qBAEE,eAAgB,CAEhB,WAAY,CAHZ,kBAAmB,CAEnB,eAEF,CACA,0CAEE,WAAY,CACZ,gBAAiB,CACjB,iBAAkB,CAHlB,UAIF,CACA,0BAEE,aAAc,CADd,cAEF,CACA,sBACE,iBACF,CACA,uBAEE,WAAY,CADZ,iBAEF,CACA,2DAUE,+CAAgD,CADhD,iBAAkB,CAElB,qBAAsB,CATtB,UAAW,CAKX,WAAY,CAHZ,QAAS,CAIT,sBAAuB,CALvB,iBAAkB,CAElB,OAAQ,CACR,UAMF,CACA,6BAEE,wDACF,CAEA,kBACE,eAAgB,CAEhB,WAAY,CADZ,eAEF,CACA,uCASE,qBAAsB,CAFtB,sCAAuC,CACvC,qCAA0C,CAE1C,UAAW,EAJX,UAAY,CADZ,cAAe,CAHf,gBAAiB,CACjB,cAAe,CACf,gBAAiB,CAHjB,iBAUF,CACA,qCACE,UAAW,CACX,QACF,CACA,sCAME,6BAAoB,CAHpB,QAAS,CAFT,iBAAkB,CAClB,OAKF,CACA,4EAIE,uBAAwB,CADxB,wBAAyB,CADzB,QAGF,CACA,sCACE,WACF,CACA,sCACE,QACF,CACA,4EAIE,wBAAyB,CADzB,yBAA0B,CAD1B,OAGF,CACA,sCACE,SACF,CACA,sCACE,UACF,CAGA,oCACE,kBAAmB,CAEnB,WAAY,CADZ,UAEF,CACA,kCAEE,4BAA6B,CAD7B,qBAEF,CACA,oCACE,eAAgB,CAChB,oBAAqB,CACrB,UACF,CACA,oDACE,kBACF,CACA,qCACE,kBAAmB,CAEnB,WAAY,CADZ,UAEF,CACA,qCACE,kBAAmB,CACnB,oBACF,CACA,qDACE,kBACF,CACA,mGAEE,UACF,CAGA,mBACE,qBAAsB,CAEtB,kBAAmB,CADnB,qCAEF,CACA,sCAIE,kBAAmB,CACnB,cAAe,CAJf,WAAY,CACZ,gBAAiB,CACjB,gBAGF,CACA,uCACE,OAAQ,CACR,KACF,CACA,4CAGE,WAAY,CAFZ,aAAc,CAGd,WAAY,CAFZ,UAGF,CACA,6DACE,UACF,CACA,kDACE,wBACF,CACA,mEACE,wBAAyB,CACzB,UACF,CACA,2DAEE,aAAc,CADd,sEAEF,CACA,2DAEE,iBAAkB,CADlB,gBAEF,CACA,oCAGE,wBAAyB,CADzB,4BAA6B,CAD7B,oBAGF,CACA,sCAGE,wBAAyB,CACzB,oBAAqB,CACrB,UAAW,CACX,cAAe,CALf,WAAY,CACZ,gBAAiB,CAKjB,kBACF,CACA,4CAEE,wBAAyB,CADzB,oBAEF,CACA,sDACE,oBACF,CAOA,uCAOE,wBAAyB,CACzB,UAAW,CAPX,aAAc,CAEd,WAAY,CAEZ,gBAAiB,CADjB,aAAc,CAEd,iBAAkB,CAJlB,WAOF,CACA,+CAEE,YAAa,CACb,gBAAiB,CACjB,gBAAiB,CAHjB,WAIF,CACA,yCACE,0BACF,CACA,qCACE,aACF,CAGA,iBACE,sCACF,CACA,oCAEE,gBAAiB,CADjB,cAEF,CACA,yCAIE,iCAAkC,CAClC,kCAAmC,CAKnC,cAAe,CAIf,cAAe,CAZf,oBAAqB,CAKrB,eAAgB,CADhB,cAAe,CAMf,eAAgB,CAJhB,4BAA6B,CAP7B,iBAAkB,CAQlB,iBAAkB,CAElB,sBAAuB,CARvB,kBAAmB,CAUnB,kBAEF,CACA,oDAIE,qBAAsB,CAFtB,yCAA0C,CAC1C,0CAA2C,CAF3C,WAAY,CAIZ,UACF,CACA,qDACE,6BACF,CACA,qBAEE,UAAW,CADX,gBAEF,CACA,wCACE,YACF,CACA,mDACE,aACF,CAGA,oBACE,eAAgB,CAChB,eACF,CACA,yCACE,gBAAiB,CACjB,iBACF,CACA,iDAGE,oBAAqB,CAFrB,iBAAkB,CAGlB,kBAAmB,CAFnB,UAGF,CACA,kDAUE,aAAc,CAFd,cAAe,CACf,cAAe,CAJf,WAAY,CACZ,gBAAiB,CACjB,gBAAiB,CALjB,cAAe,CACf,OAAQ,CACR,UAOF,CACA,yBACE,SACF,CACA,yBACE,UACF,CACA,8DAEE,aACF,CAEA,4BAQE,gCAAqC,CAJrC,QAAS,CAKT,UAAW,CAIX,WAAY,CAPZ,WAAY,CAJZ,MAAO,CAKP,gBAAiB,CAIjB,eAAgB,CAVhB,cAAe,CAEf,OAAQ,CAOR,sBAAuB,CAEvB,kBAAmB,CAPnB,UASF,CACA,8BAKE,UAAW,CAJX,oBAAqB,CAGrB,cAAe,CADf,4BAA6B,CAD7B,kBAIF,CACA,8BACE,cACF,CACA,2BAEE,WAAY,CADZ,KAEF,CACA,gCACE,cACF,CACA,sCACE,mCACF,CACA,uCACE,cACF,CACA,8BACE,aAAc,CAEd,eAAgB,CADhB,sBAAuB,CAEvB,kBACF,CACA,mCACE,yBACF,CACA,8BACE,iBACF,CAkBA,2BACE,GACE,SAAU,CAGV,mBACF,CACA,IAGE,qBACF,CACA,GAGE,kBACF,CACF,CACA,kBAME,sBAAwB,CAFxB,wBAAyB,CAFzB,8BAKF","file":"layui.css","sourcesContent":["/**\n * Layui\n */\n\n:root,\n.light {\n /* 默认主题色 */\n --lay-color-primary: #16baaa;\n --lay-color-accent: #16b777;\n\n /* 七色 */\n --lay-color-red: #ff5722;\n --lay-color-orange: #ffb800;\n --lay-color-green: #16baaa;\n --lay-color-blue: #1e9fff;\n --lay-color-purple: #a233c6;\n --lay-color-black: #2f363c;\n --lay-color-gray: #fafafa;\n\n /* 灰度 */\n --lay-gray-100: #fafafa;\n --lay-gray-200: #f7f7f7;\n --lay-gray-300: #eeeeee;\n --lay-gray-400: #d1d1d1;\n --lay-gray-500: #c8c8c8;\n --lay-gray-600: #b7b7b7;\n --lay-gray-700: #959595;\n --lay-gray-800: #777777;\n --lay-gray-900: #5a5a5a;\n\n /* 边框 */\n --lay-border-color: var(--lay-gray-300);\n --lay-border-color-accent: var(--lay-gray-400);\n --lay-border-radius: 2px;\n --lay-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15);\n --lay-box-shadow-sm: 0 0.5px 1px rgba(0, 0, 0, 0.08);\n --lay-box-shadow-lg: 0 3px 6px rgba(0, 0, 0, 0.3);\n\n /* 字体 */\n --lay-font-family:\n system-ui, -apple-system, 'Segoe UI', Roboto, 'PingFang SC',\n 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji',\n 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji';\n --lay-font-monospace: 'Courier New', Consolas, 'Lucida Console', monospace;\n\n /* 间距 */\n --lay-spacing: 16px;\n --lay-spacing-xs: 5px;\n --lay-spacing-sm: 8px;\n --lay-spacing-lg: 24px;\n --lay-spacing-xl: 32px;\n}\n","/** 初始化 **/\nbody,\ndiv,\ndl,\ndt,\ndd,\nul,\nol,\nli,\nh1,\nh2,\nh3,\nh4,\nh5,\nh6,\ninput,\nbutton,\ntextarea,\np,\nblockquote,\nth,\ntd,\nform,\npre {\n margin: 0;\n padding: 0;\n -webkit-tap-highlight-color: rgba(0, 0, 0, 0);\n}\na:active,\na:hover {\n outline: 0;\n}\nimg {\n display: inline-block;\n border: none;\n vertical-align: middle;\n}\nli {\n list-style: none;\n}\ntable {\n border-collapse: collapse;\n border-spacing: 0;\n}\nh1,\nh2,\nh3,\nh4,\nh5,\nh6 {\n font-weight: 700;\n}\nh5,\nh6 {\n font-size: 100%;\n}\nbutton,\ninput,\nselect,\ntextarea {\n font-size: 100%;\n}\ninput,\nbutton,\ntextarea,\nselect,\noptgroup,\noption {\n font-family: inherit;\n font-size: inherit;\n font-style: inherit;\n font-weight: inherit;\n outline: 0;\n}\npre {\n white-space: pre-wrap;\n word-wrap: break-word;\n}\n\n/** 初始化全局标签 **/\nbody {\n line-height: 1.6;\n color: rgba(0, 0, 0, 0.85);\n font-size: 14px;\n font-family: var(--lay-font-family);\n}\nhr {\n height: 0;\n line-height: 0;\n margin: 10px 0;\n padding: 0;\n border: none;\n border-bottom: 1px solid var(--lay-border-color);\n clear: both;\n overflow: hidden;\n background: none;\n}\na {\n color: #333;\n text-decoration: none;\n}\na cite {\n font-style: normal;\n}\n\n/** 基础通用 **/\n.layui-border-box,\n.layui-border-box * {\n box-sizing: border-box;\n}\n/* 消除第三方 ui 可能造成的冲突 */\n.layui-box,\n.layui-box * {\n box-sizing: content-box;\n}\n.layui-clear {\n clear: both;\n}\n.layui-clear:after {\n content: '\\20';\n clear: both;\n display: block;\n height: 0;\n}\n.layui-clear-space {\n word-spacing: -5px;\n}\n.layui-inline {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n}\n/* 三角形 */\n.layui-edge {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n width: 0;\n height: 0;\n border-width: 6px;\n border-style: dashed;\n border-color: transparent;\n overflow: hidden;\n}\n.layui-edge-top {\n top: -4px;\n border-bottom-color: #999;\n border-bottom-style: solid;\n}\n.layui-edge-right {\n border-left-color: #999;\n border-left-style: solid;\n}\n.layui-edge-bottom {\n top: 2px;\n border-top-color: #999;\n border-top-style: solid;\n}\n.layui-edge-left {\n border-right-color: #999;\n border-right-style: solid;\n}\n/* 单行溢出省略 */\n.layui-ellip {\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n/* 屏蔽选中 */\n.layui-unselect,\n.layui-icon,\n.layui-disabled {\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n/* 禁用 */\n.layui-disabled,\n.layui-disabled:hover {\n color: var(--lay-gray-400) !important;\n cursor: not-allowed !important;\n}\n/* 纯圆角 */\n.layui-circle {\n border-radius: 100%;\n}\n.layui-show {\n display: block !important;\n}\n.layui-hide {\n display: none !important;\n}\n.layui-show-v {\n visibility: visible !important;\n}\n.layui-hide-v {\n visibility: hidden !important;\n}\n","/** 图标字体 **/\n@font-face {\n font-family: 'layui-icon';\n src: url('iconfont.woff2') format('woff2');\n}\n\n.layui-icon {\n font-family: 'layui-icon' !important;\n font-size: 16px;\n font-style: normal;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\n/* font-class */\n.layui-icon-sound:before {\n content: '\\e69d';\n}\n.layui-icon-bot:before {\n content: '\\e7d6';\n}\n.layui-icon-leaf:before {\n content: '\\e701';\n}\n.layui-icon-folder:before {\n content: '\\eabe';\n}\n.layui-icon-folder-open:before {\n content: '\\eac1';\n}\n.layui-icon-gitee:before {\n content: '\\e69b';\n}\n.layui-icon-github:before {\n content: '\\e6a7';\n}\n.layui-icon-disabled:before {\n content: '\\e6cc';\n}\n.layui-icon-moon:before {\n content: '\\e6c2';\n}\n.layui-icon-error:before {\n content: '\\e693';\n}\n.layui-icon-success:before {\n content: '\\e697';\n}\n.layui-icon-question:before {\n content: '\\e699';\n}\n.layui-icon-lock:before {\n content: '\\e69a';\n}\n.layui-icon-eye:before {\n content: '\\e695';\n}\n.layui-icon-eye-invisible:before {\n content: '\\e696';\n}\n.layui-icon-backspace:before {\n content: '\\e694';\n}\n.layui-icon-tips-fill:before {\n content: '\\eb2e';\n}\n.layui-icon-test:before {\n content: '\\e692';\n}\n.layui-icon-clear:before {\n content: '\\e788';\n}\n.layui-icon-heart-fill:before {\n content: '\\e68f';\n}\n.layui-icon-light:before {\n content: '\\e748';\n}\n.layui-icon-music:before {\n content: '\\e690';\n}\n.layui-icon-time:before {\n content: '\\e68d';\n}\n.layui-icon-ie:before {\n content: '\\e7bb';\n}\n.layui-icon-firefox:before {\n content: '\\e686';\n}\n.layui-icon-at:before {\n content: '\\e687';\n}\n.layui-icon-bluetooth:before {\n content: '\\e689';\n}\n.layui-icon-chrome:before {\n content: '\\e68a';\n}\n.layui-icon-edge:before {\n content: '\\e68b';\n}\n.layui-icon-heart:before {\n content: '\\e68c';\n}\n.layui-icon-key:before {\n content: '\\e683';\n}\n.layui-icon-android:before {\n content: '\\e684';\n}\n.layui-icon-mike:before {\n content: '\\e6dc';\n}\n.layui-icon-mute:before {\n content: '\\e685';\n}\n.layui-icon-gift:before {\n content: '\\e627';\n}\n.layui-icon-windows:before {\n content: '\\e67f';\n}\n.layui-icon-ios:before {\n content: '\\e680';\n}\n.layui-icon-logout:before {\n content: '\\e682';\n}\n.layui-icon-wifi:before {\n content: '\\e7e0';\n}\n.layui-icon-rss:before {\n content: '\\e808';\n}\n.layui-icon-email:before {\n content: '\\e618';\n}\n.layui-icon-reduce-circle:before {\n content: '\\e616';\n}\n.layui-icon-transfer:before {\n content: '\\e691';\n}\n.layui-icon-service:before {\n content: '\\e626';\n}\n.layui-icon-addition:before {\n content: '\\e624';\n}\n.layui-icon-subtraction:before {\n content: '\\e67e';\n}\n.layui-icon-slider:before {\n content: '\\e714';\n}\n.layui-icon-print:before {\n content: '\\e66d';\n}\n.layui-icon-export:before {\n content: '\\e67d';\n}\n.layui-icon-cols:before {\n content: '\\e610';\n}\n.layui-icon-screen-full:before {\n content: '\\e622';\n}\n.layui-icon-screen-restore:before {\n content: '\\e758';\n}\n.layui-icon-rate-half:before {\n content: '\\e6c9';\n}\n.layui-icon-rate-solid:before {\n content: '\\e67a';\n}\n.layui-icon-rate:before {\n content: '\\e67b';\n}\n.layui-icon-cellphone:before {\n content: '\\e678';\n}\n.layui-icon-vercode:before {\n content: '\\e679';\n}\n.layui-icon-login-weibo:before {\n content: '\\e675';\n}\n.layui-icon-login-qq:before {\n content: '\\e676';\n}\n.layui-icon-login-wechat:before {\n content: '\\e677';\n}\n.layui-icon-username:before {\n content: '\\e66f';\n}\n.layui-icon-password:before {\n content: '\\e673';\n}\n.layui-icon-refresh-3:before {\n content: '\\e9aa';\n}\n.layui-icon-auz:before {\n content: '\\e672';\n}\n.layui-icon-shrink-right:before {\n content: '\\e668';\n}\n.layui-icon-spread-left:before {\n content: '\\e66b';\n}\n.layui-icon-snowflake:before {\n content: '\\e6b1';\n}\n.layui-icon-tips:before {\n content: '\\e702';\n}\n.layui-icon-note:before {\n content: '\\e66e';\n}\n.layui-icon-senior:before {\n content: '\\e674';\n}\n.layui-icon-refresh-1:before {\n content: '\\e666';\n}\n.layui-icon-refresh:before {\n content: '\\e669';\n}\n.layui-icon-flag:before {\n content: '\\e66c';\n}\n.layui-icon-theme:before {\n content: '\\e66a';\n}\n.layui-icon-notice:before {\n content: '\\e667';\n}\n.layui-icon-console:before {\n content: '\\e665';\n}\n.layui-icon-website:before {\n content: '\\e7ae';\n}\n.layui-icon-face-surprised:before {\n content: '\\e664';\n}\n.layui-icon-set:before {\n content: '\\e716';\n}\n.layui-icon-template:before {\n content: '\\e663';\n}\n.layui-icon-app:before {\n content: '\\e653';\n}\n.layui-icon-template-1:before {\n content: '\\e656';\n}\n.layui-icon-home:before {\n content: '\\e68e';\n}\n.layui-icon-female:before {\n content: '\\e661';\n}\n.layui-icon-male:before {\n content: '\\e662';\n}\n.layui-icon-tread:before {\n content: '\\e6c5';\n}\n.layui-icon-praise:before {\n content: '\\e6c6';\n}\n.layui-icon-rmb:before {\n content: '\\e65e';\n}\n.layui-icon-more:before {\n content: '\\e65f';\n}\n.layui-icon-camera:before {\n content: '\\e660';\n}\n.layui-icon-cart-simple:before {\n content: '\\e698';\n}\n.layui-icon-face-cry:before {\n content: '\\e69c';\n}\n.layui-icon-face-smile:before {\n content: '\\e6af';\n}\n.layui-icon-survey:before {\n content: '\\e6b2';\n}\n.layui-icon-read:before {\n content: '\\e705';\n}\n.layui-icon-location:before {\n content: '\\e715';\n}\n.layui-icon-dollar:before {\n content: '\\e659';\n}\n.layui-icon-diamond:before {\n content: '\\e735';\n}\n.layui-icon-return:before {\n content: '\\e65c';\n}\n.layui-icon-camera-fill:before {\n content: '\\e65d';\n}\n.layui-icon-fire:before {\n content: '\\e756';\n}\n.layui-icon-more-vertical:before {\n content: '\\e671';\n}\n.layui-icon-cart:before {\n content: '\\e657';\n}\n.layui-icon-star-fill:before {\n content: '\\e658';\n}\n.layui-icon-prev:before {\n content: '\\e65a';\n}\n.layui-icon-next:before {\n content: '\\e65b';\n}\n.layui-icon-upload:before {\n content: '\\e67c';\n}\n.layui-icon-upload-drag:before {\n content: '\\e681';\n}\n.layui-icon-user:before {\n content: '\\e770';\n}\n.layui-icon-file-b:before {\n content: '\\e655';\n}\n.layui-icon-component:before {\n content: '\\e857';\n}\n.layui-icon-find-fill:before {\n content: '\\e670';\n}\n.layui-icon-loading:before {\n content: '\\e63d';\n}\n.layui-icon-loading-1:before {\n content: '\\e63e';\n}\n.layui-icon-add-1:before {\n content: '\\e654';\n}\n.layui-icon-pause:before {\n content: '\\e651';\n}\n.layui-icon-play:before {\n content: '\\e652';\n}\n.layui-icon-video:before {\n content: '\\e6ed';\n}\n.layui-icon-headset:before {\n content: '\\e6fc';\n}\n.layui-icon-voice:before {\n content: '\\e688';\n}\n.layui-icon-speaker:before {\n content: '\\e645';\n}\n.layui-icon-fonts-del:before {\n content: '\\e64f';\n}\n.layui-icon-fonts-html:before {\n content: '\\e64b';\n}\n.layui-icon-fonts-code:before {\n content: '\\e64e';\n}\n.layui-icon-fonts-strong:before {\n content: '\\e62b';\n}\n.layui-icon-unlink:before {\n content: '\\e64d';\n}\n.layui-icon-picture:before {\n content: '\\e64a';\n}\n.layui-icon-link:before {\n content: '\\e64c';\n}\n.layui-icon-face-smile-b:before {\n content: '\\e650';\n}\n.layui-icon-align-center:before {\n content: '\\e647';\n}\n.layui-icon-align-right:before {\n content: '\\e648';\n}\n.layui-icon-align-left:before {\n content: '\\e649';\n}\n.layui-icon-fonts-u:before {\n content: '\\e646';\n}\n.layui-icon-fonts-i:before {\n content: '\\e644';\n}\n.layui-icon-tabs:before {\n content: '\\e62a';\n}\n.layui-icon-circle:before {\n content: '\\e63f';\n}\n.layui-icon-radio:before {\n content: '\\e643';\n}\n.layui-icon-share:before {\n content: '\\e641';\n}\n.layui-icon-edit:before {\n content: '\\e642';\n}\n.layui-icon-delete:before {\n content: '\\e640';\n}\n.layui-icon-engine:before {\n content: '\\e628';\n}\n.layui-icon-chart-screen:before {\n content: '\\e629';\n}\n.layui-icon-chart:before {\n content: '\\e62c';\n}\n.layui-icon-table:before {\n content: '\\e62d';\n}\n.layui-icon-tree:before {\n content: '\\e62e';\n}\n.layui-icon-upload-circle:before {\n content: '\\e62f';\n}\n.layui-icon-templeate-1:before {\n content: '\\e630';\n}\n.layui-icon-util:before {\n content: '\\e631';\n}\n.layui-icon-layouts:before {\n content: '\\e632';\n}\n.layui-icon-prev-circle:before {\n content: '\\e633';\n}\n.layui-icon-carousel:before {\n content: '\\e634';\n}\n.layui-icon-code-circle:before {\n content: '\\e635';\n}\n.layui-icon-water:before {\n content: '\\e636';\n}\n.layui-icon-date:before {\n content: '\\e637';\n}\n.layui-icon-layer:before {\n content: '\\e638';\n}\n.layui-icon-fonts-clear:before {\n content: '\\e639';\n}\n.layui-icon-dialogue:before {\n content: '\\e63a';\n}\n.layui-icon-cellphone-fine:before {\n content: '\\e63b';\n}\n.layui-icon-form:before {\n content: '\\e63c';\n}\n.layui-icon-file:before {\n content: '\\e621';\n}\n.layui-icon-triangle-r:before {\n content: '\\e623';\n}\n.layui-icon-triangle-d:before {\n content: '\\e625';\n}\n.layui-icon-set-sm:before {\n content: '\\e620';\n}\n.layui-icon-add-circle:before {\n content: '\\e61f';\n}\n.layui-icon-layim-download:before {\n content: '\\e61e';\n}\n.layui-icon-layim-uploadfile:before {\n content: '\\e61d';\n}\n.layui-icon-404:before {\n content: '\\e61c';\n}\n.layui-icon-about:before {\n content: '\\e60b';\n}\n.layui-icon-layim-theme:before {\n content: '\\e61b';\n}\n.layui-icon-down:before {\n content: '\\e61a';\n}\n.layui-icon-up:before {\n content: '\\e619';\n}\n.layui-icon-circle-dot:before {\n content: '\\e617';\n}\n.layui-icon-set-fill:before {\n content: '\\e614';\n}\n.layui-icon-search:before {\n content: '\\e615';\n}\n.layui-icon-friends:before {\n content: '\\e612';\n}\n.layui-icon-group:before {\n content: '\\e613';\n}\n.layui-icon-reply-fill:before {\n content: '\\e611';\n}\n.layui-icon-menu-fill:before {\n content: '\\e60f';\n}\n.layui-icon-face-smile-fine:before {\n content: '\\e60c';\n}\n.layui-icon-picture-fine:before {\n content: '\\e60d';\n}\n.layui-icon-log:before {\n content: '\\e60e';\n}\n.layui-icon-list:before {\n content: '\\e60a';\n}\n.layui-icon-release:before {\n content: '\\e609';\n}\n.layui-icon-add-circle-fine:before {\n content: '\\e608';\n}\n.layui-icon-ok:before {\n content: '\\e605';\n}\n.layui-icon-help:before {\n content: '\\e607';\n}\n.layui-icon-chat:before {\n content: '\\e606';\n}\n.layui-icon-top:before {\n content: '\\e604';\n}\n.layui-icon-right:before {\n content: '\\e602';\n}\n.layui-icon-left:before {\n content: '\\e603';\n}\n.layui-icon-star:before {\n content: '\\e600';\n}\n.layui-icon-download-circle:before {\n content: '\\e601';\n}\n.layui-icon-close:before {\n content: '\\1006';\n}\n.layui-icon-close-fill:before {\n content: '\\1007';\n}\n.layui-icon-ok-circle:before {\n content: '\\1005';\n}\n","/* 基本布局 */\n.layui-main {\n position: relative;\n width: 1160px;\n margin: 0 auto;\n}\n.layui-header {\n position: relative;\n z-index: 1000;\n height: 60px;\n}\n.layui-header a:hover {\n -webkit-transition: all 0.5s;\n transition: all 0.5s;\n}\n.layui-side {\n position: fixed;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 999;\n width: 200px;\n overflow-x: hidden;\n}\n.layui-side-scroll {\n position: relative;\n width: 220px;\n height: 100%;\n overflow-x: hidden;\n}\n.layui-body {\n position: relative;\n left: 200px;\n right: 0;\n top: 0;\n bottom: 0;\n width: auto;\n box-sizing: border-box;\n}\n\n/* 后台框架大布局 */\n.layui-layout-body {\n overflow-x: hidden;\n}\n.layui-layout-admin .layui-header {\n position: fixed;\n top: 0;\n left: 0;\n right: 0;\n background-color: #23292e;\n}\n.layui-layout-admin .layui-side {\n top: 60px;\n width: 200px;\n overflow-x: hidden;\n}\n.layui-layout-admin .layui-body {\n position: absolute;\n top: 60px;\n padding-bottom: 44px;\n}\n.layui-layout-admin .layui-main {\n width: auto;\n margin: 0 15px;\n}\n.layui-layout-admin .layui-footer {\n position: fixed;\n left: 200px;\n right: 0;\n bottom: 0;\n z-index: 990;\n height: 44px;\n line-height: 44px;\n padding: 0 15px;\n box-shadow: -1px 0 4px rgb(0 0 0 / 12%);\n background-color: var(--lay-color-gray);\n}\n.layui-layout-admin .layui-logo {\n position: absolute;\n left: 0;\n top: 0;\n width: 200px;\n height: 100%;\n line-height: 60px;\n text-align: center;\n color: var(--lay-color-primary);\n font-size: 16px;\n box-shadow: 0 1px 2px 0 rgb(0 0 0 / 15%);\n}\n.layui-layout-admin .layui-header .layui-nav {\n background: none;\n}\n.layui-layout-left {\n position: absolute !important;\n left: 200px;\n top: 0;\n}\n.layui-layout-right {\n position: absolute !important;\n right: 0;\n top: 0;\n}\n\n/* 栅格布局 */\n.layui-container {\n position: relative;\n margin: 0 auto;\n box-sizing: border-box;\n}\n.layui-fluid {\n position: relative;\n margin: 0 auto;\n padding: 0 15px;\n}\n\n.layui-row:before,\n.layui-row:after {\n content: '';\n display: block;\n clear: both;\n}\n.layui-col-xs1,\n.layui-col-xs2,\n.layui-col-xs3,\n.layui-col-xs4,\n.layui-col-xs5,\n.layui-col-xs6,\n.layui-col-xs7,\n.layui-col-xs8,\n.layui-col-xs9,\n.layui-col-xs10,\n.layui-col-xs11,\n.layui-col-xs12,\n.layui-col-sm1,\n.layui-col-sm2,\n.layui-col-sm3,\n.layui-col-sm4,\n.layui-col-sm5,\n.layui-col-sm6,\n.layui-col-sm7,\n.layui-col-sm8,\n.layui-col-sm9,\n.layui-col-sm10,\n.layui-col-sm11,\n.layui-col-sm12,\n.layui-col-md1,\n.layui-col-md2,\n.layui-col-md3,\n.layui-col-md4,\n.layui-col-md5,\n.layui-col-md6,\n.layui-col-md7,\n.layui-col-md8,\n.layui-col-md9,\n.layui-col-md10,\n.layui-col-md11,\n.layui-col-md12,\n.layui-col-lg1,\n.layui-col-lg2,\n.layui-col-lg3,\n.layui-col-lg4,\n.layui-col-lg5,\n.layui-col-lg6,\n.layui-col-lg7,\n.layui-col-lg8,\n.layui-col-lg9,\n.layui-col-lg10,\n.layui-col-lg11,\n.layui-col-lg12,\n.layui-col-xl1,\n.layui-col-xl2,\n.layui-col-xl3,\n.layui-col-xl4,\n.layui-col-xl5,\n.layui-col-xl6,\n.layui-col-xl7,\n.layui-col-xl8,\n.layui-col-xl9,\n.layui-col-xl10,\n.layui-col-xl11,\n.layui-col-xl12 {\n position: relative;\n display: block;\n box-sizing: border-box;\n}\n\n.layui-col-xs1,\n.layui-col-xs2,\n.layui-col-xs3,\n.layui-col-xs4,\n.layui-col-xs5,\n.layui-col-xs6,\n.layui-col-xs7,\n.layui-col-xs8,\n.layui-col-xs9,\n.layui-col-xs10,\n.layui-col-xs11,\n.layui-col-xs12 {\n float: left;\n}\n.layui-col-xs1 {\n width: 8.33333333%;\n}\n.layui-col-xs2 {\n width: 16.66666667%;\n}\n.layui-col-xs3 {\n width: 25%;\n}\n.layui-col-xs4 {\n width: 33.33333333%;\n}\n.layui-col-xs5 {\n width: 41.66666667%;\n}\n.layui-col-xs6 {\n width: 50%;\n}\n.layui-col-xs7 {\n width: 58.33333333%;\n}\n.layui-col-xs8 {\n width: 66.66666667%;\n}\n.layui-col-xs9 {\n width: 75%;\n}\n.layui-col-xs10 {\n width: 83.33333333%;\n}\n.layui-col-xs11 {\n width: 91.66666667%;\n}\n.layui-col-xs12 {\n width: 100%;\n}\n\n.layui-col-xs-offset1 {\n margin-left: 8.33333333%;\n}\n.layui-col-xs-offset2 {\n margin-left: 16.66666667%;\n}\n.layui-col-xs-offset3 {\n margin-left: 25%;\n}\n.layui-col-xs-offset4 {\n margin-left: 33.33333333%;\n}\n.layui-col-xs-offset5 {\n margin-left: 41.66666667%;\n}\n.layui-col-xs-offset6 {\n margin-left: 50%;\n}\n.layui-col-xs-offset7 {\n margin-left: 58.33333333%;\n}\n.layui-col-xs-offset8 {\n margin-left: 66.66666667%;\n}\n.layui-col-xs-offset9 {\n margin-left: 75%;\n}\n.layui-col-xs-offset10 {\n margin-left: 83.33333333%;\n}\n.layui-col-xs-offset11 {\n margin-left: 91.66666667%;\n}\n.layui-col-xs-offset12 {\n margin-left: 100%;\n}\n\n/* 超小屏幕 */\n@media screen and (max-width: 767.98px) {\n .layui-container {\n padding: 0 15px;\n }\n .layui-hide-xs {\n display: none !important;\n }\n .layui-show-xs-block {\n display: block !important;\n }\n .layui-show-xs-inline {\n display: inline !important;\n }\n .layui-show-xs-inline-block {\n display: inline-block !important;\n }\n}\n\n/* 小型屏幕 */\n@media screen and (min-width: 768px) {\n .layui-container {\n width: 720px;\n }\n .layui-hide-sm {\n display: none !important;\n }\n .layui-show-sm-block {\n display: block !important;\n }\n .layui-show-sm-inline {\n display: inline !important;\n }\n .layui-show-sm-inline-block {\n display: inline-block !important;\n }\n\n .layui-col-sm1,\n .layui-col-sm2,\n .layui-col-sm3,\n .layui-col-sm4,\n .layui-col-sm5,\n .layui-col-sm6,\n .layui-col-sm7,\n .layui-col-sm8,\n .layui-col-sm9,\n .layui-col-sm10,\n .layui-col-sm11,\n .layui-col-sm12 {\n float: left;\n }\n .layui-col-sm1 {\n width: 8.33333333%;\n }\n .layui-col-sm2 {\n width: 16.66666667%;\n }\n .layui-col-sm3 {\n width: 25%;\n }\n .layui-col-sm4 {\n width: 33.33333333%;\n }\n .layui-col-sm5 {\n width: 41.66666667%;\n }\n .layui-col-sm6 {\n width: 50%;\n }\n .layui-col-sm7 {\n width: 58.33333333%;\n }\n .layui-col-sm8 {\n width: 66.66666667%;\n }\n .layui-col-sm9 {\n width: 75%;\n }\n .layui-col-sm10 {\n width: 83.33333333%;\n }\n .layui-col-sm11 {\n width: 91.66666667%;\n }\n .layui-col-sm12 {\n width: 100%;\n }\n /* 列偏移 */\n .layui-col-sm-offset1 {\n margin-left: 8.33333333%;\n }\n .layui-col-sm-offset2 {\n margin-left: 16.66666667%;\n }\n .layui-col-sm-offset3 {\n margin-left: 25%;\n }\n .layui-col-sm-offset4 {\n margin-left: 33.33333333%;\n }\n .layui-col-sm-offset5 {\n margin-left: 41.66666667%;\n }\n .layui-col-sm-offset6 {\n margin-left: 50%;\n }\n .layui-col-sm-offset7 {\n margin-left: 58.33333333%;\n }\n .layui-col-sm-offset8 {\n margin-left: 66.66666667%;\n }\n .layui-col-sm-offset9 {\n margin-left: 75%;\n }\n .layui-col-sm-offset10 {\n margin-left: 83.33333333%;\n }\n .layui-col-sm-offset11 {\n margin-left: 91.66666667%;\n }\n .layui-col-sm-offset12 {\n margin-left: 100%;\n }\n}\n/* 中型屏幕 */\n@media screen and (min-width: 992px) {\n .layui-container {\n width: 960px;\n }\n .layui-hide-md {\n display: none !important;\n }\n .layui-show-md-block {\n display: block !important;\n }\n .layui-show-md-inline {\n display: inline !important;\n }\n .layui-show-md-inline-block {\n display: inline-block !important;\n }\n\n .layui-col-md1,\n .layui-col-md2,\n .layui-col-md3,\n .layui-col-md4,\n .layui-col-md5,\n .layui-col-md6,\n .layui-col-md7,\n .layui-col-md8,\n .layui-col-md9,\n .layui-col-md10,\n .layui-col-md11,\n .layui-col-md12 {\n float: left;\n }\n .layui-col-md1 {\n width: 8.33333333%;\n }\n .layui-col-md2 {\n width: 16.66666667%;\n }\n .layui-col-md3 {\n width: 25%;\n }\n .layui-col-md4 {\n width: 33.33333333%;\n }\n .layui-col-md5 {\n width: 41.66666667%;\n }\n .layui-col-md6 {\n width: 50%;\n }\n .layui-col-md7 {\n width: 58.33333333%;\n }\n .layui-col-md8 {\n width: 66.66666667%;\n }\n .layui-col-md9 {\n width: 75%;\n }\n .layui-col-md10 {\n width: 83.33333333%;\n }\n .layui-col-md11 {\n width: 91.66666667%;\n }\n .layui-col-md12 {\n width: 100%;\n }\n /* 列偏移 */\n .layui-col-md-offset1 {\n margin-left: 8.33333333%;\n }\n .layui-col-md-offset2 {\n margin-left: 16.66666667%;\n }\n .layui-col-md-offset3 {\n margin-left: 25%;\n }\n .layui-col-md-offset4 {\n margin-left: 33.33333333%;\n }\n .layui-col-md-offset5 {\n margin-left: 41.66666667%;\n }\n .layui-col-md-offset6 {\n margin-left: 50%;\n }\n .layui-col-md-offset7 {\n margin-left: 58.33333333%;\n }\n .layui-col-md-offset8 {\n margin-left: 66.66666667%;\n }\n .layui-col-md-offset9 {\n margin-left: 75%;\n }\n .layui-col-md-offset10 {\n margin-left: 83.33333333%;\n }\n .layui-col-md-offset11 {\n margin-left: 91.66666667%;\n }\n .layui-col-md-offset12 {\n margin-left: 100%;\n }\n}\n/* 大型屏幕 */\n@media screen and (min-width: 1200px) {\n .layui-container {\n width: 1150px;\n }\n .layui-hide-lg {\n display: none !important;\n }\n .layui-show-lg-block {\n display: block !important;\n }\n .layui-show-lg-inline {\n display: inline !important;\n }\n .layui-show-lg-inline-block {\n display: inline-block !important;\n }\n\n .layui-col-lg1,\n .layui-col-lg2,\n .layui-col-lg3,\n .layui-col-lg4,\n .layui-col-lg5,\n .layui-col-lg6,\n .layui-col-lg7,\n .layui-col-lg8,\n .layui-col-lg9,\n .layui-col-lg10,\n .layui-col-lg11,\n .layui-col-lg12 {\n float: left;\n }\n .layui-col-lg1 {\n width: 8.33333333%;\n }\n .layui-col-lg2 {\n width: 16.66666667%;\n }\n .layui-col-lg3 {\n width: 25%;\n }\n .layui-col-lg4 {\n width: 33.33333333%;\n }\n .layui-col-lg5 {\n width: 41.66666667%;\n }\n .layui-col-lg6 {\n width: 50%;\n }\n .layui-col-lg7 {\n width: 58.33333333%;\n }\n .layui-col-lg8 {\n width: 66.66666667%;\n }\n .layui-col-lg9 {\n width: 75%;\n }\n .layui-col-lg10 {\n width: 83.33333333%;\n }\n .layui-col-lg11 {\n width: 91.66666667%;\n }\n .layui-col-lg12 {\n width: 100%;\n }\n /* 列偏移 */\n .layui-col-lg-offset1 {\n margin-left: 8.33333333%;\n }\n .layui-col-lg-offset2 {\n margin-left: 16.66666667%;\n }\n .layui-col-lg-offset3 {\n margin-left: 25%;\n }\n .layui-col-lg-offset4 {\n margin-left: 33.33333333%;\n }\n .layui-col-lg-offset5 {\n margin-left: 41.66666667%;\n }\n .layui-col-lg-offset6 {\n margin-left: 50%;\n }\n .layui-col-lg-offset7 {\n margin-left: 58.33333333%;\n }\n .layui-col-lg-offset8 {\n margin-left: 66.66666667%;\n }\n .layui-col-lg-offset9 {\n margin-left: 75%;\n }\n .layui-col-lg-offset10 {\n margin-left: 83.33333333%;\n }\n .layui-col-lg-offset11 {\n margin-left: 91.66666667%;\n }\n .layui-col-lg-offset12 {\n margin-left: 100%;\n }\n}\n/* 超大屏幕 */\n@media screen and (min-width: 1400px) {\n .layui-container {\n width: 1330px;\n }\n .layui-hide-xl {\n display: none !important;\n }\n .layui-show-xl-block {\n display: block !important;\n }\n .layui-show-xl-inline {\n display: inline !important;\n }\n .layui-show-xl-inline-block {\n display: inline-block !important;\n }\n\n .layui-col-xl1,\n .layui-col-xl2,\n .layui-col-xl3,\n .layui-col-xl4,\n .layui-col-xl5,\n .layui-col-xl6,\n .layui-col-xl7,\n .layui-col-xl8,\n .layui-col-xl9,\n .layui-col-xl10,\n .layui-col-xl11,\n .layui-col-xl12 {\n float: left;\n }\n .layui-col-xl1 {\n width: 8.33333333%;\n }\n .layui-col-xl2 {\n width: 16.66666667%;\n }\n .layui-col-xl3 {\n width: 25%;\n }\n .layui-col-xl4 {\n width: 33.33333333%;\n }\n .layui-col-xl5 {\n width: 41.66666667%;\n }\n .layui-col-xl6 {\n width: 50%;\n }\n .layui-col-xl7 {\n width: 58.33333333%;\n }\n .layui-col-xl8 {\n width: 66.66666667%;\n }\n .layui-col-xl9 {\n width: 75%;\n }\n .layui-col-xl10 {\n width: 83.33333333%;\n }\n .layui-col-xl11 {\n width: 91.66666667%;\n }\n .layui-col-xl12 {\n width: 100%;\n }\n /* 列偏移 */\n .layui-col-xl-offset1 {\n margin-left: 8.33333333%;\n }\n .layui-col-xl-offset2 {\n margin-left: 16.66666667%;\n }\n .layui-col-xl-offset3 {\n margin-left: 25%;\n }\n .layui-col-xl-offset4 {\n margin-left: 33.33333333%;\n }\n .layui-col-xl-offset5 {\n margin-left: 41.66666667%;\n }\n .layui-col-xl-offset6 {\n margin-left: 50%;\n }\n .layui-col-xl-offset7 {\n margin-left: 58.33333333%;\n }\n .layui-col-xl-offset8 {\n margin-left: 66.66666667%;\n }\n .layui-col-xl-offset9 {\n margin-left: 75%;\n }\n .layui-col-xl-offset10 {\n margin-left: 83.33333333%;\n }\n .layui-col-xl-offset11 {\n margin-left: 91.66666667%;\n }\n .layui-col-xl-offset12 {\n margin-left: 100%;\n }\n}\n\n/* 列间隔 */\n.layui-col-space1 {\n margin: -0.5px;\n}\n.layui-col-space1 > * {\n padding: 0.5px;\n}\n.layui-col-space2 {\n margin: -1px;\n}\n.layui-col-space2 > * {\n padding: 1px;\n}\n.layui-col-space4 {\n margin: -2px;\n}\n.layui-col-space4 > * {\n padding: 2px;\n}\n.layui-col-space5 {\n margin: -2.5px;\n}\n.layui-col-space5 > * {\n padding: 2.5px;\n}\n.layui-col-space6 {\n margin: -3px;\n}\n.layui-col-space6 > * {\n padding: 3px;\n}\n.layui-col-space8 {\n margin: -4px;\n}\n.layui-col-space8 > * {\n padding: 4px;\n}\n.layui-col-space10 {\n margin: -5px;\n}\n.layui-col-space10 > * {\n padding: 5px;\n}\n.layui-col-space12 {\n margin: -6px;\n}\n.layui-col-space12 > * {\n padding: 6px;\n}\n.layui-col-space14 {\n margin: -7px;\n}\n.layui-col-space14 > * {\n padding: 7px;\n}\n.layui-col-space15 {\n margin: -7.5px;\n}\n.layui-col-space15 > * {\n padding: 7.5px;\n}\n.layui-col-space16 {\n margin: -8px;\n}\n.layui-col-space16 > * {\n padding: 8px;\n}\n.layui-col-space18 {\n margin: -9px;\n}\n.layui-col-space18 > * {\n padding: 9px;\n}\n.layui-col-space20 {\n margin: -10px;\n}\n.layui-col-space20 > * {\n padding: 10px;\n}\n.layui-col-space22 {\n margin: -11px;\n}\n.layui-col-space22 > * {\n padding: 11px;\n}\n.layui-col-space24 {\n margin: -12px;\n}\n.layui-col-space24 > * {\n padding: 12px;\n}\n.layui-col-space25 {\n margin: -12.5px;\n}\n.layui-col-space25 > * {\n padding: 12.5px;\n}\n.layui-col-space26 {\n margin: -13px;\n}\n.layui-col-space26 > * {\n padding: 13px;\n}\n.layui-col-space28 {\n margin: -14px;\n}\n.layui-col-space28 > * {\n padding: 14px;\n}\n.layui-col-space30 {\n margin: -15px;\n}\n.layui-col-space30 > * {\n padding: 15px;\n}\n.layui-col-space32 {\n margin: -16px;\n}\n.layui-col-space32 > * {\n padding: 16px;\n}\n\n/*\n * 内边距\n */\n.layui-padding-1 {\n padding: var(--lay-spacing-xs) !important;\n}\n.layui-padding-2 {\n padding: var(--lay-spacing-sm) !important;\n}\n.layui-padding-3 {\n padding: var(--lay-spacing) !important;\n}\n.layui-padding-4 {\n padding: var(--lay-spacing-lg) !important;\n}\n.layui-padding-5 {\n padding: var(--lay-spacing-xl) !important;\n}\n\n/*\n * 外边距\n */\n.layui-margin-1 {\n margin: var(--lay-spacing-xs) !important;\n}\n.layui-margin-2 {\n margin: var(--lay-spacing-sm) !important;\n}\n.layui-margin-3 {\n margin: var(--lay-spacing) !important;\n}\n.layui-margin-4 {\n margin: var(--lay-spacing-lg) !important;\n}\n.layui-margin-5 {\n margin: var(--lay-spacing-xl) !important;\n}\n","/*\r\n * 辅助类\r\n */\r\n\r\n.layui-btn,\r\n.layui-input,\r\n.layui-select,\r\n.layui-textarea,\r\n.layui-upload-button {\r\n outline: none;\r\n -webkit-appearance: none;\r\n -moz-appearance: none;\r\n appearance: none;\r\n -webkit-transition: all 0.3s;\r\n transition: all 0.3s;\r\n box-sizing: border-box;\r\n}\r\n\r\n/* 引用 */\r\n.layui-elem-quote {\r\n margin-bottom: 10px;\r\n padding: var(--lay-spacing);\r\n line-height: 1.8;\r\n border-left: 5px solid var(--lay-color-accent);\r\n border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0;\r\n background-color: var(--lay-color-gray);\r\n}\r\n.layui-quote-nm {\r\n border-style: solid;\r\n border-width: 1px;\r\n border-left-width: 5px;\r\n background: none;\r\n}\r\n\r\n/* 字段集合 */\r\n.layui-elem-field {\r\n margin-bottom: 10px;\r\n padding: 0;\r\n border-width: 1px;\r\n border-style: solid;\r\n}\r\n.layui-elem-field legend {\r\n margin-left: 20px;\r\n padding: 0 10px;\r\n font-size: 20px;\r\n}\r\n.layui-field-title {\r\n margin: var(--lay-spacing) 0;\r\n border-width: 0;\r\n border-top-width: 1px;\r\n}\r\n.layui-field-box {\r\n padding: var(--lay-spacing);\r\n}\r\n.layui-field-title .layui-field-box {\r\n padding: 10px 0;\r\n}\r\n\r\n/* 其它辅助 */\r\n.layui-auxiliar-moving {\r\n position: fixed;\r\n left: 0;\r\n right: 0;\r\n top: 0;\r\n bottom: 0;\r\n width: 100%;\r\n height: 100%;\r\n background: none;\r\n z-index: 9999999999;\r\n -moz-user-select: none;\r\n -webkit-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n.layui-scrollbar-hide {\r\n overflow: hidden !important;\r\n}\r\n","/* 进度条 */\r\n.layui-progress {\r\n position: relative;\r\n height: 6px;\r\n border-radius: 20px;\r\n background-color: var(--lay-gray-300);\r\n}\r\n.layui-progress-bar {\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n width: 0;\r\n max-width: 100%;\r\n height: 6px;\r\n border-radius: 20px;\r\n text-align: right;\r\n background-color: var(--lay-color-accent);\r\n -webkit-transition: all 0.3s;\r\n transition: all 0.3s;\r\n}\r\n.layui-progress-big,\r\n.layui-progress-big .layui-progress-bar {\r\n height: 18px;\r\n line-height: 18px;\r\n}\r\n.layui-progress-text {\r\n position: relative;\r\n top: -20px;\r\n line-height: 18px;\r\n font-size: 12px;\r\n color: #5f5f5f;\r\n}\r\n.layui-progress-big .layui-progress-text {\r\n position: static;\r\n padding: 0 10px;\r\n color: #fff;\r\n}\r\n","/*\r\n * 面板\r\n */\r\n\r\n/* 折叠面板 */\r\n.layui-collapse {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-radius: var(--lay-border-radius);\r\n}\r\n.layui-colla-item,\r\n.layui-colla-content {\r\n border-top-width: 1px;\r\n border-top-style: solid;\r\n}\r\n.layui-colla-item:first-child {\r\n border-top: none;\r\n}\r\n.layui-colla-title {\r\n position: relative;\r\n height: 42px;\r\n line-height: 42px;\r\n padding: 0 15px 0 35px;\r\n color: #333;\r\n background-color: var(--lay-color-gray);\r\n cursor: pointer;\r\n font-size: 14px;\r\n overflow: hidden;\r\n}\r\n.layui-colla-content {\r\n display: none;\r\n padding: 10px 15px;\r\n line-height: 1.6;\r\n color: #5f5f5f;\r\n}\r\n.layui-colla-icon {\r\n position: absolute;\r\n left: 15px;\r\n top: 50%;\r\n margin-top: -7px;\r\n font-size: 14px;\r\n line-height: normal;\r\n transition: all 0.2s;\r\n}\r\n.layui-colla-item.layui-show > .layui-colla-title .layui-colla-icon {\r\n transform: rotate(90deg);\r\n}\r\n.layui-colla-item.layui-show > .layui-colla-content {\r\n display: block;\r\n}\r\n\r\n/* 卡片面板 */\r\n.layui-card {\r\n margin-bottom: 15px;\r\n border-radius: var(--lay-border-radius);\r\n background-color: #fff;\r\n box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05);\r\n}\r\n.layui-card:last-child {\r\n margin-bottom: 0;\r\n}\r\n.layui-card-header,\r\n.layui-card-body {\r\n position: relative;\r\n padding: 10px 15px;\r\n}\r\n.layui-card-header {\r\n border-bottom: 1px solid #f8f8f8;\r\n color: #333;\r\n border-radius: var(--lay-border-radius) 2px 0 0;\r\n font-size: 14px;\r\n}\r\n.layui-card-body .layui-table {\r\n margin: 5px 0;\r\n}\r\n.layui-card .layui-tab {\r\n margin: 0;\r\n}\r\n\r\n/* 常规面板 */\r\n.layui-panel {\r\n position: relative;\r\n border-width: 1px;\r\n border-style: solid;\r\n border-radius: var(--lay-border-radius);\r\n box-shadow: 1px 1px 4px rgb(0 0 0 / 8%);\r\n background-color: #fff;\r\n color: #5f5f5f;\r\n}\r\n\r\n/* 窗口面板 */\r\n.layui-panel-window {\r\n position: relative;\r\n padding: 15px;\r\n border-radius: 0;\r\n border-top: 5px solid var(--lay-border-color);\r\n background-color: #fff;\r\n}\r\n","/*\r\n * 默认主题\r\n */\r\n\r\n/* 背景颜色 */\r\n.layui-bg-red {\r\n background-color: var(--lay-color-red) !important;\r\n color: #fff !important;\r\n} /*赤*/\r\n.layui-bg-orange {\r\n background-color: var(--lay-color-orange) !important;\r\n color: #fff !important;\r\n} /*橙*/\r\n.layui-bg-green {\r\n background-color: var(--lay-color-primary) !important;\r\n color: #fff !important;\r\n} /*绿*/\r\n.layui-bg-cyan {\r\n background-color: #2f4056 !important;\r\n color: #fff !important;\r\n} /*藏青*/\r\n.layui-bg-blue {\r\n background-color: var(--lay-color-blue) !important;\r\n color: #fff !important;\r\n} /*蓝*/\r\n.layui-bg-purple {\r\n background-color: var(--lay-color-purple) !important;\r\n color: #fff !important;\r\n} /*紫*/\r\n.layui-bg-black {\r\n background-color: var(--lay-color-black) !important;\r\n color: #fff !important;\r\n} /*深*/\r\n.layui-bg-gray {\r\n background-color: var(--lay-color-gray) !important;\r\n color: #5f5f5f !important;\r\n} /*浅*/\r\n\r\n/* 边框 */\r\n.layui-border,\r\n.layui-quote-nm,\r\n.layui-elem-field,\r\n.layui-collapse,\r\n.layui-panel,\r\n.layui-colla-item,\r\n.layui-colla-content,\r\n.layui-badge-rim,\r\n.layui-tab-title,\r\n.layui-tab-title .layui-this:after,\r\n.layui-tab-bar,\r\n.layui-tab-card,\r\n.layui-input,\r\n.layui-textarea,\r\n.layui-select,\r\n.layui-input-split,\r\n.layui-form-pane .layui-form-label,\r\n.layui-form-pane .layui-form-item[pane] {\r\n border-color: var(--lay-border-color);\r\n}\r\n\r\n.layui-border {\r\n border-width: 1px;\r\n border-style: solid;\r\n color: #5f5f5f !important;\r\n}\r\n.layui-border-red {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: var(--lay-color-red) !important;\r\n color: var(--lay-color-red) !important;\r\n}\r\n.layui-border-orange {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: var(--lay-color-orange) !important;\r\n color: var(--lay-color-orange) !important;\r\n}\r\n.layui-border-green {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: var(--lay-color-primary) !important;\r\n color: var(--lay-color-primary) !important;\r\n}\r\n.layui-border-cyan {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: #2f4056 !important;\r\n color: #2f4056 !important;\r\n}\r\n.layui-border-blue {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: var(--lay-color-blue) !important;\r\n color: var(--lay-color-blue) !important;\r\n}\r\n.layui-border-purple {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: var(--lay-color-purple) !important;\r\n color: var(--lay-color-purple) !important;\r\n}\r\n.layui-border-black {\r\n border-width: 1px;\r\n border-style: solid;\r\n border-color: var(--lay-color-black) !important;\r\n color: var(--lay-color-black) !important;\r\n}\r\n\r\n/* 分割线边框 */\r\nhr.layui-border-red,\r\nhr.layui-border-orange,\r\nhr.layui-border-green,\r\nhr.layui-border-cyan,\r\nhr.layui-border-blue,\r\nhr.layui-border-purple,\r\nhr.layui-border-black {\r\n border-width: 0 0 1px;\r\n}\r\n\r\n/* 背景边框 */\r\n.layui-timeline-item:before {\r\n background-color: var(--lay-gray-300);\r\n}\r\n","/* 文本区域 */\n.layui-text {\n line-height: 1.8;\n font-size: 14px;\n}\n.layui-text h1 {\n margin: 32px 0;\n font-size: 32px;\n}\n.layui-text h2 {\n margin: 24px 0;\n font-size: 24px;\n}\n.layui-text h3 {\n margin: 16px 0;\n font-size: 18px;\n}\n.layui-text h4 {\n margin: 11px 0;\n font-size: 16px;\n}\n.layui-text h5 {\n margin: 11px 0;\n font-size: 14px;\n}\n.layui-text h6 {\n margin: 11px 0;\n font-size: 13px;\n}\n.layui-text p {\n margin: 15px 0;\n}\n.layui-text p:first-child {\n margin-top: 0;\n}\n.layui-text p:last-child {\n margin-bottom: 0;\n}\n.layui-text hr {\n margin: 15px 0;\n}\n.layui-text ul,\n.layui-text ol {\n padding-left: 15px;\n}\n.layui-text ul li {\n margin-top: 5px;\n list-style-type: disc;\n}\n.layui-text ol li {\n margin-top: 5px;\n list-style-type: decimal;\n}\n.layui-text ul ul > li,\n.layui-text ol ul > li {\n list-style-type: disc;\n}\n.layui-text ul li > p:first-child,\n.layui-text ol li > p:first-child {\n margin-top: 0;\n margin-bottom: 0;\n}\n.layui-text :where(a:not(.layui-btn)) {\n color: #01aaed;\n}\n.layui-text :where(a:not(.layui-btn):hover) {\n text-decoration: underline;\n}\n.layui-text blockquote:not(.layui-elem-quote) {\n margin: 15px 0;\n padding: 5px 15px;\n border-left: 5px solid var(--lay-border-color);\n}\n.layui-text pre > code:not(.layui-code) {\n display: block;\n padding: 15px;\n font-family: 'Courier New', Consolas, 'Lucida Console', monospace;\n}\n\n/* 文本区域辅助 */\n.layui-text-em,\n.layui-word-aux {\n color: #999 !important;\n padding-left: 5px !important;\n padding-right: 5px !important;\n}\n\n/* 字体大小 */\n.layui-font-12 {\n font-size: 12px !important;\n}\n.layui-font-13 {\n font-size: 13px !important;\n}\n.layui-font-14 {\n font-size: 14px !important;\n}\n.layui-font-16 {\n font-size: 16px !important;\n}\n.layui-font-18 {\n font-size: 18px !important;\n}\n.layui-font-20 {\n font-size: 20px !important;\n}\n.layui-font-22 {\n font-size: 22px !important;\n}\n.layui-font-24 {\n font-size: 24px !important;\n}\n.layui-font-26 {\n font-size: 26px !important;\n}\n.layui-font-28 {\n font-size: 28px !important;\n}\n.layui-font-30 {\n font-size: 30px !important;\n}\n.layui-font-32 {\n font-size: 32px !important;\n}\n\n/* 字体颜色 */\n.layui-font-red {\n color: var(--lay-color-red) !important;\n} /*赤*/\n.layui-font-orange {\n color: var(--lay-color-orange) !important;\n} /*橙*/\n.layui-font-green {\n color: var(--lay-color-primary) !important;\n} /*绿*/\n.layui-font-cyan {\n color: #2f4056 !important;\n} /*藏青*/\n.layui-font-blue {\n color: #01aaed !important;\n} /*蓝*/\n.layui-font-purple {\n color: var(--lay-color-purple) !important;\n} /*紫*/\n.layui-font-black {\n color: #000 !important;\n} /*深*/\n.layui-font-gray {\n color: #c2c2c2 !important;\n} /*浅*/\n","/*\r\n * 按钮\r\n */\r\n\r\n.layui-btn {\r\n display: inline-block;\r\n vertical-align: middle;\r\n height: 38px;\r\n line-height: 36px;\r\n border: 1px solid transparent;\r\n padding: 0 18px;\r\n background-color: var(--lay-color-primary);\r\n color: #fff;\r\n white-space: nowrap;\r\n text-align: center;\r\n font-size: 14px;\r\n border-radius: var(--lay-border-radius);\r\n cursor: pointer;\r\n -webkit-user-select: none;\r\n -moz-user-select: none;\r\n -ms-user-select: none;\r\n user-select: none;\r\n}\r\n.layui-btn:hover {\r\n opacity: 0.8;\r\n filter: alpha(opacity=80);\r\n color: #fff;\r\n}\r\n.layui-btn:active {\r\n opacity: 1;\r\n filter: alpha(opacity=100);\r\n}\r\n.layui-btn + .layui-btn {\r\n margin-left: 10px;\r\n}\r\n\r\n/* 按钮容器 */\r\n.layui-btn-container {\r\n word-spacing: -5px;\r\n}\r\n.layui-btn-container .layui-btn {\r\n margin-right: 10px;\r\n margin-bottom: 10px;\r\n word-spacing: normal;\r\n}\r\n.layui-btn-container .layui-btn + .layui-btn {\r\n margin-left: 0;\r\n}\r\n.layui-table .layui-btn-container .layui-btn {\r\n margin-bottom: 9px;\r\n}\r\n\r\n/* 圆角 */\r\n.layui-btn-radius {\r\n border-radius: 100px;\r\n}\r\n.layui-btn .layui-icon {\r\n padding: 0 2px;\r\n vertical-align: middle\\0;\r\n vertical-align: bottom;\r\n}\r\n\r\n/* 原始 */\r\n.layui-btn-primary {\r\n border-color: var(--lay-border-color-accent);\r\n background: none;\r\n color: #5f5f5f;\r\n}\r\n.layui-btn-primary:hover {\r\n border-color: var(--lay-color-primary);\r\n color: #333;\r\n}\r\n/* 百搭 */\r\n.layui-btn-normal {\r\n background-color: var(--lay-color-blue);\r\n}\r\n/* 暖色 */\r\n.layui-btn-warm {\r\n background-color: var(--lay-color-orange);\r\n}\r\n/* 警告 */\r\n.layui-btn-danger {\r\n background-color: var(--lay-color-red);\r\n}\r\n/* 选中 */\r\n.layui-btn-checked {\r\n background-color: var(--lay-color-accent);\r\n}\r\n/* 禁用 */\r\n.layui-btn-disabled,\r\n.layui-btn-disabled:hover,\r\n.layui-btn-disabled:active {\r\n border-color: var(--lay-border-color) !important;\r\n background-color: #fbfbfb !important;\r\n color: var(--lay-gray-400) !important;\r\n cursor: not-allowed !important;\r\n opacity: 1;\r\n}\r\n\r\n/* 大型 */\r\n.layui-btn-lg {\r\n height: 44px;\r\n line-height: 44px;\r\n padding: 0 25px;\r\n font-size: 16px;\r\n}\r\n/* 小型 */\r\n.layui-btn-sm {\r\n height: 30px;\r\n line-height: 30px;\r\n padding: 0 10px;\r\n font-size: 12px;\r\n}\r\n/* 超小 */\r\n.layui-btn-xs {\r\n height: 22px;\r\n line-height: 22px;\r\n padding: 0 5px;\r\n font-size: 12px;\r\n}\r\n.layui-btn-xs i {\r\n font-size: 12px !important;\r\n}\r\n/* 按钮组 */\r\n.layui-btn-group {\r\n display: inline-block;\r\n vertical-align: middle;\r\n font-size: 0;\r\n}\r\n.layui-btn-group .layui-btn {\r\n margin-left: 0 !important;\r\n margin-right: 0 !important;\r\n border-left: 1px solid rgba(255, 255, 255, 0.5);\r\n border-radius: 0;\r\n}\r\n.layui-btn-group .layui-btn-primary {\r\n border-left: none;\r\n}\r\n.layui-btn-group .layui-btn-primary:hover {\r\n border-color: var(--lay-border-color-accent);\r\n color: var(--lay-color-primary);\r\n}\r\n.layui-btn-group .layui-btn:first-child {\r\n border-left: none;\r\n border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius);\r\n}\r\n.layui-btn-group .layui-btn-primary:first-child {\r\n border-left: 1px solid var(--lay-gray-400);\r\n}\r\n.layui-btn-group .layui-btn:last-child {\r\n border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0;\r\n}\r\n.layui-btn-group .layui-btn + .layui-btn {\r\n margin-left: 0;\r\n}\r\n.layui-btn-group + .layui-btn-group {\r\n margin-left: 10px;\r\n}\r\n/* 流体 */\r\n.layui-btn-fluid {\r\n width: 100%;\r\n}\r\n","/** 表单 **/\n.layui-input,\n.layui-textarea,\n.layui-select {\n height: 38px;\n line-height: 1.3;\n line-height: 38px\\9;\n border-width: 1px;\n border-style: solid;\n background-color: #fff;\n color: rgba(0, 0, 0, 0.85);\n border-radius: var(--lay-border-radius);\n}\n.layui-input::-webkit-input-placeholder,\n.layui-textarea::-webkit-input-placeholder,\n.layui-select::-webkit-input-placeholder {\n line-height: 1.3;\n}\n.layui-input,\n.layui-textarea {\n display: block;\n width: 100%;\n padding-left: 10px;\n}\n.layui-input:hover,\n.layui-textarea:hover {\n border-color: var(--lay-border-color-accent) !important;\n}\n.layui-input:focus,\n.layui-textarea:focus {\n border-color: var(--lay-color-accent) !important;\n box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08);\n}\n.layui-textarea {\n position: relative;\n min-height: 100px;\n height: auto;\n line-height: 20px;\n padding: 6px 10px;\n resize: vertical;\n}\n.layui-input[disabled],\n.layui-textarea[disabled] {\n background-color: var(--lay-color-gray);\n}\n.layui-select {\n padding: 0 10px;\n}\n.layui-form select,\n.layui-form input[type='checkbox'],\n.layui-form input[type='radio'] {\n display: none;\n}\n.layui-form *[lay-ignore] {\n display: initial;\n}\n\n.layui-form-item {\n position: relative;\n margin-bottom: 15px;\n clear: both;\n}\n.layui-form-item:after {\n content: '\\20';\n clear: both;\n display: block;\n height: 0;\n}\n.layui-form-label {\n position: relative;\n float: left;\n display: block;\n padding: 9px 15px;\n width: 80px;\n font-weight: 400;\n line-height: 20px;\n text-align: right;\n}\n.layui-form-label-col {\n display: block;\n float: none;\n padding: 9px 0;\n line-height: 20px;\n text-align: left;\n}\n.layui-form-item .layui-inline {\n margin-bottom: 5px;\n margin-right: 10px;\n}\n.layui-input-block,\n.layui-input-inline {\n position: relative;\n}\n.layui-input-block {\n margin-left: 110px;\n min-height: 36px;\n}\n.layui-input-inline {\n display: inline-block;\n vertical-align: middle;\n}\n.layui-form-item .layui-input-inline {\n float: left;\n width: 190px;\n margin-right: 10px;\n}\n.layui-form-text .layui-input-inline {\n width: auto;\n}\n\n/* 分割块 */\n.layui-form-mid {\n position: relative;\n float: left;\n display: block;\n padding: 9px 0 !important;\n line-height: 20px;\n margin-right: 10px;\n}\n\n/* 警告条 */\n.layui-form-danger:focus,\n.layui-form-danger + .layui-form-select .layui-input {\n border-color: var(--lay-color-red) !important;\n box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08);\n}\n\n/* 输入框点缀 */\n.layui-input-prefix,\n.layui-input-suffix,\n.layui-input-split,\n.layui-input-suffix .layui-input-affix {\n position: absolute;\n right: 0;\n top: 0;\n padding: 0 10px;\n width: 35px;\n height: 100%;\n text-align: center;\n transition: all 0.3s;\n box-sizing: border-box;\n}\n.layui-input-prefix {\n left: 0;\n border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius);\n}\n.layui-input-suffix {\n right: 0;\n border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0;\n}\n.layui-input-split {\n border-width: 1px;\n border-style: solid;\n}\n.layui-input-prefix .layui-icon,\n.layui-input-suffix .layui-icon,\n.layui-input-split .layui-icon {\n position: relative;\n font-size: 16px;\n color: #5f5f5f;\n transition: all 0.3s;\n}\n\n/* 输入框前后置容器 */\n.layui-input-group {\n position: relative;\n display: table;\n box-sizing: border-box;\n}\n.layui-input-group > * {\n display: table-cell;\n vertical-align: middle;\n position: relative;\n}\n.layui-input-group .layui-input {\n padding-right: 15px;\n}\n.layui-input-group > .layui-input-prefix {\n width: auto;\n border-right: 0;\n}\n.layui-input-group > .layui-input-suffix {\n width: auto;\n border-left: 0;\n}\n.layui-input-group .layui-input-split {\n white-space: nowrap;\n}\n\n/* 输入框前后缀容器 */\n.layui-input-wrap {\n position: relative;\n line-height: 38px;\n}\n.layui-input-wrap .layui-input {\n padding-right: 35px;\n}\n.layui-input-wrap .layui-input::-ms-clear,\n.layui-input-wrap .layui-input::-ms-reveal {\n display: none;\n}\n.layui-input-wrap .layui-input-prefix + .layui-input,\n.layui-input-wrap .layui-input-prefix ~ * .layui-input {\n padding-left: 35px;\n}\n.layui-input-wrap .layui-input-split + .layui-input,\n.layui-input-wrap .layui-input-split ~ * .layui-input {\n padding-left: 45px;\n}\n.layui-input-wrap .layui-input-prefix ~ .layui-form-select {\n position: static;\n}\n.layui-input-wrap .layui-input-prefix,\n.layui-input-wrap .layui-input-suffix,\n.layui-input-wrap .layui-input-split {\n pointer-events: none;\n}\n.layui-input-wrap .layui-input:hover + .layui-input-split {\n border-color: var(--lay-border-color-accent);\n}\n.layui-input-wrap .layui-input:focus + .layui-input-split {\n border-color: var(--lay-color-accent);\n}\n.layui-input-wrap .layui-input.layui-form-danger:focus + .layui-input-split {\n border-color: var(--lay-color-red);\n}\n.layui-input-wrap .layui-input-prefix.layui-input-split {\n border-width: 0;\n border-right-width: 1px;\n}\n.layui-input-wrap .layui-input-suffix.layui-input-split {\n border-width: 0;\n border-left-width: 1px;\n}\n\n/* 输入框动态点缀 */\n.layui-input-affix {\n line-height: 38px;\n}\n.layui-input-suffix .layui-input-affix {\n right: auto;\n left: -35px;\n}\n.layui-input-affix .layui-icon {\n color: rgba(0, 0, 0, 0.8);\n pointer-events: auto !important;\n cursor: pointer;\n}\n.layui-input-affix .layui-icon-clear {\n color: rgba(0, 0, 0, 0.3);\n}\n.layui-input-affix .layui-icon:hover {\n color: rgba(0, 0, 0, 0.6);\n}\n\n/* 数字输入框动态点缀 */\n.layui-input-wrap .layui-input-number {\n width: 24px;\n padding: 0;\n}\n.layui-input-wrap .layui-input-number .layui-icon {\n position: absolute;\n right: 0;\n width: 100%;\n height: 50%;\n line-height: normal;\n font-size: 12px;\n}\n.layui-input-wrap .layui-input-number .layui-icon:before {\n position: absolute;\n left: 50%;\n top: 50%;\n margin-top: -6px;\n margin-left: -6px;\n}\n.layui-input-wrap .layui-input-number .layui-icon-up {\n top: 0;\n border-bottom: 1px solid var(--lay-border-color);\n}\n.layui-input-wrap .layui-input-number .layui-icon-down {\n bottom: 0;\n}\n.layui-input-wrap .layui-input-number .layui-icon:hover {\n font-weight: 700;\n}\n.layui-input-wrap .layui-input[type='number']::-webkit-outer-spin-button,\n.layui-input-wrap .layui-input[type='number']::-webkit-inner-spin-button {\n -webkit-appearance: none !important;\n}\n.layui-input-wrap .layui-input[type='number'] {\n -moz-appearance: textfield;\n -webkit-appearance: textfield;\n appearance: textfield;\n}\n.layui-input-wrap .layui-input.layui-input-number-out-of-range,\n.layui-input-wrap .layui-input.layui-input-number-invalid {\n color: var(--lay-color-red);\n}\n\n/* 下拉选择 */\n.layui-form-select {\n position: relative;\n color: #5f5f5f;\n}\n.layui-form-select .layui-input {\n padding-right: 30px;\n cursor: pointer;\n}\n.layui-form-select .layui-edge {\n position: absolute;\n right: 10px;\n top: 50%;\n margin-top: -3px;\n cursor: pointer;\n border-width: 6px;\n border-top-color: #c2c2c2;\n border-top-style: solid;\n -webkit-transition: all 0.3s;\n transition: all 0.3s;\n}\n.layui-form-select dl {\n display: none;\n position: absolute;\n left: 0;\n top: 42px;\n padding: 5px 0;\n z-index: 899;\n min-width: 100%;\n border: 1px solid var(--lay-border-color);\n max-height: 300px;\n overflow-y: auto;\n background-color: #fff;\n border-radius: var(--lay-border-radius);\n box-shadow: 1px 1px 4px rgb(0 0 0 / 8%);\n box-sizing: border-box;\n}\n.layui-form-select dl dt,\n.layui-form-select dl dd {\n padding: 0 10px;\n line-height: 36px;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.layui-form-select dl dt {\n font-size: 12px;\n color: #999;\n}\n.layui-form-select dl dd {\n cursor: pointer;\n}\n.layui-form-select dl dd:hover {\n background-color: #f8f8f8;\n -webkit-transition: 0.5s all;\n transition: 0.5s all;\n}\n.layui-form-select .layui-select-group dd {\n padding-left: 20px;\n}\n.layui-form-select dl dd.layui-select-tips {\n padding-left: 10px !important;\n color: #999;\n}\n.layui-form-select dl dd.layui-this {\n background-color: #f8f8f8;\n color: var(--lay-color-accent);\n font-weight: 700;\n}\n/*.layui-form-select dl dd.layui-this{background-color: #f8f8f8; color: var(--lay-color-accent); font-weight: 700;}*/\n.layui-form-select dl dd.layui-disabled {\n background-color: #fff;\n}\n.layui-form-selected dl {\n display: block;\n}\n.layui-form-selected .layui-edge {\n margin-top: -9px;\n -webkit-transform: rotate(180deg);\n transform: rotate(180deg);\n}\n.layui-form-selected .layui-edge {\n margin-top: -3px\\0;\n}\n:root .layui-form-selected .layui-edge {\n margin-top: -9px\\0 / IE9;\n}\n.layui-form-selectup dl {\n top: auto;\n bottom: 42px;\n}\n.layui-select-none {\n margin: 5px 0;\n text-align: center;\n color: #999;\n}\n.layui-select-panel-wrap {\n position: absolute;\n z-index: 99999999;\n}\n.layui-select-panel-wrap dl {\n position: relative;\n display: block;\n top: 0;\n}\n\n.layui-select-disabled .layui-disabled {\n border-color: var(--lay-border-color) !important;\n}\n.layui-select-disabled .layui-edge {\n border-top-color: var(--lay-border-color-accent);\n}\n\n/* 复选框 */\n.layui-form-checkbox {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n height: 30px;\n line-height: 30px;\n margin-right: 10px;\n padding-right: 30px;\n background-color: #fff;\n cursor: pointer;\n font-size: 0;\n -webkit-transition: 0.1s linear;\n transition: 0.1s linear;\n box-sizing: border-box;\n}\n.layui-form-checkbox > * {\n display: inline-block;\n vertical-align: middle;\n}\n.layui-form-checkbox > div {\n padding: 0 11px;\n font-size: 14px;\n border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius);\n background-color: var(--lay-gray-400);\n color: #fff;\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n}\n.layui-form-checkbox > div > .layui-icon {\n line-height: normal;\n}\n.layui-form-checkbox:hover > div {\n background-color: #c2c2c2;\n}\n.layui-form-checkbox > i {\n position: absolute;\n right: 0;\n top: 0;\n width: 30px;\n height: 100%;\n border: 1px solid var(--lay-border-color-accent);\n border-left: none;\n border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0;\n color: #fff;\n color: rgba(255, 255, 255, 0);\n font-size: 20px;\n text-align: center;\n box-sizing: border-box;\n}\n.layui-form-checkbox:hover > i {\n border-color: #c2c2c2;\n color: #c2c2c2;\n}\n.layui-form-checked,\n.layui-form-checked:hover {\n border-color: var(--lay-color-accent);\n}\n.layui-form-checked > div,\n.layui-form-checked:hover > div {\n background-color: var(--lay-color-accent);\n}\n.layui-form-checked > i,\n.layui-form-checked:hover > i {\n color: var(--lay-color-accent);\n}\n.layui-form-item .layui-form-checkbox {\n margin-top: 4px;\n}\n.layui-form-checkbox.layui-checkbox-disabled > div {\n background-color: var(--lay-gray-300) !important;\n}\n.layui-form *[lay-checkbox] {\n display: none;\n}\n\n/* 复选框-默认风格 */\n.layui-form-checkbox[lay-skin='primary'] {\n height: auto !important;\n line-height: normal !important;\n min-width: 18px;\n min-height: 18px;\n border: none !important;\n margin-right: 0;\n padding-left: 24px;\n padding-right: 0;\n background: none;\n}\n.layui-form-checkbox[lay-skin='primary'] > div {\n margin-top: -1px;\n padding-left: 0;\n padding-right: 15px;\n line-height: 18px;\n background: none;\n color: #5f5f5f;\n}\n.layui-form-checkbox[lay-skin='primary'] > i {\n right: auto;\n left: 0;\n width: 16px;\n height: 16px;\n line-height: 14px;\n border: 1px solid #d2d2d2;\n font-size: 12px;\n border-radius: var(--lay-border-radius);\n background-color: #fff;\n -webkit-transition: 0.1s linear;\n transition: 0.1s linear;\n}\n.layui-form-checkbox[lay-skin='primary']:hover > i {\n border-color: var(--lay-color-accent);\n color: #fff;\n}\n.layui-form-checked[lay-skin='primary'] > i {\n border-color: var(--lay-color-accent) !important;\n background-color: var(--lay-color-accent);\n color: #fff;\n}\n.layui-checkbox-disabled[lay-skin='primary'] > div {\n background: none !important;\n}\n.layui-form-checked.layui-checkbox-disabled[lay-skin='primary'] > i {\n background: var(--lay-gray-300) !important;\n border-color: var(--lay-gray-300) !important;\n}\n.layui-checkbox-disabled[lay-skin='primary']:hover > i {\n border-color: var(--lay-border-color-accent);\n}\n.layui-form-item .layui-form-checkbox[lay-skin='primary'] {\n margin-top: 10px;\n}\n.layui-form-checkbox[lay-skin='primary'] > .layui-icon-indeterminate {\n border-color: var(--lay-color-accent);\n background-color: #fff;\n}\n.layui-form-checkbox[lay-skin='primary'] > .layui-icon-indeterminate:before {\n content: '';\n display: inline-block;\n vertical-align: middle;\n position: relative;\n width: 50%;\n height: 1px;\n margin: -1px auto 0;\n background-color: var(--lay-color-accent);\n}\n\n/* 复选框-开关风格 */\n.layui-form-switch {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n height: 24px;\n line-height: 22px;\n min-width: 44px;\n padding: 0 5px;\n margin-top: 8px;\n border: 1px solid #d2d2d2;\n border-radius: 20px;\n cursor: pointer;\n box-sizing: border-box;\n background-color: #fff;\n -webkit-transition: 0.1s linear;\n transition: 0.1s linear;\n}\n.layui-form-switch > i {\n position: absolute;\n left: 5px;\n top: 3px;\n width: 16px;\n height: 16px;\n border-radius: 20px;\n background-color: var(--lay-gray-400);\n -webkit-transition: 0.1s linear;\n transition: 0.1s linear;\n}\n.layui-form-switch > div {\n position: relative;\n top: 0;\n margin-left: 21px;\n padding: 0 !important;\n text-align: center !important;\n color: #999 !important;\n font-style: normal !important;\n font-size: 12px;\n}\n.layui-form-onswitch {\n border-color: var(--lay-color-accent);\n background-color: var(--lay-color-accent);\n}\n.layui-form-onswitch > i {\n left: 100%;\n margin-left: -21px;\n background-color: #fff;\n}\n.layui-form-onswitch > div {\n margin-left: 0;\n margin-right: 21px;\n color: #fff !important;\n}\n\n/* 无样式风格-根据模板自定义样式*/\n.layui-form-checkbox[lay-skin='none'] *,\n.layui-form-radio[lay-skin='none'] * {\n box-sizing: border-box;\n}\n.layui-form-checkbox[lay-skin='none'],\n.layui-form-radio[lay-skin='none'] {\n position: relative;\n min-height: 20px;\n margin: 0;\n padding: 0;\n height: auto;\n line-height: normal;\n}\n.layui-form-checkbox[lay-skin='none'] > div,\n.layui-form-radio[lay-skin='none'] > div {\n position: relative;\n top: 0;\n left: 0;\n cursor: pointer;\n z-index: 10;\n color: inherit;\n background-color: inherit;\n}\n.layui-form-checkbox[lay-skin='none'] > i,\n.layui-form-radio[lay-skin='none'] > i {\n display: none;\n}\n.layui-form-checkbox[lay-skin='none'].layui-checkbox-disabled > div,\n.layui-form-radio[lay-skin='none'].layui-radio-disabled > div {\n cursor: not-allowed;\n}\n\n.layui-checkbox-disabled {\n border-color: var(--lay-border-color) !important;\n}\n.layui-checkbox-disabled > div {\n color: #c2c2c2 !important;\n}\n.layui-checkbox-disabled > i {\n border-color: var(--lay-border-color) !important;\n}\n.layui-checkbox-disabled:hover > i {\n color: #fff !important;\n}\n.layui-form-checkbox[lay-skin='tag'].layui-form-checked.layui-checkbox-disabled\n > i {\n color: #c2c2c2;\n}\n.layui-form-checkbox[lay-skin='tag'].layui-form-checked.layui-checkbox-disabled:hover\n > i {\n color: #c2c2c2 !important;\n}\n\n/* 单选框 */\n.layui-form-radio {\n display: inline-block;\n vertical-align: middle;\n line-height: 28px;\n margin: 6px 10px 0 0;\n padding-right: 10px;\n cursor: pointer;\n font-size: 0;\n}\n.layui-form-radio > * {\n display: inline-block;\n vertical-align: middle;\n font-size: 14px;\n}\n.layui-form-radio > i {\n margin-right: 8px;\n font-size: 22px;\n color: #c2c2c2;\n}\n.layui-form-radioed,\n.layui-form-radioed > i,\n.layui-form-radio:hover > * {\n color: var(--lay-color-accent);\n}\n.layui-radio-disabled > i {\n color: var(--lay-gray-300) !important;\n}\n.layui-radio-disabled > * {\n color: #c2c2c2 !important;\n}\n.layui-form *[lay-radio] {\n display: none;\n}\n\n/* 表单方框风格 */\n.layui-form-pane .layui-form-label {\n width: 110px;\n padding: 8px 15px;\n height: 38px;\n line-height: 20px;\n border-width: 1px;\n border-style: solid;\n border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius);\n text-align: center;\n background-color: var(--lay-color-gray);\n overflow: hidden;\n white-space: nowrap;\n text-overflow: ellipsis;\n box-sizing: border-box;\n}\n.layui-form-pane .layui-input-inline {\n margin-left: -1px;\n}\n.layui-form-pane .layui-input-block {\n margin-left: 110px;\n left: -1px;\n}\n.layui-form-pane .layui-input {\n border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0;\n}\n.layui-form-pane .layui-form-text .layui-form-label {\n float: none;\n width: 100%;\n border-radius: var(--lay-border-radius);\n box-sizing: border-box;\n text-align: left;\n}\n.layui-form-pane .layui-form-text .layui-input-inline {\n display: block;\n margin: 0;\n top: -1px;\n clear: both;\n}\n.layui-form-pane .layui-form-text .layui-input-block {\n margin: 0;\n left: 0;\n top: -1px;\n}\n.layui-form-pane .layui-form-text .layui-textarea {\n min-height: 100px;\n border-radius: 0 0 var(--lay-border-radius) var(--lay-border-radius);\n}\n.layui-form-pane .layui-form-checkbox {\n margin: 4px 0 4px 10px;\n}\n.layui-form-pane .layui-form-switch,\n.layui-form-pane .layui-form-radio {\n margin-top: 6px;\n margin-left: 10px;\n}\n.layui-form-pane .layui-form-item[pane] {\n position: relative;\n border-width: 1px;\n border-style: solid;\n}\n.layui-form-pane .layui-form-item[pane] .layui-form-label {\n position: absolute;\n left: 0;\n top: 0;\n height: 100%;\n border-width: 0px;\n border-right-width: 1px;\n}\n.layui-form-pane .layui-form-item[pane] .layui-input-inline {\n margin-left: 110px;\n}\n\n/** 表单响应式 **/\n@media screen and (max-width: 450px) {\n .layui-form-item .layui-form-label {\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n }\n .layui-form-item .layui-inline {\n display: block;\n margin-right: 0;\n margin-bottom: 20px;\n clear: both;\n }\n .layui-form-item .layui-inline:after {\n content: '\\20';\n clear: both;\n display: block;\n height: 0;\n }\n .layui-form-item .layui-input-inline {\n display: block;\n float: none;\n left: -3px;\n width: auto !important;\n margin: 0 0 10px 112px;\n }\n .layui-form-item .layui-input-inline + .layui-form-mid {\n margin-left: 110px;\n top: -5px;\n padding: 0;\n }\n .layui-form-item .layui-form-checkbox {\n margin-right: 5px;\n margin-bottom: 5px;\n }\n}\n","/** 分页 **/\r\n.layui-laypage {\r\n display: inline-block;\r\n vertical-align: middle;\r\n margin: 10px 0;\r\n font-size: 0;\r\n}\r\n.layui-laypage > a:first-child,\r\n.layui-laypage > a:first-child em {\r\n border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius);\r\n}\r\n.layui-laypage > a:last-child,\r\n.layui-laypage > a:last-child em {\r\n border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0;\r\n}\r\n.layui-laypage > *:first-child {\r\n margin-left: 0 !important;\r\n}\r\n.layui-laypage > *:last-child {\r\n margin-right: 0 !important;\r\n}\r\n.layui-laypage a,\r\n.layui-laypage span,\r\n.layui-laypage input,\r\n.layui-laypage button,\r\n.layui-laypage select {\r\n border: 1px solid var(--lay-border-color);\r\n}\r\n.layui-laypage a,\r\n.layui-laypage span {\r\n display: inline-block;\r\n vertical-align: middle;\r\n padding: 0 15px;\r\n height: 28px;\r\n line-height: 28px;\r\n margin: 0 -1px 5px 0;\r\n background-color: #fff;\r\n color: #333;\r\n font-size: 12px;\r\n}\r\n.layui-laypage a[data-page] {\r\n color: #333;\r\n}\r\n.layui-laypage a {\r\n text-decoration: none !important;\r\n cursor: pointer;\r\n}\r\n.layui-laypage a:hover {\r\n color: var(--lay-color-primary);\r\n}\r\n.layui-laypage em {\r\n font-style: normal;\r\n}\r\n.layui-laypage .layui-laypage-spr {\r\n color: #999;\r\n font-weight: 700;\r\n}\r\n.layui-laypage .layui-laypage-curr {\r\n position: relative;\r\n}\r\n.layui-laypage .layui-laypage-curr em {\r\n position: relative;\r\n color: #fff;\r\n}\r\n.layui-laypage .layui-laypage-curr .layui-laypage-em {\r\n position: absolute;\r\n left: -1px;\r\n top: -1px;\r\n padding: 1px;\r\n width: 100%;\r\n height: 100%;\r\n background-color: var(--lay-color-primary);\r\n}\r\n.layui-laypage-em {\r\n border-radius: var(--lay-border-radius);\r\n}\r\n.layui-laypage-prev em,\r\n.layui-laypage-next em {\r\n font-family: Sim sun;\r\n font-size: 16px;\r\n}\r\n\r\n.layui-laypage .layui-laypage-count,\r\n.layui-laypage .layui-laypage-limits,\r\n.layui-laypage .layui-laypage-refresh,\r\n.layui-laypage .layui-laypage-skip {\r\n margin-left: 10px;\r\n margin-right: 10px;\r\n padding: 0;\r\n border: none;\r\n}\r\n.layui-laypage .layui-laypage-limits,\r\n.layui-laypage .layui-laypage-refresh {\r\n vertical-align: top;\r\n}\r\n.layui-laypage .layui-laypage-refresh i {\r\n font-size: 18px;\r\n cursor: pointer;\r\n}\r\n.layui-laypage select {\r\n height: 22px;\r\n padding: 3px;\r\n border-radius: var(--lay-border-radius);\r\n cursor: pointer;\r\n}\r\n.layui-laypage .layui-laypage-skip {\r\n height: 30px;\r\n line-height: 30px;\r\n color: #999;\r\n}\r\n.layui-laypage input,\r\n.layui-laypage button {\r\n height: 30px;\r\n line-height: 30px;\r\n border-radius: var(--lay-border-radius);\r\n vertical-align: top;\r\n background-color: #fff;\r\n box-sizing: border-box;\r\n}\r\n.layui-laypage input {\r\n display: inline-block;\r\n width: 40px;\r\n margin: 0 10px;\r\n padding: 0 3px;\r\n text-align: center;\r\n transition: none;\r\n}\r\n.layui-laypage input:focus,\r\n.layui-laypage select:focus {\r\n border-color: var(--lay-color-primary) !important;\r\n}\r\n.layui-laypage button {\r\n margin-left: 10px;\r\n padding: 0 10px;\r\n cursor: pointer;\r\n}\r\n","/** 流加载 **/\r\n.layui-flow-more {\r\n margin: 10px 0;\r\n text-align: center;\r\n color: #999;\r\n font-size: 14px;\r\n clear: both;\r\n}\r\n.layui-flow-more a {\r\n height: 32px;\r\n line-height: 32px;\r\n}\r\n.layui-flow-more a * {\r\n display: inline-block;\r\n vertical-align: top;\r\n}\r\n.layui-flow-more a cite {\r\n padding: 0 20px;\r\n border-radius: var(--lay-border-radius);\r\n background-color: var(--lay-gray-300);\r\n color: #333;\r\n font-style: normal;\r\n}\r\n.layui-flow-more a cite:hover {\r\n opacity: 0.8;\r\n}\r\n.layui-flow-more a i {\r\n font-size: 30px;\r\n color: #737383;\r\n}\r\n","/** 表格 **/\n.layui-table {\n width: 100%;\n margin: 10px 0;\n background-color: #fff;\n color: #5f5f5f;\n}\n.layui-table tr {\n -webkit-transition: all 0.3s;\n transition: all 0.3s;\n}\n.layui-table th {\n text-align: left;\n font-weight: 600;\n}\n\n.layui-table-mend {\n background-color: #fff;\n}\n.layui-table-hover,\n.layui-table-click,\n.layui-table[lay-even] tbody tr:nth-child(even) {\n background-color: #f8f8f8;\n}\n.layui-table-checked {\n background-color: #dbfbf0;\n}\n.layui-table-checked.layui-table-hover,\n.layui-table-checked.layui-table-click,\n.layui-table[lay-even] tbody tr:nth-child(even).layui-table-checked {\n background-color: #abf8dd;\n}\n.layui-table-disabled-transition *,\n.layui-table-disabled-transition *:before,\n.layui-table-disabled-transition *:after {\n -webkit-transition: none !important;\n -moz-transition: none !important;\n -o-transition: none !important;\n -ms-transition: none !important;\n transition: none !important;\n}\n\n.layui-table th,\n.layui-table td,\n.layui-table[lay-skin='line'],\n.layui-table[lay-skin='row'],\n.layui-table-view,\n.layui-table-tool,\n.layui-table-header,\n.layui-table-col-set,\n.layui-table-total,\n.layui-table-page,\n.layui-table-fixed-r,\n.layui-table-mend,\n.layui-table-tips-main,\n.layui-table-grid-down {\n border-width: 1px;\n border-style: solid;\n border-color: var(--lay-border-color);\n}\n\n.layui-table th,\n.layui-table td {\n position: relative;\n padding: 9px 15px;\n min-height: 20px;\n line-height: 20px;\n font-size: 14px;\n}\n\n.layui-table[lay-skin='line'] th,\n.layui-table[lay-skin='line'] td {\n border-width: 0;\n border-bottom-width: 1px;\n}\n.layui-table[lay-skin='row'] th,\n.layui-table[lay-skin='row'] td {\n border-width: 0;\n border-right-width: 1px;\n}\n.layui-table[lay-skin='nob'] th,\n.layui-table[lay-skin='nob'] td {\n border: none;\n}\n\n.layui-table img {\n max-width: 100px;\n}\n\n/* 大表格 */\n.layui-table[lay-size='lg'] th,\n.layui-table[lay-size='lg'] td {\n padding-top: 15px;\n padding-right: 30px;\n padding-bottom: 15px;\n padding-left: 30px;\n}\n.layui-table-view .layui-table[lay-size='lg'] .layui-table-cell {\n height: 50px;\n line-height: 40px;\n}\n\n/* 小表格 */\n.layui-table[lay-size='sm'] th,\n.layui-table[lay-size='sm'] td {\n padding-top: 5px;\n padding-right: 10px;\n padding-bottom: 5px;\n padding-left: 10px;\n font-size: 12px;\n}\n.layui-table-view .layui-table[lay-size='sm'] .layui-table-cell {\n height: 30px;\n line-height: 20px;\n padding-top: 5px;\n padding-left: 11px;\n padding-right: 11px;\n}\n\n/* 数据表格 */\n.layui-table[lay-data],\n.layui-table[lay-options] {\n display: none;\n}\n.layui-table-box {\n position: relative;\n overflow: hidden;\n}\n.layui-table-view {\n clear: both;\n position: relative;\n border-right: none;\n}\n.layui-table-view:after {\n content: '';\n position: absolute;\n top: 0;\n right: 0;\n width: 1px;\n height: 100%;\n background-color: var(--lay-gray-300);\n z-index: 101;\n}\n.layui-table-view .layui-table {\n position: relative;\n width: auto;\n margin: 0;\n border: 0;\n border-collapse: separate;\n}\n.layui-table-view .layui-table[lay-skin='line'] {\n border-width: 0;\n border-right-width: 1px;\n}\n.layui-table-view .layui-table[lay-skin='row'] {\n border-width: 0;\n border-bottom-width: 1px;\n}\n.layui-table-view .layui-table th,\n.layui-table-view .layui-table td {\n padding: 0;\n border-top: none;\n border-left: none;\n}\n.layui-table-view .layui-table th [lay-event],\n.layui-table-view .layui-table th.layui-unselect .layui-table-cell span {\n cursor: pointer;\n}\n.layui-table-view .layui-table th span,\n.layui-table-view .layui-table td {\n cursor: default;\n}\n.layui-table-view .layui-table td[data-edit] {\n cursor: text;\n}\n.layui-table-view .layui-table td[data-edit]:hover:after {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n border: 1px solid #16b777;\n pointer-events: none;\n content: '';\n}\n\n.layui-table-view .layui-form-checkbox[lay-skin='primary'] i {\n width: 18px;\n height: 18px;\n line-height: 16px;\n}\n.layui-table-view .layui-form-radio {\n line-height: 0;\n padding: 0;\n}\n.layui-table-view .layui-form-radio > i {\n margin: 0;\n font-size: 20px;\n}\n.layui-table-init {\n position: absolute;\n left: 0;\n top: 0;\n right: 0;\n bottom: 0;\n margin: 0;\n z-index: 199;\n transition: opacity 0.1s;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.layui-table-loading-icon {\n position: absolute;\n width: 100%\\0;\n left: 50%;\n left: auto\\0;\n top: 50%;\n margin-top: -15px\\0;\n transform: translate(-50%, -50%);\n transform: none\\0;\n text-align: center;\n}\n.layui-table-loading-icon .layui-icon {\n font-size: 30px;\n color: #c2c2c2;\n}\n.layui-table-header {\n border-width: 0;\n border-bottom-width: 1px;\n overflow: hidden;\n}\n.layui-table-header .layui-table {\n margin-bottom: -1px;\n}\n\n.layui-table-column {\n position: relative;\n width: 100%;\n min-height: 41px;\n padding: 8px 16px;\n border-width: 0;\n border-bottom-width: 1px;\n}\n.layui-table-column .layui-btn-container {\n margin-bottom: -8px;\n}\n.layui-table-column .layui-btn-container .layui-btn {\n margin-right: 8px;\n margin-bottom: 8px;\n}\n\n.layui-table-tool .layui-inline[lay-event] {\n position: relative;\n width: 26px;\n height: 26px;\n padding: 5px;\n line-height: 16px;\n margin-right: 10px;\n text-align: center;\n color: #333;\n border: 1px solid #ccc;\n cursor: pointer;\n -webkit-transition: 0.5s all;\n transition: 0.5s all;\n}\n.layui-table-tool .layui-inline[lay-event]:hover {\n border: 1px solid #999;\n}\n.layui-table-tool-temp {\n padding-right: 120px;\n}\n.layui-table-tool-self {\n position: absolute;\n right: 17px;\n top: 10px;\n}\n.layui-table-tool .layui-table-tool-self .layui-inline[lay-event] {\n margin: 0 0 0 10px;\n}\n.layui-table-tool-panel {\n position: absolute;\n top: 29px;\n left: -1px;\n z-index: 399;\n padding: 5px 0 !important;\n min-width: 150px;\n min-height: 40px;\n border: 1px solid var(--lay-border-color-accent);\n text-align: left;\n overflow-y: auto;\n background-color: #fff;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);\n}\n.layui-table-tool-panel li {\n padding: 0 10px;\n margin: 0 !important;\n line-height: 30px;\n list-style-type: none !important;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n -webkit-transition: 0.5s all;\n transition: 0.5s all;\n}\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin='primary'] {\n width: 100%;\n}\n.layui-table-tool-panel li:hover {\n background-color: #f8f8f8;\n}\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin='primary'] {\n padding-left: 28px;\n}\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin='primary'] i {\n position: absolute;\n left: 0;\n top: 0;\n}\n.layui-table-tool-panel li .layui-form-checkbox[lay-skin='primary'] span {\n padding: 0;\n}\n.layui-table-tool .layui-table-tool-self .layui-table-tool-panel {\n left: auto;\n right: -1px;\n}\n\n.layui-table-col-set {\n position: absolute;\n right: 0;\n top: 0;\n width: 20px;\n height: 100%;\n border-width: 0;\n border-left-width: 1px;\n background-color: #fff;\n}\n\n.layui-table-sort {\n width: 10px;\n height: 20px;\n margin-left: 5px;\n cursor: pointer !important;\n}\n.layui-table-sort .layui-edge {\n position: absolute;\n left: 5px;\n border-width: 5px;\n}\n.layui-table-sort .layui-table-sort-asc {\n top: 3px;\n border-top: none;\n border-bottom-style: solid;\n border-bottom-color: #b2b2b2;\n}\n.layui-table-sort .layui-table-sort-asc:hover {\n border-bottom-color: #5f5f5f;\n}\n.layui-table-sort .layui-table-sort-desc {\n bottom: 5px;\n border-bottom: none;\n border-top-style: solid;\n border-top-color: #b2b2b2;\n}\n.layui-table-sort .layui-table-sort-desc:hover {\n border-top-color: #5f5f5f;\n}\n.layui-table-sort[lay-sort='asc'] .layui-table-sort-asc {\n border-bottom-color: #000;\n}\n.layui-table-sort[lay-sort='desc'] .layui-table-sort-desc {\n border-top-color: #000;\n}\n\n.layui-table-cell {\n height: 38px;\n line-height: 28px;\n padding: 6px 15px;\n position: relative;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n box-sizing: border-box;\n}\n.layui-table-cell .layui-form-checkbox[lay-skin='primary'] {\n top: -1px;\n padding: 0;\n}\n.layui-table-cell .layui-form-checkbox[lay-skin='primary'] > div {\n padding-left: 24px;\n}\n.layui-table-cell .layui-table-link {\n color: #01aaed;\n}\n.layui-table-cell .layui-btn {\n vertical-align: inherit;\n}\n.layui-table-cell[align='center'] {\n -webkit-box-pack: center;\n}\n.layui-table-cell[align='right'] {\n -webkit-box-pack: end;\n}\n\n.laytable-cell-checkbox,\n.laytable-cell-radio,\n.laytable-cell-space,\n.laytable-cell-numbers {\n text-align: center;\n -webkit-box-pack: center;\n}\n\n.layui-table-body {\n position: relative;\n overflow: auto;\n margin-bottom: -1px;\n}\n.layui-table-body .layui-none {\n line-height: 26px;\n padding: 30px 15px;\n text-align: center;\n color: #999;\n}\n.layui-table-fixed {\n position: absolute;\n left: 0;\n top: 0;\n z-index: 101;\n}\n.layui-table-fixed .layui-table-body {\n overflow: hidden;\n}\n.layui-table-fixed-l {\n box-shadow: 1px 0 8px rgba(0, 0, 0, 0.08);\n}\n.layui-table-fixed-r {\n left: auto;\n right: 0px;\n border-width: 0;\n border-left-width: 1px;\n box-shadow: -1px 0 8px rgba(0, 0, 0, 0.08);\n}\n.layui-table-fixed-r .layui-table-header {\n position: relative;\n overflow: visible;\n}\n.layui-table-mend {\n position: absolute;\n right: -49px;\n top: 0;\n height: 100%;\n width: 50px;\n border-width: 0;\n border-left-width: 1px;\n}\n\n.layui-table-tool {\n position: relative;\n width: 100%;\n min-height: 50px;\n line-height: 30px;\n padding: 10px 15px;\n border-width: 0;\n border-bottom-width: 1px; /*box-shadow: 0 1px 8px 0 rgb(0 0 0 / 8%);*/\n}\n.layui-table-tool .layui-btn-container {\n margin-bottom: -10px;\n}\n\n.layui-table-total {\n margin-bottom: -1px;\n border-width: 0;\n border-top-width: 1px;\n overflow: hidden;\n}\n\n.layui-table-page {\n border-width: 0;\n border-top-width: 1px;\n margin-bottom: -1px;\n white-space: nowrap;\n overflow: hidden;\n}\n.layui-table-page > div {\n height: 26px;\n}\n.layui-table-page .layui-laypage {\n margin: 0;\n}\n.layui-table-page .layui-laypage a,\n.layui-table-page .layui-laypage span {\n height: 26px;\n line-height: 26px;\n margin-bottom: 10px;\n border: none;\n background: none;\n}\n.layui-table-page .layui-laypage a,\n.layui-table-page .layui-laypage span.layui-laypage-curr {\n padding: 0 12px;\n}\n.layui-table-page .layui-laypage span {\n margin-left: 0;\n padding: 0;\n}\n.layui-table-page .layui-laypage .layui-laypage-prev {\n margin-left: -11px !important;\n}\n.layui-table-page .layui-laypage .layui-laypage-curr .layui-laypage-em {\n left: 0;\n top: 0;\n padding: 0;\n}\n.layui-table-page .layui-laypage input,\n.layui-table-page .layui-laypage button {\n height: 26px;\n line-height: 26px;\n}\n.layui-table-page .layui-laypage input {\n width: 40px;\n}\n.layui-table-page .layui-laypage button {\n padding: 0 10px;\n}\n.layui-table-page select {\n height: 18px;\n}\n.layui-table-pagebar {\n float: right;\n line-height: 23px;\n}\n.layui-table-pagebar .layui-btn-sm {\n margin-top: -1px;\n}\n.layui-table-pagebar .layui-btn-xs {\n margin-top: 2px;\n}\n\n.layui-table-view select[lay-ignore] {\n display: inline-block;\n}\n.layui-table-patch .layui-table-cell {\n padding: 0;\n width: 30px;\n}\n\n.layui-table-edit {\n position: absolute;\n left: 0;\n top: 0;\n z-index: 189;\n min-width: 100%;\n min-height: 100%;\n padding: 5px 14px;\n border-radius: 0;\n box-shadow: 1px 1px 20px rgba(0, 0, 0, 0.15);\n background-color: #fff;\n}\n.layui-table-edit:focus {\n border-color: var(--lay-color-accent) !important;\n}\ninput.layui-input.layui-table-edit {\n height: 100%;\n}\nselect.layui-table-edit {\n padding: 0 0 0 10px;\n border-color: var(--lay-border-color-accent);\n}\n.layui-table-view .layui-form-switch,\n.layui-table-view .layui-form-checkbox,\n.layui-table-view .layui-form-radio {\n top: 0;\n margin: 0;\n}\n.layui-table-view .layui-form-checkbox {\n top: -1px;\n height: 26px;\n line-height: 26px;\n}\n.layui-table-view .layui-form-checkbox i {\n height: 26px;\n}\n\n/* 展开溢出的单元格 */\n.layui-table-grid .layui-table-cell {\n overflow: visible;\n}\n.layui-table-grid-down {\n position: absolute;\n top: 0;\n right: 0;\n width: 24px;\n height: 100%;\n padding: 5px 0;\n border-width: 0;\n border-left-width: 1px;\n text-align: center;\n background-color: #fff;\n color: #999;\n cursor: pointer;\n}\n.layui-table-grid-down .layui-icon {\n position: absolute;\n top: 50%;\n left: 50%;\n margin: -8px 0 0 -8px;\n font-size: 14px;\n}\n.layui-table-grid-down:hover {\n background-color: #fbfbfb;\n}\n\n/* 单元格多行展开风格 */\n.layui-table-expanded {\n height: 95px;\n}\n.layui-table-expanded .layui-table-cell,\n.layui-table-view\n .layui-table[lay-size='sm']\n .layui-table-expanded\n .layui-table-cell,\n.layui-table-view\n .layui-table[lay-size='lg']\n .layui-table-expanded\n .layui-table-cell {\n height: auto;\n max-height: 94px;\n white-space: normal;\n text-overflow: clip;\n}\n.layui-table-cell-c {\n position: absolute;\n bottom: -10px;\n right: 50%;\n margin-right: -9px;\n width: 20px;\n height: 20px;\n line-height: 18px;\n cursor: pointer;\n text-align: center;\n background-color: #fff;\n border: 1px solid var(--lay-border-color);\n border-radius: 50%;\n z-index: 1000;\n transition: 0.3s all;\n font-size: 14px;\n}\n.layui-table-cell-c:hover {\n border-color: var(--lay-color-accent);\n}\n.layui-table-expanded td:hover .layui-table-cell {\n overflow: auto;\n}\n.layui-table-main\n > .layui-table\n > tbody\n > tr:last-child\n > td\n > .layui-table-cell-c {\n bottom: 0;\n}\n\n/* 单元格 TIPS 展开风格 */\nbody .layui-table-tips .layui-layer-content {\n background: none;\n padding: 0;\n box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12);\n}\n.layui-table-tips-main {\n margin: -49px 0 0 -1px;\n max-height: 150px;\n padding: 8px 15px;\n font-size: 14px;\n overflow-y: scroll;\n background-color: #fff;\n color: #5f5f5f;\n}\n.layui-table-tips-c {\n position: absolute;\n right: -3px;\n top: -13px;\n width: 20px;\n height: 20px;\n padding: 3px;\n cursor: pointer;\n background-color: #5f5f5f;\n border-radius: 50%;\n color: #fff;\n}\n.layui-table-tips-c:hover {\n background-color: #777;\n}\n.layui-table-tips-c:before {\n position: relative;\n right: -2px;\n}\n\n/** 树表 **/\n.layui-table-tree-nodeIcon {\n max-width: 20px;\n}\n.layui-table-tree-nodeIcon > * {\n width: 100%;\n}\n.layui-table-tree-flexIcon,\n.layui-table-tree-nodeIcon {\n margin-right: 2px;\n}\n.layui-table-tree-flexIcon {\n cursor: pointer;\n}\n","/** 文件上传 **/\r\n.layui-upload-file {\r\n display: none !important;\r\n opacity: 0.01;\r\n filter: Alpha(opacity=1);\r\n}\r\n.layui-upload-list {\r\n margin: 11px 0;\r\n}\r\n.layui-upload-choose {\r\n max-width: 200px;\r\n padding: 0 10px;\r\n color: #999;\r\n font-size: 14px;\r\n text-overflow: ellipsis;\r\n overflow: hidden;\r\n white-space: nowrap;\r\n}\r\n.layui-upload-drag {\r\n position: relative;\r\n display: inline-block;\r\n padding: 30px;\r\n border: 1px dashed #e2e2e2;\r\n background-color: #fff;\r\n text-align: center;\r\n cursor: pointer;\r\n color: #999;\r\n}\r\n.layui-upload-drag .layui-icon {\r\n font-size: 50px;\r\n color: var(--lay-color-primary);\r\n}\r\n.layui-upload-drag[lay-over] {\r\n border-color: var(--lay-color-primary);\r\n}\r\n.layui-upload-form {\r\n display: inline-block;\r\n}\r\n.layui-upload-iframe {\r\n position: absolute;\r\n width: 0;\r\n height: 0;\r\n border: 0;\r\n visibility: hidden;\r\n}\r\n.layui-upload-wrap {\r\n position: relative;\r\n display: inline-block;\r\n vertical-align: middle;\r\n}\r\n.layui-upload-wrap .layui-upload-file {\r\n display: block !important;\r\n position: absolute;\r\n left: 0;\r\n top: 0;\r\n z-index: 10;\r\n font-size: 100px;\r\n width: 100%;\r\n height: 100%;\r\n opacity: 0.01;\r\n filter: Alpha(opacity=1);\r\n cursor: pointer;\r\n}\r\n.layui-btn-container .layui-upload-choose {\r\n padding-left: 0;\r\n}\r\n","/* 基础菜单元素 */\n.layui-menu {\n position: relative;\n margin: 5px 0;\n background-color: #fff;\n box-sizing: border-box;\n}\n.layui-menu * {\n box-sizing: border-box;\n}\n.layui-menu li,\n.layui-menu-body-title,\n.layui-menu-body-title a {\n padding: 5px 15px;\n color: initial;\n}\n.layui-menu li {\n position: relative;\n margin: 0 0 1px;\n line-height: 26px;\n color: rgba(0, 0, 0, 0.8);\n font-size: 14px;\n white-space: nowrap;\n cursor: pointer;\n transition: all 0.3s;\n}\n.layui-menu li:hover {\n background-color: #f8f8f8;\n}\n.layui-menu li.layui-disabled,\n.layui-menu li.layui-disabled * {\n background: none !important;\n color: #d2d2d2 !important;\n cursor: not-allowed !important;\n}\n\n.layui-menu-item-parent:hover > .layui-menu-body-panel {\n display: block;\n animation-name: layui-fadein;\n animation-duration: 0.3s;\n animation-fill-mode: both;\n animation-delay: 0.2s;\n}\n.layui-menu-item-parent > .layui-menu-body-title,\n.layui-menu-item-group > .layui-menu-body-title {\n padding-right: 38px;\n}\n\n.layui-menu .layui-menu-item-group:hover,\n.layui-menu .layui-menu-item-none:hover,\n.layui-menu .layui-menu-item-divider:hover {\n background: none;\n cursor: default;\n}\n.layui-menu .layui-menu-item-group > ul {\n margin: 5px 0 -5px;\n}\n.layui-menu .layui-menu-item-group > .layui-menu-body-title {\n color: rgba(0, 0, 0, 0.35);\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.layui-menu .layui-menu-item-none {\n color: rgba(0, 0, 0, 0.35);\n cursor: default;\n}\n\n.layui-menu .layui-menu-item-none {\n text-align: center;\n}\n.layui-menu .layui-menu-item-divider {\n margin: 5px 0;\n padding: 0;\n height: 0;\n line-height: 0;\n border-bottom: 1px solid var(--lay-border-color);\n overflow: hidden;\n}\n\n.layui-menu .layui-menu-item-up:hover,\n.layui-menu .layui-menu-item-down:hover {\n cursor: pointer;\n}\n.layui-menu .layui-menu-item-up > .layui-menu-body-title {\n color: rgba(0, 0, 0, 0.8);\n}\n.layui-menu .layui-menu-item-up > ul {\n visibility: hidden;\n height: 0;\n overflow: hidden;\n}\n.layui-menu .layui-menu-item-down > .layui-menu-body-title > .layui-icon-down {\n transform: rotate(180deg);\n}\n.layui-menu .layui-menu-item-up > .layui-menu-body-title > .layui-icon-up {\n transform: rotate(-180deg);\n}\n.layui-menu .layui-menu-item-up > .layui-menu-body-title:hover > .layui-icon,\n.layui-menu .layui-menu-item-down:hover > .layui-menu-body-title > .layui-icon {\n color: rgba(0, 0, 0, 1);\n}\n.layui-menu .layui-menu-item-down > ul {\n visibility: visible;\n height: auto;\n}\n\n.layui-menu .layui-menu-item-checked,\n.layui-menu .layui-menu-item-checked2 {\n background-color: #f8f8f8 !important;\n color: var(--lay-color-accent);\n}\n.layui-menu .layui-menu-item-checked a,\n.layui-menu .layui-menu-item-checked2 a {\n color: var(--lay-color-accent);\n}\n.layui-menu .layui-menu-item-checked:after {\n position: absolute;\n right: -1px;\n top: 0;\n bottom: 0;\n border-right: 3px solid var(--lay-color-accent);\n content: '';\n}\n\n.layui-menu-body-title {\n position: relative;\n margin: -5px -15px;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n.layui-menu-body-title a {\n display: block;\n margin: -5px -15px;\n overflow: hidden;\n text-overflow: ellipsis;\n color: rgba(0, 0, 0, 0.8);\n}\n.layui-menu-body-title a:hover {\n transition: all 0.3s;\n}\n.layui-menu-body-title > .layui-icon {\n position: absolute;\n right: 15px;\n top: 50%;\n margin-top: -6px;\n line-height: normal;\n font-size: 14px;\n -webkit-transition: all 0.2s;\n transition: all 0.2s;\n}\n.layui-menu-body-title > .layui-icon:hover {\n transition: all 0.3s;\n}\n.layui-menu-body-title > .layui-icon-right {\n right: 14px;\n}\n.layui-menu-body-panel {\n display: none;\n position: absolute;\n top: -7px;\n left: 100%;\n z-index: 1000;\n margin-left: 13px;\n padding: 5px 0;\n}\n.layui-menu-body-panel:before {\n content: '';\n position: absolute;\n width: 20px;\n left: -16px;\n top: 0;\n bottom: 0;\n}\n.layui-menu-body-panel-left {\n left: auto;\n right: 100%;\n margin: 0 13px 0;\n}\n.layui-menu-body-panel-left:before {\n left: auto;\n right: -16px;\n}\n\n.layui-menu-lg li {\n line-height: 32px;\n}\n.layui-menu-lg li:hover,\n.layui-menu-lg .layui-menu-body-title a:hover {\n background: none;\n color: var(--lay-color-accent);\n}\n.layui-menu-lg li .layui-menu-body-panel {\n margin-left: 14px;\n}\n.layui-menu-lg li .layui-menu-body-panel-left {\n margin: 0 15px 0;\n}\n\n/* 下拉菜单 */\n.layui-dropdown {\n position: absolute;\n left: -999999px;\n top: -999999px;\n z-index: 77777777;\n margin: 5px 0;\n min-width: 100px;\n}\n.layui-dropdown:before {\n content: '';\n position: absolute;\n width: 100%;\n height: 6px;\n left: 0;\n top: -6px;\n}\n.layui-dropdown-shade {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: fixed;\n pointer-events: auto;\n}\n","/* Tabs 标签页 */\n.layui-tabs {\n position: relative;\n}\n.layui-tabs.layui-hide-v {\n overflow: hidden;\n}\n.layui-tabs-header {\n position: relative;\n left: 0;\n height: 40px;\n padding: 0 !important;\n white-space: nowrap;\n font-size: 0;\n -webkit-transition: all 0.16s;\n transition: all 0.16s;\n}\n.layui-tabs-header:after,\n.layui-tabs-scroll:after {\n content: '';\n position: absolute;\n left: 0;\n bottom: 0;\n z-index: 0;\n width: 100%;\n border-bottom: 1px solid var(--lay-border-color);\n}\n.layui-tabs-header li {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n line-height: 40px;\n margin: 0 !important;\n padding: 0 16px;\n text-align: center;\n cursor: pointer;\n font-size: 14px;\n -webkit-transition: all 0.16s;\n transition: all 0.16s;\n}\n.layui-tabs-header li:first-child {\n margin-left: 0;\n}\n.layui-tabs-header li a {\n display: block;\n padding: 0 var(--lay-spacing);\n margin: 0 calc(-1 * var(--lay-spacing));\n color: inherit;\n}\n.layui-tabs-header li a:hover {\n text-decoration: none;\n}\n.layui-tabs-header li:hover,\n.layui-tabs-header .layui-this {\n color: var(--lay-color-primary);\n}\n.layui-tabs-header .layui-this:after {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n z-index: 1;\n width: 100%;\n height: 100%;\n border-bottom: 3px solid var(--lay-color-primary);\n box-sizing: border-box;\n pointer-events: none;\n}\n.layui-tabs-header .layui-badge,\n.layui-tabs-header .layui-badge-dot {\n left: 5px;\n top: -1px;\n}\n\n.layui-tabs-scroll {\n position: relative;\n overflow: hidden;\n padding: 0 40px;\n}\n.layui-tabs-scroll .layui-tabs-header:after {\n display: none;\n content: none;\n border: 0;\n}\n.layui-tabs-bar .layui-icon {\n position: absolute;\n left: 0;\n top: 0;\n z-index: 3;\n width: 40px;\n height: 100%;\n line-height: 40px;\n border: 1px solid var(--lay-border-color);\n text-align: center;\n cursor: pointer;\n box-sizing: border-box;\n background-color: #fff;\n box-shadow: 2px 0 5px 0 rgb(0 0 0 / 6%);\n}\n.layui-tabs-bar .layui-icon-next {\n left: auto;\n right: 0;\n box-shadow: -2px 0 5px 0 rgb(0 0 0 / 6%);\n}\n\n.layui-tabs-header li .layui-tabs-close {\n position: relative;\n display: inline-block;\n width: 16px;\n height: 16px;\n line-height: 18px;\n margin-left: 8px;\n top: 0px;\n text-align: center;\n font-size: 12px;\n color: #959595;\n border-radius: 50%;\n font-weight: 700;\n -webkit-transition: all 0.16s;\n transition: all 0.16s;\n}\n.layui-tabs-header li .layui-tabs-close:hover {\n background-color: var(--lay-color-red);\n color: #fff;\n}\n.layui-tabs-header li[lay-closable='false'] .layui-tabs-close {\n display: none;\n}\n\n.layui-tabs-body {\n padding: var(--lay-spacing) 0;\n}\n.layui-tabs-item {\n display: none;\n}\n\n/* tabs 卡片风格 */\n.layui-tabs-card > .layui-tabs-header .layui-this {\n background-color: #fff;\n}\n.layui-tabs-card > .layui-tabs-header .layui-this:after {\n border: 1px solid var(--lay-border-color);\n border-bottom-color: #fff;\n border-radius: var(--lay-border-radius) var(--lay-border-radius) 0 0;\n}\n.layui-tabs-card > .layui-tabs-header li:first-child.layui-this:after {\n margin-left: -1px;\n}\n.layui-tabs-card > .layui-tabs-header li:last-child.layui-this:after {\n margin-right: -1px;\n}\n.layui-tabs-card.layui-panel > .layui-tabs-header .layui-this:after {\n border-top: 0;\n border-radius: 0;\n}\n.layui-tabs-card.layui-panel > .layui-tabs-body {\n padding: var(--lay-spacing);\n}\n","/**\n * Tab 选项卡(已被 tabs 平替,仅为兼容保留)\n **/\n.layui-tab {\n margin: 10px 0;\n text-align: left !important;\n}\n.layui-tab[overflow] > .layui-tab-title {\n overflow: hidden;\n}\n.layui-tab .layui-tab-title {\n position: relative;\n left: 0;\n height: 40px;\n white-space: nowrap;\n font-size: 0;\n -webkit-transition: all 0.2s;\n transition: all 0.2s;\n}\n.layui-tab .layui-tab-title:after {\n content: '';\n border-bottom-color: var(--lay-border-color);\n border-bottom-width: 1px;\n border-style: none none solid;\n bottom: 0;\n left: 0;\n right: auto;\n top: auto;\n pointer-events: none;\n position: absolute;\n width: 100%;\n z-index: 8;\n}\n.layui-tab .layui-tab-title li {\n display: inline-block;\n vertical-align: middle;\n font-size: 14px;\n -webkit-transition: all 0.2s;\n transition: all 0.2s;\n}\n.layui-tab .layui-tab-title li {\n position: relative;\n line-height: 40px;\n min-width: 65px;\n margin: 0;\n padding: 0 15px;\n text-align: center;\n cursor: pointer;\n}\n.layui-tab .layui-tab-title li a {\n display: block;\n padding: 0 15px;\n margin: 0 -15px;\n}\n.layui-tab-title .layui-this {\n color: #000;\n}\n\n.layui-tab-title .layui-this:after {\n position: absolute;\n left: 0;\n top: 0;\n content: '';\n width: 100%;\n height: 40px;\n border-width: 1px;\n border-bottom-width: 1px;\n border-style: solid;\n border-bottom-color: #fff;\n border-radius: var(--lay-border-radius) var(--lay-border-radius) 0 0;\n box-sizing: border-box;\n pointer-events: none;\n z-index: 9;\n}\n.layui-tab-bar {\n box-sizing: border-box;\n position: absolute;\n right: 0;\n top: 0;\n z-index: 10;\n width: 30px;\n height: 40px;\n line-height: 40px;\n border-width: 1px;\n border-style: solid;\n border-radius: var(--lay-border-radius);\n text-align: center;\n background-color: #fff;\n cursor: pointer;\n}\n.layui-tab-bar .layui-icon {\n position: relative;\n display: inline-block;\n top: 3px;\n -webkit-transition: all 0.3s;\n transition: all 0.3s;\n}\n.layui-tab-item {\n display: none;\n}\n.layui-tab-more {\n padding-right: 30px;\n height: auto !important;\n white-space: normal !important;\n}\n.layui-tab-more li.layui-this:after {\n border-bottom-color: var(--lay-border-color);\n border-radius: var(--lay-border-radius);\n}\n.layui-tab-more .layui-tab-bar .layui-icon {\n top: -2px;\n top: 3px\\0;\n -webkit-transform: rotate(180deg);\n transform: rotate(180deg);\n}\n:root .layui-tab-more .layui-tab-bar .layui-icon {\n top: -2px\\0 / IE9;\n}\n\n.layui-tab-content {\n padding: 15px 0;\n}\n\n/* Tab 关闭 */\n.layui-tab-title li .layui-tab-close {\n position: relative;\n display: inline-block;\n width: 18px;\n height: 18px;\n line-height: 20px;\n margin-left: 8px;\n top: 1px;\n text-align: center;\n font-size: 14px;\n color: #c2c2c2;\n -webkit-transition: all 0.2s;\n transition: all 0.2s;\n}\n.layui-tab-title li .layui-tab-close:hover {\n border-radius: var(--lay-border-radius);\n background-color: var(--lay-color-red);\n color: #fff;\n}\n\n/* Tab 简洁风格 */\n.layui-tab-brief > .layui-tab-title .layui-this {\n color: var(--lay-color-primary);\n}\n.layui-tab-brief > .layui-tab-title .layui-this:after,\n.layui-tab-brief > .layui-tab-more li.layui-this:after {\n border: none;\n border-radius: 0;\n border-bottom: 2px solid var(--lay-color-accent);\n}\n\n/* Tab 卡片风格 */\n.layui-tab-card {\n border-width: 1px;\n border-style: solid;\n border-radius: var(--lay-border-radius);\n box-shadow: 0 2px 5px 0 rgba(0, 0, 0, 0.1);\n}\n.layui-tab-card > .layui-tab-title {\n background-color: var(--lay-color-gray);\n}\n.layui-tab-card > .layui-tab-title li {\n margin-right: -1px;\n margin-left: -1px;\n}\n.layui-tab-card > .layui-tab-title .layui-this {\n background-color: #fff;\n}\n.layui-tab-card > .layui-tab-title .layui-this:after {\n border-top: none;\n border-width: 1px;\n border-bottom-color: #fff;\n}\n.layui-tab-card > .layui-tab-title .layui-tab-bar {\n height: 40px;\n line-height: 40px;\n border-radius: 0;\n border-top: none;\n border-right: none;\n}\n.layui-tab-card > .layui-tab-more .layui-this {\n background: none;\n color: var(--lay-color-accent);\n}\n.layui-tab-card > .layui-tab-more .layui-this:after {\n border: none;\n}\n","/** 导航菜单 **/\n.layui-nav {\n position: relative;\n padding: 0 15px;\n background-color: var(--lay-color-black);\n color: #fff;\n border-radius: var(--lay-border-radius);\n font-size: 0;\n box-sizing: border-box;\n}\n.layui-nav * {\n font-size: 14px;\n}\n.layui-nav .layui-nav-item {\n position: relative;\n display: inline-block;\n margin-top: 0;\n list-style: none;\n vertical-align: middle;\n line-height: 60px;\n}\n.layui-nav .layui-nav-item a {\n display: block;\n padding: 0 20px;\n color: #fff;\n color: rgba(255, 255, 255, 0.7);\n -webkit-transition: all 0.3s;\n transition: all 0.3s;\n}\n.layui-nav-bar,\n.layui-nav .layui-this:after {\n content: '';\n position: absolute;\n left: 0;\n top: 0;\n width: 0;\n height: 3px;\n background-color: var(--lay-color-accent);\n -webkit-transition: all 0.2s;\n transition: all 0.2s;\n pointer-events: none;\n}\n.layui-nav-bar {\n z-index: 1000;\n}\n.layui-nav[lay-bar='disabled'] .layui-nav-bar {\n display: none;\n}\n.layui-nav .layui-this a,\n.layui-nav .layui-nav-item a:hover {\n color: #fff;\n text-decoration: none;\n}\n.layui-nav .layui-this:after {\n top: auto;\n bottom: 0;\n width: 100%;\n}\n.layui-nav-img {\n width: 30px;\n height: 30px;\n margin-right: 10px;\n border-radius: 50%;\n}\n\n.layui-nav .layui-nav-more {\n position: absolute;\n top: 0;\n right: 3px;\n left: auto !important;\n margin-top: 0;\n font-size: 12px;\n cursor: pointer;\n -webkit-transition: all 0.2s;\n transition: all 0.2s;\n}\n.layui-nav .layui-nav-mored,\n.layui-nav-itemed > a .layui-nav-more {\n transform: rotate(180deg);\n}\n\n.layui-nav-child {\n display: none;\n position: absolute;\n left: 0;\n top: 65px;\n min-width: 100%;\n line-height: 36px;\n padding: 5px 0;\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);\n border: 1px solid var(--lay-border-color);\n background-color: #fff;\n z-index: 100;\n border-radius: var(--lay-border-radius);\n white-space: nowrap;\n box-sizing: border-box;\n}\n.layui-nav .layui-nav-child a {\n color: #5f5f5f;\n color: rgba(0, 0, 0, 0.8);\n}\n.layui-nav .layui-nav-child a:hover {\n background-color: #f8f8f8;\n color: rgba(0, 0, 0, 0.8);\n}\n.layui-nav-child dd {\n margin: 1px 0;\n position: relative;\n}\n.layui-nav-child dd.layui-this {\n background-color: #f8f8f8;\n color: #000;\n}\n.layui-nav-child dd.layui-this:after {\n display: none;\n}\n.layui-nav-child-r {\n left: auto;\n right: 0;\n}\n.layui-nav-child-c {\n text-align: center;\n}\n\n/* 垂直导航菜单 */\n.layui-nav.layui-nav-tree {\n width: 200px;\n padding: 0;\n}\n.layui-nav-tree .layui-nav-item {\n display: block;\n width: 100%;\n line-height: 40px;\n}\n.layui-nav-tree .layui-nav-item a {\n position: relative;\n height: 40px;\n line-height: 40px;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n.layui-nav-tree .layui-nav-item > a {\n padding-top: 5px;\n padding-bottom: 5px;\n}\n.layui-nav-tree .layui-nav-more {\n right: 15px;\n}\n.layui-nav-tree .layui-nav-item > a .layui-nav-more {\n padding: 5px 0;\n}\n.layui-nav-tree .layui-nav-bar {\n width: 5px;\n height: 0;\n}\n.layui-side .layui-nav-tree .layui-nav-bar {\n width: 2px;\n}\n.layui-nav-tree .layui-this,\n.layui-nav-tree .layui-this > a,\n.layui-nav-tree .layui-this > a:hover,\n.layui-nav-tree .layui-nav-child dd.layui-this,\n.layui-nav-tree .layui-nav-child dd.layui-this a {\n background-color: var(--lay-color-primary);\n color: #fff;\n}\n.layui-nav-tree .layui-this:after {\n display: none;\n}\n.layui-nav-tree .layui-nav-title a,\n.layui-nav-tree .layui-nav-title a:hover,\n.layui-nav-itemed > a {\n color: #fff !important;\n}\n.layui-nav-tree .layui-nav-bar {\n background-color: var(--lay-color-primary);\n}\n\n.layui-nav-tree .layui-nav-child {\n position: relative;\n z-index: 0;\n top: 0;\n border: none;\n background: none;\n background-color: rgba(0, 0, 0, 0.3);\n box-shadow: none;\n}\n.layui-nav-tree .layui-nav-child dd {\n margin: 0;\n}\n.layui-nav-tree .layui-nav-child a {\n color: #fff;\n color: rgba(255, 255, 255, 0.7);\n}\n.layui-nav-tree .layui-nav-child a:hover {\n background: none;\n color: #fff;\n}\n\n/* 垂直导航 - 展开状态 */\n.layui-nav-itemed > .layui-nav-child,\n.layui-nav-itemed > .layui-nav-child > .layui-this > .layui-nav-child {\n display: block;\n}\n\n/* 垂直导航 - 侧边 */\n.layui-nav-side {\n position: fixed;\n top: 0;\n bottom: 0;\n left: 0;\n overflow-x: hidden;\n z-index: 999;\n}\n\n/* 导航浅色背景 */\n.layui-nav.layui-bg-gray .layui-nav-item a,\n.layui-nav-tree.layui-bg-gray a {\n color: #373737;\n color: rgba(0, 0, 0, 0.8);\n}\n.layui-nav-tree.layui-bg-gray .layui-nav-itemed > a {\n color: #000 !important;\n}\n.layui-nav.layui-bg-gray .layui-this a {\n color: var(--lay-color-accent);\n}\n.layui-nav-tree.layui-bg-gray .layui-nav-child {\n padding-left: 11px;\n background: none;\n}\n.layui-nav-tree.layui-bg-gray .layui-this,\n.layui-nav-tree.layui-bg-gray .layui-this > a,\n.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this,\n.layui-nav-tree.layui-bg-gray .layui-nav-child dd.layui-this a {\n background: none !important;\n color: var(--lay-color-accent) !important;\n font-weight: 700;\n}\n.layui-nav-tree.layui-bg-gray .layui-nav-bar {\n background-color: var(--lay-color-accent);\n}\n\n/** 面包屑 **/\n.layui-breadcrumb {\n visibility: hidden;\n font-size: 0;\n}\n.layui-breadcrumb > * {\n font-size: 14px;\n}\n.layui-breadcrumb a {\n color: #999 !important;\n}\n.layui-breadcrumb a:hover {\n color: var(--lay-color-accent) !important;\n}\n.layui-breadcrumb a cite {\n color: #5f5f5f;\n font-style: normal;\n}\n.layui-breadcrumb span[lay-separator] {\n margin: 0 10px;\n color: #999;\n}\n","/* 时间线 */\n.layui-timeline {\n padding-left: 5px;\n}\n.layui-timeline-item {\n position: relative;\n padding-bottom: 20px;\n}\n.layui-timeline-axis {\n position: absolute;\n left: -5px;\n top: 0;\n z-index: 10;\n width: 20px;\n height: 20px;\n line-height: 20px;\n background-color: #fff;\n color: var(--lay-color-accent);\n border-radius: 50%;\n text-align: center;\n cursor: pointer;\n}\n.layui-timeline-axis:hover {\n color: var(--lay-color-red);\n}\n.layui-timeline-item:before {\n content: '';\n position: absolute;\n left: 5px;\n top: 0;\n z-index: 0;\n width: 1px;\n height: 100%;\n}\n\n.layui-timeline-item:first-child:before {\n display: block;\n}\n.layui-timeline-item:last-child:before {\n display: none;\n}\n.layui-timeline-content {\n padding-left: 25px;\n}\n.layui-timeline-title {\n position: relative;\n margin-bottom: 10px;\n line-height: 22px;\n}\n","/* 小徽章 */\r\n.layui-badge,\r\n.layui-badge-dot,\r\n.layui-badge-rim {\r\n position: relative;\r\n display: inline-block;\r\n padding: 0 6px;\r\n font-size: 12px;\r\n text-align: center;\r\n background-color: var(--lay-color-red);\r\n color: #fff;\r\n border-radius: var(--lay-border-radius);\r\n}\r\n.layui-badge {\r\n height: 18px;\r\n line-height: 18px;\r\n}\r\n.layui-badge-dot {\r\n width: 8px;\r\n height: 8px;\r\n padding: 0;\r\n border-radius: 50%;\r\n}\r\n.layui-badge-rim {\r\n height: 18px;\r\n line-height: 18px;\r\n border-width: 1px;\r\n border-style: solid;\r\n background-color: #fff;\r\n color: #5f5f5f;\r\n}\r\n\r\n.layui-btn .layui-badge,\r\n.layui-btn .layui-badge-dot {\r\n margin-left: 5px;\r\n}\r\n.layui-nav .layui-badge,\r\n.layui-nav .layui-badge-dot {\r\n position: absolute;\r\n top: 50%;\r\n margin: -5px 6px 0;\r\n}\r\n.layui-nav .layui-badge {\r\n margin-top: -10px;\r\n}\r\n.layui-tab-title .layui-badge,\r\n.layui-tab-title .layui-badge-dot {\r\n left: 5px;\r\n top: -2px;\r\n}\r\n","/* carousel 轮播 */\n.layui-carousel {\n position: relative;\n left: 0;\n top: 0;\n background-color: #f8f8f8;\n}\n.layui-carousel > *[carousel-item] {\n position: relative;\n width: 100%;\n height: 100%;\n overflow: hidden;\n}\n.layui-carousel > *[carousel-item]:before {\n position: absolute;\n content: '\\e63d';\n left: 50%;\n top: 50%;\n width: 100px;\n line-height: 20px;\n margin: -10px 0 0 -50px;\n text-align: center;\n color: #c2c2c2;\n font-family: 'layui-icon' !important;\n font-size: 30px;\n font-style: normal;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n.layui-carousel > *[carousel-item] > * {\n display: none;\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n background-color: #f8f8f8;\n -webkit-transition-duration: 0.3s;\n transition-duration: 0.3s;\n}\n.layui-carousel-updown > * {\n -webkit-transition: 0.3s ease-in-out up;\n transition: 0.3s ease-in-out up;\n}\n.layui-carousel-arrow {\n display: none\\0;\n opacity: 0;\n position: absolute;\n left: 10px;\n top: 50%;\n margin-top: -18px;\n width: 36px;\n height: 36px;\n line-height: 36px;\n text-align: center;\n font-size: 20px;\n border: none 0;\n border-radius: 50%;\n background-color: rgba(0, 0, 0, 0.2);\n color: #fff;\n -webkit-transition-duration: 0.3s;\n transition-duration: 0.3s;\n cursor: pointer;\n}\n.layui-carousel-arrow[lay-type='add'] {\n left: auto !important;\n right: 10px;\n}\n.layui-carousel[lay-arrow='always'] .layui-carousel-arrow {\n opacity: 1;\n left: 20px;\n}\n.layui-carousel[lay-arrow='always'] .layui-carousel-arrow[lay-type='add'] {\n right: 20px;\n}\n.layui-carousel[lay-arrow='none'] .layui-carousel-arrow {\n display: none;\n}\n.layui-carousel-arrow:hover,\n.layui-carousel-ind ul:hover {\n background-color: rgba(0, 0, 0, 0.35);\n}\n.layui-carousel:hover .layui-carousel-arrow {\n display: block\\0;\n opacity: 1;\n left: 20px;\n}\n.layui-carousel:hover .layui-carousel-arrow[lay-type='add'] {\n right: 20px;\n}\n.layui-carousel-ind {\n position: relative;\n top: -35px;\n width: 100%;\n line-height: 0 !important;\n text-align: center;\n font-size: 0;\n}\n.layui-carousel[lay-indicator='outside'] {\n margin-bottom: 30px;\n}\n.layui-carousel[lay-indicator='outside'] .layui-carousel-ind {\n top: 10px;\n}\n.layui-carousel[lay-indicator='outside'] .layui-carousel-ind ul {\n background-color: rgba(0, 0, 0, 0.5);\n}\n.layui-carousel[lay-indicator='none'] .layui-carousel-ind {\n display: none;\n}\n.layui-carousel-ind ul {\n display: inline-block;\n padding: 5px;\n background-color: rgba(0, 0, 0, 0.2);\n border-radius: 10px;\n -webkit-transition-duration: 0.3s;\n transition-duration: 0.3s;\n}\n.layui-carousel-ind ul li {\n display: inline-block;\n width: 10px;\n height: 10px;\n margin: 0 3px;\n font-size: 14px;\n background-color: var(--lay-gray-300);\n background-color: rgba(255, 255, 255, 0.5);\n border-radius: 50%;\n cursor: pointer;\n -webkit-transition-duration: 0.3s;\n transition-duration: 0.3s;\n}\n.layui-carousel-ind ul li:hover {\n background-color: rgba(255, 255, 255, 0.7);\n}\n.layui-carousel-ind ul li.layui-this {\n background-color: #fff;\n}\n.layui-carousel > *[carousel-item] > .layui-this,\n.layui-carousel > *[carousel-item] > .layui-carousel-prev,\n.layui-carousel > *[carousel-item] > .layui-carousel-next {\n display: block;\n}\n.layui-carousel > *[carousel-item] > .layui-this {\n -webkit-transform: translateX(0);\n transform: translateX(0);\n}\n.layui-carousel > *[carousel-item] > .layui-carousel-prev {\n -webkit-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.layui-carousel > *[carousel-item] > .layui-carousel-next {\n -webkit-transform: translateX(100%);\n transform: translateX(100%);\n}\n.layui-carousel > *[carousel-item] > .layui-carousel-prev.layui-carousel-right,\n.layui-carousel > *[carousel-item] > .layui-carousel-next.layui-carousel-left {\n -webkit-transform: translateX(0);\n transform: translateX(0);\n}\n.layui-carousel > *[carousel-item] > .layui-this.layui-carousel-left {\n -webkit-transform: translateX(-100%);\n transform: translateX(-100%);\n}\n.layui-carousel > *[carousel-item] > .layui-this.layui-carousel-right {\n -webkit-transform: translateX(100%);\n transform: translateX(100%);\n}\n\n/* 上下切换 */\n.layui-carousel[lay-anim='updown'] .layui-carousel-arrow {\n left: 50% !important;\n top: 20px;\n margin: 0 0 0 -18px;\n}\n.layui-carousel[lay-anim='updown'] .layui-carousel-arrow[lay-type='add'] {\n top: auto !important;\n bottom: 20px;\n}\n.layui-carousel[lay-anim='updown'] .layui-carousel-ind {\n position: absolute;\n top: 50%;\n right: 20px;\n width: auto;\n height: auto;\n}\n.layui-carousel[lay-anim='updown'] .layui-carousel-ind ul {\n padding: 3px 5px;\n}\n.layui-carousel[lay-anim='updown'] .layui-carousel-ind li {\n display: block;\n margin: 6px 0;\n}\n\n.layui-carousel[lay-anim='updown'] > *[carousel-item] > * {\n left: 0 !important;\n}\n.layui-carousel[lay-anim='updown'] > *[carousel-item] > .layui-this {\n -webkit-transform: translateY(0);\n transform: translateY(0);\n}\n.layui-carousel[lay-anim='updown'] > *[carousel-item] > .layui-carousel-prev {\n -webkit-transform: translateY(-100%);\n transform: translateY(-100%);\n}\n.layui-carousel[lay-anim='updown'] > *[carousel-item] > .layui-carousel-next {\n -webkit-transform: translateY(100%);\n transform: translateY(100%);\n}\n.layui-carousel[lay-anim='updown']\n > *[carousel-item]\n > .layui-carousel-prev.layui-carousel-right,\n.layui-carousel[lay-anim='updown']\n > *[carousel-item]\n > .layui-carousel-next.layui-carousel-left {\n -webkit-transform: translateY(0);\n transform: translateY(0);\n}\n.layui-carousel[lay-anim='updown']\n > *[carousel-item]\n > .layui-this.layui-carousel-left {\n -webkit-transform: translateY(-100%);\n transform: translateY(-100%);\n}\n.layui-carousel[lay-anim='updown']\n > *[carousel-item]\n > .layui-this.layui-carousel-right {\n -webkit-transform: translateY(100%);\n transform: translateY(100%);\n}\n\n/* 渐显切换 */\n.layui-carousel[lay-anim='fade'] > *[carousel-item] > * {\n -webkit-transform: translateX(0) !important;\n transform: translateX(0) !important;\n}\n.layui-carousel[lay-anim='fade'] > *[carousel-item] > .layui-carousel-prev,\n.layui-carousel[lay-anim='fade'] > *[carousel-item] > .layui-carousel-next {\n opacity: 0;\n}\n.layui-carousel[lay-anim='fade']\n > *[carousel-item]\n > .layui-carousel-prev.layui-carousel-right,\n.layui-carousel[lay-anim='fade']\n > *[carousel-item]\n > .layui-carousel-next.layui-carousel-left {\n opacity: 1;\n}\n.layui-carousel[lay-anim='fade']\n > *[carousel-item]\n > .layui-this.layui-carousel-left,\n.layui-carousel[lay-anim='fade']\n > *[carousel-item]\n > .layui-this.layui-carousel-right {\n opacity: 0;\n}\n","/** fixbar **/\r\n.layui-fixbar {\r\n position: fixed;\r\n right: 16px;\r\n bottom: 16px;\r\n z-index: 999999;\r\n}\r\n.layui-fixbar li {\r\n width: 50px;\r\n height: 50px;\r\n line-height: 50px;\r\n margin-bottom: 1px;\r\n text-align: center;\r\n cursor: pointer;\r\n font-size: 30px;\r\n background-color: #9f9f9f;\r\n color: #fff;\r\n border-radius: var(--lay-border-radius);\r\n opacity: 0.95;\r\n}\r\n.layui-fixbar li:hover {\r\n opacity: 0.85;\r\n}\r\n.layui-fixbar li:active {\r\n opacity: 1;\r\n}\r\n.layui-fixbar .layui-fixbar-top {\r\n display: none;\r\n font-size: 40px;\r\n}\r\n","/** 穿梭框 **/\r\n.layui-transfer-box,\r\n.layui-transfer-header,\r\n.layui-transfer-search {\r\n border-width: 0;\r\n border-style: solid;\r\n border-color: var(--lay-border-color);\r\n}\r\n.layui-transfer-box {\r\n position: relative;\r\n display: inline-block;\r\n vertical-align: middle;\r\n border-width: 1px;\r\n width: 200px;\r\n height: 360px;\r\n border-radius: var(--lay-border-radius);\r\n background-color: #fff;\r\n}\r\n.layui-transfer-box .layui-form-checkbox {\r\n width: 100%;\r\n margin: 0 !important;\r\n}\r\n.layui-transfer-header {\r\n height: 38px;\r\n line-height: 38px;\r\n padding: 0 11px;\r\n border-bottom-width: 1px;\r\n}\r\n.layui-transfer-search {\r\n position: relative;\r\n padding: 11px;\r\n border-bottom-width: 1px;\r\n}\r\n.layui-transfer-search .layui-input {\r\n height: 32px;\r\n padding-left: 30px;\r\n font-size: 12px;\r\n}\r\n.layui-transfer-search .layui-icon-search {\r\n position: absolute;\r\n left: 20px;\r\n top: 50%;\r\n line-height: normal;\r\n margin-top: -8px;\r\n color: #5f5f5f;\r\n}\r\n.layui-transfer-active {\r\n margin: 0 15px;\r\n display: inline-block;\r\n vertical-align: middle;\r\n}\r\n.layui-transfer-active .layui-btn {\r\n display: block;\r\n margin: 0;\r\n padding: 0 15px;\r\n background-color: var(--lay-color-accent);\r\n border-color: var(--lay-color-accent);\r\n color: #fff;\r\n}\r\n.layui-transfer-active .layui-btn-disabled {\r\n background-color: #fbfbfb;\r\n border-color: var(--lay-border-color);\r\n color: var(--lay-gray-400);\r\n}\r\n.layui-transfer-active .layui-btn:first-child {\r\n margin-bottom: 15px;\r\n}\r\n.layui-transfer-active .layui-btn .layui-icon {\r\n margin: 0;\r\n font-size: 14px !important;\r\n}\r\n.layui-transfer-data {\r\n padding: 5px 0;\r\n overflow: auto;\r\n}\r\n.layui-transfer-data li {\r\n height: 32px;\r\n line-height: 32px;\r\n margin-top: 0 !important;\r\n padding: 0 11px;\r\n list-style-type: none !important;\r\n}\r\n.layui-transfer-data li:hover {\r\n background-color: #f8f8f8;\r\n transition: 0.5s all;\r\n}\r\n.layui-transfer-data .layui-none {\r\n padding: 15px 11px;\r\n text-align: center;\r\n color: #999;\r\n}\r\n","/** 评分组件 **/\r\n.layui-rate,\r\n.layui-rate * {\r\n display: inline-block;\r\n vertical-align: middle;\r\n}\r\n.layui-rate {\r\n padding: 11px 6px 11px 0;\r\n font-size: 0;\r\n}\r\n.layui-rate li {\r\n margin-top: 0 !important;\r\n}\r\n.layui-rate li i.layui-icon {\r\n font-size: 20px;\r\n color: var(--lay-color-orange);\r\n}\r\n.layui-rate li i.layui-icon {\r\n margin-right: 5px;\r\n -webkit-transition: all 0.3s;\r\n transition: all 0.3s;\r\n}\r\n.layui-rate li i:hover,\r\n.layui-rate-hover {\r\n cursor: pointer;\r\n -webkit-transform: scale(1.12);\r\n transform: scale(1.12);\r\n}\r\n.layui-rate[readonly] li i:hover {\r\n cursor: default;\r\n transform: scale(1);\r\n}\r\n","/** 颜色选择器 **/\r\n.layui-colorpicker {\r\n width: 38px;\r\n height: 38px;\r\n border: 1px solid var(--lay-border-color);\r\n padding: 5px;\r\n border-radius: var(--lay-border-radius);\r\n line-height: 24px;\r\n display: inline-block;\r\n cursor: pointer;\r\n -webkit-transition: all 0.3s;\r\n transition: all 0.3s;\r\n box-sizing: border-box;\r\n}\r\n.layui-colorpicker:hover {\r\n border-color: var(--lay-gray-400);\r\n}\r\n.layui-colorpicker.layui-colorpicker-lg {\r\n width: 44px;\r\n height: 44px;\r\n line-height: 30px;\r\n}\r\n.layui-colorpicker.layui-colorpicker-sm {\r\n width: 30px;\r\n height: 30px;\r\n line-height: 20px;\r\n padding: 3px;\r\n}\r\n.layui-colorpicker.layui-colorpicker-xs {\r\n width: 22px;\r\n height: 22px;\r\n line-height: 16px;\r\n padding: 1px;\r\n}\r\n\r\n.layui-colorpicker-trigger-bgcolor {\r\n display: block;\r\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);\r\n border-radius: var(--lay-border-radius);\r\n}\r\n.layui-colorpicker-trigger-span {\r\n display: block;\r\n height: 100%;\r\n box-sizing: border-box;\r\n border: 1px solid rgba(0, 0, 0, 0.15);\r\n border-radius: var(--lay-border-radius);\r\n text-align: center;\r\n}\r\n.layui-colorpicker-trigger-i {\r\n display: inline-block;\r\n color: #fff;\r\n font-size: 12px;\r\n}\r\n.layui-colorpicker-trigger-i.layui-icon-close {\r\n color: #999;\r\n}\r\n\r\n.layui-colorpicker-main {\r\n position: absolute;\r\n left: -999999px;\r\n top: -999999px;\r\n z-index: 77777777;\r\n width: 280px;\r\n margin: 5px 0;\r\n padding: 7px;\r\n background: #fff;\r\n border: 1px solid var(--lay-border-color);\r\n border-radius: var(--lay-border-radius);\r\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);\r\n}\r\n.layui-colorpicker-main-wrapper {\r\n height: 180px;\r\n position: relative;\r\n}\r\n.layui-colorpicker-basis {\r\n width: 260px;\r\n height: 100%;\r\n position: relative;\r\n overflow: hidden;\r\n}\r\n.layui-colorpicker-basis-white {\r\n width: 100%;\r\n height: 100%;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n background: linear-gradient(90deg, #fff, hsla(0, 0%, 100%, 0));\r\n}\r\n.layui-colorpicker-basis-black {\r\n width: 100%;\r\n height: 100%;\r\n position: absolute;\r\n top: 0;\r\n left: 0;\r\n background: linear-gradient(0deg, #000, transparent);\r\n}\r\n.layui-colorpicker-basis-cursor {\r\n width: 10px;\r\n height: 10px;\r\n border: 1px solid #fff;\r\n border-radius: 50%;\r\n position: absolute;\r\n top: 0%;\r\n right: 100%;\r\n cursor: pointer;\r\n transform: translate(-50%, -50%);\r\n}\r\n.layui-colorpicker-side {\r\n position: absolute;\r\n top: 0;\r\n right: 0;\r\n width: 12px;\r\n height: 100%;\r\n background: linear-gradient(#f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00);\r\n}\r\n.layui-colorpicker-side-slider {\r\n width: 100%;\r\n height: 5px;\r\n box-shadow: 0 0 1px #888888;\r\n box-sizing: border-box;\r\n background: #fff;\r\n border-radius: 1px;\r\n border: 1px solid #f0f0f0;\r\n cursor: pointer;\r\n position: absolute;\r\n left: 0;\r\n}\r\n.layui-colorpicker-main-alpha {\r\n display: none;\r\n height: 12px;\r\n margin-top: 7px;\r\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);\r\n}\r\n.layui-colorpicker-alpha-bgcolor {\r\n height: 100%;\r\n position: relative;\r\n}\r\n.layui-colorpicker-alpha-slider {\r\n width: 5px;\r\n height: 100%;\r\n box-shadow: 0 0 1px #888888;\r\n box-sizing: border-box;\r\n background: #fff;\r\n border-radius: 1px;\r\n border: 1px solid #f0f0f0;\r\n cursor: pointer;\r\n position: absolute;\r\n top: 0;\r\n}\r\n.layui-colorpicker-main-pre {\r\n padding-top: 7px;\r\n font-size: 0;\r\n}\r\n.layui-colorpicker-pre {\r\n width: 20px;\r\n height: 20px;\r\n border-radius: var(--lay-border-radius);\r\n display: inline-block;\r\n margin-left: 6px;\r\n margin-bottom: 7px;\r\n cursor: pointer;\r\n}\r\n.layui-colorpicker-pre:nth-child(11n + 1) {\r\n margin-left: 0;\r\n}\r\n.layui-colorpicker-pre-isalpha {\r\n background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);\r\n}\r\n.layui-colorpicker-pre.layui-this {\r\n box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.15);\r\n}\r\n.layui-colorpicker-pre > div {\r\n height: 100%;\r\n border-radius: var(--lay-border-radius);\r\n}\r\n.layui-colorpicker-main-input {\r\n text-align: right;\r\n padding-top: 7px;\r\n}\r\n.layui-colorpicker-main-input .layui-btn-container .layui-btn {\r\n margin: 0 0 0 10px;\r\n}\r\n.layui-colorpicker-main-input div.layui-inline {\r\n float: left;\r\n font-size: 14px;\r\n}\r\n.layui-colorpicker-main-input input.layui-input {\r\n width: 168px;\r\n height: 30px;\r\n color: #5f5f5f;\r\n padding-left: 5px;\r\n}\r\n","/** 滑块 **/\n.layui-slider {\n height: 4px;\n background: var(--lay-gray-300);\n border-radius: var(--lay-border-radius);\n position: relative;\n cursor: pointer;\n}\n.layui-slider-bar {\n border-radius: var(--lay-border-radius);\n position: absolute;\n height: 100%;\n}\n.layui-slider-step {\n position: absolute;\n top: 0;\n width: 4px;\n height: 4px;\n border-radius: 50%;\n background: #fff;\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n}\n.layui-slider-wrap {\n width: 36px;\n height: 36px;\n position: absolute;\n top: -16px;\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n z-index: 10;\n text-align: center;\n}\n.layui-slider-wrap-btn {\n width: 12px;\n height: 12px;\n border-radius: 50%;\n background: #fff;\n display: inline-block;\n vertical-align: middle;\n cursor: pointer;\n transition: 0.3s;\n}\n.layui-slider-wrap:after {\n content: '';\n height: 100%;\n display: inline-block;\n vertical-align: middle;\n}\n.layui-slider-wrap-btn:hover,\n.layui-slider-wrap-btn.layui-slider-hover {\n transform: scale(1.2);\n}\n.layui-slider-wrap-btn.layui-disabled:hover {\n transform: scale(1) !important;\n}\n.layui-slider-tips {\n position: absolute;\n top: -42px;\n z-index: 77777777;\n white-space: nowrap;\n -webkit-transform: translateX(-50%);\n transform: translateX(-50%);\n color: #fff;\n background: #000;\n border-radius: var(--lay-border-radius);\n height: 25px;\n line-height: 25px;\n padding: 0 10px;\n}\n.layui-slider-tips:after {\n content: '';\n position: absolute;\n bottom: -11px;\n left: 50%;\n margin-left: -6px;\n width: 0;\n height: 0;\n border-width: 6px;\n border-style: solid;\n border-color: #000 transparent transparent transparent;\n}\n.layui-slider-input {\n width: 70px;\n height: 32px;\n border: 1px solid var(--lay-border-color);\n border-radius: var(--lay-border-radius);\n font-size: 16px;\n line-height: 32px;\n position: absolute;\n right: 0;\n top: -14px;\n box-sizing: border-box;\n}\n.layui-slider-input-btn {\n position: absolute;\n top: 0;\n right: 0;\n width: 20px;\n height: 100%;\n border-left: 1px solid var(--lay-border-color);\n}\n.layui-slider-input-btn i {\n cursor: pointer;\n position: absolute;\n right: 0;\n bottom: 0;\n width: 20px;\n height: 50%;\n font-size: 12px;\n line-height: 16px;\n text-align: center;\n color: #999;\n}\n.layui-slider-input-btn i:first-child {\n top: 0;\n border-bottom: 1px solid var(--lay-border-color);\n}\n.layui-slider-input-txt {\n height: 100%;\n font-size: 14px;\n}\n.layui-slider-input-txt input {\n height: 100%;\n border: none;\n padding-right: 21px;\n}\n.layui-slider-input-btn i:hover {\n color: var(--lay-color-primary);\n}\n/*垂直滑块*/\n.layui-slider-vertical {\n width: 4px;\n margin-left: 33px;\n}\n.layui-slider-vertical .layui-slider-bar {\n width: 4px;\n}\n.layui-slider-vertical .layui-slider-step {\n top: auto;\n left: 0px;\n -webkit-transform: translateY(50%);\n transform: translateY(50%);\n}\n.layui-slider-vertical .layui-slider-wrap {\n top: auto;\n left: -16px;\n -webkit-transform: translateY(50%);\n transform: translateY(50%);\n}\n.layui-slider-vertical .layui-slider-tips {\n top: auto;\n left: 2px;\n}\n@media \\0screen {\n .layui-slider-wrap-btn {\n margin-left: -20px;\n }\n .layui-slider-vertical .layui-slider-wrap-btn {\n margin-left: 0;\n margin-bottom: -20px;\n }\n .layui-slider-vertical .layui-slider-tips {\n margin-left: -8px;\n }\n .layui-slider > span {\n margin-left: 8px;\n }\n}\n","/** 树组件 **/\n.layui-tree {\n line-height: 22px;\n}\n.layui-tree .layui-form-checkbox {\n margin: 0 !important;\n}\n.layui-tree-set {\n width: 100%;\n position: relative;\n}\n.layui-tree-pack {\n display: none;\n padding-left: 20px;\n position: relative;\n}\n.layui-tree-line .layui-tree-pack {\n padding-left: 27px;\n}\n.layui-tree-line .layui-tree-set .layui-tree-set:after {\n content: '';\n position: absolute;\n top: 14px;\n left: -9px;\n width: 17px;\n height: 0;\n border-top: 1px dotted #c0c4cc;\n}\n.layui-tree-entry {\n position: relative;\n padding: 3px 0;\n height: 26px;\n white-space: nowrap;\n}\n.layui-tree-entry:hover {\n background-color: var(--lay-gray-300);\n}\n.layui-tree-line .layui-tree-entry:hover {\n background-color: rgba(0, 0, 0, 0);\n}\n.layui-tree-line .layui-tree-entry:hover .layui-tree-txt {\n color: #999;\n text-decoration: underline;\n transition: 0.3s;\n}\n.layui-tree-main {\n display: inline-block;\n vertical-align: middle;\n cursor: pointer;\n padding-right: 10px;\n}\n.layui-tree-line .layui-tree-set:before {\n content: '';\n position: absolute;\n top: 0;\n left: -9px;\n width: 0;\n height: 100%;\n border-left: 1px dotted #c0c4cc;\n}\n.layui-tree-line .layui-tree-set.layui-tree-setLineShort:before {\n height: 13px;\n}\n.layui-tree-line .layui-tree-set.layui-tree-setHide:before {\n height: 0;\n}\n.layui-tree-iconClick {\n display: inline-block;\n vertical-align: middle;\n position: relative;\n height: 20px;\n line-height: 20px;\n margin: 0 10px;\n color: #c0c4cc;\n}\n.layui-tree-icon {\n height: 14px;\n line-height: 10px;\n width: 14px;\n margin: 0 11px;\n text-align: center;\n border: 1px solid #c0c4cc;\n}\n.layui-tree-icon .layui-icon {\n font-size: 12px;\n color: #5f5f5f;\n}\n.layui-tree-iconArrow {\n padding: 0 5px;\n}\n.layui-tree-iconArrow:after {\n content: '';\n position: absolute;\n left: 4px;\n top: 3px;\n z-index: 100;\n width: 0;\n height: 0;\n border-width: 5px;\n border-style: solid;\n border-color: transparent transparent transparent #c0c4cc;\n transition: 0.5s;\n}\n.layui-tree-spread\n > .layui-tree-entry\n .layui-tree-iconClick\n > .layui-tree-iconArrow:after {\n transform: rotate(90deg) translate(3px, 4px);\n}\n.layui-tree-txt {\n display: inline-block;\n vertical-align: middle;\n color: #555;\n}\n.layui-tree-search {\n margin-bottom: 15px;\n color: #5f5f5f;\n}\n.layui-tree-btnGroup {\n visibility: hidden;\n display: inline-block;\n vertical-align: middle;\n position: relative;\n}\n.layui-tree-btnGroup .layui-icon {\n display: inline-block;\n vertical-align: middle;\n padding: 0 2px;\n cursor: pointer;\n}\n.layui-tree-btnGroup .layui-icon:hover {\n color: #999;\n transition: 0.3s;\n}\n.layui-tree-entry:hover .layui-tree-btnGroup {\n visibility: visible;\n}\n.layui-tree-editInput {\n position: relative;\n display: inline-block;\n vertical-align: middle;\n height: 20px;\n line-height: 20px;\n padding: 0;\n border: none;\n background-color: rgba(0, 0, 0, 0.05);\n}\n.layui-tree-emptyText {\n text-align: center;\n color: #999;\n}\n","/** 动画 **/\r\n.layui-anim {\r\n -webkit-animation-duration: 0.3s;\r\n -webkit-animation-fill-mode: both;\r\n animation-duration: 0.3s;\r\n animation-fill-mode: both;\r\n}\r\n.layui-anim.layui-icon {\r\n display: inline-block;\r\n}\r\n.layui-anim-loop {\r\n -webkit-animation-iteration-count: infinite;\r\n animation-iteration-count: infinite;\r\n}\r\n.layui-trans,\r\n.layui-trans a {\r\n -webkit-transition: all 0.2s;\r\n transition: all 0.2s;\r\n} /* 过渡变换 */\r\n\r\n/* 循环旋转 */\r\n@-webkit-keyframes layui-rotate {\r\n from {\r\n -webkit-transform: rotate(0deg);\r\n }\r\n to {\r\n -webkit-transform: rotate(360deg);\r\n }\r\n}\r\n@keyframes layui-rotate {\r\n from {\r\n transform: rotate(0deg);\r\n }\r\n to {\r\n transform: rotate(360deg);\r\n }\r\n}\r\n.layui-anim-rotate {\r\n -webkit-animation-name: layui-rotate;\r\n animation-name: layui-rotate;\r\n -webkit-animation-duration: 1s;\r\n animation-duration: 1s;\r\n -webkit-animation-timing-function: linear;\r\n animation-timing-function: linear;\r\n}\r\n\r\n/* 从最底部往上滑入 */\r\n@-webkit-keyframes layui-up {\r\n from {\r\n -webkit-transform: translate3d(0, 100%, 0);\r\n opacity: 0.3;\r\n }\r\n to {\r\n -webkit-transform: translate3d(0, 0, 0);\r\n opacity: 1;\r\n }\r\n}\r\n@keyframes layui-up {\r\n from {\r\n transform: translate3d(0, 100%, 0);\r\n opacity: 0.3;\r\n }\r\n to {\r\n transform: translate3d(0, 0, 0);\r\n opacity: 1;\r\n }\r\n}\r\n.layui-anim-up {\r\n -webkit-animation-name: layui-up;\r\n animation-name: layui-up;\r\n}\r\n\r\n/* 微微往上滑入 */\r\n@-webkit-keyframes layui-upbit {\r\n from {\r\n -webkit-transform: translate3d(0, 15px, 0);\r\n opacity: 0.3;\r\n }\r\n to {\r\n -webkit-transform: translate3d(0, 0, 0);\r\n opacity: 1;\r\n }\r\n}\r\n@keyframes layui-upbit {\r\n from {\r\n transform: translate3d(0, 15px, 0);\r\n opacity: 0.3;\r\n }\r\n to {\r\n transform: translate3d(0, 0, 0);\r\n opacity: 1;\r\n }\r\n}\r\n.layui-anim-upbit {\r\n -webkit-animation-name: layui-upbit;\r\n animation-name: layui-upbit;\r\n}\r\n\r\n/* 从最顶部往下滑入 */\r\n@keyframes layui-down {\r\n 0% {\r\n opacity: 0.3;\r\n transform: translate3d(0, -100%, 0);\r\n }\r\n 100% {\r\n opacity: 1;\r\n transform: translate3d(0, 0, 0);\r\n }\r\n}\r\n.layui-anim-down {\r\n animation-name: layui-down;\r\n}\r\n\r\n/* 微微往下滑入 */\r\n@keyframes layui-downbit {\r\n 0% {\r\n opacity: 0.3;\r\n transform: translate3d(0, -5px, 0);\r\n }\r\n 100% {\r\n opacity: 1;\r\n transform: translate3d(0, 0, 0);\r\n }\r\n}\r\n.layui-anim-downbit {\r\n animation-name: layui-downbit;\r\n}\r\n\r\n/* 放大 */\r\n@-webkit-keyframes layui-scale {\r\n 0% {\r\n opacity: 0.3;\r\n -webkit-transform: scale(0.5);\r\n }\r\n 100% {\r\n opacity: 1;\r\n -webkit-transform: scale(1);\r\n }\r\n}\r\n@keyframes layui-scale {\r\n 0% {\r\n opacity: 0.3;\r\n -ms-transform: scale(0.5);\r\n transform: scale(0.5);\r\n }\r\n 100% {\r\n opacity: 1;\r\n -ms-transform: scale(1);\r\n transform: scale(1);\r\n }\r\n}\r\n.layui-anim-scale {\r\n -webkit-animation-name: layui-scale;\r\n animation-name: layui-scale;\r\n}\r\n\r\n/* 弹簧式放大 */\r\n@-webkit-keyframes layui-scale-spring {\r\n 0% {\r\n opacity: 0.5;\r\n -webkit-transform: scale(0.5);\r\n }\r\n 80% {\r\n opacity: 0.8;\r\n -webkit-transform: scale(1.1);\r\n }\r\n 100% {\r\n opacity: 1;\r\n -webkit-transform: scale(1);\r\n }\r\n}\r\n@keyframes layui-scale-spring {\r\n 0% {\r\n opacity: 0.5;\r\n transform: scale(0.5);\r\n }\r\n 80% {\r\n opacity: 0.8;\r\n transform: scale(1.1);\r\n }\r\n 100% {\r\n opacity: 1;\r\n transform: scale(1);\r\n }\r\n}\r\n.layui-anim-scaleSpring {\r\n -webkit-animation-name: layui-scale-spring;\r\n animation-name: layui-scale-spring;\r\n}\r\n\r\n/* 放小 */\r\n@keyframes layui-scalesmall {\r\n 0% {\r\n opacity: 0.3;\r\n transform: scale(1.5);\r\n }\r\n 100% {\r\n opacity: 1;\r\n transform: scale(1);\r\n }\r\n}\r\n.layui-anim-scalesmall {\r\n animation-name: layui-scalesmall;\r\n}\r\n\r\n/* 弹簧式放小 */\r\n@keyframes layui-scalesmall-spring {\r\n 0% {\r\n opacity: 0.3;\r\n transform: scale(1.5);\r\n }\r\n 80% {\r\n opacity: 0.8;\r\n transform: scale(0.9);\r\n }\r\n 100% {\r\n opacity: 1;\r\n transform: scale(1);\r\n }\r\n}\r\n.layui-anim-scalesmall-spring {\r\n animation-name: layui-scalesmall-spring;\r\n}\r\n\r\n/* 渐显 */\r\n@-webkit-keyframes layui-fadein {\r\n 0% {\r\n opacity: 0;\r\n }\r\n 100% {\r\n opacity: 1;\r\n }\r\n}\r\n@keyframes layui-fadein {\r\n 0% {\r\n opacity: 0;\r\n }\r\n 100% {\r\n opacity: 1;\r\n }\r\n}\r\n.layui-anim-fadein {\r\n -webkit-animation-name: layui-fadein;\r\n animation-name: layui-fadein;\r\n}\r\n\r\n/* 渐隐 */\r\n@-webkit-keyframes layui-fadeout {\r\n 0% {\r\n opacity: 1;\r\n }\r\n 100% {\r\n opacity: 0;\r\n }\r\n}\r\n@keyframes layui-fadeout {\r\n 0% {\r\n opacity: 1;\r\n }\r\n 100% {\r\n opacity: 0;\r\n }\r\n}\r\n.layui-anim-fadeout {\r\n -webkit-animation-name: layui-fadeout;\r\n animation-name: layui-fadeout;\r\n}\r\n","/**\n * code\n */\n\n/** 代码文本修饰 **/\n.layui-code {\n display: block;\n position: relative;\n padding: 15px;\n line-height: 20px;\n border: 1px solid var(--lay-border-color);\n border-left-width: 6px;\n background-color: #fff;\n color: #333;\n font-family: var(--lay-font-monospace);\n font-size: 12px;\n}\n\n/* 字体 */\n.layui-code-wrap {\n font-size: 13px;\n font-family: var(--lay-font-monospace);\n}\n\n/* 基础结构 */\n.layui-code-view {\n display: block;\n position: relative;\n padding: 0 !important;\n border: 1px solid var(--lay-border-color);\n border-left-width: 6px;\n background-color: #fff;\n color: #333;\n}\n.layui-code-view pre {\n margin: 0 !important;\n}\n\n.layui-code-header {\n position: relative;\n z-index: 3;\n padding: 0 11px;\n height: 40px;\n line-height: 40px;\n border-bottom: 1px solid var(--lay-border-color);\n background-color: var(--lay-color-gray);\n font-size: 12px;\n}\n.layui-code-header > .layui-code-header-about {\n position: absolute;\n right: 11px;\n top: 0;\n color: #b7b7b7;\n}\n.layui-code-header-about > a {\n padding-left: 10px;\n}\n\n.layui-code-wrap {\n position: relative;\n display: block;\n z-index: 1;\n margin: 0 !important;\n padding: 11px 0 !important;\n overflow-x: hidden;\n overflow-y: auto;\n}\n.layui-code-line {\n position: relative;\n line-height: 19px;\n margin: 0 !important;\n}\n.layui-code-line-number {\n position: absolute;\n left: 0;\n top: 0;\n padding: 0 8px;\n min-width: 45px;\n height: 100%;\n text-align: right;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n white-space: nowrap;\n overflow: hidden;\n}\n.layui-code-line-content {\n padding: 0 11px;\n word-wrap: break-word;\n white-space: pre-wrap;\n}\n\n.layui-code-ln-mode > .layui-code-wrap > .layui-code-line {\n padding-left: 45px;\n}\n.layui-code-ln-side {\n position: absolute;\n left: 0;\n top: 0;\n bottom: 0;\n z-index: 0;\n width: 45px;\n border-right: 1px solid var(--lay-border-color);\n border-color: rgb(126 122 122 / 15%);\n background-color: var(--lay-color-gray);\n pointer-events: none;\n}\n\n/* 不自动换行 */\n.layui-code-nowrap > .layui-code-wrap {\n overflow: auto;\n}\n.layui-code-nowrap\n > .layui-code-wrap\n > .layui-code-line\n > .layui-code-line-content {\n white-space: pre;\n word-wrap: normal;\n}\n.layui-code-nowrap > .layui-code-ln-side {\n border-right-width: 0 !important;\n background: none !important;\n}\n\n.layui-code-fixbar {\n position: absolute;\n top: 8px;\n right: 11px;\n padding-right: 45px;\n z-index: 5;\n}\n.layui-code-fixbar > span {\n position: absolute;\n right: 0;\n top: 0;\n padding: 0 8px;\n color: #777;\n transition: all 0.3s;\n}\n.layui-code-fixbar > span:hover {\n color: var(--lay-color-accent);\n}\n.layui-code-copy {\n display: none;\n cursor: pointer;\n}\n.layui-code-preview > .layui-code-view > .layui-code-fixbar .layui-code-copy {\n display: none !important;\n}\n.layui-code-view:hover > .layui-code-fixbar .layui-code-copy {\n display: block;\n}\n.layui-code-view:hover > .layui-code-fixbar .layui-code-lang-marker {\n display: none;\n}\n\n/* 深色主题 */\n.layui-code-theme-dark,\n.layui-code-theme-dark > .layui-code-header {\n border-color: rgb(126 122 122 / 15%);\n background-color: #1f1f1f;\n}\n.layui-code-theme-dark {\n border-width: 1px;\n color: #ccc;\n}\n.layui-code-theme-dark > .layui-code-ln-side {\n border-right-color: #2a2a2a;\n background: none;\n color: #6e7681;\n}\n\n/* 代码预览 */\n.layui-code textarea {\n display: none;\n}\n.layui-code-preview > .layui-code,\n.layui-code-preview > .layui-code-view {\n margin: 0;\n}\n.layui-code-preview > .layui-tab {\n position: relative;\n z-index: 1;\n margin-bottom: 0;\n}\n.layui-code-preview .layui-code-item {\n display: none;\n border-top-width: 0;\n}\n.layui-code-item-preview {\n position: relative;\n padding: var(--lay-spacing);\n}\n.layui-code-item-preview > iframe {\n position: absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n border: none;\n}\n\n/* 工具栏 */\n.layui-code-tools {\n position: absolute;\n right: 11px;\n top: 8px;\n line-height: normal;\n}\n.layui-code-tools > i {\n display: inline-block;\n margin-left: 6px;\n padding: 3px;\n cursor: pointer;\n}\n.layui-code-tools > i.layui-icon-file-b {\n color: #999;\n}\n.layui-code-tools > i:hover {\n color: var(--lay-color-accent);\n}\n\n/* 全屏风格 */\n.layui-code-full {\n position: fixed;\n left: 0;\n top: 0;\n z-index: 1111111;\n width: 100%;\n height: 100%;\n background-color: #fff;\n}\n.layui-code-full .layui-code-item {\n width: 100% !important;\n border-width: 0 !important;\n}\n.layui-code-full .layui-code-item,\n.layui-code-full .layui-code-view,\n.layui-code-full .layui-code-wrap {\n height: calc(100vh - 51px) !important;\n box-sizing: border-box;\n}\n.layui-code-full .layui-code-item-preview {\n overflow: auto;\n}\n\n/* 代码高亮重置 */\n.layui-code-view.layui-code-hl {\n line-height: 20px !important;\n border-left-width: 1px;\n}\n.layui-code-view.layui-code-hl > .layui-code-ln-side {\n background-color: transparent;\n}\n.layui-code-theme-dark.layui-code-hl,\n.layui-code-theme-dark.layui-code-hl > .layui-code-ln-side {\n border-color: rgb(126 122 122 / 15%);\n}\n\n/*行高亮*/\n.layui-code-line-highlighted {\n background-color: rgba(142, 150, 170, 0.14);\n}\n.layui-code-line-diff-add {\n background-color: rgba(16, 185, 129, 0.14);\n}\n.layui-code-line-diff-remove {\n background-color: rgba(244, 63, 94, 0.14);\n}\n.layui-code-line-diff-add:before {\n position: absolute;\n content: '+';\n color: #18794e;\n}\n.layui-code-line-diff-remove:before {\n position: absolute;\n content: '-';\n color: #b8272c;\n}\n.layui-code-has-focused-lines .layui-code-line:not(.layui-code-line-has-focus) {\n filter: blur(0.095rem);\n opacity: 0.7;\n -webkit-transition:\n filter 0.35s,\n opacity 0.35s;\n transition:\n filter 0.35s,\n opacity 0.35s;\n}\n.layui-code-has-focused-lines:hover\n .layui-code-line:not(.layui-code-line-has-focus) {\n filter: blur();\n opacity: 1;\n}\n","/**\n * laydate style\n */\n\n/* 初始化 */\n.layui-laydate * {\n margin: 0;\n padding: 0;\n}\n\n/* 主体结构 */\n.layui-laydate,\n.layui-laydate * {\n box-sizing: border-box;\n}\n.layui-laydate {\n position: absolute;\n z-index: 99999999;\n margin: 5px 0;\n border-radius: var(--lay-border-radius);\n font-size: 14px;\n line-height: normal;\n -webkit-animation-duration: 0.2s;\n animation-duration: 0.2s;\n -webkit-animation-fill-mode: both;\n animation-fill-mode: both;\n}\n.layui-laydate-main {\n width: 272px;\n}\n.layui-laydate-header *,\n.layui-laydate-content td,\n.layui-laydate-list li {\n -webkit-transition-duration: 0.3s;\n transition-duration: 0.3s;\n}\n.layui-laydate-shade {\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n position: fixed;\n pointer-events: auto;\n}\n\n/* 微微往下滑入 */\n@keyframes laydate-downbit {\n 0% {\n opacity: 0.3;\n transform: translate3d(0, -5px, 0);\n }\n 100% {\n opacity: 1;\n transform: translate3d(0, 0, 0);\n }\n}\n\n.layui-laydate {\n animation-name: laydate-downbit;\n}\n.layui-laydate-static {\n position: relative;\n z-index: 0;\n display: inline-block;\n margin: 0;\n -webkit-animation: none;\n animation: none;\n}\n\n/* 展开年月列表时 */\n.laydate-ym-show .laydate-prev-m,\n.laydate-ym-show .laydate-next-m {\n display: none !important;\n}\n.laydate-ym-show .laydate-prev-y,\n.laydate-ym-show .laydate-next-y {\n display: inline-block !important;\n}\n.laydate-ym-show .laydate-set-ym span[lay-type='month'] {\n display: none !important;\n}\n\n/* 展开时间列表时 */\n.laydate-time-show .layui-laydate-header .layui-icon,\n.laydate-time-show .laydate-set-ym span[lay-type='year'],\n.laydate-time-show .laydate-set-ym span[lay-type='month'] {\n display: none !important;\n}\n\n/* 头部结构 */\n.layui-laydate-header {\n position: relative;\n line-height: 30px;\n padding: 10px 70px 5px;\n}\n.layui-laydate-header * {\n display: inline-block;\n vertical-align: bottom;\n}\n.layui-laydate-header i {\n position: absolute;\n top: 10px;\n padding: 0 5px;\n color: #999;\n font-size: 18px;\n cursor: pointer;\n}\n.layui-laydate-header i.laydate-prev-y {\n left: 15px;\n}\n.layui-laydate-header i.laydate-prev-m {\n left: 45px;\n}\n.layui-laydate-header i.laydate-next-y {\n right: 15px;\n}\n.layui-laydate-header i.laydate-next-m {\n right: 45px;\n}\n.laydate-time-show .layui-laydate-header {\n padding-left: 10px;\n padding-right: 10px;\n}\n.laydate-set-ym {\n width: 100%;\n text-align: center;\n box-sizing: border-box;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n.laydate-set-ym span {\n padding: 0 10px;\n cursor: pointer;\n}\n.laydate-time-text {\n cursor: default !important;\n}\n\n/* 主体结构 */\n.layui-laydate-content {\n position: relative;\n padding: 10px;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.layui-laydate-content table {\n border-collapse: collapse;\n border-spacing: 0;\n}\n.layui-laydate-content th,\n.layui-laydate-content td {\n width: 36px;\n height: 30px;\n padding: 0;\n text-align: center;\n}\n.layui-laydate-content th {\n font-weight: 400;\n}\n.layui-laydate-content td {\n position: relative;\n cursor: pointer;\n}\n.laydate-day-mark {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n line-height: 30px;\n font-size: 12px;\n overflow: hidden;\n}\n.laydate-day-mark::after {\n position: absolute;\n content: '';\n right: 2px;\n top: 2px;\n width: 5px;\n height: 5px;\n border-radius: 50%;\n}\n.laydate-day-holidays:before {\n position: absolute;\n left: 0;\n top: 0;\n font-size: 12px;\n transform: scale(0.7);\n}\n.laydate-day-holidays:before {\n content: '\\4F11';\n color: #ff5722;\n}\n.laydate-day-holidays[type='workdays']:before {\n content: '\\73ED';\n color: inherit;\n}\n.layui-laydate .layui-this .laydate-day-holidays:before {\n color: #fff;\n}\n\n/* 底部结构 */\n.layui-laydate-footer {\n position: relative;\n height: 46px;\n line-height: 26px;\n padding: 10px;\n}\n.layui-laydate-footer span {\n display: inline-block;\n vertical-align: top;\n height: 26px;\n line-height: 24px;\n padding: 0 10px;\n border: 1px solid #c9c9c9;\n border-radius: var(--lay-border-radius);\n background-color: #fff;\n font-size: 12px;\n cursor: pointer;\n white-space: nowrap;\n transition: all 0.3s;\n}\n.layui-laydate-footer span:hover {\n color: var(--lay-color-accent);\n}\n.layui-laydate-footer span.layui-laydate-preview {\n cursor: default;\n border-color: transparent !important;\n}\n.layui-laydate-footer span.layui-laydate-preview:hover {\n color: #777;\n}\n.layui-laydate-footer span:first-child.layui-laydate-preview {\n padding-left: 0;\n}\n.laydate-footer-btns {\n position: absolute;\n right: 10px;\n top: 10px;\n}\n.laydate-footer-btns span {\n margin: 0 0 0 -1px;\n border-radius: 0px;\n}\n.laydate-footer-btns span:first-child {\n border-radius: var(--lay-border-radius) 0px 0px var(--lay-border-radius);\n}\n.laydate-footer-btns span:last-child {\n border-radius: 0px var(--lay-border-radius) var(--lay-border-radius) 0px;\n}\n\n/* 快捷栏 */\n.layui-laydate-shortcut {\n width: 80px;\n padding: 6px 0;\n display: inline-block;\n vertical-align: top;\n overflow: auto;\n max-height: 276px;\n text-align: center;\n}\n.layui-laydate-shortcut + .layui-laydate-main {\n display: inline-block;\n border-left: 1px solid #e2e2e2;\n}\n.layui-laydate-shortcut > li {\n padding: 5px 8px;\n cursor: pointer;\n line-height: 18px;\n}\n\n/* 年月列表 */\n.layui-laydate .layui-laydate-list {\n position: absolute;\n left: 0;\n top: 0;\n width: 100%;\n height: 100%;\n padding: 10px;\n box-sizing: border-box;\n background-color: #fff;\n}\n.layui-laydate .layui-laydate-list > li {\n position: relative;\n display: inline-block;\n width: 33.3%;\n height: 36px;\n line-height: 36px;\n margin: 3px 0;\n vertical-align: middle;\n text-align: center;\n cursor: pointer;\n list-style: none;\n}\n.layui-laydate .laydate-month-list > li {\n width: 25%;\n margin: 17px 0;\n}\n.laydate-time-list {\n display: table;\n}\n.layui-laydate .laydate-time-list > li {\n display: table-cell;\n height: 100%;\n margin: 0;\n line-height: normal;\n cursor: default;\n}\n.layui-laydate .laydate-time-list p {\n position: relative;\n top: -4px;\n margin: 0;\n line-height: 29px;\n}\n.layui-laydate .laydate-time-list ol {\n height: 181px;\n overflow: hidden;\n}\n.layui-laydate .laydate-time-list > li:hover ol {\n overflow-y: auto;\n}\n.layui-laydate .laydate-time-list ol li {\n width: 130%;\n padding-left: 33px;\n height: 30px;\n line-height: 30px;\n text-align: left;\n cursor: pointer;\n}\n.layui-laydate .laydate-time-list-hide-1 ol li {\n padding-left: 53px;\n}\n.layui-laydate .laydate-time-list-hide-2 ol li {\n padding-left: 117px;\n}\n\n/* 提示 */\n.layui-laydate-hint {\n position: absolute;\n top: 115px;\n left: 50%;\n width: 250px;\n margin-left: -125px;\n line-height: 20px;\n padding: 15px;\n text-align: center;\n font-size: 12px;\n color: #ff5722;\n white-space: pre-line;\n}\n\n/* 双日历 */\n.layui-laydate-range {\n width: 546px;\n}\n.layui-laydate-range .layui-laydate-main {\n display: inline-block;\n vertical-align: middle;\n max-width: 50%;\n}\n.layui-laydate-range .laydate-main-list-1 .layui-laydate-header,\n.layui-laydate-range .laydate-main-list-1 .layui-laydate-content {\n border-left: 1px solid #e2e2e2;\n}\n.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-m,\n.layui-laydate-range.layui-laydate-linkage .laydate-main-list-0 .laydate-next-y,\n.layui-laydate-range.layui-laydate-linkage .laydate-main-list-1 .laydate-prev-m,\n.layui-laydate-range.layui-laydate-linkage\n .laydate-main-list-1\n .laydate-prev-y {\n display: none;\n}\n.layui-laydate-range.layui-laydate-linkage\n .laydate-main-list-1\n .layui-laydate-header,\n.layui-laydate-range.layui-laydate-linkage\n .laydate-main-list-1\n .layui-laydate-content {\n border-left-style: dashed;\n}\n\n/* 默认简约主题 */\n.layui-laydate,\n.layui-laydate-hint {\n border: 1px solid var(--lay-border-color-accent);\n box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12);\n background-color: #fff;\n color: #777;\n}\n.layui-laydate-header {\n border-bottom: 1px solid #e2e2e2;\n}\n.layui-laydate-header i:hover,\n.layui-laydate-header span:hover {\n color: var(--lay-color-accent);\n}\n.layui-laydate-content {\n border-top: none 0;\n border-bottom: none 0;\n}\n.layui-laydate-content th {\n color: #333;\n}\n.layui-laydate-content td {\n color: #777;\n}\n.layui-laydate-content td.laydate-day-now {\n color: var(--lay-color-accent);\n}\n.layui-laydate-content td.laydate-day-now:after {\n content: '';\n position: absolute;\n width: 100%;\n height: 30px;\n left: 0;\n top: 0;\n border: 1px solid var(--lay-color-accent);\n box-sizing: border-box;\n}\n.layui-laydate-linkage .layui-laydate-content td.laydate-selected > div {\n background-color: #cffae9;\n transition: all 0.3s;\n}\n.layui-laydate-linkage .laydate-selected:hover > div {\n background-color: #cffae9 !important;\n}\n.layui-laydate-content td:hover:after,\n.layui-laydate-content td.laydate-selected:after {\n content: none;\n}\n.layui-laydate-content td > div:hover,\n.layui-laydate-list li:hover,\n.layui-laydate-shortcut > li:hover {\n background-color: var(--lay-gray-300);\n color: #333;\n transition: all 0.3s;\n}\n.laydate-time-list li ol {\n margin: 0;\n padding: 0;\n border: 1px solid #e2e2e2;\n border-left-width: 0;\n}\n.laydate-time-list li:first-child ol {\n border-left-width: 1px;\n}\n.laydate-time-list > li:hover {\n background: none;\n}\n.layui-laydate-content .laydate-day-prev,\n.layui-laydate-content .laydate-day-next {\n color: var(--lay-gray-400);\n}\n.layui-laydate-linkage .laydate-selected.laydate-day-prev > div,\n.layui-laydate-linkage .laydate-selected.laydate-day-next > div {\n background: none !important;\n}\n.layui-laydate-footer {\n border-top: 1px solid #e2e2e2;\n}\n.layui-laydate-hint {\n color: #ff5722;\n}\n.laydate-day-mark::after {\n background-color: var(--lay-color-accent);\n}\n.layui-laydate-content td.layui-this .laydate-day-mark::after {\n display: none;\n}\n.layui-laydate-footer span[lay-type='date'] {\n color: var(--lay-color-accent);\n}\n.layui-laydate .layui-this,\n.layui-laydate .layui-this > div {\n background-color: var(--lay-color-accent) !important;\n color: #fff !important;\n}\n.layui-laydate .laydate-disabled,\n.layui-laydate .laydate-disabled:hover {\n background: none !important;\n color: var(--lay-gray-400) !important;\n cursor: not-allowed !important;\n -moz-user-select: none;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.layui-laydate .layui-this.laydate-disabled,\n.layui-laydate .layui-this.laydate-disabled > div {\n background-color: var(--lay-gray-300) !important;\n}\n.layui-laydate-content td > div {\n padding: 7px 0;\n height: 100%;\n}\n\n/* 墨绿/自定义背景色主题 */\n.laydate-theme-molv {\n border: none;\n}\n.laydate-theme-molv.layui-laydate-range {\n width: 548px;\n}\n.laydate-theme-molv .layui-laydate-main {\n width: 274px;\n}\n.laydate-theme-molv .layui-laydate-header {\n border: none;\n background-color: var(--lay-color-primary);\n}\n.laydate-theme-molv .layui-laydate-header i,\n.laydate-theme-molv .layui-laydate-header span {\n color: #f6f6f6;\n}\n.laydate-theme-molv .layui-laydate-header i:hover,\n.laydate-theme-molv .layui-laydate-header span:hover {\n color: #fff;\n}\n.laydate-theme-molv .layui-laydate-content {\n border: 1px solid #e2e2e2;\n border-top: none;\n border-bottom: none;\n}\n.laydate-theme-molv .laydate-main-list-1 .layui-laydate-content {\n border-left: none;\n}\n.laydate-theme-molv .layui-this,\n.laydate-theme-molv .layui-this > div {\n background-color: var(--lay-color-primary) !important;\n}\n.laydate-theme-molv .layui-laydate-footer {\n border: 1px solid #e2e2e2;\n}\n\n/* 格子主题 */\n.laydate-theme-grid .layui-laydate-content td,\n.laydate-theme-grid .layui-laydate-content thead,\n.laydate-theme-grid .laydate-year-list > li,\n.laydate-theme-grid .laydate-month-list > li {\n border: 1px solid #e2e2e2;\n}\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected,\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected:hover {\n background-color: #f2f2f2 !important;\n color: var(--lay-color-primary) !important;\n}\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev,\n.layui-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next {\n color: var(--lay-gray-400) !important;\n}\n.laydate-theme-grid .laydate-year-list,\n.laydate-theme-grid .laydate-month-list {\n margin: 1px 0 0 1px;\n}\n.laydate-theme-grid .laydate-year-list > li,\n.laydate-theme-grid .laydate-month-list > li {\n margin: 0 -1px -1px 0;\n}\n.laydate-theme-grid .laydate-year-list > li {\n height: 43px;\n line-height: 43px;\n}\n.laydate-theme-grid .laydate-month-list > li {\n height: 71px;\n line-height: 71px;\n}\n.laydate-theme-grid .layui-laydate-content td > div {\n height: 29px;\n margin-top: -1px;\n}\n\n/* 圆圈高亮主题 */\n.laydate-theme-circle .layui-laydate-content td > div,\n.laydate-theme-circle .layui-laydate-content td.layui-this > div {\n width: 28px;\n height: 28px;\n line-height: 28px;\n border-radius: 14px;\n margin: 0 4px;\n padding: 0;\n}\n.layui-laydate.laydate-theme-circle .layui-laydate-content table td.layui-this {\n background-color: transparent !important;\n}\n.laydate-theme-grid.laydate-theme-circle .layui-laydate-content td > div {\n margin: 0 3.5px;\n}\n\n/* 全面板 */\n.laydate-theme-fullpanel .layui-laydate-main {\n width: 526px;\n}\n.laydate-theme-fullpanel .layui-laydate-list {\n width: 252px;\n left: 272px;\n}\n.laydate-theme-fullpanel .laydate-set-ym span {\n display: none;\n}\n.laydate-theme-fullpanel .laydate-time-show .layui-laydate-header .layui-icon,\n.laydate-theme-fullpanel\n .laydate-time-show\n .laydate-set-ym\n span[lay-type='year'],\n.laydate-theme-fullpanel\n .laydate-time-show\n .laydate-set-ym\n span[lay-type='month'] {\n display: inline-block !important;\n}\n.laydate-theme-fullpanel .laydate-btns-time {\n display: none;\n}\n.laydate-theme-fullpanel .laydate-time-list-hide-1 ol li {\n padding-left: 49px;\n}\n.laydate-theme-fullpanel .laydate-time-list-hide-2 ol li {\n padding-left: 107px;\n}\n","/**\n * layer style\n */\n\n/* common */\n.layui-layer-shade,\n.layui-layer {\n position: fixed;\n _position: absolute;\n pointer-events: auto;\n}\n.layui-layer-shade {\n opacity: 0;\n transition: opacity 0.35s cubic-bezier(0.34, 0.69, 0.1, 1);\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n}\n.layui-layer {\n top: 150px;\n left: 0;\n margin: 0;\n padding: 0;\n background-color: #fff;\n -webkit-background-clip: content;\n background-clip: content;\n border-radius: var(--lay-border-radius);\n box-shadow: 1px 1px 50px rgba(0, 0, 0, 0.3);\n}\n.layui-layer-close {\n position: absolute;\n}\n.layui-layer-content {\n position: relative;\n}\n.layui-layer-border {\n border: 1px solid #b2b2b2;\n border: 1px solid rgba(0, 0, 0, 0.1);\n box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2);\n}\n.layui-layer-load {\n background: url('data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=')\n #fff center center no-repeat;\n}\n.layui-layer-setwin span,\n.layui-layer-btn a {\n display: inline-block;\n vertical-align: middle;\n}\n\n.layui-layer-move {\n display: none;\n position: fixed;\n left: 0px;\n top: 0px;\n width: 100%;\n height: 100%;\n cursor: move;\n opacity: 0;\n filter: alpha(opacity=0);\n background-color: #fff;\n z-index: 2147483647;\n}\n.layui-layer-resize {\n position: absolute;\n width: 15px;\n height: 15px;\n right: 0;\n bottom: 0;\n cursor: se-resize;\n}\n\n/* 动画 */\n.layer-anim {\n -webkit-animation-fill-mode: both;\n animation-fill-mode: both;\n -webkit-animation-duration: 0.3s;\n animation-duration: 0.3s;\n}\n\n@-webkit-keyframes layer-bounceIn {\n /* 默认 */\n 0% {\n opacity: 0;\n -webkit-transform: scale(0.5);\n transform: scale(0.5);\n }\n 100% {\n opacity: 1;\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n}\n@keyframes layer-bounceIn {\n 0% {\n opacity: 0;\n -webkit-transform: scale(0.5);\n -ms-transform: scale(0.5);\n transform: scale(0.5);\n }\n 100% {\n opacity: 1;\n -webkit-transform: scale(1);\n -ms-transform: scale(1);\n transform: scale(1);\n }\n}\n.layer-anim-00 {\n -webkit-animation-name: layer-bounceIn;\n animation-name: layer-bounceIn;\n}\n\n@-webkit-keyframes layer-zoomInDown {\n 0% {\n opacity: 0;\n -webkit-transform: scale(0.1) translateY(-2000px);\n transform: scale(0.1) translateY(-2000px);\n -webkit-animation-timing-function: ease-in-out;\n animation-timing-function: ease-in-out;\n }\n 60% {\n opacity: 1;\n -webkit-transform: scale(0.475) translateY(60px);\n transform: scale(0.475) translateY(60px);\n -webkit-animation-timing-function: ease-out;\n animation-timing-function: ease-out;\n }\n}\n@keyframes layer-zoomInDown {\n 0% {\n opacity: 0;\n -webkit-transform: scale(0.1) translateY(-2000px);\n -ms-transform: scale(0.1) translateY(-2000px);\n transform: scale(0.1) translateY(-2000px);\n -webkit-animation-timing-function: ease-in-out;\n animation-timing-function: ease-in-out;\n }\n 60% {\n opacity: 1;\n -webkit-transform: scale(0.475) translateY(60px);\n -ms-transform: scale(0.475) translateY(60px);\n transform: scale(0.475) translateY(60px);\n -webkit-animation-timing-function: ease-out;\n animation-timing-function: ease-out;\n }\n}\n.layer-anim-01 {\n -webkit-animation-name: layer-zoomInDown;\n animation-name: layer-zoomInDown;\n}\n\n@-webkit-keyframes layer-fadeInUpBig {\n 0% {\n opacity: 0;\n -webkit-transform: translateY(2000px);\n transform: translateY(2000px);\n }\n 100% {\n opacity: 1;\n -webkit-transform: translateY(0);\n transform: translateY(0);\n }\n}\n@keyframes layer-fadeInUpBig {\n 0% {\n opacity: 0;\n -webkit-transform: translateY(2000px);\n -ms-transform: translateY(2000px);\n transform: translateY(2000px);\n }\n 100% {\n opacity: 1;\n -webkit-transform: translateY(0);\n -ms-transform: translateY(0);\n transform: translateY(0);\n }\n}\n.layer-anim-02 {\n -webkit-animation-name: layer-fadeInUpBig;\n animation-name: layer-fadeInUpBig;\n}\n\n@-webkit-keyframes layer-zoomInLeft {\n 0% {\n opacity: 0;\n -webkit-transform: scale(0.1) translateX(-2000px);\n transform: scale(0.1) translateX(-2000px);\n -webkit-animation-timing-function: ease-in-out;\n animation-timing-function: ease-in-out;\n }\n 60% {\n opacity: 1;\n -webkit-transform: scale(0.475) translateX(48px);\n transform: scale(0.475) translateX(48px);\n -webkit-animation-timing-function: ease-out;\n animation-timing-function: ease-out;\n }\n}\n@keyframes layer-zoomInLeft {\n 0% {\n opacity: 0;\n -webkit-transform: scale(0.1) translateX(-2000px);\n -ms-transform: scale(0.1) translateX(-2000px);\n transform: scale(0.1) translateX(-2000px);\n -webkit-animation-timing-function: ease-in-out;\n animation-timing-function: ease-in-out;\n }\n 60% {\n opacity: 1;\n -webkit-transform: scale(0.475) translateX(48px);\n -ms-transform: scale(0.475) translateX(48px);\n transform: scale(0.475) translateX(48px);\n -webkit-animation-timing-function: ease-out;\n animation-timing-function: ease-out;\n }\n}\n.layer-anim-03 {\n -webkit-animation-name: layer-zoomInLeft;\n animation-name: layer-zoomInLeft;\n}\n\n@-webkit-keyframes layer-rollIn {\n 0% {\n opacity: 0;\n -webkit-transform: translateX(-100%) rotate(-120deg);\n transform: translateX(-100%) rotate(-120deg);\n }\n 100% {\n opacity: 1;\n -webkit-transform: translateX(0px) rotate(0deg);\n transform: translateX(0px) rotate(0deg);\n }\n}\n@keyframes layer-rollIn {\n 0% {\n opacity: 0;\n -webkit-transform: translateX(-100%) rotate(-120deg);\n -ms-transform: translateX(-100%) rotate(-120deg);\n transform: translateX(-100%) rotate(-120deg);\n }\n 100% {\n opacity: 1;\n -webkit-transform: translateX(0px) rotate(0deg);\n -ms-transform: translateX(0px) rotate(0deg);\n transform: translateX(0px) rotate(0deg);\n }\n}\n.layer-anim-04 {\n -webkit-animation-name: layer-rollIn;\n animation-name: layer-rollIn;\n}\n\n@-webkit-keyframes layer-fadeIn {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n@keyframes layer-fadeIn {\n 0% {\n opacity: 0;\n }\n 100% {\n opacity: 1;\n }\n}\n.layer-anim-05 {\n -webkit-animation-name: layer-fadeIn;\n animation-name: layer-fadeIn;\n}\n\n@-webkit-keyframes layer-shake {\n 0%,\n 100% {\n -webkit-transform: translateX(0);\n transform: translateX(0);\n }\n 10%,\n 30%,\n 50%,\n 70%,\n 90% {\n -webkit-transform: translateX(-10px);\n transform: translateX(-10px);\n }\n 20%,\n 40%,\n 60%,\n 80% {\n -webkit-transform: translateX(10px);\n transform: translateX(10px);\n }\n}\n@keyframes layer-shake {\n 0%,\n 100% {\n -webkit-transform: translateX(0);\n -ms-transform: translateX(0);\n transform: translateX(0);\n }\n 10%,\n 30%,\n 50%,\n 70%,\n 90% {\n -webkit-transform: translateX(-10px);\n -ms-transform: translateX(-10px);\n transform: translateX(-10px);\n }\n 20%,\n 40%,\n 60%,\n 80% {\n -webkit-transform: translateX(10px);\n -ms-transform: translateX(10px);\n transform: translateX(10px);\n }\n}\n.layer-anim-06 {\n -webkit-animation-name: layer-shake;\n animation-name: layer-shake;\n}\n\n/* 从上往下 */\n@keyframes layer-slide-down {\n from {\n transform: translate3d(0, -100%, 0);\n }\n to {\n transform: translate3d(0, 0, 0);\n }\n}\n@keyframes layer-slide-down-out {\n from {\n transform: translate3d(0, 0, 0);\n }\n to {\n transform: translate3d(0, -100%, 0);\n }\n}\n.layer-anim-slide-down {\n animation-name: layer-slide-down;\n}\n.layer-anim-slide-down-out {\n animation-name: layer-slide-down-out;\n}\n\n/* 从右往左 */\n@keyframes layer-slide-left {\n from {\n transform: translate3d(100%, 0, 0);\n }\n to {\n transform: translate3d(0, 0, 0);\n }\n}\n@keyframes layer-slide-left-out {\n from {\n transform: translate3d(0, 0, 0);\n }\n to {\n transform: translate3d(100%, 0, 0);\n }\n}\n.layer-anim-slide-left {\n animation-name: layer-slide-left;\n}\n.layer-anim-slide-left-out {\n animation-name: layer-slide-left-out;\n}\n\n/* 从下往上 */\n@keyframes layer-slide-up {\n from {\n transform: translate3d(0, 100%, 0);\n }\n to {\n transform: translate3d(0, 0, 0);\n }\n}\n@keyframes layer-slide-up-out {\n from {\n transform: translate3d(0, 0, 0);\n }\n to {\n transform: translate3d(0, 100%, 0);\n }\n}\n.layer-anim-slide-up {\n animation-name: layer-slide-up;\n}\n.layer-anim-slide-up-out {\n animation-name: layer-slide-up-out;\n}\n\n/* 从左往右 */\n@keyframes layer-slide-right {\n from {\n transform: translate3d(-100%, 0, 0);\n }\n to {\n transform: translate3d(0, 0, 0);\n }\n}\n@keyframes layer-slide-right-out {\n from {\n transform: translate3d(0, 0, 0);\n }\n to {\n transform: translate3d(-100%, 0, 0);\n }\n}\n.layer-anim-slide-right {\n animation-name: layer-slide-right;\n}\n.layer-anim-slide-right-out {\n animation-name: layer-slide-right-out;\n}\n\n/* 标题栏 */\n.layui-layer-title {\n padding: 0 81px 0 16px;\n height: 50px;\n line-height: 50px;\n border-bottom: 1px solid #f0f0f0;\n font-size: 14px;\n color: #333;\n overflow: hidden;\n text-overflow: ellipsis;\n white-space: nowrap;\n border-radius: var(--lay-border-radius) var(--lay-border-radius) 0 0;\n}\n.layui-layer-setwin {\n position: absolute;\n right: 15px;\n top: 16px;\n font-size: 0;\n line-height: initial;\n}\n.layui-layer-setwin span {\n position: relative;\n width: 16px;\n height: 16px;\n line-height: 18px;\n margin-left: 10px;\n text-align: center;\n font-size: 16px;\n cursor: pointer;\n color: #000;\n _overflow: hidden;\n box-sizing: border-box;\n}\n.layui-layer-setwin .layui-layer-min:before {\n content: '';\n position: absolute;\n width: 12px;\n border-bottom: 1px solid #2e2d3c;\n left: 50%;\n top: 50%;\n margin: -0.5px 0 0 -6px;\n cursor: pointer;\n _overflow: hidden;\n}\n.layui-layer-setwin .layui-layer-min:hover:before {\n background-color: #2d93ca;\n}\n.layui-layer-setwin .layui-layer-max:before,\n.layui-layer-setwin .layui-layer-max:after {\n content: '';\n position: absolute;\n left: 50%;\n top: 50%;\n z-index: 1;\n width: 9px;\n height: 9px;\n margin: -5px 0 0 -5px;\n border: 1px solid #2e2d3c;\n}\n.layui-layer-setwin .layui-layer-max:hover:before,\n.layui-layer-setwin .layui-layer-max:hover:after {\n border-color: #2d93ca;\n}\n.layui-layer-setwin .layui-layer-min:hover:before {\n background-color: #2d93ca;\n}\n.layui-layer-setwin .layui-layer-maxmin:before,\n.layui-layer-setwin .layui-layer-maxmin:after {\n width: 7px;\n height: 7px;\n margin: -3px 0 0 -3px;\n background-color: #fff;\n}\n.layui-layer-setwin .layui-layer-maxmin:after {\n z-index: 0;\n margin: -5px 0 0 -1px;\n}\n.layui-layer-setwin .layui-layer-close {\n cursor: pointer;\n}\n.layui-layer-setwin .layui-layer-close:hover {\n opacity: 0.7;\n}\n.layui-layer-setwin .layui-layer-close2 {\n position: absolute;\n right: -28px;\n top: -28px;\n color: #fff;\n background-color: #787878;\n padding: 3px;\n border: 3px solid;\n width: 28px;\n height: 28px;\n font-size: 16px;\n font-weight: bolder;\n border-radius: 50%;\n margin-left: 0;\n}\n.layui-layer-setwin .layui-layer-close2:hover {\n opacity: unset;\n background-color: #3888f6;\n}\n\n/* 按钮栏 */\n.layui-layer-btn {\n text-align: right;\n padding: 0 15px 12px;\n pointer-events: auto;\n -webkit-user-select: none;\n -moz-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.layui-layer-btn a {\n height: 30px;\n line-height: 30px;\n margin: 5px 5px 0;\n padding: 0 var(--lay-spacing);\n border: 1px solid #dedede;\n background-color: #fff;\n color: #333;\n border-radius: var(--lay-border-radius);\n font-weight: 400;\n cursor: pointer;\n text-decoration: none;\n box-sizing: border-box;\n}\n.layui-layer-btn a:hover {\n opacity: 0.9;\n text-decoration: none;\n}\n.layui-layer-btn a:active {\n opacity: 0.8;\n}\n.layui-layer-btn .layui-layer-btn0 {\n border-color: transparent;\n background-color: #1e9fff;\n color: #fff;\n}\n.layui-layer-btn-l {\n text-align: left;\n}\n.layui-layer-btn-c {\n text-align: center;\n}\n.layui-layer-btn-is-loading {\n opacity: 0.5 !important;\n cursor: not-allowed !important;\n cursor: wait !important;\n overflow: hidden;\n white-space: nowrap;\n -webkit-user-select: none;\n -ms-user-select: none;\n user-select: none;\n}\n.layui-layer-btn-is-loading .layui-layer-btn-loading-icon {\n margin-right: 8px;\n font-size: 14px;\n}\n\n/* 定制化 */\n.layui-layer-dialog {\n min-width: 240px;\n}\n.layui-layer-dialog .layui-layer-content {\n position: relative;\n padding: 16px;\n line-height: 24px;\n word-break: break-all;\n overflow: hidden;\n font-size: 14px;\n overflow-x: hidden;\n overflow-y: auto;\n}\n.layui-layer-dialog .layui-layer-content .layui-layer-face {\n position: absolute;\n top: 18px;\n left: 16px;\n color: #959595;\n font-size: 32px;\n _left: -40px;\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-tips {\n color: #f39b12;\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-success {\n color: var(--lay-color-accent);\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-error {\n top: 19px;\n color: #ff5722;\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-question {\n color: #ffb800;\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-lock {\n color: #787878;\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-cry {\n color: #ff5722;\n}\n.layui-layer-dialog .layui-layer-content .layui-icon-face-smile {\n color: var(--lay-color-accent);\n}\n\n.layui-layer-rim {\n border: 6px solid #8d8d8d;\n border: 6px solid rgba(0, 0, 0, 0.3);\n border-radius: 5px;\n box-shadow: none;\n}\n.layui-layer-msg {\n min-width: 180px;\n border: 1px solid #d3d4d3;\n box-shadow: none;\n}\n.layui-layer-hui {\n min-width: 100px;\n background-color: #000;\n filter: alpha(opacity=60);\n background-color: rgba(0, 0, 0, 0.6);\n color: #fff;\n border: none;\n}\n.layui-layer-hui .layui-layer-close {\n color: #fff;\n}\n.layui-layer-hui .layui-layer-content {\n padding: 11px 24px;\n text-align: center;\n}\n.layui-layer-dialog .layui-layer-padding {\n padding: 18px 24px 18px 58px;\n text-align: left;\n}\n.layui-layer-page .layui-layer-content {\n position: relative;\n overflow: auto;\n}\n.layui-layer-page .layui-layer-btn,\n.layui-layer-iframe .layui-layer-btn {\n padding-top: 10px;\n}\n.layui-layer-nobg {\n background: none;\n}\n.layui-layer-iframe iframe {\n display: block;\n width: 100%;\n}\n\n.layui-layer-loading {\n border-radius: 100%;\n background: none;\n box-shadow: none;\n border: none;\n}\n.layui-layer-loading .layui-layer-content {\n width: 76px;\n height: 38px;\n line-height: 38px;\n text-align: center;\n}\n.layui-layer-loading-icon {\n font-size: 38px;\n color: #959595;\n}\n.layui-layer-loading2 {\n text-align: center;\n}\n.layui-layer-loading-2 {\n position: relative;\n height: 38px;\n}\n.layui-layer-loading-2:before,\n.layui-layer-loading-2:after {\n content: '';\n position: absolute;\n left: 50%;\n top: 50%;\n width: 38px;\n height: 38px;\n margin: -19px 0 0 -19px;\n border-radius: 50%;\n border: 3px solid var(--lay-border-color-accent);\n box-sizing: border-box;\n}\n.layui-layer-loading-2:after {\n border-color: transparent;\n border-left-color: #1e9fff;\n}\n\n.layui-layer-tips {\n background: none;\n box-shadow: none;\n border: none;\n}\n.layui-layer-tips .layui-layer-content {\n position: relative;\n line-height: 22px;\n min-width: 12px;\n padding: 8px 15px;\n font-size: 12px;\n _float: left;\n border-radius: var(--lay-border-radius);\n box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2);\n background-color: #000;\n color: #fff;\n}\n.layui-layer-tips .layui-layer-close {\n right: -2px;\n top: -1px;\n}\n.layui-layer-tips i.layui-layer-TipsG {\n position: absolute;\n width: 0;\n height: 0;\n border-width: 8px;\n border-color: transparent;\n border-style: dashed;\n}\n.layui-layer-tips i.layui-layer-TipsT,\n.layui-layer-tips i.layui-layer-TipsB {\n left: 5px;\n border-right-style: solid;\n border-right-color: #000;\n}\n.layui-layer-tips i.layui-layer-TipsT {\n bottom: -8px;\n}\n.layui-layer-tips i.layui-layer-TipsB {\n top: -8px;\n}\n.layui-layer-tips i.layui-layer-TipsR,\n.layui-layer-tips i.layui-layer-TipsL {\n top: 5px;\n border-bottom-style: solid;\n border-bottom-color: #000;\n}\n.layui-layer-tips i.layui-layer-TipsR {\n left: -8px;\n}\n.layui-layer-tips i.layui-layer-TipsL {\n right: -8px;\n}\n\n/* 内置 skin */\n.layui-layer-lan .layui-layer-title {\n background: #4476a7;\n color: #fff;\n border: none;\n}\n.layui-layer-lan .layui-layer-btn {\n padding: 5px 10px 10px;\n border-top: 1px solid #e9e7e7;\n}\n.layui-layer-lan .layui-layer-btn a {\n background: #fff;\n border-color: #e9e7e7;\n color: #333;\n}\n.layui-layer-lan .layui-layer-btn .layui-layer-btn1 {\n background: #c9c5c5;\n}\n.layui-layer-molv .layui-layer-title {\n background: #009f95;\n color: #fff;\n border: none;\n}\n.layui-layer-molv .layui-layer-btn a {\n background: #009f95;\n border-color: #009f95;\n}\n.layui-layer-molv .layui-layer-btn .layui-layer-btn1 {\n background: #92b8b1;\n}\n.layui-layer-lan .layui-layer-setwin .layui-icon,\n.layui-layer-molv .layui-layer-setwin .layui-icon {\n color: #fff;\n}\n\n/* Windows 10 风格主题 */\n.layui-layer-win10 {\n border: 1px solid #aaa;\n box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3);\n border-radius: none;\n}\n.layui-layer-win10 .layui-layer-title {\n height: 32px;\n line-height: 32px;\n padding-left: 8px;\n border-bottom: none;\n font-size: 12px;\n}\n.layui-layer-win10 .layui-layer-setwin {\n right: 0;\n top: 0;\n}\n.layui-layer-win10 .layui-layer-setwin span {\n margin-left: 0;\n width: 32px;\n height: 32px;\n padding: 8px;\n}\n.layui-layer-win10.layui-layer-page .layui-layer-setwin span {\n width: 38px;\n}\n.layui-layer-win10 .layui-layer-setwin span:hover {\n background-color: #e5e5e5;\n}\n.layui-layer-win10 .layui-layer-setwin span.layui-icon-close:hover {\n background-color: #e81123;\n color: #fff;\n}\n.layui-layer-win10.layui-layer-dialog .layui-layer-content {\n padding: var(--lay-spacing-sm) var(--lay-spacing) var(--lay-spacing-lg);\n color: #0033bc;\n}\n.layui-layer-win10.layui-layer-dialog .layui-layer-padding {\n padding-top: 18px;\n padding-left: 58px;\n}\n.layui-layer-win10 .layui-layer-btn {\n padding: 5px 5px 10px;\n border-top: 1px solid #dfdfdf;\n background-color: #f0f0f0;\n}\n.layui-layer-win10 .layui-layer-btn a {\n height: 20px;\n line-height: 18px;\n background-color: #e1e1e1;\n border-color: #adadad;\n color: #000;\n font-size: 12px;\n transition: all 0.3s;\n}\n.layui-layer-win10 .layui-layer-btn a:hover {\n border-color: #2a8edd;\n background-color: #e5f1fb;\n}\n.layui-layer-win10 .layui-layer-btn .layui-layer-btn0 {\n border-color: #0078d7;\n}\n\n/**\n * layer 拓展层\n */\n\n/* prompt */\n.layui-layer-prompt .layui-layer-input {\n display: block;\n width: 260px;\n height: 36px;\n margin: 0 auto;\n line-height: 30px;\n padding-left: 10px;\n border: 1px solid #e6e6e6;\n color: #333;\n}\n.layui-layer-prompt textarea.layui-layer-input {\n width: 300px;\n height: 100px;\n line-height: 20px;\n padding: 6px 10px;\n}\n.layui-layer-prompt .layui-layer-content {\n padding: var(--lay-spacing);\n}\n.layui-layer-prompt .layui-layer-btn {\n padding-top: 0;\n}\n\n/* tab */\n.layui-layer-tab {\n box-shadow: 1px 1px 50px rgba(0, 0, 0, 0.4);\n}\n.layui-layer-tab .layui-layer-title {\n padding-left: 0;\n overflow: visible;\n}\n.layui-layer-tab .layui-layer-title span {\n position: relative;\n display: inline-block;\n vertical-align: top;\n border-left: 1px solid transparent;\n border-right: 1px solid transparent;\n min-width: 80px;\n max-width: 300px;\n padding: 0 var(--lay-spacing);\n text-align: center;\n cursor: default;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n cursor: pointer;\n}\n.layui-layer-tab .layui-layer-title span.layui-this {\n height: 51px;\n border-left-color: var(--lay-border-color);\n border-right-color: var(--lay-border-color);\n background-color: #fff;\n z-index: 10;\n}\n.layui-layer-tab .layui-layer-title span:first-child {\n border-left-color: transparent;\n}\n.layui-layer-tabmain {\n line-height: 24px;\n clear: both;\n}\n.layui-layer-tabmain .layui-layer-tabli {\n display: none;\n}\n.layui-layer-tabmain .layui-layer-tabli.layui-this {\n display: block;\n}\n\n/* photos */\n.layui-layer-photos {\n background: none;\n box-shadow: none;\n}\n.layui-layer-photos .layui-layer-content {\n overflow: visible;\n text-align: center;\n}\n.layui-layer-photos .layer-layer-photos-main img {\n position: relative;\n width: 100%;\n display: inline-block;\n vertical-align: top;\n}\n.layui-layer-photos-prev,\n.layui-layer-photos-next {\n position: fixed;\n top: 50%;\n width: 52px;\n height: 52px;\n line-height: 52px;\n margin-top: -26px;\n cursor: pointer;\n font-size: 52px;\n color: #717171;\n}\n.layui-layer-photos-prev {\n left: 32px;\n}\n.layui-layer-photos-next {\n right: 32px;\n}\n.layui-layer-photos-prev:hover,\n.layui-layer-photos-next:hover {\n color: #959595;\n}\n\n.layui-layer-photos-toolbar {\n position: fixed;\n left: 0;\n right: 0;\n bottom: 0;\n width: 100%;\n height: 52px;\n line-height: 52px;\n background-color: rgba(0, 0, 0, 0.32);\n color: #fff;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n font-size: 0;\n}\n.layui-layer-photos-toolbar > * {\n display: inline-block;\n vertical-align: top;\n padding: 0 var(--lay-spacing);\n font-size: 12px;\n color: #fff;\n}\n.layui-layer-photos-toolbar * {\n font-size: 12px;\n}\n.layui-layer-photos-header {\n top: 0;\n bottom: auto;\n}\n.layui-layer-photos-header > span {\n cursor: pointer;\n}\n.layui-layer-photos-header > span:hover {\n background-color: rgba(51, 51, 51, 0.32);\n}\n.layui-layer-photos-header .layui-icon {\n font-size: 18px;\n}\n.layui-layer-photos-footer > h3 {\n max-width: 65%;\n text-overflow: ellipsis;\n overflow: hidden;\n white-space: nowrap;\n}\n.layui-layer-photos-footer a:hover {\n text-decoration: underline;\n}\n.layui-layer-photos-footer em {\n font-style: normal;\n}\n\n/* 关闭动画 */\n@-webkit-keyframes layer-bounceOut {\n 100% {\n opacity: 0;\n -webkit-transform: scale(0.7);\n transform: scale(0.7);\n }\n 30% {\n -webkit-transform: scale(1.05);\n transform: scale(1.05);\n }\n 0% {\n -webkit-transform: scale(1);\n transform: scale(1);\n }\n}\n@keyframes layer-bounceOut {\n 100% {\n opacity: 0;\n -webkit-transform: scale(0.7);\n -ms-transform: scale(0.7);\n transform: scale(0.7);\n }\n 30% {\n -webkit-transform: scale(1.05);\n -ms-transform: scale(1.05);\n transform: scale(1.05);\n }\n 0% {\n -webkit-transform: scale(1);\n -ms-transform: scale(1);\n transform: scale(1);\n }\n}\n.layer-anim-close {\n -webkit-animation-name: layer-bounceOut;\n animation-name: layer-bounceOut;\n -webkit-animation-fill-mode: both;\n animation-fill-mode: both;\n -webkit-animation-duration: 0.2s;\n animation-duration: 0.2s;\n}\n"]} \ No newline at end of file diff --git a/dist/index.js b/dist/index.js new file mode 100644 index 000000000..752024d8a --- /dev/null +++ b/dist/index.js @@ -0,0 +1,30 @@ +export { layui } from './core/layui.js'; +export { lay } from './core/lay.js'; +export { laytpl } from './core/laytpl.js'; +export { i18n } from './core/i18n.js'; +export { default as $, default as jquery } from 'jquery'; +export { component, component as componentBuilder } from './core/component.js'; +export { laypage } from './components/laypage.js'; +export { laydate } from './components/laydate.js'; +export { layer } from './components/layer.js'; +export { dropdown } from './components/dropdown.js'; +export { slider } from './components/slider.js'; +export { colorpicker } from './components/colorpicker.js'; +export { tab } from './components/tab.js'; +export { nav } from './components/nav.js'; +export { breadcrumb } from './components/breadcrumb.js'; +export { progress } from './components/progress.js'; +export { collapse } from './components/collapse.js'; +export { element } from './components/element.js'; +export { upload } from './components/upload.js'; +export { form } from './components/form.js'; +export { table } from './components/table.js'; +export { treeTable } from './components/treeTable.js'; +export { tabs } from './components/tabs.js'; +export { tree } from './components/tree.js'; +export { transfer } from './components/transfer.js'; +export { carousel } from './components/carousel.js'; +export { rate } from './components/rate.js'; +export { flow } from './components/flow.js'; +export { util } from './components/util.js'; +export { code } from './components/code.js'; diff --git a/dist/layui.esm.js b/dist/layui.esm.js new file mode 100644 index 000000000..be7295912 --- /dev/null +++ b/dist/layui.esm.js @@ -0,0 +1,2 @@ +/** 3.0.0-alpha.3 | MIT Licensed */var e,t=window.document,n=window.location,i={timeout:10,debug:!1,version:!1},a={modules:{},status:{},event:{},callback:{}},r=function(){this.v="3.0.0-alpha.3"},o=window.LAYUI_GLOBAL||{},l=(e=t.currentScript&&"SCRIPT"===t.currentScript.tagName.toUpperCase()?t.currentScript.src:function(){for(var e,n=t.getElementsByTagName("script"),i=n.length-1,a=i;a>0;a--)if("interactive"===n[a].readyState){e=n[a].src;break}return e||n[i].src}(),i.dir=o.dir||e.substring(0,e.lastIndexOf("/")+1)),s=function(e,t){e="[Layui warn]: "+e,/warn|error/.test((t=t||"warn").trim())&&(t="warn"),window.console[t](e)},c=Object.create(null),d=function(e,t){c._size&&c._size>100&&((c=Object.create(null))._size=0),c[e]||(c[e]=!0,c._size=(c._size||0)+1,s(e,t))},u=i.builtin={lay:"lay",layer:"layer",laydate:"laydate",laypage:"laypage",laytpl:"laytpl",form:"form",upload:"upload",dropdown:"dropdown",transfer:"transfer",tree:"tree",table:"table",treeTable:"treeTable",tabs:"tabs",tab:"tab",nav:"nav",breadcrumb:"breadcrumb",progress:"progress",collapse:"collapse",element:"element",rate:"rate",colorpicker:"colorpicker",slider:"slider",carousel:"carousel",flow:"flow",util:"util",code:"code",jquery:"jquery",component:"component",i18n:"i18n",all:"all","layui.all":"layui.all"},f=function(e,t,n){var i=function(e){("load"===e.type||/^(complete|loaded)$/.test((e.currentTarget||e.srcElement).readyState))&&(r(),"function"==typeof t&&t(e))},a=function(e){r(),"function"==typeof n&&n(e)},r=function(){e.detachEvent?e.detachEvent("onreadystatechange",i):(e.removeEventListener("load",i,!1),e.removeEventListener("error",a,!1))};!e.attachEvent||e.attachEvent.toString&&e.attachEvent.toString().indexOf("[native code")<0?(e.addEventListener("load",i,!1),e.addEventListener("error",a,!1)):e.attachEvent("onreadystatechange",i)};r.prototype.cache=Object.assign(i,a),r.prototype.config=function(e){return Object.assign(i,e),this},r.prototype.define=function(e,t){return"function"==typeof e&&(t=e,e=[]),this.use(e,function(){var e=function(e,t){h[e]=t,a.status[e]=!0};return"function"==typeof t&&t(function(n,i){e(n,i),a.callback[n]=function(){t(e)}}),this},null,"define"),this},r.prototype.use=function(e,r,o,c){var d=this,p=i.dir=i.dir?i.dir:l;if(e="string"==typeof e?[e]:"function"==typeof e?(r=e,["all"]):e,i.host||(i.host=(p.match(/\/\/([\s\S]+?)\//)||["//"+n.host+"/"])[0]),!e)return d;window.jQuery&&window.jQuery.fn.on&&(d.each(e,function(t,n){"jquery"===n&&e.splice(t,1)}),h.jquery=h.$=window.jQuery),o=o||[];var y=e[0],m=d.modules[y],v="object"==typeof m,g=function(){o.push(h[y]),e.length>1?d.use(e.slice(1),r,o,c):"function"==typeof r&&function(){if(h.jquery&&"function"==typeof h.jquery&&"define"!==c)return h.jquery(function(){r.apply(h,o)});r.apply(h,o)}()},b=function(){var e=0;!function t(){if(++e>1e3*i.timeout/5)return s(y+" is not a valid module","error");(v?h[y]=window[m.api]:a.status[y])?g():setTimeout(t,5)}()};if(0===e.length||h["layui.all"]&&u[y])return g(),d;var x=v?m.src:m,E=u[y]?p+"modules/":x?"":i.base;x||(x=y);var C,T=E+(x=x.replace(/\s/g,"").replace(/\.js[^/.]*$/,""))+".js";if(!a.modules[y]&&h[y]&&(a.modules[y]=T),a.modules[y])b();else{var w=t.getElementsByTagName("head")[0],k=t.createElement("script");k.async=!0,k.charset="utf-8",k.src=T+((C=!0===i.version?i.v||(new Date).getTime():i.version||"")?"?v="+C:""),w.appendChild(k),f(k,function(){w.removeChild(k),b()},function(){w.removeChild(k)}),a.modules[y]=T}return d},r.prototype.modules=Object.assign({},u),r.prototype.extend=function(e){var t=this,n=i.base||"",a=/^\{\/\}/;for(var r in e=e||{})if(t[r]||t.modules[r])s("the "+r+" module already exists, extend failure");else{var o=e[r];"string"==typeof o&&(a.test(o)&&(n=""),o=(n+o).replace(a,"")),t.modules[r]=o}return t},r.prototype.disuse=function(e){var t=this;return e=t.isArray(e)?e:[e],t.each(e,function(e,n){delete t[n],delete u[n],delete t.modules[n],delete a.status[n],delete a.modules[n]}),t},r.prototype.getStyle=function(e,t){var n=e.currentStyle?e.currentStyle:window.getComputedStyle(e,null);return n.getPropertyValue?n.getPropertyValue(t):n.getAttribute(t.replace(/-(\w)/g,function(e,t){return t?t.toUpperCase():""}))},r.prototype.link=function(e,n,a){var r=this,o=t.getElementsByTagName("head")[0],l="function"==typeof n;if("string"==typeof n&&(a=n),"object"==typeof e){var c="array"===r.type(a);return r.each(e,function(t,i){r.link(i,t===e.length-1&&n,c&&a[t])})}a="layuicss-"+(a=a||e.replace(/^(#|(http(s?)):\/\/|\/\/)|\.|\/|\?.+/g,""));var d=t.getElementById(a);return d||((d=t.createElement("link")).href=e+(i.debug?"?v="+(new Date).getTime():""),d.rel="stylesheet",d.id=a,o.appendChild(d)),"complete"===d.__lay_readyState__?(l&&n(d),r):(f(d,function(){d.__lay_readyState__="complete",l&&n(d)},function(){s(e+" load error","error"),o.removeChild(d)}),r)},r.prototype.addcss=function(e,t,n){return h.link(i.dir+"css/"+e,t,n)},r.prototype.factory=function(e){if(h[e])return"function"==typeof i.callback[e]?i.callback[e]:null},r.prototype.img=function(e,t,n){var i=new Image;if(i.src=e,i.complete)return t(i);i.onload=function(){i.onload=null,"function"==typeof t&&t(i)},i.onerror=function(e){i.onerror=null,"function"==typeof n&&n(e)}},r.prototype.router=r.prototype.hash=function(e){var t={path:[],pathname:[],search:{},hash:((e=e||n.hash).match(/[^#](#.*$)/)||[])[1]||"",href:""};return/^#/.test(e)?(e=e.replace(/^#/,""),t.href=e,e=e.replace(/([^#])(#.*$)/,"$1").split("/")||[],this.each(e,function(e,n){/^\w+=/.test(n)?(n=n.split("="),t.search[n[0]]=n[1]):t.path.push(n)}),t.pathname=t.path,t):t},r.prototype.url=function(e){var t,i;return{pathname:(e?((e.match(/\.[^.]+?\/.+/)||[])[0]||"").replace(/^[^/]+/,"").replace(/\?.+/,""):n.pathname).replace(/^\//,"").split("/"),search:(t={},i=(e?((e.match(/\?.+/)||[])[0]||"").replace(/#.+/,""):n.search).replace(/^\?+/,"").split("&"),this.each(i,function(e,n){var i=n.indexOf("="),a=i<0?n.substr(0,n.length):0!==i&&n.substr(0,i);a&&(t[a]=i>0?n.substr(i+1):null)}),t),hash:this.router(e?(e.match(/#.+/)||[])[0]||"/":n.hash)}},r.prototype.data=function(e,t,n){if(e=e||"layui",n=n||localStorage,null===t)return delete n[e];var i;t="object"==typeof t?t:{key:t};try{i=JSON.parse(n[e])}catch{i={}}return"value"in t&&(i[t.key]=t.value),t.remove&&delete i[t.key],n[e]=JSON.stringify(i),t.key?i[t.key]:i},r.prototype.sessionData=function(e,t){return this.data(e,t,sessionStorage)},r.prototype.device=function(e){var t=navigator.userAgent.toLowerCase(),n=function(e){var n=new RegExp(e+"/([^\\s\\_\\-]+)");return(e=(t.match(n)||[])[1])||!1},i={os:/windows/.test(t)?"windows":/linux/.test(t)?"linux":/iphone|ipod|ipad|ios/.test(t)?"ios":/mac/.test(t)?"mac":void 0,ie:!(!window.ActiveXObject&&!("ActiveXObject"in window))&&((t.match(/msie\s(\d+)/)||[])[1]||"11"),weixin:n("micromessenger")};return e&&!i[e]&&(i[e]=n(e)),i.android=/android/.test(t),i.ios="ios"===i.os,i.mobile=i.android||i.ios,i},r.prototype.hint=function(){return{error:s,errorOnce:d}},r.prototype._typeof=r.prototype.type=function(e){return null===e?String(e):"object"==typeof e||"function"==typeof e?(t=(t=Object.prototype.toString.call(e).match(/\s(.+)\]$/)||[])[1]||"Object",new RegExp("\\b(Function|Array|Date|RegExp|Object|Error|Symbol)\\b").test(t)?t.toLowerCase():"object"):typeof e;var t},r.prototype._isArray=r.prototype.isArray=function(e){var t,n=this.type(e);return!(!e||"object"!=typeof e||e===window)&&(t="length"in e&&e.length,"array"===n||0===t||"number"==typeof t&&t>0&&t-1 in e)},r.prototype.each=function(e,t){var n,i=this,a=function(e,n){return t.call(n[e],e,n[e])};if("function"!=typeof t)return i;if(e=e||[],i.isArray(e))for(n=0;na?1:i(window.innerHeight||m.documentElement.clientHeight)},v.autoIncrementer=function(e,t={}){const{target:n=m.body}=t,i="_LAY_AUTOINCREMENTER_ID_",a=n[i]=n[i]||{};return a[e]=a[e]||0,++a[e]},v.getStyleRules=function(e,t){if(e){var n=e.sheet||e.styleSheet||{},i=n.cssRules||n.rules;return"function"==typeof t&&h.each(i,function(e,n){if(t(n,e))return!0}),i}},v.style=function(e){e=e||{};var t=v.elem("style"),n=e.text||"",i=e.target;if(n){var a;if("styleSheet"in t?(t.setAttribute("type","text/css"),t.styleSheet.cssText=n):t.innerHTML=n,t.id="LAY-STYLE-"+(e.id||(a=v.style.index||0,v.style.index++,"DF-"+a)),i){var r=v(i).find("#"+t.id);r[0]&&r.remove(),v(i).append(t)}return t}},v.position=function(e,t,n){if(t){n=n||{},e!==m&&e!==v("body")[0]||(n.clickType="right");var i,a="right"===n.clickType?{left:(i=n.e||window.event||{}).clientX,top:i.clientY,right:i.clientX,bottom:i.clientY}:e.getBoundingClientRect(),r=t.offsetWidth,o=t.offsetHeight,l=function(e){return e=e?"scrollLeft":"scrollTop",m.body[e]|m.documentElement[e]},s=function(e){return m.documentElement[e?"clientWidth":"clientHeight"]},c="margin"in n?n.margin:5,d=a.left,u=a.bottom;"center"===n.align?d-=(r-e.offsetWidth)/2:"right"===n.align&&(d=d-r+e.offsetWidth),d+r+c>s("width")&&(d=s("width")-r-c),ds()&&(a.top>o+c&&a.top<=s()?u=a.top-o-2*c:n.allowBottomOut||(u=s()-o-2*c)<0&&(u=0));var f=n.position;f&&(t.style.position=f);var p=n.offset?n.offset[0]:0,h=n.offset?n.offset[1]:0;if(t.style.left=d+("fixed"===f?0:l(1))+p+"px",t.style.top=u+("fixed"===f?0:l())+h+"px",!v.hasScrollbar()){var y=t.getBoundingClientRect();!n.SYSTEM_RELOAD&&y.bottom+c>s()&&(n.SYSTEM_RELOAD=!0,setTimeout(function(){v.position(e,t,n)},50))}}},v.options=function(e,t){if(t="object"==typeof t?t:{attr:t},e===m)return{};var n=v(e),i=t.attr||"lay-options",a=n.attr(i);try{return new Function("return "+(a||"{}"))()}catch(e){return h.hint().error(t.errorText||[i+'="'+a+'"',"\n parseerror: "+e].join("\n"),"error"),{}}},v.isTopElem=function(e){var t=[m,v("body")[0]],n=!1;return v.each(t,function(t,i){if(i===e)return n=!0}),n},v.clipboard={writeText:function(e){var t=String(e.text);function n(){var n=m.createElement("textarea");n.value=t,n.style.position="fixed",n.style.opacity="0",n.style.top="0px",n.style.left="0px",m.body.appendChild(n),n.select();try{m.execCommand("copy"),"function"==typeof e.done&&e.done()}catch(t){"function"==typeof e.error&&e.error(t)}finally{n.remove?n.remove():m.body.removeChild(n)}}navigator&&"clipboard"in navigator?navigator.clipboard.writeText(t).then(e.done,function(){n()}):n()}},v.passiveSupported=function(){var e=!1;try{var t=Object.defineProperty({},"passive",{get:function(){return e=!0}});window.addEventListener("test",null,t),window.removeEventListener("test",null,t)}catch{}return e}(),v.touchEventsSupported=function(){return"ontouchstart"in window},v.touchSwipe=function(e,t){var n=t,i=v(e)[0],a=!("preventDefault"in n)||n.preventDefault;if(i&&v.touchEventsSupported()){var r={pointerStart:{x:0,y:0},pointerEnd:{x:0,y:0},distanceX:0,distanceY:0,direction:"none",timeStart:null},o=function(e){1===e.touches.length&&(c(),r.timeStart=Date.now(),r.pointerStart.x=r.pointerEnd.x=e.touches[0].clientX,r.pointerStart.y=r.pointerEnd.y=e.touches[0].clientY,r.distanceX=r.distanceY=0,r.direction="none",n.onTouchStart&&n.onTouchStart(e,r))},l=function(e){a&&e.preventDefault(),r.pointerEnd.x=e.touches[0].clientX,r.pointerEnd.y=e.touches[0].clientY,r.distanceX=r.pointerStart.x-r.pointerEnd.x,r.distanceY=r.pointerStart.y-r.pointerEnd.y,Math.abs(r.distanceX)>Math.abs(r.distanceY)?r.direction=r.distanceX>0?"left":"right":r.direction=r.distanceY>0?"up":"down",n.onTouchMove&&n.onTouchMove(e,r)},s=function(e){n.onTouchEnd&&n.onTouchEnd(e,r),d()},c=function(){i.addEventListener("touchmove",l,!!v.passiveSupported&&{passive:!1}),i.addEventListener("touchend",s),i.addEventListener("touchcancel",s)},d=function(){i.removeEventListener("touchmove",l),i.removeEventListener("touchend",s,!!v.passiveSupported&&{passive:!1}),i.removeEventListener("touchcancel",s)};i.__lay_touchswipe_cb_&&i.removeEventListener("touchstart",i.__lay_touchswipe_cb_),i.__lay_touchswipe_cb_=o,i.addEventListener("touchstart",o)}},v.addEvent=m.addEventListener?function(e,t,n,i){e.addEventListener(t,n,i)}:function(e,t,n){var i="_lay_on_"+t,a=function(t){t.target=t.srcElement,n.call(e,t)};a._rawFn=n,e[i]||(e[i]=[]);var r=!1;v.each(e[i],function(e,t){if(t._rawFn===n)return r=!0,!0}),r||(e[i].push(a),e.attachEvent("on"+t,a))},v.removeEvent=m.removeEventListener?function(e,t,n,i){e.removeEventListener(t,n,i)}:function(e,t,n){var i="_lay_on_"+t,a=e[i];if(h.isArray(a)){var r=[];v.each(a,function(i,a){a._rawFn===n?e.detachEvent("on"+t,a):r.push(a)}),e[i]=r}},v.onClickOutside=function(e,t,n){var i=(n=n||{}).event||("onpointerdown"in window?"pointerdown":"mousedown"),a=n.scope||m,r=n.ignore||[],o=!("capture"in n)||n.capture,l=n.detectIframe;function s(e,t,n,i){return e.addEventListener?e.addEventListener(t,n,i):e.attachEvent("on"+t,n),function(){e.removeEventListener?e.removeEventListener(t,n,i):e.detachEvent("on"+t,n)}}var c=[s(a,i,function(n){var i=e,a=n.target||n.srcElement,o=function(e){var t=e.composedPath&&e.composedPath()||e.path,n=e.target||e.srcElement;if(null!=t)return t;return[n].concat(function e(t,n){n=n||[];var i=t.parentNode;return i?e(i,n.concat([i])):n}(n))}(n);i&&i!==a&&-1===o.indexOf(i)&&(function(e,t){for(var n=e.target||e.srcElement,i=0;i]|&(?=#?[a-zA-Z0-9]+)/g.test(e+="")?e.replace(/&(?=#?[a-zA-Z0-9]+;?)/g,"&").replace(//g,">").replace(/'/g,"'").replace(/"/g,"""):e},v.unescape=function(e){return null==e?"":String(e).replace(/"/g,'"').replace(/'/g,"'").replace(/>/g,">").replace(/</g,"<").replace(/&/g,"&")};var C,T,w=(C=0,T=null,function(e){e=e||"id";var t=(new Date).getTime();return t===T?C++:(C=0,T=t),e+"-"+t+"-"+Math.floor(1e4*Math.random())+"-"+C});v.createSharedResizeObserver=function(e){if(void 0===window.ResizeObserver)return console.warn("ResizeObserver is not supported in this browser."),null;var t="lay-"+(e=e||"")+"-resizeobserver-key",n={},i=new ResizeObserver(function(e){for(var i=0;i0)return n[0].style[e]}():n.each(function(n,a){"object"==typeof e?v.each(e,function(e,t){a.style[e]=i(t)}):a.style[e]=i(t)})},g.fn.width=function(e){var t=this;return void 0===e?function(){if(t.length>0)return t[0].offsetWidth}():t.each(function(){t.css("width",e)})},g.fn.height=function(e){var t=this;return void 0===e?function(){if(t.length>0)return t[0].offsetHeight}():t.each(function(){t.css("height",e)})},g.fn.attr=function(e,t){var n=this;return void 0===t?function(){if(n.length>0)return n[0].getAttribute(e)}():n.each(function(n,i){i.setAttribute(e,t)})},g.fn.removeAttr=function(e){return this.each(function(t,n){n.removeAttribute(e)})},g.fn.html=function(e){var t=this;return void 0===e?function(){if(t.length>0)return t[0].innerHTML}():this.each(function(t,n){n.innerHTML=e})},g.fn.val=function(e){var t=this;return void 0===e?function(){if(t.length>0)return t[0].value}():this.each(function(t,n){n.value=e})},g.fn.append=function(e){return this.each(function(t,n){"object"==typeof e?n.appendChild(e):n.innerHTML=n.innerHTML+e})},g.fn.remove=function(e){return this.each(function(t,n){e?n.removeChild(e):n.parentNode.removeChild(n)})},g.fn.on=function(e,t,n){return this.each(function(i,a){v.addEvent(a,e,t,n)})},g.fn.off=function(e,t,n){return this.each(function(i,a){v.removeEvent(a,e,t,n)})};var k=function(){var e=this,t=e.config;return{config:t,render:function(n,i){t.data=n;var a=e.render();if(t.target){var r=document.querySelector(t.target);r&&(r.innerHTML=a)}return"function"==typeof i?(i(a),this):a},compile:function(n){return t.template=n,delete e.compilerCache,this},error:function(e){return e&&(t.error=e),this},parse:function(e,t){return this.compile(e).render(t)}}},S={escape:function(e){var t=/[<"'>]|&(?=#?[a-zA-Z0-9]+)/g;return null==e?"":(e+="",t.test(e)?e.replace(t,function(e){return"&#"+e.charCodeAt(0)+";"}):e)}},_=function(e,t){return new RegExp(e,t||"g")},L=function(e,t,n){t=t||{};var i="Laytpl "+((t=Object.assign({errorContext:""},t)).type||"")+"Error: "+e,a=t.errorContext;return delete t.errorContext,"object"==typeof console&&console.error(i,"\n",a,"\n",t),"function"==typeof n&&n(t),i},D={open:"{{",close:"}}",cache:!0,condense:!0,tagStyle:""},I=function(e,t){var n=this;t=n.config=Object.assign({template:e},D,t),n.vars=Object.assign({include:function(e,t){var i=document.getElementById(e),a=i?i.innerHTML:"";return a?n.render(a,t):""}},S),n.compile(t.template)};I.prototype.render=function(e,t){var n=this,i=n.config,a=e?n.compile(e):n.compilerCache||n.compile(i.template),r=function(){t=t||i.data||{};try{return a(t)}catch(a){return e=e||i.template,L(a,{errorContext:n.extractErrorContext(e,t),template:e,type:"Render"},i.error)}}();return i.cache&&!e&&(n.compilerCache=a),r},I.prototype.compile=function(e){var t=this,n=t.config,i=n.open,a=n.close,r=n.condense,o=_;if("string"!=typeof e||!e)return function(){return""};var l=function(e,t){var n=["(?:"+i+(e[0]||"")+"\\s*)","("+(e[1]||"[\\s\\S]")+"*?)","(?:\\s*"+(e[2]||"")+a+")"];return(t=t||{}).before&&n.unshift(t.before),t.after&&n.push(t.after),o(n.join(""))},s=r?["",""]:["(?:(?:\\n)*\\s*)","(?:\\s*?)"],c={before:s[0],after:s[1]},d=function(e,t){return r||(e=e.replace(o("\u2028"),t?"":"\n")),e.replace(/\\(\\|")/g,"$1")},u=t.parse=function(e){if(!(e=e||""))return e;r&&(e=e.replace(/\t/g," ").replace(/\s+/g," ")),e=(e=function(e){return e.replace(o("([}\\]])"+a),"$1 "+a)}(e).replace(/(?=\\|")/g,"\\").replace(/\r?\n/g,r?"":"\u2028")).replace(l(["!","","!"],c),function(e,t){return t=t.replace(o(i+"|"+a),function(e){return e.replace(/(?=.)/g,"\\")}),t});var t=function(e){return['";',e,'__laytpl__+="'].join("\n")},s=function(e,n,i){var a;return i?(a="-"===n?"":"_escape",(i=d(i,!0))?t("__laytpl__+="+a+"("+i+");"):""):""},u=function(e,n){return n?(n=d(n),t(n)):""};return e="modern"===n.tagStyle?(e=(e=e.replace(l(["#"],c),"")).replace(l(["(=|-)"]),s)).replace(l([],c),u):(e=e.replace(l(["#"],c),u)).replace(l(["(=|-)*"]),s),r||(e=e.replace(o("\u2028"),"\\n")),e},f=t.createCompiler=function(e,n){return n=n||p(e),new Function("laytpl","return "+n)(t.vars)},p=t.createBuilder=function(e,n){return n||["function(d){",'"use strict";','var __laytpl__="",'+function(){var e=[];for(var n in t.vars)e.push(("escape"===n?"_":"")+n+"=laytpl."+n);return e.join(",")}()+";",'__laytpl__="'+u(e)+'";',"return __laytpl__;","};"].join("\n")};try{return f(e)}catch(i){return delete t.compilerCache,function(){return L(i,{errorContext:t.extractErrorContext(e),template:e,type:"Compile"},n.error)}}},I.prototype.extractErrorContext=function(e,t){var n=1,i=e.split(/\r?\n/g);e=e.replace(/(?=^)/gm,function(){return"/*LINE:"+n+++"*/"});var a=this.createBuilder(e),r=a.split(/\r?\n/),o="laytpl.builder.map";try{a+="\n//# sourceURL="+o;var l=this.createCompiler(e,a);t&&l(t)}catch(e){var s=_(o.replace(/\./g,"\\.")+":(\\d+)","i"),c=(e.stack.match(s)||[])[1]||0,d=function(e,t){var n=t?/\/\*LINE:(\d+)\*\/[^*]*$/:/\/\*LINE:(\d+)\*\//,i=String(r[e-1]).match(n)||[];return!(i=i[1])&&e>0?d(e-1,!0):i},u=d(c-2);return u?function(e){e=parseInt(e)-1;for(var t=[""],n=Math.max(0,e-3),a=Math.min(i.length,e+3);n<=a;n++)t.push((n==e?"? ":" ")+(n+1)+"| "+i[n]);return t.join("\n")+"\n"}(u):e}};var A=function(e,t){var n=new I(e,t);return k.call(n)};A.extendVars=function(e){Object.assign(S,e)},A.config=A.set=function(e){Object.assign(D,e)};var N=h.hint(),M=window.LAYUI_GLOBAL||{},O=v.extend({locale:"zh-CN",messages:{"zh-CN":{code:{copy:"\u590d\u5236\u4ee3\u7801",copied:"\u5df2\u590d\u5236",copyError:"\u590d\u5236\u5931\u8d25",maximize:"\u6700\u5927\u5316\u663e\u793a",restore:"\u8fd8\u539f\u663e\u793a",preview:"\u5728\u65b0\u7a97\u53e3\u9884\u89c8"},colorpicker:{clear:"\u6e05\u9664",confirm:"\u786e\u5b9a"},dropdown:{noData:"\u6682\u65e0\u6570\u636e"},flow:{loadMore:"\u52a0\u8f7d\u66f4\u591a",noMore:"\u6ca1\u6709\u66f4\u591a\u4e86"},form:{select:{noData:"\u6682\u65e0\u6570\u636e",noMatch:"\u65e0\u5339\u914d\u6570\u636e",placeholder:"\u8bf7\u9009\u62e9"},validateMessages:{required:"\u5fc5\u586b\u9879\u4e0d\u80fd\u4e3a\u7a7a",phone:"\u624b\u673a\u53f7\u683c\u5f0f\u4e0d\u6b63\u786e",email:"\u90ae\u7bb1\u683c\u5f0f\u4e0d\u6b63\u786e",url:"\u94fe\u63a5\u683c\u5f0f\u4e0d\u6b63\u786e",number:"\u53ea\u80fd\u586b\u5199\u6570\u5b57",date:"\u65e5\u671f\u683c\u5f0f\u4e0d\u6b63\u786e",identity:"\u8eab\u4efd\u8bc1\u53f7\u683c\u5f0f\u4e0d\u6b63\u786e"},verifyErrorPromptTitle:"\u63d0\u793a"},laydate:{months:["1\u6708","2\u6708","3\u6708","4\u6708","5\u6708","6\u6708","7\u6708","8\u6708","9\u6708","10\u6708","11\u6708","12\u6708"],weeks:["\u65e5","\u4e00","\u4e8c","\u4e09","\u56db","\u4e94","\u516d"],time:["\u65f6","\u5206","\u79d2"],literal:{year:"\u5e74"},selectDate:"\u9009\u62e9\u65e5\u671f",selectTime:"\u9009\u62e9\u65f6\u95f4",startTime:"\u5f00\u59cb\u65f6\u95f4",endTime:"\u7ed3\u675f\u65f6\u95f4",tools:{confirm:"\u786e\u5b9a",clear:"\u6e05\u7a7a",now:"\u73b0\u5728",reset:"\u91cd\u7f6e"},rangeOrderPrompt:"\u7ed3\u675f\u65f6\u95f4\u4e0d\u80fd\u65e9\u4e8e\u5f00\u59cb\u65f6\u95f4\n\u8bf7\u91cd\u65b0\u9009\u62e9",invalidDatePrompt:"\u4e0d\u5728\u6709\u6548\u65e5\u671f\u6216\u65f6\u95f4\u8303\u56f4\u5185\n",formatErrorPrompt:"\u65e5\u671f\u683c\u5f0f\u4e0d\u5408\u6cd5\n\u5fc5\u987b\u9075\u5faa\uff1a\n{format}\n",autoResetPrompt:"\u5df2\u81ea\u52a8\u91cd\u7f6e",preview:"\u5f53\u524d\u9009\u4e2d\u7684\u7ed3\u679c"},layer:{confirm:"\u786e\u5b9a",cancel:"\u53d6\u6d88",defaultTitle:"\u4fe1\u606f",prompt:{InputLengthPrompt:"\u6700\u591a\u8f93\u5165 {length} \u4e2a\u5b57\u7b26"},photos:{noData:"\u6ca1\u6709\u56fe\u7247",tools:{rotate:"\u65cb\u8f6c",scaleX:"\u6c34\u5e73\u53d8\u6362",zoomIn:"\u653e\u5927",zoomOut:"\u7f29\u5c0f",reset:"\u8fd8\u539f",close:"\u5173\u95ed"},viewPicture:"\u67e5\u770b\u539f\u56fe",urlError:{prompt:"\u5f53\u524d\u56fe\u7247\u5730\u5740\u5f02\u5e38\uff0c\n\u662f\u5426\u7ee7\u7eed\u67e5\u770b\u4e0b\u4e00\u5f20\uff1f",confirm:"\u4e0b\u4e00\u5f20",cancel:"\u4e0d\u770b\u4e86"}}},laypage:{prev:"\u4e0a\u4e00\u9875",next:"\u4e0b\u4e00\u9875",first:"\u9996\u9875",last:"\u5c3e\u9875",total:"\u5171 {total} \u6761",pagesize:"\u6761/\u9875",goto:"\u5230\u7b2c",page:"\u9875",confirm:"\u786e\u5b9a"},table:{sort:{asc:"\u5347\u5e8f",desc:"\u964d\u5e8f"},noData:"\u6682\u65e0\u6570\u636e",tools:{filter:{title:"\u7b5b\u9009\u5217"},export:{title:"\u5bfc\u51fa",noDataPrompt:"\u5f53\u524d\u8868\u683c\u65e0\u6570\u636e",compatPrompt:"\u5bfc\u51fa\u529f\u80fd\u4e0d\u652f\u6301 IE\uff0c\u8bf7\u7528 Chrome \u7b49\u9ad8\u7ea7\u6d4f\u89c8\u5668\u5bfc\u51fa",csvText:"\u5bfc\u51fa CSV \u6587\u4ef6"},print:{title:"\u6253\u5370",noDataPrompt:"\u5f53\u524d\u8868\u683c\u65e0\u6570\u636e"}},dataFormatError:'\u8fd4\u56de\u7684\u6570\u636e\u4e0d\u7b26\u5408\u89c4\u8303\uff0c\u6b63\u786e\u7684\u6210\u529f\u72b6\u6001\u7801\u5e94\u4e3a\uff1a"{statusName}": {statusCode}',xhrError:"\u8bf7\u6c42\u5f02\u5e38\uff0c\u9519\u8bef\u63d0\u793a\uff1a{msg}"},transfer:{noData:"\u6682\u65e0\u6570\u636e",noMatch:"\u65e0\u5339\u914d\u6570\u636e",title:["\u5217\u8868\u4e00","\u5217\u8868\u4e8c"],searchPlaceholder:"\u5173\u952e\u8bcd\u641c\u7d22"},tree:{defaultNodeName:"\u672a\u547d\u540d",noData:"\u6682\u65e0\u6570\u636e",deleteNodePrompt:'\u786e\u8ba4\u5220\u9664"{name}"\u8282\u70b9\u5417\uff1f'},upload:{fileType:{file:"\u6587\u4ef6",image:"\u56fe\u7247",video:"\u89c6\u9891",audio:"\u97f3\u9891"},validateMessages:{fileExtensionError:"\u9009\u62e9\u7684{fileType}\u4e2d\u5305\u542b\u4e0d\u652f\u6301\u7684\u683c\u5f0f",filesOverLengthLimit:"\u540c\u65f6\u6700\u591a\u53ea\u80fd\u4e0a\u4f20: {length} \u4e2a\u6587\u4ef6",currentFilesLength:"\u5f53\u524d\u5df2\u7ecf\u9009\u62e9\u4e86: {length} \u4e2a\u6587\u4ef6",fileOverSizeLimit:"\u6587\u4ef6\u5927\u5c0f\u4e0d\u80fd\u8d85\u8fc7 {size}"},chooseText:"{length} \u4e2a\u6587\u4ef6"},util:{timeAgo:{days:"{days} \u5929\u524d",hours:"{hours} \u5c0f\u65f6\u524d",minutes:"{minutes} \u5206\u949f\u524d",future:"\u672a\u6765",justNow:"\u521a\u521a"},toDateString:{meridiem:function(e,t){var n=100*e+t;return n<500?"\u51cc\u6668":n<800?"\u65e9\u4e0a":n<1200?"\u4e0a\u5348":n<1300?"\u4e2d\u5348":n<1900?"\u4e0b\u5348":"\u665a\u4e0a"}}}}}},M.i18n),R=/\{(\w+)\}/g;function P(e){return null!=e}var H=function(e){var t=Object.create(null);function n(n){return t[n]||(t[n]=e.apply(t,arguments))}return n.cleanup=function(){t=Object.create(null)},n}(function(e,t,n){var i=e.split(":"),a=i[0],r=function(e,t,n){for(var i=t.replace(/\[(\d+)\]/g,".$1").split("."),a=e,r=0;r0&&t-1 in e)}function w(e,t){return e.nodeName&&e.nodeName.toLowerCase()===t.toLowerCase()}C.fn=C.prototype={jquery:x,constructor:C,length:0,toArray:function(){return a.call(this)},get:function(e){return null==e?a.call(this):e<0?this[e+this.length]:this[e]},pushStack:function(e){var t=C.merge(this.constructor(),e);return t.prevObject=this,t},each:function(e){return C.each(this,e)},map:function(e){return this.pushStack(C.map(this,function(t,n){return e.call(t,n,t)}))},slice:function(){return this.pushStack(a.apply(this,arguments))},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},even:function(){return this.pushStack(C.grep(this,function(e,t){return(t+1)%2}))},odd:function(){return this.pushStack(C.grep(this,function(e,t){return t%2}))},eq:function(e){var t=this.length,n=+e+(e<0?t:0);return this.pushStack(n>=0&&n+~]|"+L+")"+L+"*"),W=new RegExp(L+"|>"),z=new RegExp(H),q=new RegExp("^"+R+"$"),$={ID:new RegExp("^#("+R+")"),CLASS:new RegExp("^\\.("+R+")"),TAG:new RegExp("^("+R+"|[*])"),ATTR:new RegExp("^"+P),PSEUDO:new RegExp("^"+H),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+L+"*(even|odd|(([+-]|)(\\d*)n|)"+L+"*(?:([+-]|)"+L+"*(\\d+)|))"+L+"*\\)|)","i"),bool:new RegExp("^(?:"+O+")$","i"),needsContext:new RegExp("^"+L+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+L+"*((?:-\\d)?\\d*)"+L+"*\\)|)(?=[^-]|$)","i")},Y=/^(?:input|select|textarea|button)$/i,X=/^h\d$/i,K=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,V=/[+~]/,U=new RegExp("\\\\[\\da-fA-F]{1,6}"+L+"?|\\\\([^\\r\\n\\f])","g"),G=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},J=function(){se()},Z=fe(function(e){return!0===e.disabled&&w(e,"fieldset")},{dir:"parentNode",next:"legend"});try{m.apply(n=a.call(N.childNodes),N.childNodes),n[N.childNodes.length].nodeType}catch(e){m={apply:function(e,t){M.apply(e,a.call(t))},call:function(e){M.apply(e,a.call(arguments,1))}}}function Q(e,t,n,i){var a,r,o,l,s,d,u,y=t&&t.ownerDocument,g=t?t.nodeType:9;if(n=n||[],"string"!=typeof e||!e||1!==g&&9!==g&&11!==g)return n;if(!i&&(se(t),t=t||c,f)){if(11!==g&&(s=K.exec(e)))if(a=s[1]){if(9===g){if(!(o=t.getElementById(a)))return n;if(o.id===a)return m.call(n,o),n}else if(y&&(o=y.getElementById(a))&&Q.contains(t,o)&&o.id===a)return m.call(n,o),n}else{if(s[2])return m.apply(n,t.getElementsByTagName(e)),n;if((a=s[3])&&t.getElementsByClassName)return m.apply(n,t.getElementsByClassName(a)),n}if(!(I[e+" "]||h&&h.test(e))){if(u=e,y=t,1===g&&(W.test(e)||B.test(e))){for((y=V.test(e)&&le(t.parentNode)||t)==t&&p.scope||((l=t.getAttribute("id"))?l=C.escapeSelector(l):t.setAttribute("id",l=v)),r=(d=de(e)).length;r--;)d[r]=(l?"#"+l:":scope")+" "+ue(d[r]);u=d.join(",")}try{return m.apply(n,y.querySelectorAll(u)),n}catch(t){I(e,!0)}finally{l===v&&t.removeAttribute("id")}}}return ge(e.replace(D,"$1"),t,n,i)}function ee(){var e=[];return function t(n,a){return e.push(n+" ")>i.cacheLength&&delete t[e.shift()],t[n+" "]=a}}function te(e){return e[v]=!0,e}function ne(e){var t=c.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function ie(e){return function(t){return w(t,"input")&&t.type===e}}function ae(e){return function(t){return(w(t,"input")||w(t,"button"))&&t.type===e}}function re(e){return function(t){return"form"in t?t.parentNode&&!1===t.disabled?"label"in t?"label"in t.parentNode?t.parentNode.disabled===e:t.disabled===e:t.isDisabled===e||t.isDisabled!==!e&&Z(t)===e:t.disabled===e:"label"in t&&t.disabled===e}}function oe(e){return te(function(t){return t=+t,te(function(n,i){for(var a,r=e([],n.length,t),o=r.length;o--;)n[a=r[o]]&&(n[a]=!(i[a]=n[a]))})})}function le(e){return e&&void 0!==e.getElementsByTagName&&e}function se(e){var t,n=e?e.ownerDocument||e:N;return n!=c&&9===n.nodeType&&n.documentElement?(u=(c=n).documentElement,f=!C.isXMLDoc(c),y=u.matches||u.webkitMatchesSelector||u.msMatchesSelector,u.msMatchesSelector&&N!=c&&(t=c.defaultView)&&t.top!==t&&t.addEventListener("unload",J),p.getById=ne(function(e){return u.appendChild(e).id=C.expando,!c.getElementsByName||!c.getElementsByName(C.expando).length}),p.disconnectedMatch=ne(function(e){return y.call(e,"*")}),p.scope=ne(function(){return c.querySelectorAll(":scope")}),p.cssHas=ne(function(){try{return c.querySelector(":has(*,:jqfake)"),!1}catch(e){return!0}}),p.getById?(i.filter.ID=function(e){var t=e.replace(U,G);return function(e){return e.getAttribute("id")===t}},i.find.ID=function(e,t){if(void 0!==t.getElementById&&f){var n=t.getElementById(e);return n?[n]:[]}}):(i.filter.ID=function(e){var t=e.replace(U,G);return function(e){var n=void 0!==e.getAttributeNode&&e.getAttributeNode("id");return n&&n.value===t}},i.find.ID=function(e,t){if(void 0!==t.getElementById&&f){var n,i,a,r=t.getElementById(e);if(r){if((n=r.getAttributeNode("id"))&&n.value===e)return[r];for(a=t.getElementsByName(e),i=0;r=a[i++];)if((n=r.getAttributeNode("id"))&&n.value===e)return[r]}return[]}}),i.find.TAG=function(e,t){return void 0!==t.getElementsByTagName?t.getElementsByTagName(e):t.querySelectorAll(e)},i.find.CLASS=function(e,t){if(void 0!==t.getElementsByClassName&&f)return t.getElementsByClassName(e)},h=[],ne(function(e){var t;u.appendChild(e).innerHTML="",e.querySelectorAll("[selected]").length||h.push("\\["+L+"*(?:value|"+O+")"),e.querySelectorAll("[id~="+v+"-]").length||h.push("~="),e.querySelectorAll("a#"+v+"+*").length||h.push(".#.+[+~]"),e.querySelectorAll(":checked").length||h.push(":checked"),(t=c.createElement("input")).setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),u.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&h.push(":enabled",":disabled"),(t=c.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||h.push("\\["+L+"*name"+L+"*="+L+"*(?:''|\"\")")}),p.cssHas||h.push(":has"),h=h.length&&new RegExp(h.join("|")),A=function(e,t){if(e===t)return s=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!p.sortDetached&&t.compareDocumentPosition(e)===n?e===c||e.ownerDocument==N&&Q.contains(N,e)?-1:t===c||t.ownerDocument==N&&Q.contains(N,t)?1:o?l.call(o,e)-l.call(o,t):0:4&n?-1:1)},c):c}for(t in Q.matches=function(e,t){return Q(e,null,null,t)},Q.matchesSelector=function(e,t){if(se(e),f&&!I[t+" "]&&(!h||!h.test(t)))try{var n=y.call(e,t);if(n||p.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){I(t,!0)}return Q(t,c,null,[e]).length>0},Q.contains=function(e,t){return(e.ownerDocument||e)!=c&&se(e),C.contains(e,t)},Q.attr=function(e,t){(e.ownerDocument||e)!=c&&se(e);var n=i.attrHandle[t.toLowerCase()],a=n&&d.call(i.attrHandle,t.toLowerCase())?n(e,t,!f):void 0;return void 0!==a?a:e.getAttribute(t)},Q.error=function(e){throw new Error("Syntax error, unrecognized expression: "+e)},C.uniqueSort=function(e){var t,n=[],i=0,r=0;if(s=!p.sortStable,o=!p.sortStable&&a.call(e,0),S.call(e,A),s){for(;t=e[r++];)t===e[r]&&(i=n.push(r));for(;i--;)_.call(e,n[i],1)}return o=null,e},C.fn.uniqueSort=function(){return this.pushStack(C.uniqueSort(a.apply(this)))},i=C.expr={cacheLength:50,createPseudo:te,match:$,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(U,G),e[3]=(e[3]||e[4]||e[5]||"").replace(U,G),"~="===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]||Q.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]&&Q.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return $.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&z.test(n)&&(t=de(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(U,G).toLowerCase();return"*"===e?function(){return!0}:function(e){return w(e,t)}},CLASS:function(e){var t=x[e+" "];return t||(t=new RegExp("(^|"+L+")"+e+"("+L+"|$)"))&&x(e,function(e){return t.test("string"==typeof e.className&&e.className||void 0!==e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(e,t,n){return function(i){var a=Q.attr(i,e);return null==a?"!="===t:!t||(a+="","="===t?a===n:"!="===t?a!==n:"^="===t?n&&0===a.indexOf(n):"*="===t?n&&a.indexOf(n)>-1:"$="===t?n&&a.slice(-n.length)===n:"~="===t?(" "+a.replace(j," ")+" ").indexOf(n)>-1:"|="===t&&(a===n||a.slice(0,n.length+1)===n+"-"))}},CHILD:function(e,t,n,i,a){var r="nth"!==e.slice(0,3),o="last"!==e.slice(-4),l="of-type"===t;return 1===i&&0===a?function(e){return!!e.parentNode}:function(t,n,s){var c,d,u,f,p,h=r!==o?"nextSibling":"previousSibling",y=t.parentNode,m=l&&t.nodeName.toLowerCase(),b=!s&&!l,x=!1;if(y){if(r){for(;h;){for(u=t;u=u[h];)if(l?w(u,m):1===u.nodeType)return!1;p=h="only"===e&&!p&&"nextSibling"}return!0}if(p=[o?y.firstChild:y.lastChild],o&&b){for(x=(f=(c=(d=y[v]||(y[v]={}))[e]||[])[0]===g&&c[1])&&c[2],u=f&&y.childNodes[f];u=++f&&u&&u[h]||(x=f=0)||p.pop();)if(1===u.nodeType&&++x&&u===t){d[e]=[g,f,x];break}}else if(b&&(x=f=(c=(d=t[v]||(t[v]={}))[e]||[])[0]===g&&c[1]),!1===x)for(;(u=++f&&u&&u[h]||(x=f=0)||p.pop())&&(!(l?w(u,m):1===u.nodeType)||!++x||(b&&((d=u[v]||(u[v]={}))[e]=[g,x]),u!==t)););return(x-=a)===i||x%i===0&&x/i>=0}}},PSEUDO:function(e,t){var n,a=i.pseudos[e]||i.setFilters[e.toLowerCase()]||Q.error("unsupported pseudo: "+e);return a[v]?a(t):a.length>1?(n=[e,e,"",t],i.setFilters.hasOwnProperty(e.toLowerCase())?te(function(e,n){for(var i,r=a(e,t),o=r.length;o--;)e[i=l.call(e,r[o])]=!(n[i]=r[o])}):function(e){return a(e,0,n)}):a}},pseudos:{not:te(function(e){var t=[],n=[],i=ve(e.replace(D,"$1"));return i[v]?te(function(e,t,n,a){for(var r,o=i(e,null,a,[]),l=e.length;l--;)(r=o[l])&&(e[l]=!(t[l]=r))}):function(e,a,r){return t[0]=e,i(t,null,r,n),t[0]=null,!n.pop()}}),has:te(function(e){return function(t){return Q(e,t).length>0}}),contains:te(function(e){return e=e.replace(U,G),function(t){return(t.textContent||C.text(t)).indexOf(e)>-1}}),lang:te(function(e){return q.test(e||"")||Q.error("unsupported lang: "+e),e=e.replace(U,G).toLowerCase(),function(t){var n;do{if(n=f?t.lang:t.getAttribute("xml:lang")||t.getAttribute("lang"))return(n=n.toLowerCase())===e||0===n.indexOf(e+"-")}while((t=t.parentNode)&&1===t.nodeType);return!1}}),target:function(t){var n=e.location&&e.location.hash;return n&&n.slice(1)===t.id},root:function(e){return e===u},focus:function(e){return e===function(){try{return c.activeElement}catch(e){}}()&&c.hasFocus()&&!!(e.type||e.href||~e.tabIndex)},enabled:re(!1),disabled:re(!0),checked:function(e){return w(e,"input")&&!!e.checked||w(e,"option")&&!!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!i.pseudos.empty(e)},header:function(e){return X.test(e.nodeName)},input:function(e){return Y.test(e.nodeName)},button:function(e){return w(e,"input")&&"button"===e.type||w(e,"button")},text:function(e){var t;return w(e,"input")&&"text"===e.type&&(null==(t=e.getAttribute("type"))||"text"===t.toLowerCase())},first:oe(function(){return[0]}),last:oe(function(e,t){return[t-1]}),eq:oe(function(e,t,n){return[n<0?n+t:n]}),even:oe(function(e,t){for(var n=0;nt?t:n;--i>=0;)e.push(i);return e}),gt:oe(function(e,t,n){for(var i=n<0?n+t:n;++i1?function(t,n,i){for(var a=e.length;a--;)if(!e[a](t,n,i))return!1;return!0}:e[0]}function he(e,t,n,i,a){for(var r,o=[],l=0,s=e.length,c=null!=t;l-1&&(r[d]=!(o[d]=f))}}else p=he(p===o?p.splice(v,p.length):p),a?a(null,o,p,c):m.apply(o,p)})}function me(e){for(var t,n,a,o=e.length,s=i.relative[e[0].type],c=s||i.relative[" "],d=s?1:0,u=fe(function(e){return e===t},c,!0),f=fe(function(e){return l.call(t,e)>-1},c,!0),p=[function(e,n,i){var a=!s&&(i||n!=r)||((t=n).nodeType?u(e,n,i):f(e,n,i));return t=null,a}];d1&&pe(p),d>1&&ue(e.slice(0,d-1).concat({value:" "===e[d-2].type?"*":""})).replace(D,"$1"),n,d0,a=e.length>0,o=function(o,l,s,d,u){var p,h,y,v=0,b="0",x=o&&[],E=[],T=r,w=o||a&&i.find.TAG("*",u),S=g+=null==T?1:Math.random()||.1,_=w.length;for(u&&(r=l==c||l||u);b!==_&&null!=(p=w[b]);b++){if(a&&p){for(h=0,l||p.ownerDocument==c||(se(p),s=!f);y=e[h++];)if(y(p,l||c,s)){m.call(d,p);break}u&&(g=S)}n&&((p=!y&&p)&&v--,o&&x.push(p))}if(v+=b,n&&b!==v){for(h=0;y=t[h++];)y(x,E,l,s);if(o){if(v>0)for(;b--;)x[b]||E[b]||(E[b]=k.call(d));E=he(E)}m.apply(d,E),u&&!o&&E.length>0&&v+t.length>1&&C.uniqueSort(d)}return u&&(g=S,r=T),x};return n?te(o):o}(o,a)),l.selector=e}return l}function ge(e,t,n,a){var r,o,l,s,c,d="function"==typeof e&&e,u=!a&&de(e=d.selector||e);if(n=n||[],1===u.length){if((o=u[0]=u[0].slice(0)).length>2&&"ID"===(l=o[0]).type&&9===t.nodeType&&f&&i.relative[o[1].type]){if(!(t=(i.find.ID(l.matches[0].replace(U,G),t)||[])[0]))return n;d&&(t=t.parentNode),e=e.slice(o.shift().value.length)}for(r=$.needsContext.test(e)?0:o.length;r--&&(l=o[r],!i.relative[s=l.type]);)if((c=i.find[s])&&(a=c(l.matches[0].replace(U,G),V.test(o[0].type)&&le(t.parentNode)||t))){if(o.splice(r,1),!(e=a.length&&ue(o)))return m.apply(n,a),n;break}}return(d||ve(e,u))(a,t,!f,n,!t||V.test(e)&&le(t.parentNode)||t),n}ce.prototype=i.filters=i.pseudos,i.setFilters=new ce,p.sortStable=v.split("").sort(A).join("")===v,se(),p.sortDetached=ne(function(e){return 1&e.compareDocumentPosition(c.createElement("fieldset"))}),C.find=Q,C.expr[":"]=C.expr.pseudos,C.unique=C.uniqueSort,Q.compile=ve,Q.select=ge,Q.setDocument=se,Q.tokenize=de,Q.escape=C.escapeSelector,Q.getText=C.text,Q.isXML=C.isXMLDoc,Q.selectors=C.expr,Q.support=C.support,Q.uniqueSort=C.uniqueSort}();var O=function(e,t,n){for(var i=[],a=void 0!==n;(e=e[t])&&9!==e.nodeType;)if(1===e.nodeType){if(a&&C(e).is(n))break;i.push(e)}return i},R=function(e,t){for(var n=[];e;e=e.nextSibling)1===e.nodeType&&e!==t&&n.push(e);return n},P=C.expr.match.needsContext,H=/^<([a-z][^\/\0>:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,t,n){return h(t)?C.grep(e,function(e,i){return!!t.call(e,i,e)!==n}):t.nodeType?C.grep(e,function(e){return e===t!==n}):"string"!=typeof t?C.grep(e,function(e){return l.call(t,e)>-1!==n}):C.filter(t,e,n)}C.filter=function(e,t,n){var i=t[0];return n&&(e=":not("+e+")"),1===t.length&&1===i.nodeType?C.find.matchesSelector(i,e)?[i]:[]:C.find.matches(e,C.grep(t,function(e){return 1===e.nodeType}))},C.fn.extend({find:function(e){var t,n,i=this.length,a=this;if("string"!=typeof e)return this.pushStack(C(e).filter(function(){for(t=0;t1?C.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&&P.test(e)?C(e):e||[],!1).length}});var F,B=/^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]+))$/;(C.fn.init=function(e,t,n){var i,a;if(!e)return this;if(n=n||F,"string"==typeof e){if(!(i="<"===e[0]&&">"===e[e.length-1]&&e.length>=3?[null,e,null]:B.exec(e))||!i[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(i[1]){if(t=t instanceof C?t[0]:t,C.merge(this,C.parseHTML(i[1],t&&t.nodeType?t.ownerDocument||t:m,!0)),H.test(i[1])&&C.isPlainObject(t))for(i in t)h(this[i])?this[i](t[i]):this.attr(i,t[i]);return this}return(a=m.getElementById(i[2]))&&(this[0]=a,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):h(e)?void 0!==n.ready?n.ready(e):e(C):C.makeArray(e,this)}).prototype=C.fn,F=C(m);var W=/^(?:parents|prev(?:Until|All))/,z={children:!0,contents:!0,next:!0,prev:!0};function q(e,t){for(;(e=e[t])&&1!==e.nodeType;);return e}C.fn.extend({has:function(e){var t=C(e,this),n=t.length;return this.filter(function(){for(var e=0;e-1:1===n.nodeType&&C.find.matchesSelector(n,e))){r.push(n);break}return this.pushStack(r.length>1?C.uniqueSort(r):r)},index:function(e){return e?"string"==typeof e?l.call(C(e),this[0]):l.call(this,e.jquery?e[0]:e):this[0]&&this[0].parentNode?this.first().prevAll().length:-1},add:function(e,t){return this.pushStack(C.uniqueSort(C.merge(this.get(),C(e,t))))},addBack:function(e){return this.add(null==e?this.prevObject:this.prevObject.filter(e))}}),C.each({parent:function(e){var t=e.parentNode;return t&&11!==t.nodeType?t:null},parents:function(e){return O(e,"parentNode")},parentsUntil:function(e,t,n){return O(e,"parentNode",n)},next:function(e){return q(e,"nextSibling")},prev:function(e){return q(e,"previousSibling")},nextAll:function(e){return O(e,"nextSibling")},prevAll:function(e){return O(e,"previousSibling")},nextUntil:function(e,t,n){return O(e,"nextSibling",n)},prevUntil:function(e,t,n){return O(e,"previousSibling",n)},siblings:function(e){return R((e.parentNode||{}).firstChild,e)},children:function(e){return R(e.firstChild)},contents:function(e){return null!=e.contentDocument&&i(e.contentDocument)?e.contentDocument:(w(e,"template")&&(e=e.content||e),C.merge([],e.childNodes))}},function(e,t){C.fn[e]=function(n,i){var a=C.map(this,t,n);return"Until"!==e.slice(-5)&&(i=n),i&&"string"==typeof i&&(a=C.filter(i,a)),this.length>1&&(z[e]||C.uniqueSort(a),W.test(e)&&a.reverse()),this.pushStack(a)}});var $=/[^\x20\t\r\n\f]+/g;function Y(e){return e}function X(e){throw e}function K(e,t,n,i){var a;try{e&&h(a=e.promise)?a.call(e).done(t).fail(n):e&&h(a=e.then)?a.call(e,t,n):t.apply(void 0,[e].slice(i))}catch(e){n.apply(void 0,[e])}}C.Callbacks=function(e){e="string"==typeof e?function(e){var t={};return C.each(e.match($)||[],function(e,n){t[n]=!0}),t}(e):C.extend({},e);var t,n,i,a,r=[],o=[],l=-1,s=function(){for(a=a||e.once,i=t=!0;o.length;l=-1)for(n=o.shift();++l-1;)r.splice(n,1),n<=l&&l--}),this},has:function(e){return e?C.inArray(e,r)>-1:r.length>0},empty:function(){return r&&(r=[]),this},disable:function(){return a=o=[],r=n="",this},disabled:function(){return!r},lock:function(){return a=o=[],n||t||(r=n=""),this},locked:function(){return!!a},fireWith:function(e,n){return a||(n=[e,(n=n||[]).slice?n.slice():n],o.push(n),t||s()),this},fire:function(){return c.fireWith(this,arguments),this},fired:function(){return!!i}};return c},C.extend({Deferred:function(t){var n=[["notify","progress",C.Callbacks("memory"),C.Callbacks("memory"),2],["resolve","done",C.Callbacks("once memory"),C.Callbacks("once memory"),0,"resolved"],["reject","fail",C.Callbacks("once memory"),C.Callbacks("once memory"),1,"rejected"]],i="pending",a={state:function(){return i},always:function(){return r.done(arguments).fail(arguments),this},catch:function(e){return a.then(null,e)},pipe:function(){var e=arguments;return C.Deferred(function(t){C.each(n,function(n,i){var a=h(e[i[4]])&&e[i[4]];r[i[1]](function(){var e=a&&a.apply(this,arguments);e&&h(e.promise)?e.promise().progress(t.notify).done(t.resolve).fail(t.reject):t[i[0]+"With"](this,a?[e]:arguments)})}),e=null}).promise()},then:function(t,i,a){var r=0;function o(t,n,i,a){return function(){var l=this,s=arguments,c=function(){var e,c;if(!(t=r&&(i!==X&&(l=void 0,s=[e]),n.rejectWith(l,s))}};t?d():(C.Deferred.getErrorHook?d.error=C.Deferred.getErrorHook():C.Deferred.getStackHook&&(d.error=C.Deferred.getStackHook()),e.setTimeout(d))}}return C.Deferred(function(e){n[0][3].add(o(0,e,h(a)?a:Y,e.notifyWith)),n[1][3].add(o(0,e,h(t)?t:Y)),n[2][3].add(o(0,e,h(i)?i:X))}).promise()},promise:function(e){return null!=e?C.extend(e,a):a}},r={};return C.each(n,function(e,t){var o=t[2],l=t[5];a[t[1]]=o.add,l&&o.add(function(){i=l},n[3-e][2].disable,n[3-e][3].disable,n[0][2].lock,n[0][3].lock),o.add(t[3].fire),r[t[0]]=function(){return r[t[0]+"With"](this===r?void 0:this,arguments),this},r[t[0]+"With"]=o.fireWith}),a.promise(r),t&&t.call(r,r),r},when:function(e){var t=arguments.length,n=t,i=Array(n),r=a.call(arguments),o=C.Deferred(),l=function(e){return function(n){i[e]=this,r[e]=arguments.length>1?a.call(arguments):n,--t||o.resolveWith(i,r)}};if(t<=1&&(K(e,o.done(l(n)).resolve,o.reject,!t),"pending"===o.state()||h(r[n]&&r[n].then)))return o.then();for(;n--;)K(r[n],l(n),o.reject);return o.promise()}});var V=/^(Eval|Internal|Range|Reference|Syntax|Type|URI)Error$/;C.Deferred.exceptionHook=function(t,n){e.console&&e.console.warn&&t&&V.test(t.name)&&e.console.warn("jQuery.Deferred exception: "+t.message,t.stack,n)},C.readyException=function(t){e.setTimeout(function(){throw t})};var U=C.Deferred();function G(){m.removeEventListener("DOMContentLoaded",G),e.removeEventListener("load",G),C.ready()}C.fn.ready=function(e){return U.then(e).catch(function(e){C.readyException(e)}),this},C.extend({isReady:!1,readyWait:1,ready:function(e){(!0===e?--C.readyWait:C.isReady)||(C.isReady=!0,!0!==e&&--C.readyWait>0||U.resolveWith(m,[C]))}}),C.ready.then=U.then,"complete"===m.readyState||"loading"!==m.readyState&&!m.documentElement.doScroll?e.setTimeout(C.ready):(m.addEventListener("DOMContentLoaded",G),e.addEventListener("load",G));var J=function(e,t,n,i,a,r,o){var l=0,s=e.length,c=null==n;if("object"===b(n))for(l in a=!0,n)J(e,t,l,n[l],!0,r,o);else if(void 0!==i&&(a=!0,h(i)||(o=!0),c&&(o?(t.call(e,i),t=null):(c=t,t=function(e,t,n){return c.call(C(e),n)})),t))for(;l1,null,!0)},removeData:function(e){return this.each(function(){re.remove(this,e)})}}),C.extend({queue:function(e,t,n){var i;if(e)return t=(t||"fx")+"queue",i=ae.get(e,t),n&&(!i||Array.isArray(n)?i=ae.access(e,t,C.makeArray(n)):i.push(n)),i||[]},dequeue:function(e,t){t=t||"fx";var n=C.queue(e,t),i=n.length,a=n.shift(),r=C._queueHooks(e,t);"inprogress"===a&&(a=n.shift(),i--),a&&("fx"===t&&n.unshift("inprogress"),delete r.stop,a.call(e,function(){C.dequeue(e,t)},r)),!i&&r&&r.empty.fire()},_queueHooks:function(e,t){var n=t+"queueHooks";return ae.get(e,n)||ae.access(e,n,{empty:C.Callbacks("once memory").add(function(){ae.remove(e,[t+"queue",n])})})}}),C.fn.extend({queue:function(e,t){var n=2;return"string"!=typeof e&&(t=e,e="fx",n--),arguments.length\x20\t\r\n\f]*)/i,we=/^$|^module$|\/(?:java|ecma)script/i;xe=m.createDocumentFragment().appendChild(m.createElement("div")),(Ee=m.createElement("input")).setAttribute("type","radio"),Ee.setAttribute("checked","checked"),Ee.setAttribute("name","t"),xe.appendChild(Ee),p.checkClone=xe.cloneNode(!0).cloneNode(!0).lastChild.checked,xe.innerHTML="",p.noCloneChecked=!!xe.cloneNode(!0).lastChild.defaultValue,xe.innerHTML="",p.option=!!xe.lastChild;var ke={thead:[1,"","
                          "],col:[2,"","
                          "],tr:[2,"","
                          "],td:[3,"","
                          "],_default:[0,"",""]};function Se(e,t){var n;return n=void 0!==e.getElementsByTagName?e.getElementsByTagName(t||"*"):void 0!==e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&w(e,t)?C.merge([e],n):n}function _e(e,t){for(var n=0,i=e.length;n",""]);var Le=/<|&#?\w+;/;function De(e,t,n,i,a){for(var r,o,l,s,c,d,u=t.createDocumentFragment(),f=[],p=0,h=e.length;p-1)a&&a.push(r);else if(c=pe(r),o=Se(u.appendChild(r),"script"),c&&_e(o),n)for(d=0;r=o[d++];)we.test(r.type||"")&&n.push(r);return u}var Ie=/^([^.]*)(?:\.(.+)|)/;function Ae(){return!0}function Ne(){return!1}function Me(e,t,n,i,a,r){var o,l;if("object"==typeof t){for(l in"string"!=typeof n&&(i=i||n,n=void 0),t)Me(e,l,n,i,t[l],r);return e}if(null==i&&null==a?(a=n,i=n=void 0):null==a&&("string"==typeof n?(a=i,i=void 0):(a=i,i=n,n=void 0)),!1===a)a=Ne;else if(!a)return e;return 1===r&&(o=a,a=function(e){return C().off(e),o.apply(this,arguments)},a.guid=o.guid||(o.guid=C.guid++)),e.each(function(){C.event.add(this,t,a,i,n)})}function Oe(e,t,n){n?(ae.set(e,t,!1),C.event.add(e,t,{namespace:!1,handler:function(e){var n,i=ae.get(this,t);if(1&e.isTrigger&&this[t]){if(i)(C.event.special[t]||{}).delegateType&&e.stopPropagation();else if(i=a.call(arguments),ae.set(this,t,i),this[t](),n=ae.get(this,t),ae.set(this,t,!1),i!==n)return e.stopImmediatePropagation(),e.preventDefault(),n}else i&&(ae.set(this,t,C.event.trigger(i[0],i.slice(1),this)),e.stopPropagation(),e.isImmediatePropagationStopped=Ae)}})):void 0===ae.get(e,t)&&C.event.add(e,t,Ae)}C.event={global:{},add:function(e,t,n,i,a){var r,o,l,s,c,d,u,f,p,h,y,m=ae.get(e);if(ne(e))for(n.handler&&(n=(r=n).handler,a=r.selector),a&&C.find.matchesSelector(fe,a),n.guid||(n.guid=C.guid++),(s=m.events)||(s=m.events=Object.create(null)),(o=m.handle)||(o=m.handle=function(t){return void 0!==C&&C.event.triggered!==t.type?C.event.dispatch.apply(e,arguments):void 0}),c=(t=(t||"").match($)||[""]).length;c--;)p=y=(l=Ie.exec(t[c])||[])[1],h=(l[2]||"").split(".").sort(),p&&(u=C.event.special[p]||{},p=(a?u.delegateType:u.bindType)||p,u=C.event.special[p]||{},d=C.extend({type:p,origType:y,data:i,handler:n,guid:n.guid,selector:a,needsContext:a&&C.expr.match.needsContext.test(a),namespace:h.join(".")},r),(f=s[p])||((f=s[p]=[]).delegateCount=0,u.setup&&!1!==u.setup.call(e,i,h,o)||e.addEventListener&&e.addEventListener(p,o)),u.add&&(u.add.call(e,d),d.handler.guid||(d.handler.guid=n.guid)),a?f.splice(f.delegateCount++,0,d):f.push(d),C.event.global[p]=!0)},remove:function(e,t,n,i,a){var r,o,l,s,c,d,u,f,p,h,y,m=ae.hasData(e)&&ae.get(e);if(m&&(s=m.events)){for(c=(t=(t||"").match($)||[""]).length;c--;)if(p=y=(l=Ie.exec(t[c])||[])[1],h=(l[2]||"").split(".").sort(),p){for(u=C.event.special[p]||{},f=s[p=(i?u.delegateType:u.bindType)||p]||[],l=l[2]&&new RegExp("(^|\\.)"+h.join("\\.(?:.*\\.|)")+"(\\.|$)"),o=r=f.length;r--;)d=f[r],!a&&y!==d.origType||n&&n.guid!==d.guid||l&&!l.test(d.namespace)||i&&i!==d.selector&&("**"!==i||!d.selector)||(f.splice(r,1),d.selector&&f.delegateCount--,u.remove&&u.remove.call(e,d));o&&!f.length&&(u.teardown&&!1!==u.teardown.call(e,h,m.handle)||C.removeEvent(e,p,m.handle),delete s[p])}else for(p in s)C.event.remove(e,p+t[c],n,i,!0);C.isEmptyObject(s)&&ae.remove(e,"handle events")}},dispatch:function(e){var t,n,i,a,r,o,l=new Array(arguments.length),s=C.event.fix(e),c=(ae.get(this,"events")||Object.create(null))[s.type]||[],d=C.event.special[s.type]||{};for(l[0]=s,t=1;t=1))for(;c!==this;c=c.parentNode||this)if(1===c.nodeType&&("click"!==e.type||!0!==c.disabled)){for(r=[],o={},n=0;n-1:C.find(a,this,null,[c]).length),o[a]&&r.push(i);r.length&&l.push({elem:c,handlers:r})}return c=this,s\s*$/g;function je(e,t){return w(e,"table")&&w(11!==t.nodeType?t:t.firstChild,"tr")&&C(e).children("tbody")[0]||e}function Fe(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function Be(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function We(e,t){var n,i,a,r,o,l;if(1===t.nodeType){if(ae.hasData(e)&&(l=ae.get(e).events))for(a in ae.remove(t,"handle events"),l)for(n=0,i=l[a].length;n1&&"string"==typeof m&&!p.checkClone&&Pe.test(m))return e.each(function(a){var r=e.eq(a);v&&(t[0]=m.call(this,a,r.html())),qe(r,t,n,i)});if(f&&(o=(a=De(t,e[0].ownerDocument,!1,e,i)).firstChild,1===a.childNodes.length&&(a=o),o||i)){for(s=(l=C.map(Se(a,"script"),Fe)).length;u0&&_e(o,!s&&Se(e,"script")),l},cleanData:function(e){for(var t,n,i,a=C.event.special,r=0;void 0!==(n=e[r]);r++)if(ne(n)){if(t=n[ae.expando]){if(t.events)for(i in t.events)a[i]?C.event.remove(n,i):C.removeEvent(n,i,t.handle);n[ae.expando]=void 0}n[re.expando]&&(n[re.expando]=void 0)}}}),C.fn.extend({detach:function(e){return $e(this,e,!0)},remove:function(e){return $e(this,e)},text:function(e){return J(this,function(e){return void 0===e?C.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 qe(this,arguments,function(e){1!==this.nodeType&&11!==this.nodeType&&9!==this.nodeType||je(this,e).appendChild(e)})},prepend:function(){return qe(this,arguments,function(e){if(1===this.nodeType||11===this.nodeType||9===this.nodeType){var t=je(this,e);t.insertBefore(e,t.firstChild)}})},before:function(){return qe(this,arguments,function(e){this.parentNode&&this.parentNode.insertBefore(e,this)})},after:function(){return qe(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&&(C.cleanData(Se(e,!1)),e.textContent="");return this},clone:function(e,t){return e=null!=e&&e,t=null==t?e:t,this.map(function(){return C.clone(this,e,t)})},html:function(e){return J(this,function(e){var t=this[0]||{},n=0,i=this.length;if(void 0===e&&1===t.nodeType)return t.innerHTML;if("string"==typeof e&&!Re.test(e)&&!ke[(Te.exec(e)||["",""])[1].toLowerCase()]){e=C.htmlPrefilter(e);try{for(;n=0&&(s+=Math.max(0,Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-r-s-l-.5))||0),s+c}function lt(e,t,n){var i=Ke(e),a=(!p.boxSizingReliable()||n)&&"border-box"===C.css(e,"boxSizing",!1,i),r=a,o=Ge(e,t,i),l="offset"+t[0].toUpperCase()+t.slice(1);if(Ye.test(o)){if(!n)return o;o="auto"}return(!p.boxSizingReliable()&&a||!p.reliableTrDimensions()&&w(e,"tr")||"auto"===o||!parseFloat(o)&&"inline"===C.css(e,"display",!1,i))&&e.getClientRects().length&&(a="border-box"===C.css(e,"boxSizing",!1,i),(r=l in e)&&(o=e[l])),(o=parseFloat(o)||0)+ot(e,t,n||(a?"border":"content"),r,i,o)+"px"}function st(e,t,n,i,a){return new st.prototype.init(e,t,n,i,a)}C.extend({cssHooks:{opacity:{get:function(e,t){if(t){var n=Ge(e,"opacity");return""===n?"1":n}}}},cssNumber:{animationIterationCount:!0,aspectRatio:!0,borderImageSlice:!0,columnCount:!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,scale:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeMiterlimit:!0,strokeOpacity:!0},cssProps:{},style:function(e,t,n,i){if(e&&3!==e.nodeType&&8!==e.nodeType&&e.style){var a,r,o,l=te(t),s=Xe.test(t),c=e.style;if(s||(t=tt(l)),o=C.cssHooks[t]||C.cssHooks[l],void 0===n)return o&&"get"in o&&void 0!==(a=o.get(e,!1,i))?a:c[t];"string"==(r=typeof n)&&(a=de.exec(n))&&a[1]&&(n=me(e,t,a),r="number"),null!=n&&n==n&&("number"!==r||s||(n+=a&&a[3]||(C.cssNumber[l]?"":"px")),p.clearCloneStyle||""!==n||0!==t.indexOf("background")||(c[t]="inherit"),o&&"set"in o&&void 0===(n=o.set(e,n,i))||(s?c.setProperty(t,n):c[t]=n))}},css:function(e,t,n,i){var a,r,o,l=te(t);return Xe.test(t)||(t=tt(l)),(o=C.cssHooks[t]||C.cssHooks[l])&&"get"in o&&(a=o.get(e,!0,n)),void 0===a&&(a=Ge(e,t,i)),"normal"===a&&t in at&&(a=at[t]),""===n||n?(r=parseFloat(a),!0===n||isFinite(r)?r||0:a):a}}),C.each(["height","width"],function(e,t){C.cssHooks[t]={get:function(e,n,i){if(n)return!nt.test(C.css(e,"display"))||e.getClientRects().length&&e.getBoundingClientRect().width?lt(e,t,i):Ve(e,it,function(){return lt(e,t,i)})},set:function(e,n,i){var a,r=Ke(e),o=!p.scrollboxSize()&&"absolute"===r.position,l=(o||i)&&"border-box"===C.css(e,"boxSizing",!1,r),s=i?ot(e,t,i,l,r):0;return l&&o&&(s-=Math.ceil(e["offset"+t[0].toUpperCase()+t.slice(1)]-parseFloat(r[t])-ot(e,t,"border",!1,r)-.5)),s&&(a=de.exec(n))&&"px"!==(a[3]||"px")&&(e.style[t]=n,n=C.css(e,t)),rt(0,n,s)}}}),C.cssHooks.marginLeft=Je(p.reliableMarginLeft,function(e,t){if(t)return(parseFloat(Ge(e,"marginLeft"))||e.getBoundingClientRect().left-Ve(e,{marginLeft:0},function(){return e.getBoundingClientRect().left}))+"px"}),C.each({margin:"",padding:"",border:"Width"},function(e,t){C.cssHooks[e+t]={expand:function(n){for(var i=0,a={},r="string"==typeof n?n.split(" "):[n];i<4;i++)a[e+ue[i]+t]=r[i]||r[i-2]||r[0];return a}},"margin"!==e&&(C.cssHooks[e+t].set=rt)}),C.fn.extend({css:function(e,t){return J(this,function(e,t,n){var i,a,r={},o=0;if(Array.isArray(t)){for(i=Ke(e),a=t.length;o1)}}),C.Tween=st,st.prototype={constructor:st,init:function(e,t,n,i,a,r){this.elem=e,this.prop=n,this.easing=a||C.easing._default,this.options=t,this.start=this.now=this.cur(),this.end=i,this.unit=r||(C.cssNumber[n]?"":"px")},cur:function(){var e=st.propHooks[this.prop];return e&&e.get?e.get(this):st.propHooks._default.get(this)},run:function(e){var t,n=st.propHooks[this.prop];return this.options.duration?this.pos=t=C.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):st.propHooks._default.set(this),this}},st.prototype.init.prototype=st.prototype,st.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=C.css(e.elem,e.prop,""))&&"auto"!==t?t:0},set:function(e){C.fx.step[e.prop]?C.fx.step[e.prop](e):1!==e.elem.nodeType||!C.cssHooks[e.prop]&&null==e.elem.style[tt(e.prop)]?e.elem[e.prop]=e.now:C.style(e.elem,e.prop,e.now+e.unit)}}},st.propHooks.scrollTop=st.propHooks.scrollLeft={set:function(e){e.elem.nodeType&&e.elem.parentNode&&(e.elem[e.prop]=e.now)}},C.easing={linear:function(e){return e},swing:function(e){return.5-Math.cos(e*Math.PI)/2},_default:"swing"},C.fx=st.prototype.init,C.fx.step={};var ct,dt,ut=/^(?:toggle|show|hide)$/,ft=/queueHooks$/;function pt(){dt&&(!1===m.hidden&&e.requestAnimationFrame?e.requestAnimationFrame(pt):e.setTimeout(pt,C.fx.interval),C.fx.tick())}function ht(){return e.setTimeout(function(){ct=void 0}),ct=Date.now()}function yt(e,t){var n,i=0,a={height:e};for(t=t?1:0;i<4;i+=2-t)a["margin"+(n=ue[i])]=a["padding"+n]=e;return t&&(a.opacity=a.width=e),a}function mt(e,t,n){for(var i,a=(vt.tweeners[t]||[]).concat(vt.tweeners["*"]),r=0,o=a.length;r1)},removeAttr:function(e){return this.each(function(){C.removeAttr(this,e)})}}),C.extend({attr:function(e,t,n){var i,a,r=e.nodeType;if(3!==r&&8!==r&&2!==r)return void 0===e.getAttribute?C.prop(e,t,n):(1===r&&C.isXMLDoc(e)||(a=C.attrHooks[t.toLowerCase()]||(C.expr.match.bool.test(t)?gt:void 0)),void 0!==n?null===n?void C.removeAttr(e,t):a&&"set"in a&&void 0!==(i=a.set(e,n,t))?i:(e.setAttribute(t,n+""),n):a&&"get"in a&&null!==(i=a.get(e,t))?i:null==(i=C.find.attr(e,t))?void 0:i)},attrHooks:{type:{set:function(e,t){if(!p.radioValue&&"radio"===t&&w(e,"input")){var n=e.value;return e.setAttribute("type",t),n&&(e.value=n),t}}}},removeAttr:function(e,t){var n,i=0,a=t&&t.match($);if(a&&1===e.nodeType)for(;n=a[i++];)e.removeAttribute(n)}}),gt={set:function(e,t,n){return!1===t?C.removeAttr(e,n):e.setAttribute(n,n),n}},C.each(C.expr.match.bool.source.match(/\w+/g),function(e,t){var n=bt[t]||C.find.attr;bt[t]=function(e,t,i){var a,r,o=t.toLowerCase();return i||(r=bt[o],bt[o]=a,a=null!=n(e,t,i)?o:null,bt[o]=r),a}});var xt=/^(?:input|select|textarea|button)$/i,Et=/^(?:a|area)$/i;function Ct(e){return(e.match($)||[]).join(" ")}function Tt(e){return e.getAttribute&&e.getAttribute("class")||""}function wt(e){return Array.isArray(e)?e:"string"==typeof e&&e.match($)||[]}C.fn.extend({prop:function(e,t){return J(this,C.prop,e,t,arguments.length>1)},removeProp:function(e){return this.each(function(){delete this[C.propFix[e]||e]})}}),C.extend({prop:function(e,t,n){var i,a,r=e.nodeType;if(3!==r&&8!==r&&2!==r)return 1===r&&C.isXMLDoc(e)||(t=C.propFix[t]||t,a=C.propHooks[t]),void 0!==n?a&&"set"in a&&void 0!==(i=a.set(e,n,t))?i:e[t]=n:a&&"get"in a&&null!==(i=a.get(e,t))?i:e[t]},propHooks:{tabIndex:{get:function(e){var t=C.find.attr(e,"tabindex");return t?parseInt(t,10):xt.test(e.nodeName)||Et.test(e.nodeName)&&e.href?0:-1}}},propFix:{for:"htmlFor",class:"className"}}),p.optSelected||(C.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)}}),C.each(["tabIndex","readOnly","maxLength","cellSpacing","cellPadding","rowSpan","colSpan","useMap","frameBorder","contentEditable"],function(){C.propFix[this.toLowerCase()]=this}),C.fn.extend({addClass:function(e){var t,n,i,a,r,o;return h(e)?this.each(function(t){C(this).addClass(e.call(this,t,Tt(this)))}):(t=wt(e)).length?this.each(function(){if(i=Tt(this),n=1===this.nodeType&&" "+Ct(i)+" "){for(r=0;r-1;)n=n.replace(" "+a+" "," ");o=Ct(n),i!==o&&this.setAttribute("class",o)}}):this:this.attr("class","")},toggleClass:function(e,t){var n,i,a,r,o=typeof e,l="string"===o||Array.isArray(e);return h(e)?this.each(function(n){C(this).toggleClass(e.call(this,n,Tt(this),t),t)}):"boolean"==typeof t&&l?t?this.addClass(e):this.removeClass(e):(n=wt(e),this.each(function(){if(l)for(r=C(this),a=0;a-1)return!0;return!1}});var kt=/\r/g;C.fn.extend({val:function(e){var t,n,i,a=this[0];return arguments.length?(i=h(e),this.each(function(n){var a;1===this.nodeType&&(null==(a=i?e.call(this,n,C(this).val()):e)?a="":"number"==typeof a?a+="":Array.isArray(a)&&(a=C.map(a,function(e){return null==e?"":e+""})),(t=C.valHooks[this.type]||C.valHooks[this.nodeName.toLowerCase()])&&"set"in t&&void 0!==t.set(this,a,"value")||(this.value=a))})):a?(t=C.valHooks[a.type]||C.valHooks[a.nodeName.toLowerCase()])&&"get"in t&&void 0!==(n=t.get(a,"value"))?n:"string"==typeof(n=a.value)?n.replace(kt,""):null==n?"":n:void 0}}),C.extend({valHooks:{option:{get:function(e){var t=C.find.attr(e,"value");return null!=t?t:Ct(C.text(e))}},select:{get:function(e){var t,n,i,a=e.options,r=e.selectedIndex,o="select-one"===e.type,l=o?null:[],s=o?r+1:a.length;for(i=r<0?s:o?r:0;i-1)&&(n=!0);return n||(e.selectedIndex=-1),r}}}}),C.each(["radio","checkbox"],function(){C.valHooks[this]={set:function(e,t){if(Array.isArray(t))return e.checked=C.inArray(C(e).val(),t)>-1}},p.checkOn||(C.valHooks[this].get=function(e){return null===e.getAttribute("value")?"on":e.value})});var St=e.location,_t={guid:Date.now()},Lt=/\?/;C.parseXML=function(t){var n,i;if(!t||"string"!=typeof t)return null;try{n=(new e.DOMParser).parseFromString(t,"text/xml")}catch(e){}return i=n&&n.getElementsByTagName("parsererror")[0],n&&!i||C.error("Invalid XML: "+(i?C.map(i.childNodes,function(e){return e.textContent}).join("\n"):t)),n};var Dt=/^(?:focusinfocus|focusoutblur)$/,It=function(e){e.stopPropagation()};C.extend(C.event,{trigger:function(t,n,i,a){var r,o,l,s,c,u,f,p,v=[i||m],g=d.call(t,"type")?t.type:t,b=d.call(t,"namespace")?t.namespace.split("."):[];if(o=p=l=i=i||m,3!==i.nodeType&&8!==i.nodeType&&!Dt.test(g+C.event.triggered)&&(g.indexOf(".")>-1&&(b=g.split("."),g=b.shift(),b.sort()),c=g.indexOf(":")<0&&"on"+g,(t=t[C.expando]?t:new C.Event(g,"object"==typeof t&&t)).isTrigger=a?2:3,t.namespace=b.join("."),t.rnamespace=t.namespace?new RegExp("(^|\\.)"+b.join("\\.(?:.*\\.|)")+"(\\.|$)"):null,t.result=void 0,t.target||(t.target=i),n=null==n?[t]:C.makeArray(n,[t]),f=C.event.special[g]||{},a||!f.trigger||!1!==f.trigger.apply(i,n))){if(!a&&!f.noBubble&&!y(i)){for(s=f.delegateType||g,Dt.test(s+g)||(o=o.parentNode);o;o=o.parentNode)v.push(o),l=o;l===(i.ownerDocument||m)&&v.push(l.defaultView||l.parentWindow||e)}for(r=0;(o=v[r++])&&!t.isPropagationStopped();)p=o,t.type=r>1?s:f.bindType||g,(u=(ae.get(o,"events")||Object.create(null))[t.type]&&ae.get(o,"handle"))&&u.apply(o,n),(u=c&&o[c])&&u.apply&&ne(o)&&(t.result=u.apply(o,n),!1===t.result&&t.preventDefault());return t.type=g,a||t.isDefaultPrevented()||f._default&&!1!==f._default.apply(v.pop(),n)||!ne(i)||c&&h(i[g])&&!y(i)&&((l=i[c])&&(i[c]=null),C.event.triggered=g,t.isPropagationStopped()&&p.addEventListener(g,It),i[g](),t.isPropagationStopped()&&p.removeEventListener(g,It),C.event.triggered=void 0,l&&(i[c]=l)),t.result}},simulate:function(e,t,n){var i=C.extend(new C.Event,n,{type:e,isSimulated:!0});C.event.trigger(i,null,t)}}),C.fn.extend({trigger:function(e,t){return this.each(function(){C.event.trigger(e,t,this)})},triggerHandler:function(e,t){var n=this[0];if(n)return C.event.trigger(e,t,n,!0)}});var At=/\[\]$/,Nt=/\r?\n/g,Mt=/^(?:submit|button|image|reset|file)$/i,Ot=/^(?:input|select|textarea|keygen)/i;function Rt(e,t,n,i){var a;if(Array.isArray(t))C.each(t,function(t,a){n||At.test(e)?i(e,a):Rt(e+"["+("object"==typeof a&&null!=a?t:"")+"]",a,n,i)});else if(n||"object"!==b(t))i(e,t);else for(a in t)Rt(e+"["+a+"]",t[a],n,i)}C.param=function(e,t){var n,i=[],a=function(e,t){var n=h(t)?t():t;i[i.length]=encodeURIComponent(e)+"="+encodeURIComponent(null==n?"":n)};if(null==e)return"";if(Array.isArray(e)||e.jquery&&!C.isPlainObject(e))C.each(e,function(){a(this.name,this.value)});else for(n in e)Rt(n,e[n],t,a);return i.join("&")},C.fn.extend({serialize:function(){return C.param(this.serializeArray())},serializeArray:function(){return this.map(function(){var e=C.prop(this,"elements");return e?C.makeArray(e):this}).filter(function(){var e=this.type;return this.name&&!C(this).is(":disabled")&&Ot.test(this.nodeName)&&!Mt.test(e)&&(this.checked||!Ce.test(e))}).map(function(e,t){var n=C(this).val();return null==n?null:Array.isArray(n)?C.map(n,function(e){return{name:t.name,value:e.replace(Nt,"\r\n")}}):{name:t.name,value:n.replace(Nt,"\r\n")}}).get()}});var Pt=/%20/g,Ht=/#.*$/,jt=/([?&])_=[^&]*/,Ft=/^(.*?):[ \t]*([^\r\n]*)$/gm,Bt=/^(?:GET|HEAD)$/,Wt=/^\/\//,zt={},qt={},$t="*/".concat("*"),Yt=m.createElement("a");function Xt(e){return function(t,n){"string"!=typeof t&&(n=t,t="*");var i,a=0,r=t.toLowerCase().match($)||[];if(h(n))for(;i=r[a++];)"+"===i[0]?(i=i.slice(1)||"*",(e[i]=e[i]||[]).unshift(n)):(e[i]=e[i]||[]).push(n)}}function Kt(e,t,n,i){var a={},r=e===qt;function o(l){var s;return a[l]=!0,C.each(e[l]||[],function(e,l){var c=l(t,n,i);return"string"!=typeof c||r||a[c]?r?!(s=c):void 0:(t.dataTypes.unshift(c),o(c),!1)}),s}return o(t.dataTypes[0])||!a["*"]&&o("*")}function Vt(e,t){var n,i,a=C.ajaxSettings.flatOptions||{};for(n in t)void 0!==t[n]&&((a[n]?e:i||(i={}))[n]=t[n]);return i&&C.extend(!0,e,i),e}Yt.href=St.href,C.extend({active:0,lastModified:{},etag:{},ajaxSettings:{url:St.href,type:"GET",isLocal:/^(?:about|app|app-storage|.+-extension|file|res|widget):$/.test(St.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":C.parseXML},flatOptions:{url:!0,context:!0}},ajaxSetup:function(e,t){return t?Vt(Vt(e,C.ajaxSettings),t):Vt(C.ajaxSettings,e)},ajaxPrefilter:Xt(zt),ajaxTransport:Xt(qt),ajax:function(t,n){"object"==typeof t&&(n=t,t=void 0),n=n||{};var i,a,r,o,l,s,c,d,u,f,p=C.ajaxSetup({},n),h=p.context||p,y=p.context&&(h.nodeType||h.jquery)?C(h):C.event,v=C.Deferred(),g=C.Callbacks("once memory"),b=p.statusCode||{},x={},E={},T="canceled",w={readyState:0,getResponseHeader:function(e){var t;if(c){if(!o)for(o={};t=Ft.exec(r);)o[t[1].toLowerCase()+" "]=(o[t[1].toLowerCase()+" "]||[]).concat(t[2]);t=o[e.toLowerCase()+" "]}return null==t?null:t.join(", ")},getAllResponseHeaders:function(){return c?r:null},setRequestHeader:function(e,t){return null==c&&(e=E[e.toLowerCase()]=E[e.toLowerCase()]||e,x[e]=t),this},overrideMimeType:function(e){return null==c&&(p.mimeType=e),this},statusCode:function(e){var t;if(e)if(c)w.always(e[w.status]);else for(t in e)b[t]=[b[t],e[t]];return this},abort:function(e){var t=e||T;return i&&i.abort(t),k(0,t),this}};if(v.promise(w),p.url=((t||p.url||St.href)+"").replace(Wt,St.protocol+"//"),p.type=n.method||n.type||p.method||p.type,p.dataTypes=(p.dataType||"*").toLowerCase().match($)||[""],null==p.crossDomain){s=m.createElement("a");try{s.href=p.url,s.href=s.href,p.crossDomain=Yt.protocol+"//"+Yt.host!=s.protocol+"//"+s.host}catch(e){p.crossDomain=!0}}if(p.data&&p.processData&&"string"!=typeof p.data&&(p.data=C.param(p.data,p.traditional)),Kt(zt,p,n,w),c)return w;for(u in(d=C.event&&p.global)&&0===C.active++&&C.event.trigger("ajaxStart"),p.type=p.type.toUpperCase(),p.hasContent=!Bt.test(p.type),a=p.url.replace(Ht,""),p.hasContent?p.data&&p.processData&&0===(p.contentType||"").indexOf("application/x-www-form-urlencoded")&&(p.data=p.data.replace(Pt,"+")):(f=p.url.slice(a.length),p.data&&(p.processData||"string"==typeof p.data)&&(a+=(Lt.test(a)?"&":"?")+p.data,delete p.data),!1===p.cache&&(a=a.replace(jt,"$1"),f=(Lt.test(a)?"&":"?")+"_="+_t.guid+++f),p.url=a+f),p.ifModified&&(C.lastModified[a]&&w.setRequestHeader("If-Modified-Since",C.lastModified[a]),C.etag[a]&&w.setRequestHeader("If-None-Match",C.etag[a])),(p.data&&p.hasContent&&!1!==p.contentType||n.contentType)&&w.setRequestHeader("Content-Type",p.contentType),w.setRequestHeader("Accept",p.dataTypes[0]&&p.accepts[p.dataTypes[0]]?p.accepts[p.dataTypes[0]]+("*"!==p.dataTypes[0]?", "+$t+"; q=0.01":""):p.accepts["*"]),p.headers)w.setRequestHeader(u,p.headers[u]);if(p.beforeSend&&(!1===p.beforeSend.call(h,w,p)||c))return w.abort();if(T="abort",g.add(p.complete),w.done(p.success),w.fail(p.error),i=Kt(qt,p,n,w)){if(w.readyState=1,d&&y.trigger("ajaxSend",[w,p]),c)return w;p.async&&p.timeout>0&&(l=e.setTimeout(function(){w.abort("timeout")},p.timeout));try{c=!1,i.send(x,k)}catch(e){if(c)throw e;k(-1,e)}}else k(-1,"No Transport");function k(t,n,o,s){var u,f,m,x,E,T=n;c||(c=!0,l&&e.clearTimeout(l),i=void 0,r=s||"",w.readyState=t>0?4:0,u=t>=200&&t<300||304===t,o&&(x=function(e,t,n){for(var i,a,r,o,l=e.contents,s=e.dataTypes;"*"===s[0];)s.shift(),void 0===i&&(i=e.mimeType||t.getResponseHeader("Content-Type"));if(i)for(a in l)if(l[a]&&l[a].test(i)){s.unshift(a);break}if(s[0]in n)r=s[0];else{for(a in n){if(!s[0]||e.converters[a+" "+s[0]]){r=a;break}o||(o=a)}r=r||o}if(r)return r!==s[0]&&s.unshift(r),n[r]}(p,w,o)),!u&&C.inArray("script",p.dataTypes)>-1&&C.inArray("json",p.dataTypes)<0&&(p.converters["text script"]=function(){}),x=function(e,t,n,i){var a,r,o,l,s,c={},d=e.dataTypes.slice();if(d[1])for(o in e.converters)c[o.toLowerCase()]=e.converters[o];for(r=d.shift();r;)if(e.responseFields[r]&&(n[e.responseFields[r]]=t),!s&&i&&e.dataFilter&&(t=e.dataFilter(t,e.dataType)),s=r,r=d.shift())if("*"===r)r=s;else if("*"!==s&&s!==r){if(!(o=c[s+" "+r]||c["* "+r]))for(a in c)if((l=a.split(" "))[1]===r&&(o=c[s+" "+l[0]]||c["* "+l[0]])){!0===o?o=c[a]:!0!==c[a]&&(r=l[0],d.unshift(l[1]));break}if(!0!==o)if(o&&e.throws)t=o(t);else try{t=o(t)}catch(e){return{state:"parsererror",error:o?e:"No conversion from "+s+" to "+r}}}return{state:"success",data:t}}(p,x,w,u),u?(p.ifModified&&((E=w.getResponseHeader("Last-Modified"))&&(C.lastModified[a]=E),(E=w.getResponseHeader("etag"))&&(C.etag[a]=E)),204===t||"HEAD"===p.type?T="nocontent":304===t?T="notmodified":(T=x.state,f=x.data,u=!(m=x.error))):(m=T,!t&&T||(T="error",t<0&&(t=0))),w.status=t,w.statusText=(n||T)+"",u?v.resolveWith(h,[f,T,w]):v.rejectWith(h,[w,T,m]),w.statusCode(b),b=void 0,d&&y.trigger(u?"ajaxSuccess":"ajaxError",[w,p,u?f:m]),g.fireWith(h,[w,T]),d&&(y.trigger("ajaxComplete",[w,p]),--C.active||C.event.trigger("ajaxStop")))}return w},getJSON:function(e,t,n){return C.get(e,t,n,"json")},getScript:function(e,t){return C.get(e,void 0,t,"script")}}),C.each(["get","post"],function(e,t){C[t]=function(e,n,i,a){return h(n)&&(a=a||i,i=n,n=void 0),C.ajax(C.extend({url:e,type:t,dataType:a,data:n,success:i},C.isPlainObject(e)&&e))}}),C.ajaxPrefilter(function(e){var t;for(t in e.headers)"content-type"===t.toLowerCase()&&(e.contentType=e.headers[t]||"")}),C._evalUrl=function(e,t,n){return C.ajax({url:e,type:"GET",dataType:"script",cache:!0,async:!1,global:!1,converters:{"text script":function(){}},dataFilter:function(e){C.globalEval(e,t,n)}})},C.fn.extend({wrapAll:function(e){var t;return this[0]&&(h(e)&&(e=e.call(this[0])),t=C(e,this[0].ownerDocument).eq(0).clone(!0),this[0].parentNode&&t.insertBefore(this[0]),t.map(function(){for(var e=this;e.firstElementChild;)e=e.firstElementChild;return e}).append(this)),this},wrapInner:function(e){return h(e)?this.each(function(t){C(this).wrapInner(e.call(this,t))}):this.each(function(){var t=C(this),n=t.contents();n.length?n.wrapAll(e):t.append(e)})},wrap:function(e){var t=h(e);return this.each(function(n){C(this).wrapAll(t?e.call(this,n):e)})},unwrap:function(e){return this.parent(e).not("body").each(function(){C(this).replaceWith(this.childNodes)}),this}}),C.expr.pseudos.hidden=function(e){return!C.expr.pseudos.visible(e)},C.expr.pseudos.visible=function(e){return!!(e.offsetWidth||e.offsetHeight||e.getClientRects().length)},C.ajaxSettings.xhr=function(){try{return new e.XMLHttpRequest}catch(e){}};var Ut={0:200,1223:204},Gt=C.ajaxSettings.xhr();p.cors=!!Gt&&"withCredentials"in Gt,p.ajax=Gt=!!Gt,C.ajaxTransport(function(t){var n,i;if(p.cors||Gt&&!t.crossDomain)return{send:function(a,r){var o,l=t.xhr();if(l.open(t.type,t.url,t.async,t.username,t.password),t.xhrFields)for(o in t.xhrFields)l[o]=t.xhrFields[o];for(o in t.mimeType&&l.overrideMimeType&&l.overrideMimeType(t.mimeType),t.crossDomain||a["X-Requested-With"]||(a["X-Requested-With"]="XMLHttpRequest"),a)l.setRequestHeader(o,a[o]);n=function(e){return function(){n&&(n=i=l.onload=l.onerror=l.onabort=l.ontimeout=l.onreadystatechange=null,"abort"===e?l.abort():"error"===e?"number"!=typeof l.status?r(0,"error"):r(l.status,l.statusText):r(Ut[l.status]||l.status,l.statusText,"text"!==(l.responseType||"text")||"string"!=typeof l.responseText?{binary:l.response}:{text:l.responseText},l.getAllResponseHeaders()))}},l.onload=n(),i=l.onerror=l.ontimeout=n("error"),void 0!==l.onabort?l.onabort=i:l.onreadystatechange=function(){4===l.readyState&&e.setTimeout(function(){n&&i()})},n=n("abort");try{l.send(t.hasContent&&t.data||null)}catch(e){if(n)throw e}},abort:function(){n&&n()}}}),C.ajaxPrefilter(function(e){e.crossDomain&&(e.contents.script=!1)}),C.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 C.globalEval(e),e}}}),C.ajaxPrefilter("script",function(e){void 0===e.cache&&(e.cache=!1),e.crossDomain&&(e.type="GET")}),C.ajaxTransport("script",function(e){var t,n;if(e.crossDomain||e.scriptAttrs)return{send:function(i,a){t=C(" diff --git a/docs/.template/index.md b/docs/.template/index.md new file mode 100644 index 000000000..543402347 --- /dev/null +++ b/docs/.template/index.md @@ -0,0 +1,64 @@ +--- +title: 组件中文名 组件名 +toc: true +--- + +# 组件中文名 + +> 组件介绍 + +

                          示例

                          + +
                          +{{- d.include("/组件名/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| const { 组件名 } = layui | 获得 `组件名` 模块。 | +| [组件名.render(options)](#render) | 组件名 组件渲染,核心方法。 | +| …… | …… | + +

                          渲染

                          + +`组件名.render(options);` + +- 参数 `options` : 基础选项。[#详见选项](#options) + +

                          选项

                          + +
                          +{{- d.include("/组件名/detail/options.md") }} +
                          + +_更多方法的详细介绍_ + +方法传入的参数(`opts`)是一个 `Object` 类型的选项,需按照表格的方式展示,如: + +```markdown +| 选项 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| 选项名 | 该选项的详细介绍 | 该选项支持的数据类型 | 该选项的默认值,若无则填写 `-` | +``` + +## 事件 + +_若有的话_ + +| 事件名 | 描述 | +| --- | --- | +| eventName | 描述 | + +

                          事件名

                          + +触发时机的描述,若事件支持阻断机制(`return false`),必须在文档中明确说明。 + +```js +// 示例代码 +``` + +## 💖 心语 + +通常是开发者开发该组件时的内心独白,通过带有感性化的文字与受众建立奇妙的意识沟通。 \ No newline at end of file diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 000000000..2668c792b --- /dev/null +++ b/docs/README.md @@ -0,0 +1,6 @@ +# Layui 文档 + +## 预览 + +- [最新](https://layui.dev/docs/) +- [2.x](https://layui.dev/docs/2/) \ No newline at end of file diff --git a/docs/anim/index.md b/docs/anim/index.md new file mode 100644 index 000000000..2f18177e1 --- /dev/null +++ b/docs/anim/index.md @@ -0,0 +1,139 @@ +--- +title: 动画 +toc: true +--- + + + +# 动画 + +> Layui 内置了几种常见的 `CSS3` 动画。 + +

                          示例

                          + +
                          +  
                          +
                          + +对需要动画的标签添加 `class="lay-anim"` 基础类,再追加其他不同的动画类,即可让元素产生动画。 + +

                          动画列表

                          + +点击下述绿色圆体,即可预览不同类名的动画效果。 + +
                          +  
                          +
                          + + + diff --git a/docs/auxiliar/index.md b/docs/auxiliar/index.md new file mode 100644 index 000000000..04fccb8ff --- /dev/null +++ b/docs/auxiliar/index.md @@ -0,0 +1,70 @@ +--- +title: 辅助元素 blockquote,fieldset,hr +toc: true +--- + +# 辅助元素 + +> 辅助元素是指对 `blockquote,fieldset,hr` 等标签的美化,主要是静态展示作用。 + +

                          引用

                          + +
                          +  
                          +
                          + +

                          字段集

                          + +
                          +  
                          +
                          + + +

                          水平线

                          + +
                          +  
                          +
                          diff --git a/docs/badge/index.md b/docs/badge/index.md new file mode 100644 index 000000000..03564b00f --- /dev/null +++ b/docs/badge/index.md @@ -0,0 +1,89 @@ +--- +title: 徽章 badge +toc: true +--- + +# 徽章 + +> 徽章 `badge` 通常作为修饰用途而存在,它们本身细小而并不显眼,但掺杂在其它元素中就显得尤为突出了。 + + +

                          普通徽章

                          + +
                          +  
                          +
                          + + +

                          小圆点

                          + +
                          +  
                          +
                          + + +

                          徽章的搭配

                          + +
                          +  
                          +
                          + +徽章还可以自由佩戴在其他更多元素中,此处不做逐一列举。 + + diff --git a/docs/base.md b/docs/base.md new file mode 100644 index 000000000..ac4d87419 --- /dev/null +++ b/docs/base.md @@ -0,0 +1,166 @@ +--- +title: 底层方法 +toc: true +--- + +# 底层方法 + +> Layui 提供了一系列基础 API,以更好地辅助组件的使用。 + +

                          全局配置

                          + +`layui.config(options);` + +您可以在 Layui 模块使用之前,采用该方法进行一些全局化的基础配置,其支持的属性如下: + +``` +layui.config({ + base: '', // 设定 Layui 扩展模块的所在目录,一般与 extend 方法搭配使用 + version: false, // 用于更新模块缓存,默认 false。若设为 true,即让浏览器不缓存。也可设为一个任意数值 + dir: 'layui/', // layui 基础目录,用于动态导入 src/layui.js 时的内置模块的加载。一般无需设置 + debug: false // 用于开启调试模式,默认 false。若设为 true,则模块的引入节点会保留在页面 +}); +``` + + + + +

                          链接解析

                          + +`var url = layui.url(href);` + +参数 `href` 可选,默认自动读取当前页面 URL(`location.href`)。该方法用于将一段 URL 链接中的 `pathname、search、hash` 等属性进行对象化处理, 以下是对一个 URL 解析后的返回结果: + +``` +// 假设当前页面 url 为: https://domain.com/docs/base.html?a=1&c=3#/user/set/id=123/ +var url = layui.url(); + +// url 返回结果为: +{ + "pathname": ["docs","base.html"], // 路径 + "search": {"a":"1","c":"3"}, // 参数 + "hash": { // hash 解析 + "path": ["user","set",""], // hash 中的路径 + "search": {"id":"123"}, // hash 中的参数 + "hash": "", // hash 中的 hash + "href": "/user/set/id=123/" // hash 中的完整链接 + } +} +``` + +该方法通常可搭配 `location.hash` 和 `hashchange ` 事件,或 `history.pushState()` 和 `popstate` 事件使用,从而实现*单页面应用开发*。 Layui 的 AdminUI 主题模板则正是基于该方法完成的路由系统。 + + +

                          本地存储

                          + +本地存储是对 localStorage 和 sessionStorage 的友好封装,可更方便地管理本地数据。方法如下: + +- `layui.data(table, settings);` 即 localStorage,数据在浏览器中的持久化存储,除非物理删除。 +- `layui.sessionData(table, settings);` 即 sessionStorage ,数据在浏览器中的会话性存储,页面关闭后即失效。 + +两者使用方式完全一致。其中参数 `table` 为表名,`settings` 是一个对象,用于设置 `key/value`。下面以 `layui.data()` 方法为例: + +``` +// 【增】:向 test 表插入一个 nickname 字段,如果该表不存在,则自动建立。 +layui.data('test', { + key: 'nickname', + value: '张三' +}); + +// 【删】:删除 test 表的 nickname 字段 +layui.data('test', { + key: 'nickname', + remove: true +}); +layui.data('test', null); // 删除 test 表 + +// 【改】:同【增】,会覆盖已经存储的数据 + +// 【查】:向 test 表读取全部的数据 +var localTest = layui.data('test'); +console.log(localTest.nickname); // 获得“张三” +``` + +

                          浏览器信息

                          + +`var device = layui.device(key);` + +参数 `key` 可选。可利用该方法对不同的设备进行差异化处理,`device` 即为不同设备下返回的不同信息,如下: + +``` +{ + os: "windows", // 当前浏览器所在的底层操作系统,如:Windows、Linux、Mac 等 + ie: false, // 当前浏览器是否为 ie6-11 的版本,如果不是 ie 浏览器,则为 false + weixin: false, // 当前浏览器是否为微信 App 环境 + android: false, // 当前浏览器是否为安卓系统环境 + ios: false, // 当前浏览器是否为 IOS 系统环境 + mobile: false // 当前浏览器是否为移动设备环境(v2.5.7 新增) +} +``` + +有时,你的 App 可能会对 userAgent 插入一段特定标识,如: + +``` +Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/53.0.2785.143 MYAPP/1.8.6 Safari/537.36 +``` + +要验证当前页面是否在你的 App 环境中,即可通过上述 `MYAPP`(即 Native 给 Webview 插入的标识,可自由定义)来判断。 + +``` +var device = layui.device('MYAPP'); +if(device.MYAPP){ + alert('在 MYAPP 环境中'); +} +``` + +

                          API 列表

                          + +前面我们特别介绍了几个相对特殊的基础方法,而以下是 Layui 提供的全部基础 API: + +| API | 描述 | +| --- | --- | +| layui.cache | 获得 UI 的一些配置及临时缓存信息 | +| layui.config(options) | 基础配置。[#用法](#config) | +| layui.define([modules], callback) | 定义模块。[#用法](modules.html#define) | +| layui.use([modules], callback) | 加载模块。[#用法](modules.html#use) | +| layui.extend(obj) | 扩展模块。[#用法](modules.html#extend) | +| layui.disuse([modules]) 2.7+ | 弃用模块,以便重新扩展新的同名模块。参数支持数组,即可同时弃用多个模块。 如:`layui.disuse(['table'])` | +| layui.link(href) | 加载 CSS,`href` 即为 css 路径。一般用于动态加载你的外部 CSS 文件 | +| layui.getStyle(node, name) | 获得一个原始 DOM 节点的 style 属性值,如:
                          `layui.getStyle(document.body, 'font-size')` | +| layui.img(src, callback, error) | 图片预加载 | +| layui.each(obj, callback) | 对象(Array、Object、DOM 对象等)遍历,可用于取代 for 语句 | +| layui.type(operand) 2.6.7+ | 获取基本数据类型和各类常见引用类型,如:
                          `layui.type([]); // array`
                          `layui.type({}); //object`
                          `layui.type(new Date()); // date` | +| layui.isArray(obj) 2.7+ | 对象是否为泛数组结构。如 Array、NodeList、jQuery 对象等
                          `layui.isArray([1,6]); // true`
                          `layui.isArray($('div')); // true` | +| layui.sort(obj, key, desc) | 将数组中的对象按某个成员重新对该数组排序,如:`layui.sort([{a: 3},{a: 1},{a: 5}], 'a'); // 返回:[{"a":1},{"a":3},{"a":5}]` | +| layui.url(href) | 链接解析。[#用法](#url) | +| layui.data(table, settings) | 持久化存储。[#用法](#data) | +| layui.sessionData(table, settings) | 会话性存储。[#用法](#data) | +| layui.device(key) | 获取浏览器信息。[#用法](#device) | +| layui.hint() | 向控制台打印一些异常信息,目前只返回了 error 方法,如:
                          `var hint = layui.hint();`
                          `hint.error('出错啦');` | +| layui.onevent(modName, events, callback) | 增加自定义模块事件,一般在内置组件中使用。 | +| layui.event(modName, events, params) | 执行自定义模块事件,搭配 onevent 使用。注2.8+:当 events 参数中未设定 filter 时则可重复执行该事件,否则只会执行一次最新添加的事件。 | +| layui.off(events, modName) 2.5.7+ | 用于移除模块相关事件,如:`layui.off('select(filter)', 'form')`,那么`form.on('select(filter)', callback)`事件将会被移除 | +| layui.debounce(fn, wait) 2.8.3+ | 防抖,函数按指定毫秒延时执行 | +| layui.throttle(fn, wait) 2.8.3+ | 节流,限制函数在指定毫秒内不重复执行 | +| layui.getDefineCallback(modName) | 用于获取通过 `layui.define` 定义模块时的回调函数 | +| layui.lay | 基础模块,提供了更多基础 API,一般供 Layui 内置组件中使用 | + +> 基础 API 是整个 UI 的有力支撑,我们在组件的使用过程中也经常会用到。 + + diff --git a/docs/button/index.md b/docs/button/index.md new file mode 100644 index 000000000..09fe62a9b --- /dev/null +++ b/docs/button/index.md @@ -0,0 +1,213 @@ +--- +title: 按钮 +toc: true +--- + +# 按钮 + +> 向任意 `HTML` 标签设定`class="lay-btn"` 建立一个基础按钮。通过追加格式为`lay-btn-{type}`的 `class` 来定义其它按钮风格。内置的按钮 `class` 可以进行任意组合,从而形成更多种按钮风格。 + +

                          按钮主题

                          + +
                          +  
                          +
                          + +

                          按钮尺寸

                          + +
                          +  
                          +
                          + +

                          按钮圆角

                          + +
                          +  
                          +
                          + +

                          按钮图标

                          + +
                          +  
                          +
                          + +

                          按钮混搭

                          + +
                          +  
                          +
                          + +

                          按钮组合

                          + +
                          +  
                          +
                          + +

                          按钮容器

                          + +
                          +  
                          +
                          + +
                          + +## 小贴士 + +> 按钮的主题、尺寸、图标、圆角的交叉组合,可以形成丰富多样的按钮种类。其中颜色也可以根据使用场景自主更改。 diff --git a/docs/carousel/detail/demo.md b/docs/carousel/detail/demo.md new file mode 100644 index 000000000..926fb4712 --- /dev/null +++ b/docs/carousel/detail/demo.md @@ -0,0 +1,219 @@ +

                          常规用法

                          + +
                          +  
                          +
                          + +- 在元素外层设置 `class="lay-carousel"` 来定义一个轮播容器 +- 在元素内层设置属性 `carousel-item` 用来定义条目容器 + +

                          可选项预览

                          + +
                          +  
                          +
                          + +

                          填充图片轮播

                          + +
                          +  
                          +
                          + diff --git a/docs/carousel/detail/options.md b/docs/carousel/detail/options.md new file mode 100644 index 000000000..57bf9f919 --- /dev/null +++ b/docs/carousel/detail/options.md @@ -0,0 +1,239 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          width + +设定轮播容器宽度,值支持:*像素*、*auto*、*百分比*。 + +string + +`600px` + +
                          height + +设定轮播容器高度,值支持的类型同 `width` 属性 + +string + +`280px` + +
                          full + +是否全屏轮播 + +boolean + +`false` + +
                          anim + +轮播切换动画方式。可选值有: + +- `default` 左右切换 +- `updown` 上下切换 +- `fade` 渐隐渐显切换 + +string + +`default` + +
                          autoplay + +是否自动切换,可选值有: + +- `true` 自动滚动,鼠标移入会暂停、移出重新恢复 +- `false` 不自动滚动 +- `always` 始终自动滚动,不受鼠标移入移出影响 2.7+ + + +boolean
                          string
                          + +`true` + +
                          interval + +自动切换的时间间隔,单位: ms (毫秒),不能低于 800 + +number + +`3000` + +
                          index + +初始开始的条目下标 + +number + +`0` + +
                          arrow + +切换箭头默认显示状态,可选值有: + +- `hover` 鼠标悬停显示 +- `always` 始终显示 +- `none` 始终不显示 + +string + +`hover` + +
                          indicator + +指示器位置,可选值有: + +- `inside` 显示在容器内部 +- `outside` 显示在容器外部 +- `none` 不显示 + +注 : 若设定了 `anim: 'updown'` ,则 `outside` 值无效 + +string + +`inside` + +
                          trigger + +指示器的触发事件 + +string + +`click` + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          change 2.7+ + +
                          +轮播切换后的回调函数,返回一个对象参数。 +
                          + +``` +carousel.render({ + elem: '#id', + change: function(obj){ + console.log(obj.index); // 当前条目的索引 + console.log(obj.prevIndex); // 上一个条目的索引 + console.log(obj.item); // 当前条目的元素对象 + } +}); +``` + +注:在 `2.7` 之前的版本,需通过 carousel 的 `change` 事件来实现,如: + +``` +var carousel = layui.carousel; + +// 轮播渲染 +carousel.render(options); + +// 触发轮播切换事件 +carousel.on('change(filter)', function(obj){ // filter 对应轮播容器的 lay-filter 属性值 + console.log(obj); +}); +``` + +
                          + +### 贴士 + +> 若轮播的填充内容为图片,且 `width` 或 `height` 为自适应,那么需动态获取父容器宽高,从而适配父容器。 当浏览器窗口尺寸发生变化时,可在窗口 `resize` 事件中通过轮播重载来重设宽高值。 + diff --git a/docs/carousel/index.md b/docs/carousel/index.md new file mode 100644 index 000000000..8c0b1c262 --- /dev/null +++ b/docs/carousel/index.md @@ -0,0 +1,80 @@ +--- +title: 轮播组件 carousel +toc: true +--- + +# 轮播组件 + +> 轮播组件 `carousel` 主要适用于跑马灯/轮播等交互场景。它并非单纯地为焦点图而生,准确地说,它可以满足任何内容的轮播式切换操作,亦可胜任 `fullpage`(全屏上下轮播)的需求。 + +

                          示例

                          + + + +
                          +{{- d.include("/carousel/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var carousel = layui.carousel | 获得 `carousel` 模块。 | +| [基础接口](../component/#export) 2.13+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [var inst = carousel.render(options)](#render) | carousel 组件渲染,核心方法。 | +| [inst.reload(options)](#reload) | 轮播实例重载 | +| [inst.goto(index)](#goto) 2.8+ | 轮播切换到特定下标 | + +

                          渲染

                          + +`carousel.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法返回一个实例对象,包含操作当前实例的相关方法成员。 + +``` +var inst = carousel.render(options); +console.log(inst); // 得到当前实例对象 +``` + +

                          重载

                          + +`inst.reload(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +通过渲染返回的实例对象,可获得重载方法,用于实现对实例的属性重载。 + +``` +var inst = carousel.render(options); // 轮播初始渲染 +inst.reload(options); // 轮播重载 +``` + +详细用法可参考:[#示例](#demo) + +

                          属性

                          + +
                          +{{- d.include("/carousel/detail/options.md") }} +
                          + + +

                          切换 2.8+

                          + +`inst.goto(index);` + +- 参数 `index` : 轮播下标,从 `0` 开始计算 + +通过渲染返回的实例对象,可获得切换方法,用于实现对轮播的手动定向切换。 + +``` +var inst = carousel.render(options); // 轮播初始渲染 +inst.goto(0); // 轮播切换到第一项 +inst.goto(1); // 轮播切换到第二项 +``` diff --git a/docs/class/index.md b/docs/class/index.md new file mode 100644 index 000000000..a23eae379 --- /dev/null +++ b/docs/class/index.md @@ -0,0 +1,231 @@ +--- +title: 公共类 class +toc: true +--- + +# 公共类 + +> 公共类是 `layui.css` 中并不以组件形式存在的公共 `class` 选择器,而又能用于任何地方。 + +

                          普通类

                          + +| className | 描述 | +| --- | --- | +| lay-main | 设置一个固定宽度为 `1160px` 的水平居中块 | +| lay-border-box | 设置元素及其所有子元素均为 `box-sizing: border-box` 模型的容器 | +| lay-clear | 清除前面的同级元素产生的浮动 | +| lay-clear-space 2.8+ | 清除容器内的空白符 | +| lay-inline | 设置元素为内联块状结构 | +| lay-ellip | 设置单行文本溢出并显示省略号 | +| lay-unselect | 屏蔽选中 | +| lay-disabled | 设置元素为不可点击状态 | +| lay-circle | 设置元素为圆形。需确保 `width` 和 `height` 相同 | + +

                          显示隐藏

                          + +| className | 描述 | +| --- | --- | +| lay-show | 设置元素为 `display: block` 可见状态 | +| lay-hide | 设置元素为 `display: none` 隐藏状态,且不占用空间 | +| lay-show-v | 设置元素为 `visibility: visible` 可见状态 | +| lay-hide-v | 设置元素为 `visibility: hidden` 不可见状态,且依旧占用空间 | + + +

                          三角实体

                          + +| className | 描述 | +| --- | --- | +| lay-edge | 定义一个三角形基础类 | +| lay-edge-top | 设置向上三角 | +| lay-edge-right | 设置向右三角 | +| lay-edge-bottom | 设置向下三角 | +| lay-edge-left | 设置向左三角 | + +示例 + +
                          +  
                          +
                          + +

                          内外边距

                          + +| className | 描述 | +| --- | --- | +| lay-padding-1 | 4px 内边距 | +| lay-padding-2 | 8px 内边距 | +| lay-padding-3 | 16px 内边距 | +| lay-padding-4 | 32px 内边距 | +| lay-padding-5 | 48px 内边距 | +| lay-margin-1 | 4px 外边距 | +| lay-margin-2 | 8px 外边距 | +| lay-margin-3 | 16px 外边距 | +| lay-margin-4 | 32px 外边距 | +| lay-margin-5 | 48px 外边距 | + + +

                          背景颜色

                          + +| className | 背景色 | 预览 | +| --- | --- | --- | +| lay-bg-red | 红 |
                           
                          | +| lay-bg-orange | 橙 |
                           
                          | +| lay-bg-green | 绿 |
                           
                          | +| lay-bg-blue | 蓝 |
                           
                          | +| lay-bg-purple 2.8+ | 紫 |
                           
                          | +| lay-bg-black | 深 |
                           
                          | +| lay-bg-gray | 浅 |
                           
                          | + +

                          文字大小

                          + +| className | 文字大小和预览 | +| --- | --- | +| lay-font-12 | 12px | +| lay-font-13 2.8+ | 13px | +| lay-font-14 | 14px | +| lay-font-16 | 16px | +| lay-font-18 | 18px | +| lay-font-20 | 20px | +| lay-font-22 2.8+ | 22px | +| lay-font-24 2.8+ | 24px | +| lay-font-26 2.8+ | 26px | +| lay-font-28 2.8+ | 28px | +| lay-font-30 2.8+ | 30px | +| lay-font-32 2.8+ | 32px | + +

                          文字颜色

                          + +| className | 文字颜色和预览 | +| --- | --- | +| lay-font-red | | +| lay-font-orange | | +| lay-font-green | 绿 | +| lay-font-blue | | +| lay-font-purple 2.8+ | | +| lay-font-black | | +| lay-font-gray | | + +

                          文本容器

                          + +通过设置 `class="lay-text"` 定义一段包含标题、段落、列表等组合的文本区域,通常用于 Markdown 文档。 + +
                          +  
                          +
                          + diff --git a/docs/code/detail/options.md b/docs/code/detail/options.md new file mode 100644 index 000000000..2f3466743 --- /dev/null +++ b/docs/code/detail/options.md @@ -0,0 +1,461 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          code 2.8.18+ + +设置原始 code 值,默认取目标元素中的内容 + +string-
                          preview 2.8+ + +是否开启 Code 预览功能,可选值有: + +- `true` 开启 Code 的普通预览 +- `false` 关闭 Code 预览(默认) +- `"iframe"` 开启 Code 在 iframe 模式中预览 + +当开启该属性时,`elem` 指定的元素需要设置成以下结构: + +``` +
                          +  
                          +
                          +``` + +
                          boolean
                          string
                          + +`false` + +
                          layout 2.8+ + +开启预览后的面板布局方式,值为一个数组,数组的可选成员有: + +- `code` 代码区域 +- `preview` 预览区域 + +面板将根据数组的排列顺序来显示,如: + +``` +layout: ['code', 'preview'] +``` + +array-
                          style 2.8+ + +设置 Code 和预览区域的公共样式 + +string-
                          codeStyle 2.8+ + +设置 Code 区域的局部样式,优先级高于 `style` 属性 + +string-
                          previewStyle 2.8+ + +设置预览区域的局部样式,优先级高于 `style` 属性 + +string-
                          id 2.8+ + +设置实例的唯一索引,以便用于其他操作 + +string-
                          className 2.8+ + +追加实例面板的 `className`,以便对其自定义样式 + +string-
                          tools + +用于设置组件右上角面板工具列表,仅 `preview: true` 时有效。值为一个数组,可选值(内置工具): + +- `copy` : 代码复制 +- `full` : 最大化显示 +- `window` : 在新窗口预览。一般当 `layout: 'iframe'` 时开启,且 code 中须包含完整的 HTML 方可在新窗口正常预览。 + +工具图标将根据数组的排列顺序来显示,如: + +```js +tools: ['full', 'window','copy'] +``` + +array-
                          extendToolkit + +用于扩展工具包。 + +```js +extendToolkit: { + // 主题工具 + theme: { + title: ['切换高亮主题'], // 工具标题 + iconName: 'theme', // 工具图标名 + // 点击事件 + onClick(obj) { + // do something + console.log(obj); // 当前实例相关信息 + } + } +} +``` + +选项解释: + +- `title` 值为数组形式,以支持不同状态时的默认标题 +- `iconName` 值对应[图标](../icon/) `className` 的 `lay-icon-` 后的名称。如图标:`lay-icon-theme`,那么 `iconName` 设置值为 `theme` 即可。 + +扩展后,即可在 `tools` 选项中设置,如:`tools: ['theme']` + +object-
                          onToolClick + +点击任意工具触发的回调函数。 + +```js +onToolClick: function(obj) { + console.log(obj); // 返回信息 + console.log(obj.name); // 当前工具 name +} +``` + +通过该函数与 `tools` 属性的搭配,可实现对工具栏的扩展。 + +function-
                          copy 2.8.2+ + +用于开启代码复制功能图标。若开启 `priview`,则自动放置在 `tools` 属性中,复制图标将显示在容器右上角工具栏;若未开启 `priview`,则显示在 code 区域右上角。 + +boolean + +`true` + +
                          text 2.8+ + +自定义默认文本,值为一个对象,可选成员有: + +``` +text: { + code: '代码栏标题', // 默认: + preview: '预览栏标题' // 默认: Preview +} +``` + +object-
                          header 2.8+ + +是否开启 Code 栏头部区域。 + +boolean + +`false` + +
                          ln + +是否显示 Code 区域的行号 + +boolean + +`true` + +
                          theme 2.8.17+ + +Code 容器的主题风格,可选值有: + +- `light` 浅色模式(默认) +- `dark` 深色模式 + +string-
                          encode + +是否对 code 中的 html 进行编码(转义)。 + +boolean + +`true` + +
                          lang 2.8.17+ + +指定语言类型。如:`lang: 'html'` + +string-
                          langMarker 2.8.17+ + +是否在代码区域右上角显示语言类型 + +boolean + +`false` + +
                          wordWrap 2.8.17+ + +Code 文字是否自动换行 + +boolean + +`true` + +
                          highlighter 2.8.17+ + +设置语法高亮器,可选值: + +- `hljs` : 指定 `highlight.js` 库 +- `prism` : 指定 `prism.js` 库 +- `shiki` : 指定 `shiki.js` 库 + +注:对应的语法高亮器 JS 库和相关主题 CSS 需自主引入,该属性仅用于内部适配。 + +string-
                          + +[codeRender](#options.codeRender) 2.8+ + + + +
                          +用于重新渲染 code,譬如代码高亮处理。 +
                          + +``` +codeRender: function(code, opts){ + // 此处以 highlight.js 为例 + return hljs.highlight(code, {language: opts.lang}).value; +} +``` + +code 组件语法高亮相关示例: + +- highlight 和 prism 语法高亮示例 +- shiki 语法高亮示例 + +
                          + +[done](#options.done) 2.8+ + + + +
                          +组件渲染完毕的回调函数,函数返回一个 object 类型参数 +
                          + +``` +done: function(obj){ + var container = obj.container; // 当前面板的容器对象 + obj.render(); // 对预览中的 `element,form` 等组件进行渲染 +} +``` + +
                          + +[onCopy](#options.onCopy) 2.8.2+ + + + +
                          +点击复制图标时的回调函数。 +
                          + +``` +onCopy: function(code, copied){ + console.log(code); // 得到当前 code 内容 + console.log(copied); // 是否复制成功(2.9.21+) + + return false; // 返回 false 阻止内置提示(2.9.21+) +} + +``` + +
                          + +[highlightLine](#options.highlightLine) 2.12+ + + + +
                          + +设置行高亮,可选项: +- `hl` : 高亮 +- `++` : diff++ +- `--` : diff-- +- `focus` : 聚焦 + +
                          + +可通过 `hl.range` 选项来设置行高亮范围: + +``` +highlightLine: { + hl: { + range: '1,3-5,8', // 指定行高亮范围 '1,3,4,5,8' + comment: true, // 是否解析行中的高亮注释 + } +} +``` + +或通过特定注释格式: `[!code :]` 指定行高亮范围,规则解释: +- `` : `highlightLine` 的可选项,如 `h1, focus` 等 +- `` : 行数(含本行) + +``` +111 聚焦 2 行(含本行) // [!code focus:2] +222 高亮本行 // [!code hl] +333 +``` + +highlightLine 选项的详细用法可参考:highlightLine 行高亮在线示例 + +
                          + diff --git a/docs/code/index.md b/docs/code/index.md new file mode 100644 index 000000000..87d4500c2 --- /dev/null +++ b/docs/code/index.md @@ -0,0 +1,66 @@ +--- +title: Code 预览组件 code +toc: true +--- + +# Code 预览组件 + +> 代码预览组件 `code` 主要用于对代码区块的修饰和对应的效果预览,如 Layui 各组件文档中的示例演示。 + + +

                          方法

                          + +`var codeInst = layui.code(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options)。 + +其中 `codeInst` 即实例返回的对象,包含对当前实例进行重载等方法成员,如: + +``` +var codeInst = layui.code(options); +console.log(codeInst); // 查看所有成员 +codeInst.config; // 当前实例配置项 +codeInst.reload(options); // 重载 +``` + + +另外,属性除了在该方法中传递,也可以直接写在元素的 `lay-options` 属性上,如: + +
                          +  
                          +
                          + +

                          属性

                          + +
                          +{{- d.include("/code/detail/options.md") }} +
                          + +

                          小贴士

                          + +> code 组件可广泛应用于技术类文档、博客等页面,可轻松适配第三方主流语法高亮器。 + diff --git a/docs/color/index.md b/docs/color/index.md new file mode 100644 index 000000000..66f218a4c --- /dev/null +++ b/docs/color/index.md @@ -0,0 +1,140 @@ +--- +title: 颜色 +toc: true +--- + +# 颜色 + +> Layui 试图在清新与深沉之间寻求某种柔和,以不过分刺激大脑皮层的神经介质,反馈出经久耐看的微妙视图。您可以在我们精心调配的如下色系中合理搭配,减少不必要的违和感,从而使您的 Web 页面看上去尽可能融洽。 + +

                          基色调

                          + +
                          +
                          +
                          +

                          #16baaa

                          +

                          蓝绿色

                          +
                          +
                          +
                          +
                          +

                          #16b777

                          +

                          清新绿

                          +
                          +
                          +
                          +
                          +

                          #1e9fff

                          +

                          经典蓝

                          +
                          +
                          +
                          + +Layui 选取以象征清新与包容的「蓝绿色」作为主色调,它介于蓝与绿之间,亦可称之为「青色」,所谓青者,取之于蓝而深于绿,此间包罗万象,跨越时空。这也是我们对技术创作与人生哲学之间的一点思考。 + + +

                          辅色调

                          + +
                          +
                          +
                          +

                          #ff5722

                          +

                          错误 - Danger

                          +
                          +
                          +
                          +
                          +

                          #ffb800

                          +

                          警示 - Warning

                          +
                          +
                          + +
                          +
                          +

                          #16b777

                          +

                          成功 - Success

                          +
                          +
                          +
                          +
                          +

                          #31bdec

                          +

                          引导 - Info

                          +
                          +
                          +
                          + +页面中同样也少不了辅助色彩的点缀,以对不同含义的内容加以区分。Layui 从暖色系(红/橙)和冷色系(绿/蓝)中,各自调取了我们认为最具代表性的颜色值,它们通常在不同的场景中发挥着不同的作用。 + +

                          中色调

                          + +
                          +
                          +
                          +

                          #fafafa

                          +
                          +
                          +
                          +

                          #f7f7f7

                          +
                          +
                          +

                          #eeeeee

                          +
                          +
                          +

                          #e2e2e2

                          +
                          +
                          +

                          #dddddd

                          +
                          +
                          +

                          #d2d2d2

                          +
                          +
                          +

                          #cccccc

                          +
                          +
                          +

                          #c2c2c2

                          +
                          +
                          +

                          #2f363c

                          +
                          +
                          +

                          #23292e

                          +
                          +
                          + +中性的颜色是页面中的重要组成部分,也被称之为无彩色系,一般用于文本、背景和边框等。它能对由彩色进行视觉冲淡,以达到和谐自然的效果。Layui 认为恰当的灰度调配代表着极简,这是一种神奇的色系,是视觉疲劳的栖息,低调而优雅,且永不过时。 + +

                          七色调

                          + +
                          +
                          + #ff5722 - 红 +
                          +
                          + #ffb800 - 橙 +
                          +
                          + #16baaa - 绿 +
                          +
                          + #1e9fff - 蓝 +
                          +
                          + #a233c6 - 紫 +
                          +
                          + #2f363c - 深 +
                          +
                          + #fafafa - 浅 +
                          +
                          + +Layui 的色调基础,除了前面提到的主辅中色之外,还建立在以上罗列的七种颜色之上。你同样也可以遵循我们提供的色调方案去扩展你的页面元素,使得能与 Layui 的主题风格无缝融合。 + +
                          + +## 标语 + +> 不热衷于视觉设计的开发者不是一个好作家。 —— 贤心 + diff --git a/docs/colorpicker/detail/demo.md b/docs/colorpicker/detail/demo.md new file mode 100644 index 000000000..81e21bc3f --- /dev/null +++ b/docs/colorpicker/detail/demo.md @@ -0,0 +1,256 @@ +
                          +  
                          +
                          + +

                          将颜色值赋给表单

                          + +
                          +  
                          +
                          + +

                          设置 RGB / RGBA

                          + +
                          +  
                          +
                          + +

                          开启透明度

                          + +
                          +  
                          +
                          + +

                          预定义颜色项

                          + +
                          +  
                          +
                          + +

                          全功能和回调的使用

                          + +
                          +  
                          +
                          + +

                          颜色框尺寸

                          + +
                          +  
                          +
                          + +

                          同时绑定多个元素

                          + +
                          +  
                          +
                          diff --git a/docs/colorpicker/detail/options.md b/docs/colorpicker/detail/options.md new file mode 100644 index 000000000..510a2ccd7 --- /dev/null +++ b/docs/colorpicker/detail/options.md @@ -0,0 +1,178 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          color + +默认颜色值,值的格式跟随 `format` 属性的设定。 + +string-
                          format + +颜色显示/输入格式,支持 `hex` `rgb` 。 若同时开启 `alpha` 属性,则颜色值自动变为 `rgba`。 + +string + +`hex` + +
                          alpha + +是否开启透明度。当同时开启 `format: 'rgb'` 时,`color` 值将采用 `rgba` 格式。 + +boolean + +`false` + +
                          predefine + +是否开启预定义颜色栏 + +boolean + +`false` + +
                          colors + +设置可选的颜色列表,需开启 `predefine: true` 有效。 +
                          用法详见:[#预定义颜色项](#demo-predefine) + +
                          array-
                          size + +颜色框的尺寸,可选值: `lg` `sm` `xs` + +string + +`sm` + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          change + +颜色被改变的回调函数。用法详见:[#示例](#demo-all) + +``` +change: function(value){ + console.log(value); // 当前颜色值 +} +``` + +
                          done + +颜色选择完毕的回调函数。点击“确认”和“清除”按钮均会触发 + +``` +done: function(value){ + console.log(value); // 当前选中的颜色值 +} +``` + +用法详见:[#示例](#demo-all) + +
                          cancel 2.8+ + +取消颜色选择的回调函数,一般点击非颜色选择面板区域触发。 + +``` +cancel: function(value){ + console.log(value); // 当前颜色值 +} +``` + +用法详见:[#示例](#demo-all) + +
                          close 2.8+ + +颜色选择面板被关闭后即触发。 + +``` +close: function(value){ + console.log(value); // 当前颜色值 +} +``` + +
                          + diff --git a/docs/colorpicker/index.md b/docs/colorpicker/index.md new file mode 100644 index 000000000..fdff02d46 --- /dev/null +++ b/docs/colorpicker/index.md @@ -0,0 +1,63 @@ +--- +title: 颜色选择器 colorpicker +toc: true +--- + +# 颜色选择器 + +> 颜色选择器 `colorpicker` 用于对颜色的快捷选择,支持 `hex,rgb,rgba` 三种颜色类型。 + +

                          示例

                          + +
                          +{{- d.include("/colorpicker/detail/demo.md") }} +
                          + +

                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var colorpicker = layui.colorpicker | 获得 `colorpicker` 模块。 | +| [基础接口](../component/#export) 2.13+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [colorpicker.render(options)](#render) | colorpicker 组件渲染,核心方法。 | + + +

                          渲染

                          + +`colorpicker.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) +
                          2.7+ : 除 `elem` 属性外,其他基础属性也可以直接写在元素的 `lay-options="{}"` 属性中。 + +``` +
                          +
                          +
                          + + + +``` + +

                          属性

                          + +
                          +{{- d.include("/colorpicker/detail/options.md") }} +
                          + +## 兼容性 + +> colorpicker 组件支持 `Chrome,Edge,Firefox` 等所有高级浏览器,不支持 IE10 低版本浏览器。 diff --git a/docs/component/detail/options.md b/docs/component/detail/options.md new file mode 100644 index 000000000..f6a32d1a4 --- /dev/null +++ b/docs/component/detail/options.md @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          name + +组件名称。如 `name:'tabs'`,在使用组件时,即可通过 `layui.tabs` 获得该组件。注:*组件名必须唯一*。 + +string-
                          config + +定义组件渲染时的默认配置项。 + +object-
                          CONST + +通用常量集,一般存放固定字符,如类名等。如: + +``` +CONST: { + ELEM: 'lay-tabs', +} +``` + +上述常量可通过 `component.CONST.ELEM` 获得。 + +object-
                          isDeepReload
                          实验性
                          + +组件重载时是否允许深度重载,即对重载时选项进行深度合并。 + +boolean + +`false` + +
                          + +
                          + +[回调函数](#options.callback) + +
                          + +
                          render + +组件渲染的逻辑。 + +```js +render: function() { + // 组件的容器构建、插入等 + // … +} +``` + +也可以通过原型 `component.Class.prototype.render` 进行定义。 + +
                          beforeInit + +组件初始化之前的回调函数。 + +```js +beforeInit: function(options) { + console.log(options); // 获得组件初始化前的配置项 +} +``` + +
                          beforeRender + +渲染之前的回调函数。 + +```js +beforeRender: function(options) { + console.log(options); // 获得组件渲染前的配置项 +} +``` + +
                          extendsInstance + +扩展组件渲染的实例对象的回调函数。如: + +```js +extendsInstance: function(that) { + return { + // 关闭组件 + close: function() { + that.remove(); // 调用组件原型中的 remove 方法 + } + } +} +``` + +当组件渲染时,即可通过它返回的对象调用实例方法: + +```js +var inst = xxx.render(); // 某组件渲染 +inst.close(); // 关闭某组件 +``` + +
                          events + +定义组件各内部事件。 + +```js +events: function() { + // 亦可包含针对组件的 window, document 等全局事件 + // … +} +``` + +也可以通过原型 `component.Class.prototype.events` 进行定义。 + +
                          + diff --git a/docs/component/index.md b/docs/component/index.md new file mode 100644 index 000000000..7edcbff1d --- /dev/null +++ b/docs/component/index.md @@ -0,0 +1,304 @@ +--- +title: 组件构建器 component +toc: true +--- + +# 组件构建器 2.10+ + +> 组件构建器 `component` 是 2.10 版本新增的重要模块,旨在为 Layui 2 系列版本逐步构建统一 API 规范的组件。 + +

                          API

                          + +| API | 描述 | +| --- | --- | +| [layui.component(options)](#create) | 创建组件 | + +

                          创建组件

                          + +`layui.component(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法返回一个对象,包含用于组件对外的基础接口,如:组件渲染、重载、事件操作,及构造函数等等。用法示例: + +```js +/** + * tabs + * 标签页组件 + */ +layui.define('component', function(exports) { + // 创建组件 + var component = layui.component({ + name: 'tabs', // 组件名称 + config: { // 组件默认配置项 + // … + }, + render: function() { // 组件渲染逻辑 + // … + }, + // 其他选项 + }); + + // 将创建组件时返回的 `component` 对象作为组件的接口输出 + // 组件将继承通用的基础接口,如 render, reload, set 等方法 + exports(component.CONST.MOD_NAME, component); +}); +``` + +

                          属性选项

                          + +
                          +{{- d.include("/component/detail/options.md") }} +
                          + +

                          基础接口 🔥

                          + +通过 `component` 模块创建的组件,均会继承内部定义的「基础对外接口」和「组件渲染的通用选项」。 + +| 接口 | 描述 | +| --- | --- | +| [component.render(options)](#render) | 组件渲染 | +| [component.reload(id, options)](#reload) | 组件重载 | +| [component.set(options)](#set) | 设置组件渲染时的全局配置项 | +| [component.on(\'event(filter)\', callback)](#on) | 组件的自定义事件 | +| [component.getInst(id)](#getInst) | 获取组件指定的实例对象 | +| [component.removeInst(id)](#removeInst) 2.10.2+ | 删除组件指定的实例对象 | +| component.index | 获得组件的自增索引 | +| component.config | 获得组件渲染时的全局配置项。一般通过 `set` 方法设置 | +| component.cache | 获得组件的缓存数据集。如组件实例 ID 集 | +| [component.CONST](#CONST) | 获得组件的通用常量集。如 `MOD_NAME` 等 | +| [component.Class](#Class) | 获得组件的构造函数。一般用于扩展原型方法 | + +> 😊 注:上表中的 `component` 为组件的基础对象,实际使用时,请根据实组件名称进行替换。如 `tabs` 组件,对应的接口则为:`tabs.render(options)` `tabs.on('event(filter)', callback)` 等。 + +

                          组件渲染

                          + +`component.render(options)` + +- 参数 `options` : 组件渲染的配置项。可继承的通用选项见下表: + +| 选项 | 描述 | +| --- | --- | +| elem | 组件渲染指定的目标元素选择器或 DOM 对象 | +| id | 组件渲染的唯一实例 ID | +| show | 是否初始即渲染组件。通常结合创建组件设定的 `isRenderOnEvent` 选项决定是否启用 | + +更多渲染时的选项则由各组件内部单独定义,具体可查阅各组件对应的文档。 + +```js +// 以 tabs 组件为例 +// 渲染 +tabs.render({ + elem: '#id', + // … +}); +``` + +

                          组件重载

                          + +`component.reload(id, options)` + +- 参数 `id` : 组件实例 ID。 +- 参数 `options` : 组件重载的配置项。 + +该方法可实现对组件的完整重载。部分组件通常还提供了「仅数据重载」,具体可参考各组件对应的文档。 + +```js +// 以 tabs 组件为例 +// 重载 tabs 组件实例 +tabs.reload('id', { + // … +}) +``` + +

                          全局设置

                          + +`component.set(options)` + +- 参数 `options` : 组件渲染的配置项。 + +该方法用于全局设置组件渲染时的默认配置项,需在组件渲染之前执行。 + +```js +// 以 tabs 组件为例 +// 全局设置。后续所有渲染均会生效,除非对选项进行覆盖 +tabs.set({ + trigger: 'mouseenter' // 默认的触发事件 + // … +}); + +// 渲染实例 1 +tabs.render({ id: 'id1'}); // 继承全局设置 + +// 渲染实例 2 +tabs.render({ + id: 'id2', + trigger: 'click' // 覆盖全局的触发事件 +}); +``` + +

                          事件定义

                          + +`component.on('event(id)', callback)` + +- 参数 `event(id)` : 是事件的特定结构。 `event` 为事件名,支持的事件见各组件列表。`id` 为组件的实例 ID。 +- 参数 `callback` : 事件回调函数。返回的参数由各组件内部单独定义。 + +具体事件一般由组件内部单独定义,具体可查看各组件对应的文档。 + +```js +// 以 tabs 组件为例: +// 组件渲染成功后的事件 +tabs.on('afterRender(id)', function(data) { + console.log(obj); +}); +``` + +

                          获取实例

                          + +`component.getInst(id)` + +- 参数 `id` : 组件的实例 ID。 + +该方法可获取组件渲染时对应的实例,以调用组件内部的原型方法,一般用于在外部对组件进行扩展或重构。 + +```js +// 以 tabs 组件为例 +var tabInstance = tabs.getInst('id'); +// 调用内部的标签滚动方法 +tabInstance.roll(); +``` + +

                          删除实例 2.10.2+

                          + +`component.removeInst(id)` + +- 参数 `id` : 组件的实例 ID。 + +该方法可删除组件渲染时对应的实例,*一般在完全移除组件时使用,否则可能造成组件相关方法失效*。 + +```js +// 以 tabs 组件为例 +tabs.removeInst('id'); +``` + +

                          基础常量

                          + +`component.CONST` + +获取组件的通用常量集,一般存放固定字符,如类名等。 + +```js +// 基础常量如下 +component.CONST.MOD_NAME; // 组件名称 +component.CONST.MOD_INDEX; // 组件自增索引 +component.CONST.CLASS_THIS; // lay-this +component.CONST.CLASS_SHOW; // lay-show +component.CONST.CLASS_HIDE; // lay-hide +component.CONST.CLASS_HIDEV; // lay-hide-v +component.CONST.CLASS_DISABLED; // lay-disabled +component.CONST.CLASS_NONE; // lay-none + +// 更多常量一般在各组件内部单独定义,以 tabs 组件为例 +tabs.CONST.ELEM; // lay-tabs +``` + +

                          扩展接口

                          + +除上述「基础接口」外,你也可以对接口进行任意扩展,如: + +```js +/** + * 定义组件 + */ +layui.define('component', function(exports) { + // 创建组件 + var component = layui.component({ + name: 'test', + // … + }); + // 扩展组件接口 + layui.$.extend(component, { + // 以扩展一个关闭组件面板的接口为例 + close: function(id) { + var that = component.getInst(id); + if(!that) return this; + that.remove(obj); // 调用原型中的 remove 方法 + } + }); + // 输出组件接口 + exports(component.CONST.MOD_NAME, component); +}); +``` + +```js +/** + * 使用组件(以上述定义的 test 组件为例) + */ +layui.use('test', function() { + var test = layui.test; + // 渲染组件 + test.render({ + elem: '#id', + id: 'test-1' + }); + // 关闭组件面板(通常在某个事件中使用) + test.close('test-1'); +}); +``` + +

                          扩展原型

                          + +`component.Class` + +当通过 `layui.component()` 方法创建一个新的组件时,通常需借助 `Class` 构造函数扩展组件原型,以灵活实现组件的个性化定制。但一般不推荐重写 `component.js` 原型中已经定义的基础方法,如:`init, reload, cache` + +``` +/** + * 定义组件 + */ +layui.define('component', function(exports) { + // 创建组件 + var component = layui.component({ + name: '', // 组件名称 + // … + }); + + // 获取构造器 + var Class = component.Class; + + // 扩展原型 + Class.prototype.xxx = function() { + // … + }; + Class.prototype.aaa = function() { + // … + }; + + // 输出组件接口 + exports(component.CONST.MOD_NAME, component); +}); +``` + +通过 `Class` 构造函数也可以对某个组件的原型进行重构,但一般不推荐,因为这可能破坏组件的基础功能。 + +``` +// 以 tabs 组件为例 +var tabs = layui.tabs; + +// 获得 tabs 组件构造函数 +var Class = tabs.Class; + +// 重构 tabs 组件内部的 xxx 方法(不推荐) +Class.prototype.xxx = function() { + // … +}; +``` + +您也可以直接参考 tabs 组件源码中关于扩展原型的具体实践。 + +## 💖 心语 + +一直以来,Layui 的很多组件自成一体,使得无法对组件进行较好的统一管理。尽管我们也曾努力尝试改善这个问题,但很多时候为了向下兼容而又不得不保留许多旧有的特性,随着组件的增加,该问题也显得越加明显。而 component 模块的出现,将在一定程度上填补这一缺憾,它的初衷正是为了确保 Layui 组件的一致性,如核心逻辑和 API 设计等,主要意义在于:**给 Layui 2 系列版本提供一个构建通用组件的方式**,增强其「生命力」。 + + diff --git a/docs/dropdown/detail/demo.md b/docs/dropdown/detail/demo.md new file mode 100644 index 000000000..4afcb6184 --- /dev/null +++ b/docs/dropdown/detail/demo.md @@ -0,0 +1,57 @@ +

                          基础用法

                          + +
                          +  
                          +
                          + +

                          复杂结构

                          + +
                          +  
                          +
                          + +

                          在表格中应用

                          + +
                          +  
                          +
                          + +

                          自定义事件

                          + +
                          +  
                          +
                          + +

                          右键菜单

                          + +
                          +  
                          +
                          + +

                          水平对齐方式

                          + +
                          +  
                          +
                          + +

                          自定义内容

                          + +如下以弹出一个 `tab` 为例 + +
                          +  
                          +
                          diff --git a/docs/dropdown/detail/options.data.md b/docs/dropdown/detail/options.data.md new file mode 100644 index 000000000..4e48b5fa0 --- /dev/null +++ b/docs/dropdown/detail/options.data.md @@ -0,0 +1,116 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          title + +菜单标题 + +string-
                          id + +菜单 ID。用户菜单项唯一索引 + + +number/string-
                          type + +菜单项的类型,支持的可选值如下: + +- `normal` 普通菜单项(默认) +- `group` 纵向组合收缩菜单 +- `parent` 横向父级菜单 +- `-` 分割线 + +string + +`normal` + +
                          href + +菜单项的 url 地址。若填写,点击菜单将直接发生跳转。 + +string-
                          target + +菜单 url 打开方式,需设置 `href` 属性后才生效。 一般可设为 `_blank` 或 `_self` 等 + +string + +`_self` + +
                          disabled 2.8+ + +菜单项是否禁用状态 + +boolean + +`false` + +
                          templet + +自定义当前菜单项模板,优先级高于基础属性 `templet` + +string/function-
                          child + +子级菜单数据集合。参数同父级,可无限嵌套。 + +array-
                          diff --git a/docs/dropdown/detail/options.md b/docs/dropdown/detail/options.md new file mode 100644 index 000000000..27f3c24e0 --- /dev/null +++ b/docs/dropdown/detail/options.md @@ -0,0 +1,354 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          + +[data](#options.data) + + + +下拉菜单的数据源。格式详见:[#data 格式](#options.data) + +array-
                          id + +设定实例唯一索引,以便用于其他方法对例进行相关操作。若该属性未设置,则默认从 `elem` 属性绑定的元素中的 `id` 属性值中获取。 + +string-
                          trigger + +触发组件的事件类型。支持所有事件,如: `click,hover,mousedown,contextmenu` 等 + +string + +`click` + +
                          closeOnClick 2.9.18+ + +下拉面板打开后,再次点击目标元素时是否关闭该面板。 + +boolean + +`true` + +
                          show + +是否渲染即显示组件面板。该属性一般在重载方法中传递。 + +boolean + +`false` + +
                          align + +下拉面板相对绑定元素的水平对齐方式。支持以下可选值: + +- `left` 左对齐(默认) +- `center` 居中对齐 +- `right` 右对齐 + +string + +`left` + +
                          isAllowSpread + +是否允许菜单组展开收缩 + +boolean + +`true` + +
                          isSpreadItem + +是否初始展开子菜单 + +boolean + +`true` + +
                          accordion 2.8.18+ + +是否开启手风琴效果 + +boolean + +`false` + +
                          delay + +延迟触发的毫秒数。当 `trigger: 'hover'` 时才生效。示例: + +- `delay: 300` : 表示显示与隐藏的延迟时间均为 300 毫秒 +- `delay: [200, 300]` 2.9.2+ : 数组成员值分别表示显示延迟时间和隐藏延迟时间 + +number/array + +`[200, 300]` + +
                          className + +自定义组件主容器的样式类名,从而在外部重新定义样式。 + +string-
                          style + +设置组件主容器的 `CSS` 样式。 + +string-
                          shade 2.8+ + +设置弹出时的遮罩。支持以下方式赋值: + +- 若值为 `number` 类型,则表示为遮罩透明度,如: +
                          `shade: 0.3` +- 若值为 `array` 类型,则可同时设置透明度和背景色,如: +
                          `shade: [0.3, '#000']` + +
                          number
                          array
                          + +`0` + +
                          templet + +全局定义菜单的列表模板,可添加任意 `html` 字符,且支持 [laytpl](../laytpl/) 模板语法。用法详见:[#示例](#demo-complex) + +注 2.8+ : 模板亦可采用函数写法: + +``` +templet: function(d){ + return ' ' + d.title; +} +``` + +string
                          function
                          -
                          content + + 自定义组件内容,从而替代默认的菜单结构。用法详见:[#示例](#demo-content) + +string-
                          clickScope 2.8+ + +设置触发点击事件的菜单范围。 支持以下可选值: + +- `all` : 即代表父子菜单均可触发事件 + +默认无需设置,即父级菜单不触发事件 + +string-
                          + +[customName](#options.customName) 2.8.14+ + + + +自定义 `data` 数据源中常用的字段名称。 + +object-
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          ready + +组件成功弹出后的回调函数。返回的参数如下: + +``` +ready: function(elemPanel, elem){ + console.log(elemPanel); // 组件面板元素对象 + console.log(elem); // 当前组件绑定的目标元素对象 +} +``` + +
                          + +[click](#options.click) + + + +
                          +菜单项被点击时的回调函数。返回的参数如下: +
                          + +``` +click: function(data, othis, event){ + console.log(data); // 当前所点击的菜单项对应的数据 + console.log(othis); // 当前所点击的菜单项元素对象 + console.log(this.elem); // 当前组件绑定的目标元素对象,批量绑定中常用 + console.log(event); // 事件对象 2.9.18+ + + // 若返回 false,则点击选项可不关闭面板 --- 2.8+ + /* + return false; + */ +} +``` + +用法详见:[#示例](#examples) + +
                          close 2.9.7+ + +面板关闭后的回调函数。返回的参数如下: + +``` +close: function(elem){ + console.log(elem); // 当前组件绑定的目标元素对象 +} +``` + +
                          onClickOutside 2.9.18+ + +点击 dropdown 外部时的回调函数,返回 `false` 可阻止关闭。 + +``` +onClickOutside: function(event){ + // 参数 event 即为当前点击的事件对象 + // … + // return false; // 若返回 false,当点击面板外部时可阻止关闭 +} +``` + +
                          + diff --git a/docs/dropdown/examples/align.md b/docs/dropdown/examples/align.md new file mode 100644 index 000000000..6ed7efe5c --- /dev/null +++ b/docs/dropdown/examples/align.md @@ -0,0 +1,38 @@ +
                          + + + +
                          + + + diff --git a/docs/dropdown/examples/base.md b/docs/dropdown/examples/base.md new file mode 100644 index 000000000..7451cdc27 --- /dev/null +++ b/docs/dropdown/examples/base.md @@ -0,0 +1,123 @@ +
                          + + +
                          + +
                          + +
                          +
                          + 可以绑定任意元素, + + 比如这段文字 + + +
                          + + + + diff --git a/docs/dropdown/examples/complex.md b/docs/dropdown/examples/complex.md new file mode 100644 index 000000000..a51f47262 --- /dev/null +++ b/docs/dropdown/examples/complex.md @@ -0,0 +1,129 @@ + + + + diff --git a/docs/dropdown/examples/content.md b/docs/dropdown/examples/content.md new file mode 100644 index 000000000..045517c99 --- /dev/null +++ b/docs/dropdown/examples/content.md @@ -0,0 +1,42 @@ + + + + + + + diff --git a/docs/dropdown/examples/contextmenu.md b/docs/dropdown/examples/contextmenu.md new file mode 100644 index 000000000..64785df85 --- /dev/null +++ b/docs/dropdown/examples/contextmenu.md @@ -0,0 +1,92 @@ +
                          + 在此区域单击鼠标右键 +
                          + + + + + + diff --git a/docs/dropdown/examples/on.md b/docs/dropdown/examples/on.md new file mode 100644 index 000000000..10f0b2625 --- /dev/null +++ b/docs/dropdown/examples/on.md @@ -0,0 +1,38 @@ +
                          + + + +
                          + + + diff --git a/docs/dropdown/examples/reload.md b/docs/dropdown/examples/reload.md new file mode 100644 index 000000000..ca6d8f42f --- /dev/null +++ b/docs/dropdown/examples/reload.md @@ -0,0 +1,40 @@ + + + + diff --git a/docs/dropdown/examples/reloadData.md b/docs/dropdown/examples/reloadData.md new file mode 100644 index 000000000..a307a899c --- /dev/null +++ b/docs/dropdown/examples/reloadData.md @@ -0,0 +1,58 @@ +
                          +
                          + +
                          + +
                          +
                          +
                          + + + diff --git a/docs/dropdown/examples/table.md b/docs/dropdown/examples/table.md new file mode 100644 index 000000000..7dfc6f6d2 --- /dev/null +++ b/docs/dropdown/examples/table.md @@ -0,0 +1,78 @@ +
                          + + + + + + diff --git a/docs/dropdown/index.md b/docs/dropdown/index.md new file mode 100644 index 000000000..db056ba74 --- /dev/null +++ b/docs/dropdown/index.md @@ -0,0 +1,181 @@ +--- +title: 下拉菜单 dropdown +toc: true +--- + +# 下拉菜单 2.6+ + +> 下拉菜单 `dropdown` 是基于基础菜单结构衍生的多功能通用下拉菜单组件,它将原本静态呈现的菜单,通过各种事件的形式触发,从而以独立面板的形式弹出。不仅可用作常见的*下拉菜单*,更可用于*右键菜单*来实现更多的交互可能。 + +

                          示例

                          + +
                          +{{- d.include("/dropdown/detail/demo.md") }} +
                          + +在 `content` 属性中传入任意的 html 内容,可替代默认的下拉菜单结构,从而实现更丰富的弹出内容。 + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var dropdown = layui.dropdown | 获得 `dropdown` 模块。 | +| [dropdown.render(options)](#render) | dropdown 组件渲染,核心方法。 | +| [dropdown.reload(id, options)](#reload) | 完整重载 | +| [dropdown.reloadData(id, options)](#reload) 2.8+ | 仅重载数据或内容 | +| [dropdown.close(id)](#close) | 关闭对应的组件面板 | +| [dropdown.open(id)](#open) 2.9.8+ | 打开对应的组件面板 | + +

                          渲染

                          + +`dropdown.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) +
                          2.8+ : 除 `elem` 属性外,其他基础属性也可以直接写在元素的 `lay-options="{}"` 属性中。 + +``` + + + + + + +``` + +

                          属性

                          + +
                          +{{- d.include("/dropdown/detail/options.md") }} +
                          + +

                          data 格式

                          + +
                          +{{- d.include("/dropdown/detail/options.data.md") }} +
                          + +
                          + +您可以对上述 `data` 中常用的字段进行自定义名称 2.8.14+ : + +
                          + +``` +var dropdown = layui.dropdown; +// 渲染 +dropdown.render({ + elem: '', // 绑定元素选择器 + data: [], // 数据源 + customName: { // 自定义 data 字段名 --- 2.8.14+ + id: 'id', + title: 'title', + children: 'child' + }, + // 其他属性 … +}); +``` + + +

                          重载

                          + +即对一段已经渲染好的下拉菜单重新设置相关属性并渲染,可分为以下几种重载方式: + +| 重载方式 | API | +| --- | --- | +| [完整重载](#dropdown.reload) | [dropdown.reload(id, options, deep)](#dropdown.reload) | +| [仅数据或内容重载](#dropdown.reloadData) 2.8+ | [dropdown.reloadData(id, options, deep)](#dropdown.reloadData) | + + +两者重载的使用方式完全相同,区别只是在于参与重载时的属性差异及其对应的效果差异。一般按照实际需求选择使用。 + + + +`dropdown.reload(id, options);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法用于对下拉菜单进行完整重载,所有属性均可参与到重载中。 + +
                          +  
                          +
                          + + + +`dropdown.reloadData(id, options);` + +- 参数同 `dropdown.reload(id, options)` 参数 + +使用该方法时,与数据无关的属性不会参与到重载中。因此若只是更新数据或内容,该方法可大幅提升体验。 + +
                          +  
                          +
                          + + +

                          关闭面板 2.8+

                          + +`dropdown.close(id);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值 + +该方法用于关闭对应的 `dropdown` 组件面板。 + +``` +var dropdown = layui.dropdown; + +// 渲染 +dropdown.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id + // 其他属性 … +}); +// 关闭对应的组件面板 +dropdown.close('test'); +``` + + +

                          打开面板 2.9.8+

                          + +`dropdown.open(id);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值 + +该方法用于打开对应的 `dropdown` 组件面板。 + +``` +var dropdown = layui.dropdown; + +// 渲染 +dropdown.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id + // 其他属性 … +}); +// 打开对应的组件面板 +dropdown.open('test'); +``` + diff --git a/docs/favicon.ico b/docs/favicon.ico new file mode 100644 index 000000000..5457e78a1 Binary files /dev/null and b/docs/favicon.ico differ diff --git a/docs/fixbar/detail/demo.md b/docs/fixbar/detail/demo.md new file mode 100644 index 000000000..3cf1aaa22 --- /dev/null +++ b/docs/fixbar/detail/demo.md @@ -0,0 +1,70 @@ +
                          +  
                          +
                          + diff --git a/docs/fixbar/detail/options.md b/docs/fixbar/detail/options.md new file mode 100644 index 000000000..7c08fa338 --- /dev/null +++ b/docs/fixbar/detail/options.md @@ -0,0 +1,171 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          bars 2.8+ + +设置固定工具条列表。可支持定义以下子属性: + +``` +bars: [ + { + type: '', // bar 类型名,用于事件区分 + icon: '', // bar 图标的 className + content: '', // bar 任意内容 + style: '' // bar 任意样式 + }, + // … +] +``` + +该属性比较灵活,具体用法可参考:[#示例](#examples) + +array + + + +
                          default 2.8+ + +是否显示默认的固定条 ,如 `top` (点击可让滚动条置顶)等 + +boolean + +`true` + +
                          bgcolor + +固定条的默认背景色 + +string-
                          css + +工具条外层容器的任意 css 属性。如设置工具条的坐标: + +``` +css: {right: 32, bottom: 32} +``` + +object-
                          target 2.8+ + +插入固定条的目标元素选择器 + +object + +`body` + +
                          scroll 2.8+ + +固定条最外层容器滚动条所在的元素,若不设置则默认取 `target` 属性值 + +object + +`body` + +
                          margin 2.8+ + +用于设置默认 `TOP` 条出现滚动条的高度临界值 + +number + +`200` + +
                          duration 2.8+ + +用于默认 `TOP` 条等动画时长 + +number + +`200` + +
                          on 2.8+ + +用于定义固定条列表的任意事件,触发事件时的回调将返回 `bars` 属性的 `type` 值。 + +``` +on: { + // 点击事件 + click: function(type){ + // bars 对属性应的 type 值 + console.log(type); + }, + // … +} +``` + +该属性一般与 `bars` 属性搭配使用,具体用法可参考:[#示例](#examples) + +object-
                          + + +### 贴士 + +> 灵活运用 `bars` 属性的 `content,style` 子属性,可实现更多丰富多样的固定条。 diff --git a/docs/fixbar/index.md b/docs/fixbar/index.md new file mode 100644 index 000000000..5f458c70e --- /dev/null +++ b/docs/fixbar/index.md @@ -0,0 +1,33 @@ +--- +title: 固定条组件 fixbar +toc: true +--- + +# 固定条组件 + +> 固定条组件 `fixbar` 是指当滚动条滑动时,始终固定在页面一侧的工具条元素,除了内置的 `TOP` 条功能外,还可以灵活地扩展任意自定义的工具条。在 `2.x` 版本中,`fixbar` 属于 `util` 模块的子集。 + +

                          示例

                          + +
                          +{{- d.include("/fixbar/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var util = layui.util | 获得 `util` 模块。 | +| [util.fixbar(options)](#fixbar) | fixbar 组件渲染,核心方法。 | + +

                          渲染

                          + +`util.fixbar(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +

                          属性

                          + +
                          +{{- d.include("/fixbar/detail/options.md") }} +
                          diff --git a/docs/flow/detail/demo.md b/docs/flow/detail/demo.md new file mode 100644 index 000000000..d26ab9cf8 --- /dev/null +++ b/docs/flow/detail/demo.md @@ -0,0 +1,65 @@ +

                          滚动加载

                          + +
                          +  
                          +
                          + +

                          手动加载

                          + +
                          +  
                          +
                          diff --git a/docs/flow/detail/options.md b/docs/flow/detail/options.md new file mode 100644 index 000000000..651a632f0 --- /dev/null +++ b/docs/flow/detail/options.md @@ -0,0 +1,155 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string-
                          scrollElem + +指定触发流加载的滚动条所在元素选择器。 + +string + +`document` + +
                          isAuto + +是否自动加载。 若设为 `false`,则会在列表底部生成一个「加载更多」的按钮,那么可点击该按钮加载下一页数据。 + +boolean + +`true` + +
                          moreText 2.9.11+ + +设置「加载更多」按钮的文本 + +string + +加载更多 + +
                          end + +设置加载完毕后的最尾部的内容,可传入任意 HTML 字符。 + +string + +没有更多了 + +
                          isLazyimg + +是否开启信息流中的图片懒加载。若设为 `true` ,则只会对在可视区域的图片进行按需加载。但同时,在拼接列表字符的时候,您不能给列表中的 `` 标签赋值 `src`,必须要用 `lay-src` 属性取代,如: + +``` +data.forEach(function(item){ + lis.push('
                        • '); +}); +``` + +
                          boolean + +`false` + +
                          mb + +与底部的临界距离。 即当滚动条与底部产生该距离时,触发加载。 必须 `isAuto:true` 时有效。 + +*小贴士*: 此处 `mb` 属性名是 css 中 `margin-bottom` 的简写,可并非国粹之语 😅 + +number + +`50` + +
                          direction 2.9.7+ + +指定触发加载的方向,可选值: +- `bottom` 滚动容器底部触发加载 +- `top` 滚动容器顶部触发加载 + +string'bottom'
                          done + +
                          +滚动条到达临界点触发加载的回调函数。函数返回的参数如下: +
                          + +``` +done: function(page, next){ + console.log(page) // 获得当前页 + + // 执行下一页渲染,第二参数为:满足“加载更多”的条件,即后面仍有分页 + // 只有当前页小于总页数的情况下,才会继续出现加载更多 + next('列表 HTML 片段', page < res.pages); +} +``` + +详细用法可参考:[#示例](#examples) + +
                          + diff --git a/docs/flow/index.md b/docs/flow/index.md new file mode 100644 index 000000000..2c8cebd90 --- /dev/null +++ b/docs/flow/index.md @@ -0,0 +1,94 @@ +--- +title: 流加载 flow +toc: true +--- + +# 流加载 + +> 流加载 `flow` 是用于在*信息流*和*图片列表*场景中的滚动按需加载,对前后端的体验和性能优化具有一定帮助。 + +

                          示例

                          + + + +
                          +{{- d.include("/flow/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var flow = layui.flow | 获得 `flow` 模块。 | +| [基础接口](../component/#export) 2.13+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [flow.load(options)](#load) | 信息流加载,核心方法。 | +| [flow.lazyimg(options)](#lazyimg) | 图片懒加载。 | + +

                          信息流

                          + +`flow.load(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +信息流是分页的另一种表现形式,新加载的内容不替换原有的内容,而是随着滚动条滚动而追加显示。[#详见示例](#examples) + +

                          属性

                          + +
                          +{{- d.include("/flow/detail/options.md") }} +
                          + +

                          图片懒加载

                          + +`flow.lazyimg(options);` + +- 参数 `options` : 属性选项。可选项见下表。 + +| 属性名 | 描述 | +| --- | --- | +| elem | 绑定容器中需进行懒加载的图片元素选择器 | +| scrollElem | 滚动条所在元素选择器,默认 `document` 。 | + +
                          +  
                          +
                          + +无论滚动条上滑还是下滑,都会始终加载当前屏的图片。 + + diff --git a/docs/form/checkbox.md b/docs/form/checkbox.md new file mode 100644 index 000000000..c20b3e17c --- /dev/null +++ b/docs/form/checkbox.md @@ -0,0 +1,192 @@ +--- +title: 复选框 +toc: true +--- + +# 复选框 + +> 复选框组件是对 `` 元素的美化替代,在原有的特性基础上,对 UI 进行了加强。 + + +

                          默认风格

                          + +
                          +  
                          +
                          + +- 属性 `title` 可设置复选框标题 +- 属性 `checked` 可设置默认选中 +- 属性 `disabled` 可设置禁用状态 +- 属性 `value` 可设置值,否则选中时返回的默认值为 `on`(浏览器默认机制) +- 属性 `lay-skin` 可设置复选框风格,可选值:`tag`2.8+,`switch`,`none`(无样式)2.9.8+ 默认风格可不填 + +特别地,当表单提交时,只有选中状态的复选框才能获取到 `value`,这点和浏览器原有的复选框机制相同。 + +注 2.8+: `lay-skin` 属性在之前版本默认为标签风格,新版本调整为默认原始风格(`lay-skin="primary"`)。 + +

                          标签风格

                          + +
                          +  
                          +
                          + + +

                          开关风格

                          + +
                          +  
                          +
                          + +在 `title` 属性中通过 `|` 分隔符可设置两种状态下的不同标题 + + +

                          自定义标题模板 2.8.3+

                          + +在 `checkbox` 元素后的相邻元素设置特定属性 `lay-checkbox`,可以与 `checkbox` 标题进行绑定。 + +
                          +  
                          +
                          + +

                          自定义任意风格 2.9.8+

                          + +通过对 `checkbox` 元素设置 `lay-skin="none"` 属性禁用默认样式,从而实现任意风格的多选组件。
                          +**注:** 这意味着你需要掌握一定的 `CSS` 技能,以下示例中的样式均为外部自主实现,并非 Layui 内置。 + +
                          +  
                          +
                          + + +

                          复选框事件

                          + +| 风格 | 事件 | +| --- | --- | +| 默认风格 / 标签风格 | `form.on('checkbox(filter)', callback);` | +| 开关风格 | `form.on('switch(filter)', callback);` | + +- `checkbox` 和 `switch` 为复选框事件固定名称 +- `filter` 为复选框元素对应的 `lay-filter` 属性值 + +该事件在复选框选中或取消选中时触发。 + +
                          +  
                          +
                          + diff --git a/docs/form/examples/checkbox.skin.md b/docs/form/examples/checkbox.skin.md new file mode 100644 index 000000000..9421226aa --- /dev/null +++ b/docs/form/examples/checkbox.skin.md @@ -0,0 +1,92 @@ + + +
                          + {{- d.include("/form/examples/checkboxAndRadio.style.md") }} +

                          自定义“卡片风格”的多选组件

                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Chrome
                          +
                          + 由 Google 公司开发的网页浏览器,被大多数人所使用。 +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Edge
                          +
                          + 由 Microsoft 开发的网页浏览器,基于 Chromeium 内核。 +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Firefox
                          +
                          + 由 Mozilla 开发的开放源代码的网页浏览器。 +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Internet Explorer
                          +
                          + 由 Microsoft 出品的网页浏览器,俗称 IE,已被微软放弃。 +
                          +
                          +
                          +
                          +
                          + +

                          自定义“标签风格”的多选组件

                          +
                          + +
                          + +
                          + +
                          rap
                          + +
                          篮球
                          +
                          + +
                          +

                          更多风格可自主实现,为避免影响文档其他重要版面的阅读,此处不做过多演示。

                          + +
                          + + + + diff --git a/docs/form/examples/checkboxAndRadio.style.md b/docs/form/examples/checkboxAndRadio.style.md new file mode 100644 index 000000000..e7a434af5 --- /dev/null +++ b/docs/form/examples/checkboxAndRadio.style.md @@ -0,0 +1,192 @@ + + + + + + diff --git a/docs/form/examples/form.demo.md b/docs/form/examples/form.demo.md new file mode 100644 index 000000000..c6082ad78 --- /dev/null +++ b/docs/form/examples/form.demo.md @@ -0,0 +1,259 @@ +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          6 到 12 位字符
                          +
                          +
                          +
                          + +
                          + +
                          +
                          -
                          +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          + +
                          + + + +
                          +
                          +
                          + +
                          + + + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + + + +
                          +
                          +
                          + +
                          + <textarea placeholder="请输入内容" class="lay-textarea"></textarea> +
                          +
                          +
                          +
                          + + +
                          +
                          +
                          + + + + diff --git a/docs/form/examples/form.grid.md b/docs/form/examples/form.grid.md new file mode 100644 index 000000000..4bf2695c3 --- /dev/null +++ b/docs/form/examples/form.grid.md @@ -0,0 +1,109 @@ +
                          +
                          + +
                          +
                          +
                          + +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          +
                          + + +
                          +
                          + + + diff --git a/docs/form/examples/form.login.md b/docs/form/examples/form.login.md new file mode 100644 index 000000000..dcf6fd59d --- /dev/null +++ b/docs/form/examples/form.login.md @@ -0,0 +1,80 @@ + +
                          + +
                          + + + diff --git a/docs/form/examples/form.pane.md b/docs/form/examples/form.pane.md new file mode 100644 index 000000000..f18035ede --- /dev/null +++ b/docs/form/examples/form.pane.md @@ -0,0 +1,102 @@ + +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          请务必填写用户名
                          +
                          +
                          +
                          + +
                          + +
                          +
                          -
                          +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + + + +
                          +
                          +
                          + +
                          + <textarea placeholder="请输入内容" class="lay-textarea"></textarea> +
                          +
                          +
                          + + +
                          +
                          + + + diff --git a/docs/form/examples/form.reg.md b/docs/form/examples/form.reg.md new file mode 100644 index 000000000..4613c2c16 --- /dev/null +++ b/docs/form/examples/form.reg.md @@ -0,0 +1,131 @@ + +
                          +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          + +
                          +
                          + + + + + + + 登录已有帐号 +
                          +
                          +
                          + + + diff --git a/docs/form/examples/form.val.md b/docs/form/examples/form.val.md new file mode 100644 index 000000000..a4689aa54 --- /dev/null +++ b/docs/form/examples/form.val.md @@ -0,0 +1,113 @@ +
                          +
                          + + +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + + + +
                          +
                          + +
                          + +
                          + +
                          +
                          + +
                          + +
                          + + +
                          +
                          + +
                          + +
                          + <textarea placeholder="请输入" class="lay-textarea" name="desc"></textarea> +
                          +
                          + +
                          +
                          + + +
                          +
                          +
                          + + + diff --git a/docs/form/examples/form.validate.md b/docs/form/examples/form.validate.md new file mode 100644 index 000000000..30fbba6cd --- /dev/null +++ b/docs/form/examples/form.validate.md @@ -0,0 +1,57 @@ +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          + +
                          +
                          +
                          + + + diff --git a/docs/form/examples/form.verify.md b/docs/form/examples/form.verify.md new file mode 100644 index 000000000..76ce4f0d9 --- /dev/null +++ b/docs/form/examples/form.verify.md @@ -0,0 +1,63 @@ +
                          + +
                          + +
                          + +
                          + +
                          + + + + diff --git a/docs/form/examples/input.affix.custom.md b/docs/form/examples/input.affix.custom.md new file mode 100644 index 000000000..3d2ae2fa9 --- /dev/null +++ b/docs/form/examples/input.affix.custom.md @@ -0,0 +1,40 @@ +
                          +
                          + +
                          +
                          +
                          + +
                          +
                          + + + diff --git a/docs/form/examples/input.group.md b/docs/form/examples/input.group.md new file mode 100644 index 000000000..c2eebee05 --- /dev/null +++ b/docs/form/examples/input.group.md @@ -0,0 +1,84 @@ +
                          +
                          +
                          +
                          + 身高 +
                          + +
                          + cm +
                          +
                          +
                          +
                          +
                          +
                          + 手机号 +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + 用户名 +
                          + +
                          +
                          + +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + 搜索 +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + 身高 +
                          + +
                          + cm +
                          +
                          +
                          +
                          +
                          +
                          + 昵称 +
                          + +
                          +
                          +
                          +
                          + +
                          + 任意后置内容 +
                          +
                          +
                          +
                          + + diff --git a/docs/form/examples/input.pre.suf.md b/docs/form/examples/input.pre.suf.md new file mode 100644 index 000000000..0221bbfff --- /dev/null +++ b/docs/form/examples/input.pre.suf.md @@ -0,0 +1,96 @@ +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + diff --git a/docs/form/examples/radio.skin.md b/docs/form/examples/radio.skin.md new file mode 100644 index 000000000..3a31be7f2 --- /dev/null +++ b/docs/form/examples/radio.skin.md @@ -0,0 +1,104 @@ + + +
                          + {{- d.include("/form/examples/checkboxAndRadio.style.md") }} +

                          自定义“卡片风格”的单选组件

                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Chrome
                          +
                          + 由 Google 公司开发的网页浏览器,被大多数人所使用。 +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Edge
                          +
                          + 由 Microsoft 开发的网页浏览器,基于 Chromeium 内核。 +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Firefox
                          +
                          + 由 Mozilla 开发的开放源代码的网页浏览器。 +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          Internet Explorer
                          +
                          + 由 Microsoft 出品的网页浏览器,俗称 IE,已被微软放弃。 +
                          +
                          +
                          +
                          +
                          + +

                          自定义“标签风格”的单选组件

                          +
                          + +
                          + +
                          + +
                          rap
                          + +
                          篮球
                          +
                          + +

                          自定义“颜色选择”的单选组件

                          +
                          + +
                          + +
                          + +
                          + +
                          +
                          + +
                          +

                          更多风格可自主实现,为避免影响文档其他重要版面的阅读,此处不做过多演示。

                          + +
                          + + + + diff --git a/docs/form/index.md b/docs/form/index.md new file mode 100644 index 000000000..ef12d613b --- /dev/null +++ b/docs/form/index.md @@ -0,0 +1,464 @@ +--- +title: 表单组件 form +toc: true +--- + +# 表单组件 🔥 + +> 表单组件`form`是包含输入框、选择框、复选框、开关、单选框等表单项组件的集合,主要用于对表单域进行各类动态化渲染和相关的交互操作。`form`是 Layui 最常用的组件之一。 + +

                          示例

                          + +

                          综合演示

                          + +
                          +  
                          +
                          + +

                          方框风格

                          + +
                          +  
                          +
                          + +

                          登录模板 2.8+

                          + +
                          +  
                          +
                          + +

                          注册模板 2.8+

                          + +
                          +  
                          +
                          + +更多其他表单模板均可自由布局实现,为了避免影响文档其他重要版面的阅读,我们就不做过多演示了。 + + +

                          表单布局

                          + +### 🌕 普通布局 + +在上文的「[综合演示](#examples)」示例中,我们用的是 form 组件自身的普通布局。其要点为: + +- 通过 `class="lay-form"` 定义一个表单域,通常设置在`
                          `标签上, 或普通`
                          ` 标签亦可。 +- 通过 `class="lay-form-item"` 定义一个块级元素的表单项容器 +- 通过 `class="lay-form-label"` 定义标签 +- 通过 `class="lay-input-block"` 定义表单项父容器为块级元素 +- 通过 `class="lay-input-inline"` 或 `class="lay-inline"` 定义表单项父容器为行内块元素 + +即必须按照规定的层级定义相应的 `class`。 + +### 🌕 栅格布局 + +form 还可以借助*栅格*实现更灵活的响应式布局。 + +
                          +  
                          +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var form = layui.form | 获得 `form` 模块。 | +| [form.render(type, filter)](#render) | 表单域组件渲染,核心方法。[#用法](#render) | +| [form.verify(obj)](#verify) | 自定义表单验证的规则。[#用法](#verify) | +| [form.validate(elem)](#validate) 2.7+ | 主动触发执行验证。[#用法](#validate) | +| [form.val(filter, obj)](#val) | 表单赋值或取值。 [#用法](#val) | +| [form.submit(filter, callback)](#submit) 2.7+ | 用于主动执行指定表单的提交。[#用法](#submit) | +| [form.on(\'event(filter)\', callback)](#on) | 事件。[#用法](#on) | +| [form.set(options)](#set) | 设置 form 组件全局配置项。 | +| form.config | 获取 form 组件全局配置项。 | + +

                          属性

                          + +在表单域中,有时还需要定义一些特定属性来配合组件的使用,它们一般以 `lay-*` 为命名格式,如: + +``` + + + + + + +``` + +以下为 `form` 组件的特定属性列表: + +| 属性 | 值 | 描述 | +| --- | --- | --- | +| title | 自定义 | 设置表单元素标题,一般用于 `checkbox,radio` 元素 | +| lay-filter | 自定义 | 设置表单元素的过滤器,以便用于执行相关方法时的参数匹配 | +| lay-verify | `required`必填项
                          `phone`手机号
                          `email`邮箱
                          `url`网址
                          `number`数字
                          `date`日期
                          `identity`身份证
                          `自定义规则值` | 设置表单项的验证规则,支持单条或多条规则(多条用`\|`分隔),如:
                          `lay-verify="required"`
                          `lay-verify="required\|email"`
                          `lay-verify="其他自定义规则值"`
                          自定义规则的用法:[#详见](#verify)
                          注:2.8.3 版本中调整了内置规则,不再强制必填。
                          如需保留必填,可叠加 `required` 规则,如:
                          `lay-verify="required\|number"` | +| lay-vertype | `tips`吸附层
                          `alert` 对话框
                          `msg` 默认 | 设置验证异常时的提示层模式 | +| lay-reqtext | 自定义 | 设置*必填项*(`lay-verify="required"`)的默认提示文本 | +| lay-affix | [#详见](input.html#affix) | 输入框动态点缀,``元素 **私有属性** | +| lay-skin | [#详见](checkbox.html#default) | 设置 UI 风格。 ``,`` 元素 **私有属性** | +| lay-search |2.9.15+ `lay-search="{caseSensitive:false, fuzzy: false}"`
                          `caseSensitive` 是否区分大小写,默认值为 `false`
                          `fuzzy`是否开启模糊匹配,开启后将会忽略匹配字符出现在字符串中的位置,默认值为 `false`
                          设置`cs`区分大小写(2.9.15+ 已弃用) | 给 `select` 组件开启搜索功能。`` 元素 **私有属性** | +| lay-append-to 2.9.12+ 实验性 | `body` | 是否将 select 面板追加到 body 元素中。`` 元素 **私有属性** | +| lay-submit | 无需值 | 设置元素(一般为` +
                          +``` + +注:上述代码指定的均为内置的验证规则,具体可参考:[#属性介绍](#attr) + +

                          自定义验证规则

                          + +`form.verify(obj);` + +- 参数 `obj` 是一个对象,用于定义验证规则的集合。 + +除了内置的验证规则外,form 还允许自定义验证规则,规则以函数命名,返回的参数如下: + +``` +// 自定义验证规则 +form.verify({ + rule: function(value, elem) { + console.log(value); // 当前进入验证的表单项的值 + console.log(elem); // 当前进入验证的表单项的 DOM 元素 + } +}); +``` + +在自定义规则中,可根据规则函数返回的 value 自行判断是否必填,如: + +``` +form.verify({ + // 必填项 + rule1: function(value, elem) { + // 自定义规则 + if (value.length < 6) { + return '不能小于 6 个字符'; + } + }, + // 非必填项,只有当值填写时才验证自定义规则 + rule2: function(value, elem) { + if (!value) return; // 若值未填写,不进行后续规则验证 + + // 自定义规则 + if (/^[A-Z]/.test(value)) { + return '必须用大写字符开头'; + } + }, + // 自定义提示方式 + rule3: function(value, elem) { + // 自定义规则和自定义提示方式 + if(value === 'xxx'){ + alert('用户名不能为敏感词'); // 此处以系统自带的 alert 提示方式为例 + return true; // 返回 true 即可阻止 form 默认的提示风格 + } + } +}); +``` + +以下是一个自定义验证规则的示例: + +
                          +  
                          +
                          + +更多「自定义验证规则」示例参考: + +> - 将 form 提示语显示在表单项旁边,并在提交时批量触发验证 + + +

                          主动触发验证 2.7+

                          + +`form.validate(elem);` + +- 参数 `elem` 为元素选择器或 jQuery 对象; 若验证通过,该方法将返回 true,否则返回 false + +
                          +  
                          +
                          + + +

                          赋值/取值

                          + +`form.val(filter, obj);` + +- 参数 `filter` 为表单域容器(`class="lay-form"`)的 `lay-filter` 属性值 +- 参数 `obj` 可选。若参数存在,则对表单域进行赋值;若参数不存在,则为对表单域进行取值。 + +
                          +  
                          +
                          + + +

                          提交

                          + +表单的提交可以通过事件触发或方法触发 + +### **提交事件** + +在表单域中,对指定按钮设置 `lay-submit` 属性,即意味着点击该按钮时,将触发提交事件。如: + +
                          +  
                          +
                          + +### **提交方法** 2.7+ + +`form.submit(filter, callback);` + +- 参数 `filter` 为表单域容器的 `lay-filter` 属性值 +- 参数 `callback` 为执行提交事件后的回调函数 + +使用该方法可以实现在任意位置对指定表单的主动提交,相比上述的提交事件更加灵活。 + +
                          +  
                          +
                          + +

                          事件

                          + +`form.on('event(filter)', callback);` + +- 参数 `event(filter)` 是一个特定结构。`event` 为事件名,支持:`select,checkbox,switch,radio,submit`;`filter` 为元素属性 `lay-filter` 对应的值,若不填,则指向所有同类组件的事件。 +- 参数 `callback` 为事件执行时的回调函数,并返回一个包含各种值的 `object` 类型的参数。 + +如下以 `select` 事件为例: +``` +// 指向所有 select 组件的选择事件 +form.on('select', function(data){ + console.log(data); +}); + +// 指向元素为 `` 的选择事件 +form.on('select(test)', function(data){ + console.log(data); +}); +``` + +

                          全局设置

                          + +`form.set(options);` + +- 参数 `options` : 全局属性选项。详见下表: + +| 属性名 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| autocomplete | 设置 input 框的 `autocomplete` 属性初始值 | string | - | + +该方法用于对 form 组件进行全局设置。 + +``` +form.set({ + autocomplete: 'off' // 阻止 input 框默认的自动输入完成功能 +}); +``` + diff --git a/docs/form/input.md b/docs/form/input.md new file mode 100644 index 000000000..fb7ea8256 --- /dev/null +++ b/docs/form/input.md @@ -0,0 +1,248 @@ +--- +title: 输入框 / 文本域 +toc: true +--- + +# 输入框 + +> 输入框组件是对文本框``和多行文本框` + + + +

                          输入框点缀 2.8+

                          + +输入框点缀是指给普通输入框附加其他元素来进行动静态修饰,其结构包含:*容器、前缀、输入框、后缀*。 + +``` +
                          +
                          + +
                          +
                          +``` + +- 容器类: + - 前置和后置结构:`class="lay-input-group"` + - 前缀和后缀结构:`class="lay-input-wrap"` +- 前缀类:`class="lay-input-prefix"` +- 后缀类:`class="lay-input-suffix"` +- 前缀显示分隔框:`class="lay-input-prefix lay-input-split"` +- 后缀显示分隔框:`class="lay-input-suffix lay-input-split"` + +通过在不同层级中设置规定的 CSS 类来实现点缀布局,再按照不同需求,在前缀和后缀中放置图标等任意内容。 + + +

                          前置和后置

                          + +前置和后置结构是*输入框的自适应结构*,可以很灵活地控制前后置内容与输入框的宽度比例。 + +- 结构: + +``` +
                          +
                          前置内容
                          + +
                          后缀内容
                          +
                          +``` + +- 示例: + +
                          +  
                          +
                          + + +

                          前缀和后缀

                          + +输入框前缀和后缀是*输入框的纯修饰结构*,前缀和后缀宽度固定且其元素不可触及,即只能触及输入框本身。 + +- 结构: + +``` +
                          +
                          前缀图标
                          + +
                          后缀图标
                          +
                          +``` + +- 示例: + +
                          +  
                          +
                          + +注意「前置和后置」与「前缀和后缀」 二者使用时切勿混淆。 + + +

                          动态点缀 2.8+

                          + +该功能允许对输入框内容进行相关动态操作。通过对输入框元素设置 `lay-affix` 属性来开启动态点缀。 + +| 点缀 | 属性值 | +| --- | --- | +| [数字输入框](#affix-number) 2.8.9+ | `lay-affix="number"` | +| [密码框显隐](#affix-eye) | `lay-affix="eye"` | +| [内容清除](#affix-clear) | `lay-affix="clear"` | +| [自定义动态点缀](#affix-custom) | `lay-affix="customName"` | + + +

                          + 数字输入框 2.8.9+ +

                          + +一般搭配 `` 使用,用于替代原生数字输入框,支持的属性如下: +注:2.10+ 之前的版本,使用 `type="number"` 类型的输入框。 + +| 属性 | 描述 | +| --- | --- | +| step | 设置数字的加减间隔 | +| min | 设置数字的最小值 | +| max | 设置数字的最大值 | +| lay-precision 2.8.18+ | 设置数字的小数位精度。注2.9.8+:若值为 `0`,则表示取整。 | +| lay-step-strictly 2.10+ | 步长严格模式,只能输入步长的倍数 | +| lay-wheel 2.10+ | 是否启用滚轮或触摸板事件处理 | + +### 示例 + +
                          +  
                          +
                          + + +

                          密码显隐

                          + +一般搭配 `` 使用,用于控制输入框内容的显示和隐藏。 + +
                          +  
                          +
                          + +

                          内容清除

                          + +一般搭配 `` 使用,用于清除输入框的内容。 + +
                          +  
                          +
                          + +

                          自定义动态点缀

                          + +我们还可以对 `lay-affix` 属性设置任意图标值,从而实现自定义动态点缀功能。 其中 `lay-affix="customName"` 值对应图标类`lay-icon-`后面的名称([#详见图标列表](../icon/#list))。且可通过「[点缀事件](#affix-event)」完成自定义操作。 + +
                          +  
                          +
                          + +输入框的自定义动态点缀功能,让原本单一的输入框有了更多的想象空间。 + + +

                          点缀事件

                          + +`form.on('input-affix(filter)', callback);` + +- `input-affix` 为输入框动态点缀事件固定名称 +- `filter` 为输入框对应的 `lay-filter` 属性值 + +该事件在点击输入框的点缀图标时触发,通过该事件可以完成一些自定义操作。 + +``` +form.on('input-affix(filter)', function(data){ + var elem = data.elem; // 获取输入框 DOM 对象 + var affix = data.affix; // 获取输入框 lay-affix 属性值 + console.log(this); // 当前触发点缀事件的图标元素 +}); +``` + + + + + diff --git a/docs/form/radio.md b/docs/form/radio.md new file mode 100644 index 000000000..980052987 --- /dev/null +++ b/docs/form/radio.md @@ -0,0 +1,123 @@ +--- +title: 单选框 +toc: true +--- + +# 单选框 + +> 单选框组件是对 `` 元素的美化替代。 + +

                          普通单选框

                          + +
                          +  
                          +
                          + +- 属性 `title` 可设置单选框标题 +- 属性 `checked` 可设置默认选中 +- 属性 `disabled` 可设置禁用状态 +- 属性 `value` 可设置值,否则选中时返回的默认值为 `on`(浏览器默认机制)。同组单选框一般设置相同值。 +- 属性 `lay-skin` 可设置单选框风格,可选值:`none`(无样式)2.9.8+ 默认风格可不填 + +

                          自定义标题模板

                          + +在 `radio` 元素后的相邻元素设置特定属性 `lay-radio`,可以与 `radio` 标题进行绑定。 + +
                          +  
                          +
                          + +

                          自定义任意风格 2.9.8+

                          + +通过对 `radio` 元素设置 `lay-skin="none"` 属性禁用默认样式,从而实现任意风格的单选组件。
                          +**注:** 这意味着你需要掌握一定的 `CSS` 技能,以下示例中的样式均为外部自主实现,并非 Layui 内置。 + +
                          +  
                          +
                          + +

                          单选框事件

                          + +`form.on('radio(filter)', callback);` + +- `radio` 为单选框事件固定名称 +- `filter` 为单选框元素对应的 `lay-filter` 属性值 + +该事件在单选框被点击或选中时触发。 + +
                          +  
                          +
                          +
                          diff --git a/docs/form/select.md b/docs/form/select.md
                          new file mode 100644
                          index 000000000..0f7c62385
                          --- /dev/null
                          +++ b/docs/form/select.md
                          @@ -0,0 +1,285 @@
                          +---
                          +title: 选择框
                          +toc: true
                          +---
                          + 
                          +# 选择框
                          +
                          +> 选择框组件是对 `
                          +
                          + +- 若第一项 `value` 为空,通常只作为选择框提示性引导;若第一项 `value` 不为空,则作为默认选中项。 +- 通过给选项添加 `selected` 属性优先设置默认选中项。 +- 通过给 `` 标签上同样支持设置表单的其他公共属性([#详见](./#attr))。 + +

                          分组选择框

                          + +通过 `` 标签给选择框分组 + +
                          +  
                          +
                          + + + + +在 `` 元素上设置 `lay-creatable=""` 可允许创建新的 option,需开启 `lay-search` 后生效。 + +
                          +  
                          +
                          + +

                          独立选择框 2.9.12+

                          + +在 ` + + + +

                          选择框事件

                          + +`form.on('select(filter)', callback);` + +- `select` 为选择框事件固定名称 +- `filter` 为选择框元素对应的 `lay-filter` 属性值 + +该事件在选择框选项选中后触发。 + +
                          +  
                          +
                          + diff --git a/docs/i18n/detail/demo.md b/docs/i18n/detail/demo.md new file mode 100644 index 000000000..20fcb498b --- /dev/null +++ b/docs/i18n/detail/demo.md @@ -0,0 +1,785 @@ + + + + + i18n 演示 - Layui + + + + +
                          {{! + !}} + + + + + + + + diff --git a/docs/i18n/detail/options.md b/docs/i18n/detail/options.md new file mode 100644 index 000000000..aa5fb5be5 --- /dev/null +++ b/docs/i18n/detail/options.md @@ -0,0 +1,185 @@ +
                          +  
                          +
                          + diff --git a/docs/i18n/index.md b/docs/i18n/index.md new file mode 100644 index 000000000..f0ff31f6e --- /dev/null +++ b/docs/i18n/index.md @@ -0,0 +1,111 @@ +--- +title: 国际化 i18n +toc: true +--- + +# 国际化 2.12+ + +> `i18n` 是 2.12 版本新增的国际化模块,用于为 Layui 各组件实现多语言支持。 + +

                          完整演示

                          + +为了避免语言包配置冗长而影响示例源代码的查看,此处只演示「简体中文 / English / 繁體中文」语言环境,你可以点击该示例头部的「切换语言」选择框查看 Layui 组件在不同语言环境中的显示效果。 + +
                          + +
                          +  
                          +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var i18n = layui.i18n | 获得 `i18n` 模块。| +| [i18n.set(options)](#set) | 设置语言环境及语言包。| + +

                          配置方式

                          + +i18n 支持两种配置方式,你可以根据实际应用场景选择任一方式。 + +#### 1. 通过 `i18n.set()` 方法配置 + +`i18n.set(options)` + +- 参数 `options` : 基础属性选项。[#详见语言包选项](#options) + +```js +layui.use(function() { + var i18n = layui.i18n; + + // 设置语言 + i18n.set({ + locale: 'zh-CN', // 当前语言环境。zh-CN 为内置简体中文语言包 + messages: { // 扩展其他语言包 + 'en': {}, + 'zh-HK': {}, + } + }); +}); +``` + +🔔 请注意:如果你的页面有用到 Layui 组件的自动渲染(如 table 模板配置渲染方式),因为执行顺序的问题,组件在自动渲染时可能无法读取到 `i18n.set()` 的配置信息,此时建议采用下述 `LAYUI_GLOBAL.i18n` 全局配置。 + +#### 2. 通过 `LAYUI_GLOBAL.i18n` 全局配置(推荐) + +由于 i18n 配置与组件渲染存在执行顺序问题,为了确保 i18n 配置始终在组件渲染之前生效,更推荐采用该全局配置方式。 + +```html + + +``` + +

                          语言包选项

                          + +i18n 默认采用简体中文(`zh-CN`)语言环境,以下为各组件消息文本对应的选项: + +
                          +{{- d.include("/i18n/detail/options.md") }} +
                          + + +基于上述选项,还可以扩展更多语言包,如: + +```js +i18n.set({ + locale: 'en', // 当前语言环境 + messages: { // 扩展更多语言包 + 'en': { // 通用英语 + code: { + copy: 'Copy Code', + copied: 'Copied', + // …… + }, + // …… + }, + 'fr': {}, // 通用法语 + 'zh-HK': {}, // 繁体中文 + // …… // 更多语言 + } +}); +``` + +对消息文本进行翻译时,为了节省时间,你可以使用 AI 直接生成不同语言的消息文本,或者使用第三方提供的 Layui 多语言 AI 翻译工具(如:https://gitee.com/mail_osc/translate/tree/master/extend/lay-i18n-object-translate By @xnx3)。 + +## 💖 心语 + +i18n 模块是在众多开发者的广泛需求背景下完成开发,它通过简练的设计,为 Layui 组件实现了多语言的无缝接入,并且兼容了一些原本自带简单多语言或消息配置的组件,从而使 Layui 2 系列版本全面支持国际化。 + diff --git a/docs/icon/index.md b/docs/icon/index.md new file mode 100644 index 000000000..ae8b69de7 --- /dev/null +++ b/docs/icon/index.md @@ -0,0 +1,1252 @@ +--- +title: 图标 +toc: true +--- + +# 图标 + +> Layui 图标采用字体形式,取材于阿里巴巴矢量图标库 `iconfont`,因此可以把一个 `icon` 看作是一个普通的文本,直接通过 `css` 即可设定其样式。图标支持 `font-class` 或 `unicode` 两种格式。 + +

                          示例

                          + +
                          +  
                          +
                          + +通过对一个内联元素(如 ``标签)添加基础类 `class="lay-icon"` 来定义一个图标,然后对元素加上图标对应的 `font-class`,即可显示出你想要的图标,如上所示。 + + +

                          图标列表(192 个)

                          + +
                          +
                          + +
                          机器人
                          +
                          &#xe7d6;
                          +
                          lay-icon-bot
                          +
                          +
                          + +
                          叶子节点
                          +
                          &#xe701;
                          +
                          lay-icon-leaf
                          +
                          +
                          + +
                          文件夹
                          +
                          &#xeabe;
                          +
                          lay-icon-folder
                          +
                          +
                          + +
                          文件夹打开
                          +
                          &#xeac1;
                          +
                          lay-icon-folder-open
                          +
                          +
                          + +
                          Gitee
                          +
                          &#xe69b;
                          +
                          lay-icon-gitee
                          +
                          +
                          + +
                          Github
                          +
                          &#xe6a7;
                          +
                          lay-icon-github
                          +
                          + +
                          + +
                          太阳/明亮
                          +
                          &#xe748;
                          +
                          lay-icon-light
                          +
                          +
                          + +
                          月亮
                          +
                          &#xe6c2;
                          +
                          lay-icon-moon
                          +
                          +
                          + +
                          错误
                          +
                          &#xe693;
                          +
                          lay-icon-error
                          +
                          +
                          + +
                          成功
                          +
                          &#xe697;
                          +
                          lay-icon-success
                          +
                          +
                          + +
                          问号
                          +
                          &#xe699;
                          +
                          lay-icon-question
                          +
                          +
                          + +
                          锁定
                          +
                          &#xe69a;
                          +
                          lay-icon-lock
                          +
                          + +
                          + +
                          显示
                          +
                          &#xe695;
                          +
                          lay-icon-eye
                          +
                          +
                          + +
                          隐藏
                          +
                          &#xe696;
                          +
                          lay-icon-eye-invisible
                          +
                          +
                          + +
                          清空/删除
                          +
                          &#xe788;
                          +
                          lay-icon-clear
                          +
                          +
                          + +
                          退格
                          +
                          &#xe694;
                          +
                          lay-icon-backspace
                          +
                          +
                          + +
                          禁用
                          +
                          &#xe6cc;
                          +
                          lay-icon-disabled
                          +
                          +
                          + +
                          感叹号/提示
                          +
                          &#xeb2e;
                          +
                          lay-icon-tips-fill
                          +
                          + +
                          + +
                          测试/K线图
                          +
                          &#xe692;
                          +
                          lay-icon-test
                          +
                          +
                          + +
                          音乐/音符
                          +
                          &#xe690;
                          +
                          lay-icon-music
                          +
                          +
                          + +
                          Chrome
                          +
                          &#xe68a;
                          +
                          lay-icon-chrome
                          +
                          +
                          + +
                          Firefox
                          +
                          &#xe686;
                          +
                          lay-icon-firefox
                          +
                          +
                          + +
                          Edge
                          +
                          &#xe68b;
                          +
                          lay-icon-edge
                          +
                          +
                          + +
                          IE
                          +
                          &#xe7bb;
                          +
                          lay-icon-ie
                          +
                          +
                          + +
                          实心
                          +
                          &#xe68f;
                          +
                          lay-icon-heart-fill
                          +
                          +
                          + +
                          空心
                          +
                          &#xe68c;
                          +
                          lay-icon-heart
                          +
                          +
                          + +
                          时间/历史
                          +
                          &#xe68d;
                          +
                          lay-icon-time
                          +
                          +
                          + +
                          @艾特
                          +
                          &#xe687;
                          +
                          lay-icon-at
                          +
                          +
                          + +
                          邮箱
                          +
                          &#xe618;
                          +
                          lay-icon-email
                          +
                          +
                          + +
                          RSS
                          +
                          &#xe808;
                          +
                          lay-icon-rss
                          +
                          +
                          + +
                          声音
                          +
                          &#xe69d;
                          +
                          lay-icon-sound
                          +
                          +
                          + +
                          静音
                          +
                          &#xe685;
                          +
                          lay-icon-mute
                          +
                          +
                          + +
                          录音/麦克风
                          +
                          &#xe6dc;
                          +
                          lay-icon-mike
                          +
                          +
                          + +
                          密钥/钥匙
                          +
                          &#xe683;
                          +
                          lay-icon-key
                          +
                          +
                          + +
                          礼物/活动
                          +
                          &#xe627;
                          +
                          lay-icon-gift
                          +
                          +
                          + +
                          蓝牙
                          +
                          &#xe689;
                          +
                          lay-icon-bluetooth
                          +
                          +
                          + +
                          WiFi
                          +
                          &#xe7e0;
                          +
                          lay-icon-wifi
                          +
                          +
                          + +
                          退出/注销
                          +
                          &#xe682;
                          +
                          lay-icon-logout
                          +
                          +
                          + +
                          Android 安卓
                          +
                          &#xe684;
                          +
                          lay-icon-android
                          +
                          +
                          + +
                          Apple IOS 苹果
                          +
                          &#xe680;
                          +
                          lay-icon-ios
                          +
                          +
                          + +
                          Windows
                          +
                          &#xe67f;
                          +
                          lay-icon-windows
                          +
                          +
                          + +
                          穿梭框
                          +
                          &#xe691;
                          +
                          lay-icon-transfer
                          +
                          +
                          + +
                          客服
                          +
                          &#xe626;
                          +
                          lay-icon-service
                          +
                          +
                          + +
                          +
                          &#xe67e;
                          +
                          lay-icon-subtraction
                          +
                          +
                          + +
                          +
                          &#xe624;
                          +
                          lay-icon-addition
                          +
                          +
                          + +
                          滑块
                          +
                          &#xe714;
                          +
                          lay-icon-slider
                          +
                          +
                          + +
                          打印
                          +
                          &#xe66d;
                          +
                          lay-icon-print
                          +
                          +
                          + +
                          导出
                          +
                          &#xe67d;
                          +
                          lay-icon-export
                          +
                          +
                          + +
                          +
                          &#xe610;
                          +
                          lay-icon-cols
                          +
                          +
                          + +
                          退出全屏
                          +
                          &#xe758;
                          +
                          lay-icon-screen-restore
                          +
                          +
                          + +
                          全屏
                          +
                          &#xe622;
                          +
                          lay-icon-screen-full
                          +
                          + +
                          + +
                          半星
                          +
                          &#xe6c9;
                          +
                          lay-icon-rate-half
                          +
                          +
                          + +
                          星星-空心
                          +
                          &#xe67b;
                          +
                          lay-icon-rate
                          +
                          +
                          + +
                          星星-实心
                          +
                          &#xe67a;
                          +
                          lay-icon-rate-solid
                          +
                          +
                          + +
                          手机
                          +
                          &#xe678;
                          +
                          lay-icon-cellphone
                          +
                          +
                          + +
                          验证码
                          +
                          &#xe679;
                          +
                          lay-icon-vercode
                          +
                          +
                          + +
                          微信
                          +
                          &#xe677;
                          +
                          lay-icon-login-wechat
                          +
                          +
                          + +
                          QQ
                          +
                          &#xe676;
                          +
                          lay-icon-login-qq
                          +
                          + +
                          + +
                          微博
                          +
                          &#xe675;
                          +
                          lay-icon-login-weibo
                          +
                          +
                          + +
                          密码
                          +
                          &#xe673;
                          +
                          lay-icon-password
                          +
                          +
                          + +
                          用户名
                          +
                          &#xe66f;
                          +
                          lay-icon-username
                          +
                          +
                          + +
                          刷新-粗
                          +
                          &#xe9aa;
                          +
                          lay-icon-refresh-3
                          +
                          +
                          + +
                          授权
                          +
                          &#xe672;
                          +
                          lay-icon-auz
                          +
                          +
                          + +
                          左向右伸缩菜单
                          +
                          &#xe66b;
                          +
                          lay-icon-spread-left
                          +
                          +
                          + +
                          右向左伸缩菜单
                          +
                          &#xe668;
                          +
                          lay-icon-shrink-right
                          +
                          + +
                          + +
                          雪花
                          +
                          &#xe6b1;
                          +
                          lay-icon-snowflake
                          +
                          +
                          + +
                          提示说明
                          +
                          &#xe702;
                          +
                          lay-icon-tips
                          +
                          +
                          + +
                          便签
                          +
                          &#xe66e;
                          +
                          lay-icon-note
                          +
                          +
                          + +
                          主页
                          +
                          &#xe68e;
                          +
                          lay-icon-home
                          +
                          +
                          + +
                          高级
                          +
                          &#xe674;
                          +
                          lay-icon-senior
                          +
                          +
                          + +
                          刷新
                          +
                          &#xe669;
                          +
                          lay-icon-refresh
                          +
                          +
                          + +
                          刷新
                          +
                          &#xe666;
                          +
                          lay-icon-refresh-1
                          +
                          + +
                          + +
                          旗帜
                          +
                          &#xe66c;
                          +
                          lay-icon-flag
                          +
                          +
                          + +
                          主题
                          +
                          &#xe66a;
                          +
                          lay-icon-theme
                          +
                          +
                          + +
                          消息-通知
                          +
                          &#xe667;
                          +
                          lay-icon-notice
                          +
                          +
                          + +
                          网站
                          +
                          &#xe7ae;
                          +
                          lay-icon-website
                          +
                          +
                          + +
                          控制台
                          +
                          &#xe665;
                          +
                          lay-icon-console
                          +
                          +
                          + +
                          表情-惊讶
                          +
                          &#xe664;
                          +
                          lay-icon-face-surprised
                          +
                          +
                          + +
                          设置-空心
                          +
                          &#xe716;
                          +
                          lay-icon-set
                          +
                          + +
                          + +
                          模板
                          +
                          &#xe656;
                          +
                          lay-icon-template-1
                          +
                          +
                          + +
                          应用
                          +
                          &#xe653;
                          +
                          lay-icon-app
                          +
                          +
                          + +
                          模板
                          +
                          &#xe663;
                          +
                          lay-icon-template
                          +
                          +
                          + +
                          +
                          &#xe6c6;
                          +
                          lay-icon-praise
                          +
                          +
                          + +
                          +
                          &#xe6c5;
                          +
                          lay-icon-tread
                          +
                          +
                          + +
                          +
                          &#xe662;
                          +
                          lay-icon-male
                          +
                          + +
                          + +
                          +
                          &#xe661;
                          +
                          lay-icon-female
                          +
                          +
                          + +
                          相机-空心
                          +
                          &#xe660;
                          +
                          lay-icon-camera
                          +
                          +
                          + +
                          相机-实心
                          +
                          &#xe65d;
                          +
                          lay-icon-camera-fill
                          +
                          +
                          + +
                          菜单-水平
                          +
                          &#xe65f;
                          +
                          lay-icon-more
                          +
                          +
                          + +
                          菜单-垂直
                          +
                          &#xe671;
                          +
                          lay-icon-more-vertical
                          +
                          +
                          + +
                          金额-人民币
                          +
                          &#xe65e;
                          +
                          lay-icon-rmb
                          +
                          +
                          + +
                          金额-美元
                          +
                          &#xe659;
                          +
                          lay-icon-dollar
                          +
                          +
                          + +
                          钻石-等级
                          +
                          &#xe735;
                          +
                          lay-icon-diamond
                          +
                          + +
                          + +
                          +
                          &#xe756;
                          +
                          lay-icon-fire
                          +
                          +
                          + +
                          返回
                          +
                          &#xe65c;
                          +
                          lay-icon-return
                          +
                          +
                          + +
                          位置-地图
                          +
                          &#xe715;
                          +
                          lay-icon-location
                          +
                          +
                          + +
                          办公-阅读
                          +
                          &#xe705;
                          +
                          lay-icon-read
                          +
                          +
                          + +
                          调查
                          +
                          &#xe6b2;
                          +
                          lay-icon-survey
                          +
                          +
                          + +
                          表情-微笑
                          +
                          &#xe6af;
                          +
                          lay-icon-face-smile
                          +
                          +
                          + +
                          表情-哭泣
                          +
                          &#xe69c;
                          +
                          lay-icon-face-cry
                          +
                          + +
                          + +
                          购物车
                          +
                          &#xe698;
                          +
                          lay-icon-cart-simple
                          +
                          +
                          + +
                          购物车
                          +
                          &#xe657;
                          +
                          lay-icon-cart
                          +
                          +
                          + +
                          下一页
                          +
                          &#xe65b;
                          +
                          lay-icon-next
                          +
                          +
                          + +
                          上一页
                          +
                          &#xe65a;
                          +
                          lay-icon-prev
                          +
                          +
                          + +
                          上传-空心-拖拽
                          +
                          &#xe681;
                          +
                          lay-icon-upload-drag
                          +
                          +
                          + +
                          上传-实心
                          +
                          &#xe67c;
                          +
                          lay-icon-upload
                          +
                          +
                          + +
                          下载-圆圈
                          +
                          &#xe601;
                          +
                          lay-icon-download-circle
                          +
                          + +
                          + +
                          组件
                          +
                          &#xe857;
                          +
                          lay-icon-component
                          +
                          +
                          + +
                          文件-粗
                          +
                          &#xe655;
                          +
                          lay-icon-file-b
                          +
                          +
                          + +
                          用户
                          +
                          &#xe770;
                          +
                          lay-icon-user
                          +
                          +
                          + +
                          发现-实心
                          +
                          &#xe670;
                          +
                          lay-icon-find-fill
                          +
                          +
                          + +
                          loading
                          +
                          &#xe63d;
                          +
                          lay-icon-loading
                          +
                          +
                          + +
                          loading
                          +
                          &#xe63e;
                          +
                          lay-icon-loading-1
                          +
                          +
                          + +
                          添加
                          +
                          &#xe654;
                          +
                          lay-icon-add-1
                          +
                          + +
                          + +
                          播放
                          +
                          &#xe652;
                          +
                          lay-icon-play
                          +
                          +
                          + +
                          暂停
                          +
                          &#xe651;
                          +
                          lay-icon-pause
                          +
                          +
                          + +
                          音频-耳机
                          +
                          &#xe6fc;
                          +
                          lay-icon-headset
                          +
                          +
                          + +
                          视频
                          +
                          &#xe6ed;
                          +
                          lay-icon-video
                          +
                          +
                          + +
                          语音-声音
                          +
                          &#xe688;
                          +
                          lay-icon-voice
                          +
                          +
                          + +
                          消息-通知-喇叭
                          +
                          &#xe645;
                          +
                          lay-icon-speaker
                          +
                          +
                          + +
                          删除线
                          +
                          &#xe64f;
                          +
                          lay-icon-fonts-del
                          +
                          + +
                          + +
                          代码
                          +
                          &#xe64e;
                          +
                          lay-icon-fonts-code
                          +
                          +
                          + +
                          HTML
                          +
                          &#xe64b;
                          +
                          lay-icon-fonts-html
                          +
                          +
                          + +
                          字体加粗
                          +
                          &#xe62b;
                          +
                          lay-icon-fonts-strong
                          +
                          +
                          + +
                          删除链接
                          +
                          &#xe64d;
                          +
                          lay-icon-unlink
                          +
                          +
                          + +
                          图片
                          +
                          &#xe64a;
                          +
                          lay-icon-picture
                          +
                          +
                          + +
                          链接
                          +
                          &#xe64c;
                          +
                          lay-icon-link
                          +
                          +
                          + +
                          表情-笑-粗
                          +
                          &#xe650;
                          +
                          lay-icon-face-smile-b
                          +
                          + +
                          + +
                          左对齐
                          +
                          &#xe649;
                          +
                          lay-icon-align-left
                          +
                          +
                          + +
                          右对齐
                          +
                          &#xe648;
                          +
                          lay-icon-align-right
                          +
                          +
                          + +
                          居中对齐
                          +
                          &#xe647;
                          +
                          lay-icon-align-center
                          +
                          +
                          + +
                          字体-下划线
                          +
                          &#xe646;
                          +
                          lay-icon-fonts-u
                          +
                          +
                          + +
                          字体-斜体
                          +
                          &#xe644;
                          +
                          lay-icon-fonts-i
                          +
                          +
                          + +
                          Tabs 选项卡
                          +
                          &#xe62a;
                          +
                          lay-icon-tabs
                          +
                          +
                          + +
                          单选框-选中
                          +
                          &#xe643;
                          +
                          lay-icon-radio
                          +
                          + +
                          + +
                          单选框-候选
                          +
                          &#xe63f;
                          +
                          lay-icon-circle
                          +
                          +
                          + +
                          编辑
                          +
                          &#xe642;
                          +
                          lay-icon-edit
                          +
                          +
                          + +
                          分享
                          +
                          &#xe641;
                          +
                          lay-icon-share
                          +
                          +
                          + +
                          删除
                          +
                          &#xe640;
                          +
                          lay-icon-delete
                          +
                          +
                          + +
                          表单
                          +
                          &#xe63c;
                          +
                          lay-icon-form
                          +
                          +
                          + +
                          手机-细体
                          +
                          &#xe63b;
                          +
                          lay-icon-cellphone-fine
                          +
                          +
                          + +
                          聊天 对话 沟通
                          +
                          &#xe63a;
                          +
                          lay-icon-dialogue
                          +
                          + +
                          + +
                          文字格式化
                          +
                          &#xe639;
                          +
                          lay-icon-fonts-clear
                          +
                          +
                          + +
                          窗口
                          +
                          &#xe638;
                          +
                          lay-icon-layer
                          +
                          +
                          + +
                          日期
                          +
                          &#xe637;
                          +
                          lay-icon-date
                          +
                          +
                          + +
                          水 下雨
                          +
                          &#xe636;
                          +
                          lay-icon-water
                          +
                          +
                          + +
                          代码-圆圈
                          +
                          &#xe635;
                          +
                          lay-icon-code-circle
                          +
                          +
                          + +
                          轮播组图
                          +
                          &#xe634;
                          +
                          lay-icon-carousel
                          +
                          +
                          + +
                          翻页
                          +
                          &#xe633;
                          +
                          lay-icon-prev-circle
                          +
                          + +
                          + +
                          布局
                          +
                          &#xe632;
                          +
                          lay-icon-layouts
                          +
                          +
                          + +
                          工具
                          +
                          &#xe631;
                          +
                          lay-icon-util
                          +
                          +
                          + +
                          选择模板
                          +
                          &#xe630;
                          +
                          lay-icon-templeate-1
                          +
                          +
                          + +
                          上传-圆圈
                          +
                          &#xe62f;
                          +
                          lay-icon-upload-circle
                          +
                          +
                          + +
                          +
                          &#xe62e;
                          +
                          lay-icon-tree
                          +
                          +
                          + +
                          表格
                          +
                          &#xe62d;
                          +
                          lay-icon-table
                          +
                          +
                          + +
                          图表
                          +
                          &#xe62c;
                          +
                          lay-icon-chart
                          +
                          + +
                          + +
                          图标 报表 屏幕
                          +
                          &#xe629;
                          +
                          lay-icon-chart-screen
                          +
                          +
                          + +
                          引擎
                          +
                          &#xe628;
                          +
                          lay-icon-engine
                          +
                          +
                          + +
                          下三角
                          +
                          &#xe625;
                          +
                          lay-icon-triangle-d
                          +
                          +
                          + +
                          右三角
                          +
                          &#xe623;
                          +
                          lay-icon-triangle-r
                          +
                          +
                          + +
                          文件
                          +
                          &#xe621;
                          +
                          lay-icon-file
                          +
                          +
                          + +
                          设置-小型
                          +
                          &#xe620;
                          +
                          lay-icon-set-sm
                          +
                          +
                          + +
                          减少-圆圈
                          +
                          &#xe616;
                          +
                          lay-icon-reduce-circle
                          +
                          +
                          + +
                          添加-圆圈
                          +
                          &#xe61f;
                          +
                          lay-icon-add-circle
                          +
                          + + +
                          + +
                          404
                          +
                          &#xe61c;
                          +
                          lay-icon-404
                          +
                          +
                          + +
                          关于
                          +
                          &#xe60b;
                          +
                          lay-icon-about
                          +
                          +
                          + +
                          箭头 向上
                          +
                          &#xe619;
                          +
                          lay-icon-up
                          +
                          +
                          + +
                          箭头 向下
                          +
                          &#xe61a;
                          +
                          lay-icon-down
                          +
                          +
                          + +
                          箭头 向左
                          +
                          &#xe603;
                          +
                          lay-icon-left
                          +
                          +
                          + +
                          箭头 向右
                          +
                          &#xe602;
                          +
                          lay-icon-right
                          +
                          +
                          + +
                          圆点
                          +
                          &#xe617;
                          +
                          lay-icon-circle-dot
                          +
                          + +
                          + +
                          搜索
                          +
                          &#xe615;
                          +
                          lay-icon-search
                          +
                          +
                          + +
                          设置-实心
                          +
                          &#xe614;
                          +
                          lay-icon-set-fill
                          +
                          +
                          + +
                          群组
                          +
                          &#xe613;
                          +
                          lay-icon-group
                          +
                          +
                          + +
                          好友
                          +
                          &#xe612;
                          +
                          lay-icon-friends
                          +
                          +
                          + +
                          回复 评论 实心
                          +
                          &#xe611;
                          +
                          lay-icon-reply-fill
                          +
                          +
                          + +
                          菜单 隐身 实心
                          +
                          &#xe60f;
                          +
                          lay-icon-menu-fill
                          +
                          +
                          + +
                          记录
                          +
                          &#xe60e;
                          +
                          lay-icon-log
                          +
                          + +
                          + +
                          图片-细体
                          +
                          &#xe60d;
                          +
                          lay-icon-picture-fine
                          +
                          +
                          + +
                          表情-笑-细体
                          +
                          &#xe60c;
                          +
                          lay-icon-face-smile-fine
                          +
                          +
                          + +
                          列表
                          +
                          &#xe60a;
                          +
                          lay-icon-list
                          +
                          +
                          + +
                          发布 纸飞机
                          +
                          &#xe609;
                          +
                          lay-icon-release
                          +
                          +
                          + +
                          对 OK
                          +
                          &#xe605;
                          +
                          lay-icon-ok
                          +
                          +
                          + +
                          帮助
                          +
                          &#xe607;
                          +
                          lay-icon-help
                          +
                          +
                          + +
                          客服
                          +
                          &#xe606;
                          +
                          lay-icon-chat
                          +
                          + +
                          + +
                          top 置顶
                          +
                          &#xe604;
                          +
                          lay-icon-top
                          +
                          +
                          + +
                          收藏-空心
                          +
                          &#xe600;
                          +
                          lay-icon-star
                          +
                          +
                          + +
                          收藏-实心
                          +
                          &#xe658;
                          +
                          lay-icon-star-fill
                          +
                          +
                          + +
                          关闭-实心
                          +
                          &#x1007;
                          +
                          lay-icon-close-fill
                          +
                          +
                          + +
                          关闭-空心
                          +
                          &#x1006;
                          +
                          lay-icon-close
                          +
                          +
                          + +
                          正确
                          +
                          &#x1005;
                          +
                          lay-icon-ok-circle
                          +
                          +
                          + +
                          添加-圆圈-细体
                          +
                          &#xe608;
                          +
                          lay-icon-add-circle-fine
                          +
                          +
                          + + +

                          跨域处理

                          + +由于浏览器存在同源策略,若 Layui 文件地址与你当前的页面地址*不在同一个域下*,即会出现图标跨域问题。因此,要么将 Layui 文件与网站放在同一服务器,要么对 Layui 文件所在的静态资源服务器的 `Response Headers` 添加:`Access-Control-Allow-Origin: *` 或对跨资源共享指定域名,即可解决图标跨域问题。 + + + +
                          +  
                          +
                          + diff --git a/docs/index.md b/docs/index.md new file mode 100644 index 000000000..4372fdc0b --- /dev/null +++ b/docs/index.md @@ -0,0 +1,122 @@ +--- +title: 开始使用 +toc: true +--- + +

                          开始使用

                          + +> Layui 是一套免费的开源 Web UI 组件库,采用自身轻量级模块化规范,遵循原生态的 HTML/CSS/JavaScript 开发模式,极易上手,拿来即用。其风格简约轻盈,而内在雅致丰盈,甚至包括文档在内的每一处细节都经过精心雕琢,非常适合网页界面的快速构建。Layui 区别于一众主流的前端框架,却并非逆道而行,而是信奉返璞归真之道。确切地说,它更多是面向于追求简单的务实主义者,即无需涉足各类构建工具,只需面向浏览器本身,便可将页面所需呈现的元素与交互信手拈来。 + +

                          + Layui +

                          + + + + + + + + + + + + +
                          谐音:类 UI用途:用于更简单快速地构建网页界面
                          环境:详见不同版本的浏览器兼容说明 N特性:原生态开发 / 轻量级模块化 / 外简内丰 / 开箱即用
                          + +

                          下载引用

                          + +您可以通过以下任意一种方式获得 Layui : + +### 🌕 官网下载 + +您可以在 [官网首页](/) 或 [更新日志](./versions.html) 页面下载到 Layui,它经过了自动化构建,更适合用于生产环境。目录结构如下: + +``` +layui/ + ├─css + │ └─layui.css # 核心样式库 + └─layui.js # 核心模块库 +``` + +### 🌕 Git 下载 + +> 您也可以通过 [GitHub](https://github.com/layui/layui/releases) 或 [Gitee](https://gitee.com/layui/layui/releases) 的 releases 列表下载,或直接下载整个仓库。 + +

                          + + +

                          +
                          + GitHub + Gitee +
                          + +### 🌕 npm 下载 + +``` +npm i layui +``` + +### 🌕 第三方 CDN 方式引入: + +> 以下均为知名第三方免费开放的公共资源 CDN,每期版本通过 NPM / GitHub 自动同步。 + + + + +``` + + +``` +``` + + +``` + +

                          快速上手

                          + +现在,让我们以一个最简单的示例开始入门: + +
                          +  
                          +
                          + +点击上方 `Preview` 标签可进行效果预览。 + +

                          其他帮助

                          + +- 在线测试 +- 深色主题 (社区贡献) + + +## 初识寄语 + +> 愿 Layui 从此成为您得心应手的 Web 界面解决方案,化作您方寸屏幕前的亿万字节! + diff --git a/docs/laydate/detail/demo.md b/docs/laydate/detail/demo.md new file mode 100644 index 000000000..2ccca60f8 --- /dev/null +++ b/docs/laydate/detail/demo.md @@ -0,0 +1,105 @@ +

                          常规用法

                          + +
                          +  
                          +
                          + +

                          多类型选择器

                          + +默认为日期选择器,即上文「常规用法」示例中的效果。以下主要呈现其他类型选择器: + +
                          +  
                          +
                          + +

                          范围选择

                          + +
                          +  
                          +
                          + +

                          配置快捷选项 2.8+

                          + +
                          +  
                          +
                          + + +

                          自定义格式

                          + +
                          +  
                          +
                          + + +

                          节日及标注

                          + +
                          +  
                          +
                          + + +

                          限制可选日期

                          + +
                          +  
                          +
                          + + +

                          批量绑定元素

                          + +
                          +  
                          +
                          + + +

                          更多功能示例

                          + +
                          +  
                          +
                          + +

                          自定义主题

                          + +
                          +  
                          +
                          + +

                          静态显示

                          + +
                          +  
                          +
                          + +

                          扩展农历 🔥

                          + +
                          +  
                          +
                          + diff --git a/docs/laydate/detail/options.md b/docs/laydate/detail/options.md new file mode 100644 index 000000000..69e6616e7 --- /dev/null +++ b/docs/laydate/detail/options.md @@ -0,0 +1,860 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          + +[type](#options.type) + + + +
                          + 组件面板选择类型。支持以下可选值: +
                          + +- `year` 年选择器,只提供年列表选择 +- `month` 年月选择器,只提供年、月选择 +- `date` 日期选择器(默认),可选择:年、月、日选择 +- `time` 时间选择器,只提供时、分、秒选择 +- `datetime` 日期时间选择器,可选择:年月日、时分秒 + +效果详见: [#示例](#demo-type) + +
                          string + +`date` + +
                          id + +设定实例唯一索引,以便用于其他方法对例进行相关操作。若该属性未设置,则默认从 `elem` 属性绑定的元素中的 `id` 属性值中获取。 + +string-
                          + +[range](#options.range) + + + +
                          + +开启左右面板的范围选择,将会根据 `type` 类型呈现对应的范围选择面板。该属性值支持以下类型: + +
                          + +- 若为 `boolean` 类型,即表示是否开启范围选择,若设为 `true`,则开始日期与结束日期默认采用 `-` 连接符 +- 若为 `string` 类型,则表示开启范围选择,且自定义开始日期与结束日期的连接符。如: `range: '~'` +- 若为 `array` 类型,即表示开启范围选,且开始日期和结束日期分别赋值在两个目标选择器中,如: + +``` +range: ['#start', '#end'] +``` + +详细用法可参考: [#示例](#demo-range) + + +
                          boolean
                          string
                          array
                          + +`false` + +
                          rangeLinked 2.8+ + +是否开启日期范围选择时的区间联动标注模式,该模式必须开启 `range` 属性才能生效。日期范围默认采用的是*左右面板独立选择模式*,设置该属性后,将采用*左右面板联动选择模式*。 +
                          效果详见: [#示例](#demo-range) + +
                          boolean + +`false` + +
                          fullPanel 2.8+ + +是否开启全面板,即日期和时间显示在同一面板。 当 `type: 'datetime'` 且未设置 `range` 属性时生效。 +
                          效果详见: [#示例](#demo-type) + +
                          boolean + +`false` + +
                          + +[format](#options.format) + + + +
                          + +自定义日期和时间值的返回格式,默认值: `yyyy-MM-dd`。 其格式符规则如下: + +
                          + + +| 格式符 | 描述 | +| --- | --- | +| yyyy | 年份,输出四个字符。若不足四位,则前置补零 | +| y | 年份,允许一位 | +| MM | 月份,输出两个字符。若不足两位,则前置补零 | +| M | 月份,允许一位 | +| dd | 日期,输出两个字符。若不足两位,则前置补零 | +| d | 日期,允许一位 | +| HH | 小时,输出两个字符。若不足两位,则前面补零 | +| H | 小时,允许一位 | +| mm | 分钟,输出两个字符。若不足两位,则前面补零 | +| m | 分钟,允许一位 | +| ss | 秒数,输出两个字符。若不足两位,则前面补零 | +| s | 秒数,允许一位 | + +通过上述格式符组成日期时间字符串,如下所示: + +``` +// 返回值示例: 2008-08-08 20:08:08 +format: 'yyyy-MM-dd HH:mm:ss' + +// 返回值示例: 北京时间 6 点 30 分 +format: '北京时间 H 点 m 分' +``` + +相关用法可参考: [#示例](#demo-format) + +
                          formatToDisplay 2.9.9+ + +仅用于格式化日期显示的格式,不影响日期值 + +``` +formatToDisplay: function (value) { + // value - 日期字符串 + var date = new Date(value); + var displayValue = [ + value, + date.toLocaleDateString(Intl.LocalesArgument, { weekday: 'long' }) + ].join(' '); + return displayValue; +}; + +``` + +function-
                          + +[value](#options.value) + + + +
                          +初始值。值支持以下类型: +
                          + +- 若为 `string` 类型,则必须和 `format` 属性格式对应 + +``` +value: '2018-08-18' +``` + +- 若为 `date` 对象类型,则可直接赋值 `new Date()` + +``` +value: new Date(1534766888000) // 参数即为:2018-08-20 20:08:08 的毫秒数 +``` + +- 当开启 `range` 时,初始设置日期范围值 + +``` + // 开始日期 - 结束日期 +value: '1900-01-01 - 2100-01-01' +``` + +
                          string
                          date
                          + +`new Date()` + +
                          isInitValue + +是否将初始值填充在目标元素中,一般配合 `value` 属性使用 + +boolean + +`true` + +
                          + +[shortcuts](#options.shortcuts) 2.8+ + + + +
                          +用于开启面板左侧的快捷选择栏。其值配置规则如下: +
                          + +``` +shortcuts: [ + { + text: "快捷选项文本", + value: '快捷选项值' + }, + // 更多选项 … +] +``` + +其中 `value` 支持以下类型: + +- 若为 `string` 类型,必须和 `format` 设置的格式对应; +- 若为 `date` 对象类型,则可通过操作 `new Date()` 来对选项值进行相应的返回计算; +- 若为 `array` 类型,则数组成员可填写开始日期和结束日期。 +- 若为 `function` 类型,返回值同上。2.8.16+ + +详细用法可参考: [#示例](#demo-shortcut) + +
                          string
                          date
                          array
                          function
                          -
                          weekStart 2.7+ + +设置起始周。 支持 0-6 的数字,`0` 即代表从周日开始。 + +``` +weekStart: 1 // 设置周一为起始周 +``` + +number + +`0` + +
                          isPreview + +用于是否在面板左下角显示当前结果的预览。当 `type:datetime` 时强制为 `false`。 + +boolean + +`true` + +
                          + +[min / max](#options.minmax) + + + +
                          + +限制可供选择的最小或最大日期时间值。默认值: + +- `min: '1900-1-1'` +- `max: '2099-12-31'` + +
                          + +属性值支持以下可选类型: + +- 若值为字符类型,则:年月日必须用 `-` 连接,且时分秒必须用 `:` 连接。 此处无需遵循 `format` 设定的格式; +- 若值为整数类型,且数字 < 86400000,则数字代表天数,如: `min: -7` 即代表最小日期在 7 天前,正数代表若干天后; +- 若值为整数类型,且数字 ≥ 86400000,则数字代表毫秒数,如:`max: 4073558400000` 即代表最大日期在公元 3000年1月1日。 + +示例: + +``` +min: '2017-1-1 00:00:00' // 最小日期时间值 +min: -7 // 最小日期为 7 天前 +max: 7 // 最大日期为 7 天后 +``` + +相关效果可参考: [#示例](#demo-limit) + +
                          disabledDate 2.9.8+ + +用于设置不可选取的日期。示例: + +```js +disabledDate: function(date, type){ + // date - 当前的日期对象 + // type - 面板类型,'start'/'end' + + // 返回值为 true 的日期会被禁用 + return date.getTime() < new Date(2024, 1).getTime(); // 2024-02-01 +} + +``` + +function -
                          disabledTime 2.9.8+ + +用于设置不可选取的时间。示例: + +```js +disabledTime: function(date, type){ + // date - 当前的日期对象 + // type - 面板类型,'start'/'end' + + // 数组中指定的时间会被禁用 + return { + hours: function(){ + return range(0, 10); + }, + minutes:function(hour){ + return hour > 5 ? range(0, 20) : []; + }, + seconds:function(hour, minute){ + return range(0, 2); + } + }; +} + +function range(start, end) { + var result = []; + for (var i = start; i < end; i++) { + result.push(i); + } + return result; +} + +``` + +function -
                          trigger + +自定义弹出组件面板的事件 + +string + +`click` + +
                          show + +是否在渲染时默认显示组件面板。组件在执行渲染时,默认需通过触发目标元素的事件,方可显示组件面板,而该属性可跳过目标元素的事件,直接显示组件面板。 + +boolean + +`false` + +
                          position + +设置组件面板的定位方式。支持以下可选值: + +- `absolute` 绝对定位,始终吸附在绑定元素周围。 +- `fixed` 固定定位,初始吸附在绑定元素周围,不随浏览器滚动条所左右。一般用于在固定定位的弹层中使用。 +- `static` 静态定位,控件将直接嵌套显示在指定容器中。用法详见:[#示例](#demo-static) + +string + +`absolute` + +
                          zIndex + +设置组件面板的层叠顺序。一般用于解决与其它元素的互相被遮掩的问题。若 `position: 'static'` 时,则该属性无效。 + +number + +`99999999` + +
                          + +[shade](#options.shade) 2.8+ + +
                          +用于开启弹出日期面板时的遮罩。值支持以下可选类型: +
                          + +- 若为 `number` 类型,则表示遮罩透明度。如: + +``` +shade: 0.5 +``` + +- 若为 `array` 类型,则可设置遮罩颜色和透明度,如: + +``` +shade: [0.5, '#000'] // 遮罩的透明度和背景色 +``` + +效果详见: [#示例](#demo-more) + +
                          number
                          array
                          -
                          showBottom + +是否显示组件面板的底部栏 + +boolean + +`true` + +
                          btns + +自定义排版组件面板底部栏中的按钮,按钮将按照数组顺序排列。内置按钮名称:`clear,now,confirm` 。 + +``` + // 显示清空、确认按钮 +btns: ['clear', 'confirm'] +``` + +array-
                          autoConfirm 2.8+ + +是否在选中目标值时即自动确认。 +
                          当开启 `range` 属性时,该属性无效。 + +
                          boolean + +`true` + +
                          lang + +设置组件的语言版本。可选值如下: + +- `cn` 中文版 +- `en` 英文版 + +string + +`cn` + +
                          + +[theme](#options.theme) + + + +
                          + +设置组件面板主题。除了默认主题,还内置主题: `molv` `grid` `circle`2.8+ ,且支持直接传入自定义的主题色。 + +
                          + +``` +theme: '#FF5722' +``` + +注 2.8+ : 多个主题可用数组格式,如: + +``` +theme: ['grid', '#FF5722'] +``` + +若第 1 个成员为 hex 格式的主色值,则第 2 个成员为辅色值 + +``` +// 主色、辅色 --- 2.8.4 新增 +theme: ['#16baaa', '#16b777'] +``` + +效果及用法详见: [#示例](#demo-theme) + +
                          string
                          array
                          -
                          calendar + +是否显示我国常见的公历节日。当 `lang: 'en'` 时无效。 + +boolean + +`true` + +
                          + +[mark](#options.mark) + + + +
                          + +自定义日期标记。该属性是对 `calendar` 属性的进一步延伸,灵活度更高。属性可批量设置多个日期标记,如: + +
                          + +- object 类型 + +``` +mark: { + '0-10-14': '生日', //每年每月的某一天 + '0-0-10': '工资', // 每月 10 号 + '2008-8-8': '开幕', // 指定的日期 +} +``` + +前缀 `0-` 即代表每年,`0-0-` 即代表每年每月。 + +- function 类型 2.9.9+ + +``` +mark: function (ymd, render) { + var y = ymd.year; + var m = ymd.month; + var d = ymd.date; + + // 字符串 + if (m === 6 && d === 1) return render('儿童节'); + + // 对象 + render ({ + '0-10-14': '生日', + '0-0-15': '中旬', + '2024-03-20': 'v2', + '2024-03-31': '月底', + }); +} +``` + +效果详见: [#示例](#demo-mark) + + +
                          object-
                          + +[holidays](#options.holidays) 2.7+ + + + +
                          +用于标注节假日及补班日。 +
                          + +- 若为 array 类型,值是一个二维数组,如: + +``` +holidays: [ + // 2023 年的节假日 + ['2023-1-1','2023-1-2','2023-1-3'], + // 2023 年的补班日 + ['2023-1-28','2023-1-29'] +] +``` + +- 若为 function 类型 2.9.9+ + +``` +holidays: function (ymd, render) { + var y = ymd.year; + var m = ymd.month; + var d = ymd.date; + + // 字符串 + if (y === 2023 && m === 6) { + render('holidays'); // 'holidays'/'workdays' + // 数组 + } else if (y === 2024) { + render([ + ['2024-03-01', '2024-03-02', '2024-03-03'], + ['2024-03-6', '2024-03-25'], + ]); + } +} +``` + +相关日期值可详细参考国家每年公布的法定节假日安排 + +效果详见: [#示例](#demo-mark) + +
                          array-
                          cellRender 2.9.9+ + +自定义单元格内容。 + +``` +cellRender: function(ymd, render, info){ + var y = ymd.year; + var m = ymd.month; + var d = ymd.date; + + // 面板类型 'year' | 'month' | 'date' + if(info.type === 'date'){ + render(d); // 参数为 string, HTMLElement, JQuery 类型 + } +} +``` + +function -
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          + +[ready](#options.ready) + + + +
                          +组件面板初始打开的回调函数。返回的参数如下: +
                          + +``` +ready: function(date){ + /* 得到初始的日期时间对象,date 参数格式如下: + { + year: 2017, // 年 + month: 8, // 月 + date: 18, // 日 + hours: 0, // 时 + minutes: 0, // 分 + seconds: 0 // 秒 + } + */ + console.log(date); +} +``` + +
                          + +[change](#options.change) + + + +
                          +日期时间被切换后的回调函数。返回的参数如下: +
                          + +``` +change: function(value, date, endDate){ + console.log(value); // 日期字符,如: 2017-08-18 + console.log(date); // 包含年月日时分秒各项值的对象 + console.log(endDate); // 结束日期时间对象,当设置 range 时才会返回。对象成员同上。 +} +``` + +
                          + +[done](#options.done) + + + +
                          +日期时间选择完毕的回调函数,点击清空、现在、确定也均会触发。返回的参数如下: +
                          + +``` +done: function(value, date, endDate){ + console.log(value); // 日期字符,如: 2017-08-18 + console.log(date); // 包含年月日时分秒各项值的对象 + console.log(endDate); // 结束日期时间对象,当设置 range 时才会返回。对象成员同上。 +} +``` + +
                          onConfirm 2.8+ + +点击底部栏「确定」按钮时的回调函数。返回的参数同 `done`。 + +
                          onNow 2.8+ + +点击底部栏「现在」按钮时的回调函数。返回的参数同 `done`。 + +
                          onClear 2.8+ + +点击底部栏「清空」按钮时的回调函数。返回的参数同 `done`。 + +
                          close 2.7+ + +组件面板被关闭(移除)后的回调函数。无返回参数。 + +
                          + diff --git a/docs/laydate/examples/cell.md b/docs/laydate/examples/cell.md new file mode 100644 index 000000000..4c1bb6190 --- /dev/null +++ b/docs/laydate/examples/cell.md @@ -0,0 +1,188 @@ + + + + + + + Document + + + + +
                          + + + + + + diff --git a/docs/laydate/examples/elem.md b/docs/laydate/examples/elem.md new file mode 100644 index 000000000..46be4b909 --- /dev/null +++ b/docs/laydate/examples/elem.md @@ -0,0 +1,25 @@ +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/format.md b/docs/laydate/examples/format.md new file mode 100644 index 000000000..2c4351cd9 --- /dev/null +++ b/docs/laydate/examples/format.md @@ -0,0 +1,78 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/limit.md b/docs/laydate/examples/limit.md new file mode 100644 index 000000000..c5dde7c93 --- /dev/null +++ b/docs/laydate/examples/limit.md @@ -0,0 +1,106 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          + 这里以控制在 9:30-17:30 为例 +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/mark.md b/docs/laydate/examples/mark.md new file mode 100644 index 000000000..7d4514bf3 --- /dev/null +++ b/docs/laydate/examples/mark.md @@ -0,0 +1,66 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/more.md b/docs/laydate/examples/more.md new file mode 100644 index 000000000..0f8ed575a --- /dev/null +++ b/docs/laydate/examples/more.md @@ -0,0 +1,201 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          + 2.8+ +
                          +
                          +
                          +
                          +
                          + 覆盖实例与解除实例 2.8+ : +
                          +
                          +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          +
                          +
                          + + + + diff --git a/docs/laydate/examples/normal.md b/docs/laydate/examples/normal.md new file mode 100644 index 000000000..f334b92fc --- /dev/null +++ b/docs/laydate/examples/normal.md @@ -0,0 +1,33 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/range.md b/docs/laydate/examples/range.md new file mode 100644 index 000000000..b1e8b2d7f --- /dev/null +++ b/docs/laydate/examples/range.md @@ -0,0 +1,111 @@ +
                          +
                          + 左右面板独立选择模式(默认) : +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          -
                          +
                          + +
                          +
                          +
                          +
                          +
                          + 左右面板联动选择模式 2.8+ : +
                          +
                          +
                          + +
                          +
                          + +
                          +
                          -
                          +
                          + +
                          +
                          +
                          +
                          +
                          其他类型的范围选择 :
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/shortcut.md b/docs/laydate/examples/shortcut.md new file mode 100644 index 000000000..53c09b17f --- /dev/null +++ b/docs/laydate/examples/shortcut.md @@ -0,0 +1,559 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + + + + diff --git a/docs/laydate/examples/static.md b/docs/laydate/examples/static.md new file mode 100644 index 000000000..371c0f660 --- /dev/null +++ b/docs/laydate/examples/static.md @@ -0,0 +1,34 @@ +
                          +
                          +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/theme.md b/docs/laydate/examples/theme.md new file mode 100644 index 000000000..750c28eb8 --- /dev/null +++ b/docs/laydate/examples/theme.md @@ -0,0 +1,73 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          + +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/examples/type.md b/docs/laydate/examples/type.md new file mode 100644 index 000000000..1a33aee35 --- /dev/null +++ b/docs/laydate/examples/type.md @@ -0,0 +1,78 @@ +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          +
                          + 同时显示日期和时间选择器(全面板) 2.8+ : +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + + + diff --git a/docs/laydate/index.md b/docs/laydate/index.md new file mode 100644 index 000000000..a7b24f1d5 --- /dev/null +++ b/docs/laydate/index.md @@ -0,0 +1,186 @@ +--- +title: 日期与时间选择器 laydate +toc: true +--- + +# 日期与时间选择器 + +> 日期与时间选择器 `laydate` 提供了年、月、日、时、分、秒的多类型选择面板,也是 Layui 的常用组件之一。 + +

                          示例

                          + + + +
                          +{{- d.include("/laydate/detail/demo.md") }} +
                          + +

                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var laydate = layui.laydate | 获得 `laydate` 模块。 | +| [laydate.render(options)](#render) | laydate 组件渲染,核心方法。 | +| [laydate.hint(id, opts)](#hint) 2.8+ | 在对应的 laydate 组件面板上弹出提示层。 | +| [laydate.getInst(id)](#getInst) 2.8+ | 获取组件对应的渲染实例。 | +| [laydate.unbind(id)](#unbind) 2.8+ | 对目标元素解除当前实例的绑定。 | +| [laydate.close(id)](#close) 2.7+ | 关闭日期面板。 | +| [laydate.getEndDate(month, year)](#getEndDate) | 获取某月的最后一天。 | + +

                          渲染

                          + +`laydate.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) +
                          2.8+ : 除 `elem` 属性外,其他基础属性也可以直接写在元素的 `lay-options="{}"` 属性中。 + +``` + + + + + + +``` + +

                          属性

                          + +
                          +{{- d.include("/laydate/detail/options.md") }} +
                          + +

                          弹出提示 2.8+

                          + +`laydate.hint(id, opts);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值 +- 参数 `opts` : 该方法支持的属性选项,详见下表 + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| content | 提示内容 | string | - | +| ms | 提示层自动消失所需的毫秒数 | number | 3000 | + +该方法用于在指定的日期面板弹出一个提示层。 + +``` +var laydate = layui.laydate; +// 渲染 +laydate.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id + // 其他属性 … +}); +// 弹出提示 +laydate.hint('test', { + content: '提示内容' +}); +``` + +

                          获取实例 2.8+

                          + +`laydate.getInst(id);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值 + +该方法用于获取 laydate 对应 id 的渲染实例,以获得该实例对应的成员属性。 + +``` +var laydate = layui.laydate; +// 渲染 +laydate.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id + // 其他属性 … +}); +// 获取对应的实例 +var inst = laydate.getInst('test'); +console.log(inst); // 实例对象 +``` + + +

                          解除实例绑定 2.8+

                          + +`laydate.unbind(id);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值 + +该方法用于对目标元素对应的实例的绑定完全解除,即触发元素事件时,不再执行组件渲染。 + +``` +var laydate = layui.laydate; +// 渲染 +laydate.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id + // 其他属性 … +}); +// 解除对应的实例绑定 +laydate.unbind('test'); +``` + + +

                          关闭日期面板 2.7+

                          + +`laydate.close(id);` + +- 参数 `id` : 组件渲染时定义的 `id` 属性值。 若 `id` 参数不填,则关闭当前打开的日期面板 + +该方法用于关闭对应的日期面板 + +``` +var laydate = layui.laydate; +// 渲染 +laydate.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id + // 其他属性 … +}); +// 关闭对应的日期面板 +laydate.close('test'); +``` + +

                          获取某月的最后一天

                          + +`laydate.getEndDate(month, year);` + +- 参数 `month` : 月份,默认为当前月。 +- 参数 `year` : 年份,默认为今年。 + +该方法用于获取某个月份的最后一天 + +``` +var days1 = laydate.getEndDate(10); // 获得 10 月的最后一天为 31 号 +var days2 = laydate.getEndDate(2, 2080); // 获得 2080 年 2 月的最后一天为 29 号 +``` + +## 贴士 + +> laydate 曾经可作为单独组件使用,鉴于维护成本的考量,目前 laydate 组件已完全集成到 Layui 中,而单独版本已不做同步维护。 +因此,建议直接使用 layui 中 laydate 即可。 + + + diff --git a/docs/layer/detail/demo.md b/docs/layer/detail/demo.md new file mode 100644 index 000000000..2d81a5a32 --- /dev/null +++ b/docs/layer/detail/demo.md @@ -0,0 +1,110 @@ +

                          在线测试

                          + +
                          +  
                          +
                          + +
                          + +

                          弹层类型

                          + +
                          +  
                          +
                          + +

                          信息框

                          + +信息框即 `dialog` 类型层,对应默认的 `type: 0`,该类型的弹层同时只能存在一个。更多说明详见:[#type](#options) + +
                          +  
                          +
                          + +

                          页面层

                          + +
                          +  
                          +
                          + +

                          iframe 层

                          + +
                          +  
                          +
                          + +

                          加载层

                          + +为了不影响继续体验,以下每个 loading 示例均会在 3 秒后自动模拟关闭 + +
                          +  
                          +
                          + +

                          Tips 层

                          + +
                          +  
                          +
                          + +

                          其他层

                          + +
                          +  
                          +
                          + +

                          更多演示

                          + +
                          +  
                          +
                          + +
                          +  
                          +
                          + +
                          +  
                          +
                          + +
                          +  
                          +
                          + + +

                          主题风格

                          + +
                          +  
                          +
                          + +### 小贴士 + +> 事实上 layer 丰富的基础属性,可足够让您的弹出层变得千变万化,为了避免占用太多篇幅,就不做过多演示了。 + diff --git a/docs/layer/detail/options.md b/docs/layer/detail/options.md new file mode 100644 index 000000000..4e1f197e3 --- /dev/null +++ b/docs/layer/detail/options.md @@ -0,0 +1,965 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          type + +弹层类型。 可选值有: + +- `0` dialog 信息框(默认),*同时只能存在一个层* +- `1` page 页面层,*可同时存在多个层* +- `2` iframe 内联框架层,*可同时存在多个层* +- `3` loading 加载层,*同时只能存在一个层* +- `4` tips 贴士层,*可配置同时存在多个层* + +`layer` 弹层由以上 5 种类型构成。 不同的类型代表不同的弹出形态,`layer` 提供的所有的弹出方式均由此衍生。 + +number + +`0` + +
                          title + +弹层标题。其值支持以下可选类型: + +- 若为 `string` 类型 : 则表示为弹层的标题文本,如: + +``` +title: '标题' +``` + +- 若为 `array` 类型 : 则可设置标题文本和标题栏 CSS 样式: + +``` + title: ['标题', 'font-size: 18px;'] +``` + +- 若为 `boolean` 类型 : 则可设为 `false` 不显示标题栏。 + +``` +title: false // 不显示标题栏 +``` + +string
                          array
                          boolean
                          + +`信息` + +
                          + +[content](#options.content) + + + +
                          + +弹层内容。 可传入的值比较灵活,支持以下使用场景: + +- 若 `type: 1`(页面层): 则 `content` 可传入值如下: + +``` +// 普通字符 +layer.open({ + type: 1, + content: '传入任意文本或 HTML' +}); +// 捕获页面已存在的 DOM 元素或 jQuery 对象 +layer.open({ + type: 1, + content: $('#id') // 捕获层 +}); +``` + +注意: 若采用捕获层,则捕获的元素必须存放在 `` 根节点下,否则可能被父级容器的相对定位所影响。 + +
                          + +- 若 `type: 2`(iframe 层): 则 `content` 可传入值如下: + +``` +// iframe URL +layer.open({ + type: 2, + content: 'http://cn.bing.com' // URL +}); +// 是否屏蔽 iframe 滚动条 +layer.open({ + type: 2, + // 数组第二个成员设为 no,即屏蔽 iframe 滚动条 + content: ['http://cn.bing.com', 'yes'] +}); +``` + +- 若为其他弹层类型,传入普通字符即可。 + +相关效果可参考:[#示例](#demo-page) + +
                          + +[area](#options.area) + + + +
                          +设置弹层的宽高,其值支持以下可选类型: +
                          + +- 若为 `array` 类型,则可同时设置宽高 + - `area: ['520px', '320px']` 固定宽度和高度 + - `area: ['auto', '320px']` 宽度自动,高度固定 + - `area: ['520px', 'auto']` 宽度固定,高度自动 +- 若为 `string` 类型,则可定义宽度和宽高均自适应: + - `area: '520px'` 宽度固定,高度自适应 + - `area: 'auto'` 宽度和高度均自适应 + +
                          array
                          string
                          + +`auto` + +
                          maxWidth + +弹层的最大宽度。当 `area` 属性设置宽度自适应时有效。 + +number + +`360` + +
                          maxHeight + +弹层的最大高度。当 `area` 属性设置高度自适应时有效。 + +number-
                          + +[offset](#options.offset) + + + +
                          +弹层的偏移坐标。 支持以下可选值: +
                          + +- `offset: 'auto'` 坐标始终垂直水平居中 +- `offset: '16px'` 只设置垂直坐标,水平保持居中 +- `offset: ['16px', '16px']` 设置垂直和水平坐标 +- `offset: 't'` 上边缘 +- `offset: 'r'` 右边缘 +- `offset: 'b'` 下边缘 +- `offset: 'l'` 左边缘 +- `offset: 'rt'` 右上角 +- `offset: 'rb'` 右下角 +- `offset: 'lt'` 左上角 +- `offset: 'lb'` 左下角 + +当设置边缘坐标时,可配合 `anim` 属性实现抽屉弹出效果。 + +
                          string
                          array
                          + +`auto` + +
                          + +[anim](#options.anim) + + + +
                          +弹层的出场动画。支持以下可选值: +
                          + +- `anim: 0` 平滑放大。默认 +- `anim: 1` 从上掉落 +- `anim: 2` 从最底部往上滑入 +- `anim: 3` 从左滑入 +- `anim: 4` 从左翻滚 +- `anim: 5` 渐显 +- `anim: 6` 抖动 + +边缘抽屉动画 2.8+: + +- `anim: 'slideDown'` 从上边缘往下 +- `anim: 'slideLeft'` 从右边缘往左 +- `anim: 'slideUp'` 从下边缘往上 +- `anim: 'slideRight'` 从左边缘往右 + +抽屉动画一般配合 `offset` 属性实现边缘弹出。[#详见示例](#demo-more) + + +
                          number
                          string
                          + +`0` + +
                          isOutAnim + +是否开启弹层关闭时的动画。 + +boolean + +`true` + +
                          maxmin + +是否开启标题栏的最大化和最小化图标。 + +boolean + +`false` + +
                          + +[closeBtn](#options.closeBtn) + + + +
                          +是否开启标题栏的关闭图标,或设置关闭图标风格。 +
                          + +- `closeBtn: 0` 不显示关闭图标 +- `closeBtn: 1` 关闭图标默认风格 +- `closeBtn: 2` 关闭图标风格二 + +
                          number + +`1` + +
                          + +[icon](#options.icon) + + + +
                          +提示图标。 信息框和加载层的私有参数。 +
                          + +- 若为信息框,支持传入 `0-6` 的可选值。
                          默认为 `-1`,即不显示图标。 +- 若为加载层,支持传入 `0-2` 的可选值 + +``` +// eg1 +layer.alert('成功提示', {icon: 1}); + +// eg2 +layer.msg('开心表情', {icon: 6}); + +// eg3 +layer.load(1); // 加载层风格一 +``` + +
                          number + +`-1` + +
                          + +[btn](#options.btn) + + + +
                          +自定义按钮。 页面层默认不开启。 按钮可无限数量,每一个按钮均会按照数组顺序生成对应的回调函数,如: +
                          + +``` +// eg1 +layer.confirm('询问框?', { + btn: ['按钮1', '按钮2', '按钮3'] +}); +// eg2 +layer.open({ + content: 'test', + btn: ['按钮1', '按钮2', '按钮3'], + // 按钮1 的回调 + btn1: function(index, layero, that){}, + btn2: function(index, layero, that){ + // 按钮2 的回调 + // return false // 点击该按钮后不关闭弹层 + }, + btn3: function(index, layero, that){ + // 按钮3 的回调 + // return false // 点击该按钮后不关闭弹层 + } +}); +``` + +
                          string-
                          + +[btnAlign](#options.btnAlign) + + + +
                          +按钮水平对其方式。支持以下可选值: +
                          + +- `btnAlign: 'l'` 按钮左对齐 +- `btnAlign: 'c'` 按钮水平居中对齐 +- `btnAlign: 'r'` 按钮右对齐。默认值,不用设置 + + +
                          string + +`r` + +
                          + +[btnAsync](#options.btnAsync) 2.9.12+ + + + +
                          + +异步按钮。开启之后,除 `layer.prompt` 的按钮外,按钮回调的返回值将支持 `boolean | Promise | JQueryDeferred` 类型,返回 `false` 或 `Promise.reject` 时阻止关闭。 + +注意,此时 `yes` 和 `btn1`(两者等效) 回调的默认行为发生了变化,即由触发时不关闭弹层变为关闭弹层。 + +
                          + +``` +var sleep = function (time) { + return $.Deferred(function (defer) { + setTimeout(function () { + defer.resolve(); + }, time) + }) +} +// 下面以 confirm 层为例 +layer.confirm('一个询问框的示例?', { + btnAsync: true, + btn: ['确定', '关闭'] // 按钮 + }, + function (index, layero, that) { + var defer = $.Deferred(); + // 注: that.loading() 仅 btnAsync 开启后支持,参数为 boolean 类型,表示打开或关闭按钮的加载效果。 + that.loading(true); + sleep(1000).then(defer.resolve); + return defer.promise(); + } +); +``` + +
                          boolean + +`false` + +
                          + +[skin](#options.skin) + + + +
                          +弹层的主题风格。通过赋值对应的 className,实现对主题样式的定制。除了默认主题风格,还支持以下可选主题: +
                          + +- `lay-layer-molv` 墨绿主题 +- `lay-layer-lan` 深蓝主题 +- `lay-layer-win10` Windows 10 主题 2.8+ + +还可传入其他任意 className 来自定义主题。 参考:[#示例](#demo-skin) + + +
                          string-
                          + +[shade](#options.shade) + + + +
                          +弹层的遮罩。 支持以下写法: +
                          + +- `shade: 0.3` 设置遮罩深色背景的透明度 +- `shade: [0.3, '#FFF']` 设置遮罩透明度和颜色值 +- `shade: 0` 不显示遮罩 + +
                          number
                          array
                          + +`0.3` + +
                          shadeClose + +是否点击遮罩时关闭弹层。当遮罩存在时有效。 + +boolean + +`false` + +
                          id + +弹层的唯一索引值。 一般用于页面层或 iframe 层弹出时的状态识别,设置该属性可防止弹层的重复弹出。 + +string-
                          hideOnClose 2.8.3+ + +关闭弹层时,是否将弹层设置为隐藏状态(而非移除),当再次打开,直接显示原来的弹层。 若设为 `true`,则必须同时设置 `id` 属性方可有效。 + +boolean + +`false` + +
                          time + +弹层自动关闭所需的毫秒数。 如 `time: 3000` ,即代表 3 秒后自动关闭。 提示框、加载层、Tips 层三种弹出模式默认开启。 + +number + +`0` + +
                          fixed + +弹层是否固定定位,即始终显示在页面可视区域。 + +boolean + +`true` + +
                          zIndex + +弹层的初始层叠顺序值。 + +number + +`19891014` + +
                          resize + +是否允许拖拽弹层右下角拉伸尺寸。 该属性对加载层和 tips 层无效。 + +boolean + +`true` + +
                          scrollbar + +打开弹层时,是否允许浏览器出现滚动条。 + +boolean + +`true` + +
                          minStack 2.6+ + +点击标题栏的最小化时,是否从页面左下角堆叠排列。 + +boolean + +`true` + +
                          removeFocus 2.8+ + +是否移除弹层触发元素的焦点,避免按回车键时重复弹出。 + +boolean + +`true` + +
                          move + +绑定弹层的拖拽元素。 默认为触发弹层的标题栏进行拖拽。也可以设置 `move: false` 禁止拖拽。 +用法参考:[#示例](#demo-page) + +string
                          DOM
                          boolean
                          -
                          moveOut + +否允许拖拽到窗口外 + +boolean + +`false` + +
                          tips + +设置 tips 层的吸附位置和背景色,tips 层的私有属性。 + +- 若为 `number` 类型,则支持 `1-4` 的可选值,分别代表*上右下左*的吸附位置。如: `tips: 1` +- 若为 `array` 类型,则支持设置吸附位置和背景色,如: + +``` +tips: [1, '#000'] // 吸附在上的深色贴士层 +``` + +number
                          array
                          + +`2` + +
                          tipsMore + +是否允许同时存在多个 tips 层,即不销毁上一个 tips。 + +boolean + +`false` + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          + +[success](#options.success) + + + +
                          +打开弹层成功后的回调函数。返回的参数如下: +
                          + +``` +layer.open({ + type: 1, + content: '内容', + success: function(layero, index, that){ + // 弹层的最外层元素的 jQuery 对象 + console.log(layero); + // 弹层的索引值 + console.log(index); + // 弹层内部原型链中的 this --- 2.8+ + console.log(that); + } +}); +``` + +
                          + +[yes](#options.yes) + + + +
                          + +点击「确定」按钮的回调函数。返回的参数同 `success` + +
                          + +``` +layer.open({ + content: '内容', + yes: function(index, layero, that){ + // do something + layer.close(index); // 关闭弹层 + } +}); +``` + +
                          + +[cancel](#options.cancel) + + + +
                          +点击标题栏关闭按钮的回调函数。返回的参数同 `success` +
                          + +``` +layer.open({ + content: '内容', + cancel: function(index, layero, that){ + if(confirm('确定要关闭么')){ + layer.close(index); + } + return false; // 阻止默认关闭行为 + } +}); +``` + +
                          + +[beforeEnd](#options.beforeEnd) 2.9.11+ + + + +
                          +弹层被关闭前的回调函数。如果返回 false 或者 Promise.reject,将会取消关闭操作。 +
                          + +``` +layer.open({ + content: '
                          ', + /** @type {(layero: JQuery, index: number) => boolean | JQueryDeferred | Promise} */ + beforeEnd: function(layero, index, that){ + return $.Deferred(function(defer){ + var el = layero.find('#id'); + var val = el.val().trim(); + if(val){ + layer.confirm('关闭后您填写的内容将不会得到保存,确定关闭吗?', function (i) { + layer.close(i); + defer.resolve(true) + }); + }else{ + defer.resolve(true) + } + }).promise(); + } +}); +``` + +
                          + +[end](#options.end) + + + +
                          +弹层被关闭且销毁后的回调函数。 +
                          + +``` +layer.open({ + content: '内容', + end: function(){ + console.log('弹层已被移除'); + } +}); +``` + +
                          + +[moveEnd](#options.moveEnd) + + + +
                          +弹层拖拽完毕后的回调函数。 +
                          + +``` +layer.open({ + type: 1, + content: '内容', + moveEnd: function(layero){ + console.log('拖拽完毕'); + } +}); +``` + +
                          + +[resizing](#options.resizing) + + + +
                          +弹层拉伸过程中的回调函数 +
                          + +``` +layer.open({ + type: 1, + content: '内容', + resizing: function(layero){ + console.log('拉伸中'); + } +}); +``` + +
                          + +[full](#options.full) + + + +
                          + +弹层最大化后的回调函数。返回的参数同 `success` + +
                          + +``` +layer.open({ + type: 1, + content: '内容', + full: function(layero, index, that){ + console.log('弹层已最大化'); + } +}); +``` + +
                          + +[min](#options.min) + + + +
                          + +弹层最小化后的回调函数。返回的参数同 `success` + +
                          + +``` +layer.open({ + type: 1, + content: '内容', + min: function(layero, index, that){ + // do something + // return false; // 阻止默认最小化 + } +}); +``` + +
                          + +[restore](#options.restore) + + + +
                          +弹层被还原后的回调函数。返回的参数同 `success` +
                          + +``` +layer.open({ + type: 1, + content: '内容', + restore: function(layero, index, that){ + console.log('弹层已还原'); + } +}); +``` + +
                          + diff --git a/docs/layer/detail/run.md b/docs/layer/detail/run.md new file mode 100644 index 000000000..df627586d --- /dev/null +++ b/docs/layer/detail/run.md @@ -0,0 +1,35 @@ +
                          +
                          + <textarea class="lay-textarea ws-demo-editor" id="ID-demo-editor" > +// 在此处输入 layer 的任意代码 +layer.open({ + type: 1, // page 层类型 + area: ['500px', '300px'], + title: 'Hello layer', + shade: 0.6, // 遮罩透明度 + shadeClose: true, // 点击遮罩区域,关闭弹层 + maxmin: true, // 允许全屏最小化 + anim: 0, // 0-6 的动画形式,-1 不开启 + content: '
                          一个普通的页面层,传入了自定义的 HTML
                          ' +});</textarea> +
                          +
                          + +
                          +
                          + + diff --git a/docs/layer/examples/alert.md b/docs/layer/examples/alert.md new file mode 100644 index 000000000..4cec974e9 --- /dev/null +++ b/docs/layer/examples/alert.md @@ -0,0 +1,79 @@ +
                          + + + + + + +
                          + + + diff --git a/docs/layer/examples/btnasync.md b/docs/layer/examples/btnasync.md new file mode 100644 index 000000000..d93c33206 --- /dev/null +++ b/docs/layer/examples/btnasync.md @@ -0,0 +1,90 @@ + + + + + + + + diff --git a/docs/layer/examples/direction.md b/docs/layer/examples/direction.md new file mode 100644 index 000000000..a6ac10724 --- /dev/null +++ b/docs/layer/examples/direction.md @@ -0,0 +1,69 @@ +从页面四个边缘弹出(抽屉效果): + +
                          + + + + +
                          + + + diff --git a/docs/layer/examples/iframe.md b/docs/layer/examples/iframe.md new file mode 100644 index 000000000..f674ddd54 --- /dev/null +++ b/docs/layer/examples/iframe.md @@ -0,0 +1,76 @@ +
                          + + + + +
                          + + + + diff --git a/docs/layer/examples/load.md b/docs/layer/examples/load.md new file mode 100644 index 000000000..4bf5444be --- /dev/null +++ b/docs/layer/examples/load.md @@ -0,0 +1,49 @@ +
                          + + + + +
                          + + + diff --git a/docs/layer/examples/more.md b/docs/layer/examples/more.md new file mode 100644 index 000000000..28c9e0b49 --- /dev/null +++ b/docs/layer/examples/more.md @@ -0,0 +1,172 @@ +
                          + + + + + +
                          + + + + + + diff --git a/docs/layer/examples/offset.md b/docs/layer/examples/offset.md new file mode 100644 index 000000000..7757f8e19 --- /dev/null +++ b/docs/layer/examples/offset.md @@ -0,0 +1,43 @@ +
                          + + + + + + + + + + +
                          + + + diff --git a/docs/layer/examples/other.md b/docs/layer/examples/other.md new file mode 100644 index 000000000..24d09e6f6 --- /dev/null +++ b/docs/layer/examples/other.md @@ -0,0 +1,102 @@ +
                          + + + + + + +
                          + + + + diff --git a/docs/layer/examples/page.md b/docs/layer/examples/page.md new file mode 100644 index 000000000..9a133f790 --- /dev/null +++ b/docs/layer/examples/page.md @@ -0,0 +1,151 @@ +
                          + + + + + +
                          + + + + + diff --git a/docs/layer/examples/skin.md b/docs/layer/examples/skin.md new file mode 100644 index 000000000..99c4314dc --- /dev/null +++ b/docs/layer/examples/skin.md @@ -0,0 +1,77 @@ +
                          + + + + +
                          + + + + + diff --git a/docs/layer/examples/tips.md b/docs/layer/examples/tips.md new file mode 100644 index 000000000..69a9f4b8e --- /dev/null +++ b/docs/layer/examples/tips.md @@ -0,0 +1,48 @@ +
                          + + + + + + +
                          + + + diff --git a/docs/layer/examples/type.md b/docs/layer/examples/type.md new file mode 100644 index 000000000..8fd630984 --- /dev/null +++ b/docs/layer/examples/type.md @@ -0,0 +1,106 @@ +
                          + + + + + + + + + +
                          + + + + diff --git a/docs/layer/index.md b/docs/layer/index.md new file mode 100644 index 000000000..2369049e1 --- /dev/null +++ b/docs/layer/index.md @@ -0,0 +1,615 @@ +--- +title: 通用弹出层组件 layer +toc: true +--- + +# 弹出层组件 🔥 + +> 弹出层组件 `layer` 是 `Layui` 最古老的组件,也是使用覆盖面最广泛的代表性组件。 `layer` 集众多弹层功能为一体,灵活而多样,是许多开发者的网页弹出层的首选交互方案,在各类业务场景都能发挥重要作用。 + + +

                          示例

                          + +点击下述按钮,查看每个示例对应的弹层效果。 + +
                          +{{- d.include("/layer/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var layer = layui.layer | 获得 `layer` 模块。 | +| 弹出 : | - | +| [layer.open(options)](#open) | 打开弹层,核心方法。下述所有弹出方式均为该方法的二次封装 | +| [layer.alert(content, options, yes)](#alert) | 弹出 `dialog` 类型信息框。 | +| [layer.confirm(content, options, yes, cancel)](#confirm) | 弹出 `dialog` 类型询问框。 | +| [layer.msg(content, options, end)](#msg) | 弹出 `dialog` 类型提示框。 | +| [layer.load(icon, options)](#load) | 弹出 `loading` 类型加载层。 | +| [layer.tips(content, elem, options)](#tips) | 弹出 `tips` 类型贴士层。 | +| [layer.prompt(options, yes)](#prompt) | 弹出 `page` 类型输入框层。 | +| [layer.photos(options)](#photos) | 弹出 `page` 类型图片层。 | +| [layer.tab(options)](#tab) | 弹出 `page` 类型标签页层。 | +| 关闭 : | - | +| [layer.close(index, callback)](#close) | 关闭对应的层,核心方法。 | +| [layer.closeAll(type, callback)](#closeAll) | 关闭所有对应类型的层。 | +| [layer.closeLast(type, callback)](#closeLast) 2.8+ | 关闭最近打开的对应类型的层。 | +| 其他 : | - | +| [layer.config(options)](#config) | 全局配置默认属性。 | +| [layer.ready(callback)](#ready) | 样式初始化就绪。 | +| [layer.style(index, css)](#set-style) | 重新设置弹层样式。 | +| [layer.title(title, index)](#set-title) | 设置弹层的标题。 | +| [layer.getChildFrame(selector, index)](#getChildFrame) | 获取 iframe 页中的元素。 | +| [layer.getFrameIndex(window.name)](#getFrameIndex) | 在 iframe 页中获取弹层索引。 | +| [layer.iframeAuto(index)](#iframeAuto) | 设置 iframe 层高度自适应。 | +| [layer.iframeSrc(index, url)](#iframeSrc) | 重新设置 iframe 层 URL。 | +| layer.index | 获取最新弹出层的索引 | +| layer.zIndex | 获取最新弹出层的层叠顺序 | +| [layer.setTop(layero)](#setTop) | 将对应弹层的层叠顺序为置顶。 | +| [layer.full(index)](#full) | 设置弹层最大化尺寸。 | +| [layer.min(index)](#min) | 设置弹层最小化尺寸。 | +| [layer.restore(index)](#restore) | 还原弹层尺寸。 | + + +

                          打开弹层

                          + +`layer.open(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +打开弹层的核心方法,其他不同类型的弹出方法均为该方法的二次封装。 + +``` +// 该方法返回当前层的唯一索引,以便其他方法对该弹层进行相关操作 +var index = layer.open({ + type: 1, // page 层类型,其他类型详见「基础属性」 + content: '
                          test
                          ' +}); +``` + +

                          基础属性

                          + +
                          +{{- d.include("/layer/detail/options.md") }} +
                          + +

                          弹出信息框

                          + +`layer.alert(content, options, yes);` + +- 参数 `content` : 弹出内容 +- 参数 `options` : 基础属性选项。[#详见属性](#options) +- 参数 `yes` : 点击确定后的回调函数 + +该方法用于弹出 `dialog` 类型信息框(`type: 0`),参数自动向左补位。 + +``` +// eg1 +layer.alert('一个简单的信息框'); +// eg2 +layer.alert('开启图标', {icon: 1}, function(index){ + // do something + // … + layer.close(index); +}); +// eg3 +layer.alert('不开启图标', function(index){ + // do something + // … + layer.close(index); +}); +``` + +

                          弹出询问框

                          + +`layer.confirm(content, options, yes, cancel);` + +- 参数 `content` : 弹出内容 +- 参数 `options` : 基础属性选项。[#详见属性](#options) +- 参数 `yes` : 点击确定后的回调函数 +- 参数 `cancel` : 点击第二个按钮(默认「取消」)后的回调函数 + +该方法用于弹出 `dialog` 类型询问框(`type: 0`),参数自动向左补位。 + +``` +// eg1 +layer.confirm('确定吗?', {icon: 3, title:'提示'}, function(index){ + // do something + // … + layer.close(index); +}); +// eg2 +layer.confirm('确定吗?', function(index){ + // do something + // … + layer.close(index); +}); +``` + + +

                          弹出提示框

                          + +`layer.msg(content, options, end);` + +- 参数 `content` : 弹出内容 +- 参数 `options` : 基础属性选项。[#详见属性](#options) +- 参数 `end` : 提示框关闭后的回调函数 + +该方法用于弹出 `dialog` 类型提示框(`type: 0`),默认 `3` 秒后自动关闭。参数自动向左补位。 + +``` +// eg1 +layer.msg('普通提示'); +// eg2 +layer.msg('带 icon 的提示', {icon: 6}); +// eg3 +layer.msg('关闭后想做些什么', function(){ + // do something +}); +// eg +layer.msg('提示框', { + icon: 1, + time: 2000 // 设置 2 秒后自动关闭 +}, function(){ + // do something +}); +``` + + +

                          弹出加载层

                          + +`layer.load(icon, options);` + +- 参数 `icon` : 加载图标风格,支持 `0-2` 可选值 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法用于弹出 `load` 类型加载层(`type: 3`)。 + +``` +// eg1 +var index = layer.load(); // 默认加载图标风格 +// eg2 +var index = layer.load(1); // 加载图标风格 1 +// eg3 +var index = layer.load(2, {time: 10*1000}); // 加载图标风格,并设置最长等待 10 秒 + +// 关闭加载层 +layer.close(index); +``` + +

                          弹出贴士层

                          + +`layer.tips(content, elem, options);` + +- 参数 `content` : 弹出内容 +- 参数 `elem` : 吸附的目标元素选择器或对象 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法用于弹出 `tips` 类型贴士层(`type: 4`),默认 `3` 秒后自动关闭。 + +``` +// eg1 +layer.tips('小贴士', '#id'); +// eg2 +$('#id').on('click', function(){ + var elem = this; + layer.tips('小贴士', elem); //在元素的事件回调体中,follow直接赋予this即可 +}); +// eg3 +layer.tips('显示在目标元素上方', '#id', { + tips: 1 // 支持 1-4 可选值,更多详见基础属性中的 tips 介绍 +}); +``` + +

                          弹出输入框

                          + +`layer.prompt(options, yes);` + +- 参数 `options` : 基础属性选项。除了支持 [基础属性](#options) 之外,还支持下表私有属性: + +| 私有属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| formType | 输入框类型。支持以下可选值:
                          • `0` 文本输入框
                          • `1` 密令输入框
                          • `2` 多行文本输入框
                          • MDN: input 类型(2.13+)
                          | number/string | `0` | +| value | 输入框初始值 | string | - | +| maxlength | 可输入的最大字符长度 | number | `500` | +| placeholder | 输入框内容为空时的占位符 | string | - | + + +- 参数 `yes` : 点击确定后的回调函数 + +该方法用于弹出输入框层,基于 `type: 1`(即 `page` 层)的自定义内容。 效果参考: [#示例](#demo-other) + +``` +// eg1 +layer.prompt(function(value, index, elem){ + alert(value); // 得到 value + layer.close(index); // 关闭层 +}); + +// eg2 +layer.prompt({ + formType: 2, + value: '初始值', + title: '请输入值', + area: ['800px', '350px'] // 自定义文本域宽高 +}, function(value, index, elem){ + alert(value); // 得到 value + layer.close(index); // 关闭层 +}); +``` + +

                          弹出图片层

                          + +`layer.photos(options);` + +- 参数 `options` : 基础属性选项。除了支持 [基础属性](#options) 之外,还支持下表私有属性: + +| 私有属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| photos | 图片层的数据源,格式详见下述示例。 | object | - | +| toolbar 2.8.16+ | 是否显示顶部工具栏 | boolean | `true` | +| footer 2.8.16+ | 是否隐藏底部栏 | boolean | `true` | +| tab | 图片层切换后的回调函数,返回的参数见下述示例 | function | - | + +该方法用于弹出图片层,基于 `type: 1`(即 `page` 层)的自定义内容。 + +**用法一:直接赋值图片数据**。 效果参考: [#示例](#demo-other) + +``` +layer.photos({ + photos: { // 图片层的数据源 + "title": "", // 相册标题 + "id": 123, // 相册 id + "start": 0, // 初始显示的图片序号,默认 0 + "data": [ // 相册包含的图片,数组格式 + { + "alt": "图片名", + "pid": 666, // 图片id + "src": "", // 原图地址 + "thumb": "" // 缩略图地址 + }, + // … + ] + }, + tab: function(data, layero){ // 图片层切换后的回调 + console.log(data); // 当前图片数据信息 + console.log(layero); // 图片层的容器对象 + } +}); +``` + +**用法二:绑定页面图片元素**。点击图片时,弹出对应的图片层。 + +
                          +  
                          +
                          + + +

                          弹出标签层

                          + +`layer.tab(options);` + +- 参数 `options` : 基础属性选项。除了支持 [基础属性](#options) 之外,还支持下表私有属性: + +| 私有属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| tab | 标签层的数据源,格式详见下述示例。 | array | - | + +该方法用于弹出标签层,基于 `type: 1`(即 `page` 层)的自定义内容。 效果参考: [#示例](#demo-other) + +``` +layer.tab({ + area: ['600px', '300px'], + tab: [{ // 标签层的数据源 + title: '标题 1', + content: '内容 1' + }, { + title: '标题 2', + content: '内容 2' + }, { + title: '标题 3', + content: '内容 3' + }] +}); +``` + + +

                          关闭弹层

                          + +`layer.close(index, callback);` + +- 参数 `index` : 打开弹层时返回的唯一索引 +- 参数 `callback` : 关闭弹层后的回调函数 + +该方法用于关闭对应的弹层。 + +``` +// 每一种弹层调用方式,都会返回一个 index +var index1 = layer.open(); +var index2 = layer.alert(); +var index3 = layer.load(); +var index4 = layer.tips(); + +// 关闭对应的弹层 +layer.close(index1); +``` + +在 iframe 弹层页面中关闭自身 + +``` +var index = parent.layer.getFrameIndex(window.name); // 先得到当前 iframe 层的索引 +parent.layer.close(index); // 再执行关闭 +``` + + +

                          关闭所有层

                          + +`layer.closeAll(type, callback);` + +- 参数 `type` : 弹层的类型。可选值:`dialog,page,iframe,loading,tips` +- 参数 `callback` : 关闭弹层后的回调函数 + +该方法用于关闭所有同类型的弹层。 + +``` +layer.closeAll(); // 关闭所有类型的层 +layer.closeAll('dialog'); // 关闭所有的信息框 +layer.closeAll('page'); // 关闭所有的页面层 +layer.closeAll('iframe'); // 关闭所有的 iframe 层 +layer.closeAll('loading'); // 关闭所有的加载层 +layer.closeAll('tips'); // 关闭所有的 tips 层 +``` + +

                          关闭最近一次打开的层 2.8+

                          + +`layer.closeLast(type, callback);` + +- 参数 `type` : 弹层的类型。可选值:`dialog,page,iframe,loading,tips` +- 参数 `callback` 2.9+: 关闭弹层后的回调函数 + +该方法用于关闭最近一次打开的对应类型的层。 + +``` +layer.closeLast('dialog'); // 关闭最近一次打开的信息框 +layer.closeLast('page'); // 关闭最近一次打开的页面层 +layer.closeLast('iframe'); // 关闭最近一次打开的 iframe 层 +layer.closeLast('loading'); // 关闭最近一次打开的加载层 +layer.closeLast('tips'); // 关闭最近一次打开的 tips 层 +layer.closeLast(['dialog', 'page']); // 关闭最近一次打开的信息框或页面层,2.9.7+ +``` + +

                          全局配置默认属性

                          + +`layer.config(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法用于全局设置弹层的默认基础属性。 + +``` +layer.config({ + title: '默认标题', + skin: '', // 设置默认主题 + // … 其他任意基础属性 +}) +``` + +

                          样式初始化就绪

                          + +`layer.ready(callback);` + +- 参数 `callback` : 初始化完毕后的回调函数 + +该方法一般是在源码方式引入 `layui.js`,且要在页面初始即弹出层时使用,以确保弹层所依赖的样式文件先行加载。 而引入 release 版的 `layui.js` 则无需使用该方法,因为弹层样式已经统一合并到 `layui.css` 中。 + +``` +// 页面初始弹出层 +layer.ready(function(){ + layer.alert('对话框内容'); +}); +``` + +

                          重新设置弹层样式

                          + +`layer.style(index, css);` + +- 参数 `index` : 打开弹层时返回的唯一索引 +- 参数 `css` : 要设置的 `css` 属性 + +该方法对 `loading` 层和 `tips` 层无效。 + +``` +// 打开弹层 +var index = layer.open({ + type: 1, + content: '内容' +}); + +// 重新给对应层设定 width、top 等 +layer.style(index, { + width: '1000px', + top: '10px' +}); +``` + +

                          设置弹层的标题

                          + +`layer.title(title, index);` + +- 参数 `title` : 标题 +- 参数 `index` : 打开弹层时返回的唯一索引 + +``` +// 打开弹层 +var index = layer.open({ + type: 1, + content: '内容' +}); + +// 重新设置标题 +layer.title('新标题', index) +``` + +

                          获取 iframe 页中的元素

                          + +`layer.getChildFrame(selector, index);` + +- 参数 `selector` : iframe 子页面的选择器或元素对象 +- 参数 `index` : 打开弹层时返回的唯一索引 + +该方法用于在父页面获取 iframe 子页面中的元素 + +``` +layer.open({ + type: 2, // iframe 层 + content: '/layer/test/iframe.html', + success: function(layero, index){ + // 获取 iframe 中 body 元素的 jQuery 对象 + var body = layer.getChildFrame('body', index); + // 给 iframe 页中的某个输入框赋值 + body.find('input').val('Hello layer.'); + } +}); +``` + +

                          在 iframe 页中获取弹层索引

                          + +`layer.getFrameIndex(window.name);` + +- 参数 `window.name` : 当前 iframe 窗口的 `name` 属性值 + +该方法用于在 iframe 页面内部获取当前 iframe 弹层的索引,以便关闭自身。 + +``` +var index = parent.layer.getFrameIndex(window.name); // 获取当前 iframe 层的索引 +parent.layer.close(index); // 关闭当前 iframe 弹层 +``` + +

                          设置 iframe 层高度自适应

                          + +`layer.iframeAuto(index);` + +- 参数 `index` : 打开弹层时返回的唯一索引 + +该方法可让 iframe 高度跟随内容自适应 + +``` +layer.open({ + type: 2, // iframe 层 + content: '/layer/test/iframe.html', + area: '600px', // 弹层初始宽度 + success: function(layero, index, that){ + layer.iframeAuto(index); // 让 iframe 高度自适应 + that.offset(); // 重新自适应弹层坐标 + } +}); +``` + +

                          重新设置 iframe 层 URL

                          + +`layer.iframeSrc(index, url);` + +- 参数 `index` : 打开弹层时返回的唯一索引 +- 参数 `url` : URL 地址 + +``` +// 打开弹层 +var index = layer.open({ + type: 2, // iframe 层 + content: '/layer/test/iframe.html' +}); +// 重置 iframe 页面 URL +layer.iframeSrc(index, 'https://cn.bing.com/'); +``` + +

                          置顶弹层

                          + +`layer.setTop(layero);` + +- 参数 `layero` : layer 最外层容器的元素对象,一般可通过各个回调函数返回的参数获取。 + +该方法一般用于多弹层模式时,实现点击某个弹层让其层叠顺序置顶。效果参考:[#示例](#demo-more) + +``` +// 多弹层模式的层叠顺序置顶 +layer.open({ + type: 1, // 页面层 + shade: false, + area: ['520px', '320px'], + maxmin: true, + content: '
                          多弹层模式的层叠顺序置顶
                          ', + zIndex: layer.zIndex, // 重点 1 --- 初始设置当前最高层叠顺序, + success: function(layero){ + layer.setTop(layero); // 重点 2 --- 保持选中窗口置顶 + } +}); +``` + +

                          设置弹层最大化

                          + +`layer.full(index);` + +- 参数 `index` : 打开弹层时返回的唯一索引 + +``` +// 打开弹窗 +var index = layer.open({ + type: 1, // 页面层 + content: '弹层内容' +}); +// 设置弹层最大化 +layer.full(index); +``` + +

                          设置弹层最小化

                          + +`layer.min(index);` + +- 参数 `index` : 打开弹层时返回的唯一索引 + +``` +// 打开弹窗 +var index = layer.open({ + type: 1, // 页面层 + content: '弹层内容' +}); +// 设置弹层最大化 +layer.min(index); +``` + +

                          还原弹层

                          + +`layer.restore(index);` + +- 参数 `index` : 打开弹层时返回的唯一索引 + +当弹层最大化或最小化状态时,执行该方法可还原弹层。 + + +## 贴士 + +> layer 曾经可作为单独组件使用,鉴于维护成本的考量,目前 layer 组件已完全集成到 Layui 中,而单独版本已不做同步维护。 因此,建议直接使用 layui 中 layer 即可。 + diff --git a/docs/layout/grid.md b/docs/layout/grid.md new file mode 100644 index 000000000..cf60dc96d --- /dev/null +++ b/docs/layout/grid.md @@ -0,0 +1,542 @@ +--- +title: 栅格布局 +toc: true +--- + +# 栅格布局 + +> Layui 栅格系统是一套具备响应式能力的布局方案,采用业界比较常用的容器横向 `12` 等分规则,预设了 `5*12` 种 CSS 排列类,内置多种大小尺寸的多终端适配,能很好地实现响应式布局,这意味着一套系统,能同时适配于电脑的不同大小屏幕和手机、平板等移动屏幕,使得网页布局变得更加灵活,同时也极大地降低了 `HTML/CSS` 代码的耦合。 + +

                          示例

                          + +> 贴士:以下示例中的*背景色*仅仅只是为了让布局效果显得更加直观,实际使用时并不需要背景色。 + + + +- 始终等比例水平排列: + +
                          +  
                          +
                          + +- 移动设备、桌面端的组合响应式展现: + +
                          +  
                          +
                          + +- 移动设备、平板、桌面端的复杂组合响应式展现: + +
                          +  
                          +
                          + +- 常规布局:从小屏幕堆叠到桌面水平排列: + +
                          +  
                          +
                          + +- 列间隔: + +
                          +  
                          +
                          + +- 列偏移 + +
                          +  
                          +
                          + +- 栅格嵌套: + +> 理论上,你可以对栅格进行无穷层次的嵌套,这更加增强了栅格的表现能力 + +
                          +  
                          +
                          + +- 流体容器(宽度自适应,不固定): + +
                          +  
                          +
                          + +
                          + +

                          栅格布局规则

                          + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          1.采用 lay-row 来定义行,如:<div class="lay-row"></div>
                          2. + 采用类似 lay-col-md* 这样的预设类来定义一组列(column),且放在行(row)内。其中: +
                          +
                            +
                          • 变量md 代表的是不同屏幕下的标记(可选值见下文)
                          • +
                          • 变量* 代表的是该列所占用的 12 等分数(如 6/12),可选值为 1 - 12
                          • +
                          • 如果多个列的“等分数值”总和等于 12,则刚好满行排列。如果大于12,多余的列将自动另起一行。
                          • +
                          +
                          +
                          3.列可以同时出现最多 5 种不同的组合,分别是:xs / sm / md / lg / xl 2.8+,以在不同尺寸屏幕下进行自动适配。
                          4.可对列追加类似 lay-col-space5lay-col-md-offset3 这样的预设类来定义列的间距和偏移。
                          5.最后,在列(column)元素中放入你自己的任意元素填充内容,完成布局!
                          + +

                          响应式规则

                          + +栅格的响应式能力,得益于 `CSS3` 媒体查询(`Media Queries`),针对不同尺寸的屏幕进行相应的适配处理。 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          超小屏幕
                          (手机<768px)
                          小屏幕
                          (平板≥768px)
                          中等屏幕
                          (桌面≥992px)
                          大型屏幕
                          (桌面≥1200px)
                          超大屏幕
                          (桌面≥1400px)
                          lay-containerauto750px970px1170px1330px
                          标记xssmmdlgxl 2.8+
                          列对应类lay-col-xs*lay-col-sm*lay-col-md*lay-col-lg*lay-col-xl*
                          总列数12
                          响应行为始终按比例水平排列在当前屏幕下水平排列,如果屏幕大小低于临界值则堆叠排列
                          + +

                          响应式公共类

                          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          类名(class)说明
                          lay-show-*-block定义不同设备下的 display: block; * 可选值有:xs、sm、md、lg、xl
                          lay-show-*-inline定义不同设备下的 display: inline; * 可选值同上
                          lay-show-*-inline-block定义不同设备下的 display: inline-block; * 可选值同上
                          lay-hide-*定义不同设备下的隐藏类,即: display: none; * 可选值同上
                          + +

                          布局容器

                          + +将栅格放入一个带有 `class="lay-container"` 的特定容器中,以便在小屏幕以上的设备中固定宽度,让列可控。 + +``` +
                          +
                          + …… +
                          +
                          +``` + +当然,你还可以不固定容器宽度。将栅格或其它元素放入一个带有 `class="lay-fluid"`的容器中,那么宽度将不会固定,而是 100% 适应 + +``` +
                          + …… +
                          +``` + +

                          列间距

                          + + + + + + + + + + + + + + +
                          通过“列间距”的预设类,来设定列之间的间距。且一行中最左的列不会出现左边距,最右的列不会出现右边距。列间距在保证排版美观的同时,还可以进一步保证分列的宽度精细程度。我们结合网页常用的边距,预设了 12 种不同尺寸的边距,分别是:
                          +
                          +lay-col-space1
                          +lay-col-space2
                          +lay-col-space4
                          +lay-col-space5
                          +lay-col-space6
                          +lay-col-space8
                          +lay-col-space10
                          +lay-col-space12
                          +lay-col-space14
                          +lay-col-space15
                          +lay-col-space16
                          +lay-col-space18
                          +lay-col-space20
                          +lay-col-space22
                          +lay-col-space24
                          +lay-col-space25
                          +lay-col-space26
                          +lay-col-space28
                          +lay-col-space30
                          +lay-col-space32
                          +
                          +即:支持列之间为 1px-32px 区间的所有双数间隔,以及 1px、5px、15px、25px 的单数间隔
                          +
                          + +下面是一个简单的例子,列间距为 `16px`: + +``` +
                          +
                          + 1/3 +
                          +
                          + 1/3 +
                          +
                          + 1/3 +
                          +
                          +``` + +

                          列偏移

                          + +对列追加类似 `lay-col-md-offset*` 的预设类,从而让列向右偏移。如:`lay-col-md-offset3`,即代表在“中型桌面屏幕”下,让该列向右偏移 3 个列宽度。下面是一个采用「列偏移」机制让两个列左右对齐的实例 + +``` +div class="lay-row"> +
                          + 4/12 +
                          +
                          + 偏移4列,从而在最右 +
                          +
                        +``` + +> 请注意,列偏移可针对不同屏幕的标准进行设定,比如上述的例子,只会在桌面屏幕下有效,当低于桌面屏幕的规定的临界值,就会堆叠排列。 + +

                        IE8/9 兼容方案

                        + +事实上 `IE8/IE9` 并不支持 `Media Queries`,但你可以使用下面的补丁进行兼容(补丁来自于开源社区): + +``` + + +``` + +将上述代码放入你页面 `` 标签内的任意位置即可。 + diff --git a/docs/layout/index.md b/docs/layout/index.md new file mode 100644 index 000000000..54e08d617 --- /dev/null +++ b/docs/layout/index.md @@ -0,0 +1,149 @@ +--- +title: Admin UI 框体布局 +toc: true +--- + +# 框体布局 + +> Layui 的主要应用场景是面向中后台的界面搭建,因此也提供了大框体布局方案。 + +

                        示例

                        + +
                        +  
                        +
                        + +
                        + +> 小贴士:以上是一个基础的框体布局方案,若要实现诸如 `iframe` 跳转、侧边菜单收缩等功能,还需按照实际的业务需求自主实现。当然,也可以采用社区已有的 AdminUI 主题方案,如:layuiAdmin 等。 + +

                        Admin UI

                        + +layuiAdmin 是一套用于开发通用型管理系统的纯静态的 `HTML` 网页界面主题,基于开源的 Layui Web 组件库制作而成,没有任何后端程序及数据库存储等服务端代码。开发者使用该网页模板,可省去前端的大量工作,从而更高效地开发 Web 应用系统。 + diff --git a/docs/laypage/detail/demo.md b/docs/laypage/detail/demo.md new file mode 100644 index 000000000..4be66bbf9 --- /dev/null +++ b/docs/laypage/detail/demo.md @@ -0,0 +1,279 @@ +
                        +  
                        +
                        + +

                        自定义主题

                        + +
                        +  
                        +
                        + +

                        自定义文本

                        + +
                        +  
                        +
                        + +

                        不显示上一页、下一页

                        + +
                        +  
                        +
                        + +

                        只显示上一页、下一页、当前页

                        + +
                        +  
                        +
                        + +

                        自定义排版

                        + +
                        +  
                        +
                        + +

                        自定义每页条数的选择项

                        + +
                        +  
                        +
                        + +

                        完整显示

                        + +
                        +  
                        +
                        + +

                        高级 - 开启 HASH

                        + +
                        +  
                        +
                        + +

                        高级 - 将一段已知数组分页展示

                        + +
                        +  
                        +
                        + diff --git a/docs/laypage/detail/options.md b/docs/laypage/detail/options.md new file mode 100644 index 000000000..22c7424e7 --- /dev/null +++ b/docs/laypage/detail/options.md @@ -0,0 +1,290 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                        属性名描述类型默认值
                        elem + +绑定分页容器。值可以是容器 `id` 或 DOM 对象。如: + +- `elem: 'id'` 注意:这里不能加 `#` 号 +- `elem: document.getElementById('id')` + +string
                        DOM
                        -
                        count + +数据总数。一般通过后端得到 + +number-
                        limit + +每页显示的条数。 + +number + +`10` + +
                        limits + +每页条数的选择项。 若 `layout` 参数开启了 `limit` ,则会出现每页条数的 select 选择框 + +array + +`[10,…,50]` + +
                        curr + +初始化当前页码。 + +number + +`1` + +
                        groups + +连续出现的页码数量 + +number + +`5` + +
                        prev + +自定义“上一页”的内容,支持传入普通文本和 HTML + +string + +`上一页` + +
                        next + +自定义“下一页”的内容,用法同上。 + +string + +`下一页` + +
                        first + +自定义“首页”的内容,用法同上。 + +string + +`1` + +
                        last + +自定义“尾页”的内容,用法同上。 + +string + +*自动获得* + +
                        layout + +自定义分页功能区域排版。可自由排列,可选值有: + +- `count` 数据总数区域 +- `prev` 上一页区域 +- `page` 分页区域 +- `next` 下一页区 +- `limit` 条目选项区域 +- `refresh` 页面刷新区 +- `skip` 快捷跳页区 + +array + + + +
                        limitTemplet 2.8.18+ + +用于自定义条目模板,如: + +``` +limitTemplet: function(item) { + return item + ' / page'; +} +``` + +function-
                        skipText 2.8.18+ + +用于自定义跳页区域文本,如: + +``` +skipText: ['Go to', '', 'Confirm'] +``` + +array-
                        countText 2.9.1+ + +用于自定义总数区域文本,如: + +``` +countText: ['Total ',''] +``` + +array-
                        theme + +自定义主题。支持传入:颜色值或任意普通字符。如: + +- `theme: '#c00'` 直接设置当前页按钮背景色 +- `theme: 'xxx'` 会生成 `class="lay-laypage-xxx"` 的 CSS 类,以便自定义主题 + +string-
                        hash + +设置 `hash` 名称。设置该属性后,点击分页将会自动对当前 `url` 追加:`#{hash}={curr}`,从而在页面刷新时初始化当前页码。[#详细用法参考示例](#demo-hash) + +string-
                        + + +
                        + +[回调函数](#options.callback) + +
                        + +
                        + +[jump](#options.jump) + + + +
                        分页跳转后的回调函数。函数返回两个参数:
                        + +- 参数 `obj` : 当前分页相关的所有选项值 +- 参数 `first` : 是否首次渲染,一般用于初始加载的判断 + +``` +laypage.render({ + elem: 'id', + count: 70, // 数据总数,从后端得到 + jump: function(obj, first){ + console.log(obj.curr); // 得到当前页,以便向服务端请求对应页的数据。 + console.log(obj.limit); // 得到每页显示的条数 + + // 首次不执行 + if(!first){ + // do something + } + } +}); +``` + +
                        + + diff --git a/docs/laypage/index.md b/docs/laypage/index.md new file mode 100644 index 000000000..52f8a4612 --- /dev/null +++ b/docs/laypage/index.md @@ -0,0 +1,37 @@ +--- +title: 分页组件 laypage +toc: true +--- + +# 分页组件 + +> 分页组件 `laypage` 提供了前端的分页逻辑,使得我们可以很灵活处理不同量级的数据,从而提升渲染效率。 + +

                        示例

                        + +
                        +{{- d.include("/laypage/detail/demo.md") }} +
                        + +

                        API

                        + +| API | 描述 | +| --- | --- | +| var laypage = layui.laypage | 获得 `laypage` 模块。 | +| [laypage.render(options)](#render) | laypage 组件渲染,核心方法。 | + +

                        渲染

                        + +`laypage.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +

                        属性

                        + +
                        +{{- d.include("/laypage/detail/options.md") }} +
                        + +## 小贴士 + +laypage 组件只负责分页本身的逻辑,具体的数据请求及对应的视图渲染需要另外去完成。laypage 不仅能应用在一般的异步分页上,还可直接对一段已知数据进行分页展现,如 table 组件的分页就是采用的 laypage。 diff --git a/docs/laytpl/detail/demo.md b/docs/laytpl/detail/demo.md new file mode 100644 index 000000000..e8380ca5e --- /dev/null +++ b/docs/laytpl/detail/demo.md @@ -0,0 +1,187 @@ +
                        +  
                        +
                        + diff --git a/docs/laytpl/detail/options.md b/docs/laytpl/detail/options.md new file mode 100644 index 000000000..df90fd295 --- /dev/null +++ b/docs/laytpl/detail/options.md @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + {{! + + + + + + + + + + + + + + + + + + + + + + + + + !}} +
                        标签描述类型默认值
                        open + +用于设置起始界定符 + +string + +`{{` + +
                        close + +用于设置结束界定符 + +string + +`}}` + +
                        cache 2.11+ + +是否开启模板缓存,以便下次渲染时不重新编译模板 + +boolean + +`true` + +
                        condense 2.11+ + +是否压缩模板空白符,如:将多个连续的空白符压缩为单个空格 + +boolean + +`true` + +
                        + diff --git a/docs/laytpl/detail/tags.md b/docs/laytpl/detail/tags.md new file mode 100644 index 000000000..c971ad282 --- /dev/null +++ b/docs/laytpl/detail/tags.md @@ -0,0 +1,67 @@ + + + + + + + + + + + + {{! + + + + + + + + + + + + + + + + !}} + + + + + +
                        标签描述
                        {{= }} + +转义输出。若字段存在 HTML,将进行转义。 + +
                        {{- }} + +原文输出。即不对 HTML 字符进行转义,但需做好 XSS 防护。 + +
                        {{ }} + +Scriptlet 标签。一般用于流程控制,如: + + ```js +{{ if (d.title) { }} + 标题:{{= d.title }} +{{ } else { }} + 默认标题 +{{ } }} + ``` + +
                        {{# }} + +注释标签。即仅在模板中显示,不在视图中输出。 + +
                        {{!{{! !}}!}} + +忽略标签。即该区域中的标签不会被解析,一般用于输出原始标签。如: + +```js +{{! {{! 这里面的 {{= escape }} 等模板标签不会被解析 !}} !}} +``` + +
                        + diff --git a/docs/laytpl/index.md b/docs/laytpl/index.md new file mode 100644 index 000000000..284373815 --- /dev/null +++ b/docs/laytpl/index.md @@ -0,0 +1,271 @@ +--- +title: 模板引擎 laytpl +toc: true +--- + +# 模板引擎 + +> `laytpl` 是 Layui 内置的 JavaScript 模板引擎,采用原生控制流,在模板解析上有着比较出色的表现。 + +

                        在线测试

                        + +对文本框中的*模板*或*数据*进行编辑,下方将呈现对应的*渲染结果*。 + +
                        +{{- d.include("/laytpl/detail/demo.md") }} +
                        + +

                        API

                        + +| API | 描述 | +| --- | --- | +| var laytpl = layui.laytpl | 获得 `laytpl` 模块。 | +| [var templateInst = laytpl(template, options)](#laytpl) | 创建模板实例。 | +| [laytpl.config(options)](#config) | 设置基础选项默认值 | +| [laytpl.extendVars(variables)](#variables) 2.11+ | 扩展模板内部变量 | + +

                        创建模板实例

                        + +`var templateInst = laytpl(template, options)` + +- 参数 `template` : 原始模板字符 +- 参数 `options` 2.8+ : 当前模板实例的选项。详见下述:[#基础选项](#options) + +该方法返回一个模板编译器实例,用于对模板进行数据渲染等操作,实例对象的成员有: + +| 实例成员 | 描述 | +| --- | --- | +| templateInst.render(data, callback) | 给模板实例进行数据渲染,返回渲染后的 HTML 字符 | +| templateInst.compile(template) 2.11+ | 编译新的模板,会强制清除旧模板缓存 | +| templateInst.config 2.11+ | 获取当前模板实例的配置选项 | + +通过将模板编译与渲染两个环节分开,我们可以在模板仅编译一次的情况下,对其渲染不同的数据,如: + +{{! +```js +var laytpl = layui.laytpl; + +// 创建模板实例 +var templateInst = laytpl('{{= d.name }}是一名{{= d.role }}'); + +// 数据渲染 1 +templateInst.render({ + name: '张三', + role: '全栈开发者' +}, function(html) { + console.log(html); // 张三是一名全栈开发者 +}); + +// 数据渲染 2 +var html = templateInst.render({ + name: '王五', + role: '架构师' +}); +``` +!}} + +若每次需要对不同的模板进行编译和数据渲染,你也可以使用链式写法,如: + +{{! +```js +laytpl('{{= d.name }}是一名{{= d.role }}').render({ + name: '张三', + role: '全栈开发者' +}, function(html) { + console.log(html); // 张三是一名全栈开发者 +}); +``` +!}} + +若模板字符较大,你可以将模板存放在页面某个标签中,如: + +{{! +```js + + +
                        + + + +``` +!}} + +实际使用时,若模板通用,而数据不同,为了避免对模板进行不必要的重复编译,推荐将创建模板实例与数据渲染分开书写。 + +

                        基础选项

                        + +创建模板实例时,你还可以对其设置一些选项,如: + +{{! +```js +// 创建模板实例 +var templateInst = laytpl(` + {{ let role = d.role || '全栈开发者'; }} + {{= d.name }}是一名{{= role }} +`); +var html = templateInst.render({ name: '张三' }); +``` +!}} + +支持设置的完整选项如下: + +
                        +{{- d.include("/laytpl/detail/options.md") }} +
                        + +

                        标签规则

                        + +
                        +{{- d.include("/laytpl/detail/tags.md") }} +
                        + +#### ⚡ 请注意: +> *开发者在使用模板标签时,需确保模板中待输出的内容在开发者自身的可控范围内,尤其对于用户输入的字符要做好 XSS 防护,否则请避免使用该模板引擎,以免产生 XSS 安全隐患*。 + +

                        导入子模板 2.11+

                        + +{{! +laytpl 支持在模板中通过添加 `{{- include(id, data) }}` 语句引入子模板。`include` 语句参数解释: + +- `id` : 子模板 ID +- `data` : 向子模版传入的数据 + +为了引入的子模板不被转义,因此这里应该使用 `{{- }}`,即对子模板进行原文输出。示例: + +
                        +  
                        +
                        + +!}} + +若在 Node.js 环境,可通过 `laytpl.extendVars()` 方法重置 `include` 语句实现模板文件的导入。 + +

                        设置选项默认值

                        + +`laytpl.config(options);` + +- 参数 `options`: 基础选项 + +你可以设置任意选项的默认值,如: + +{{! +```js +laytpl.config({ + open: '<%', // 自定义起始界定符 + close: '%>', // 自定义起始界定符 +}); + +// 创建模板实例 +var templateInst = laytpl(` + <% var roles = ["前端工程师","全栈工程师","架构师"]; %> + <%= d.name %>是一名<%= roles[d.role] %> +`); +// 渲染 +templateInst.render({ + name: '张三', + role: 1 +}, function(string){ + console.log(string); // 张三是一名全栈工程师 +}); +``` +!}} + +

                        扩展模板内变量

                        + +`laytpl.extendVars(variables)` + +- 参数 `variables` : 扩展的变量列表,变量值通常是一个函数 + +事实上 laytpl 内置了一些模板内部方法,如 `_escape, include`。你可以对它们进行重构,或扩展更多内部变量,如: + +{{! +```js +// 扩展模板内部变量 +laytpl.extendVars({ + // 重构 include 方法,实现引入模板文件 + include: function(filename, data) { + // … + }, + // 添加 toDataString 方法 + toDataString: function(date) { + date = date || new Date(); + return new Date(date).toLocaleDateString(); + } +}); + +// 在模板中使用扩展的变量 +var templateInst = laytpl('日期:{{= toDataString(d.time) }}'); +templateInst.render({ time: 1742745600000 }, function(html) { + console.log(html); +}); +``` +!}} + +## 💖 心语 + +我们在 `2.11` 版本对 laytpl 完成了重要重构,使其能够具备应对更多复杂模板结构的解析能力。同时,为了与业界常用的 JavaScript 模板引擎 ejs 对齐,我们新增了与 ejs 相同的标签规则,这意味着同一套模板可以在 laytpl 和 ejs 中任意切换。 + +作为 Layui 为数不多的一个纯功能型的模块,laytpl 承载了一些重要组件的功能支撑,如 table, dropdown 等,使得它们也能够自定义动态模板,增强了组件的可定制化。当然,laytpl 也可以作为前端单页面应用及 Express 等 Web 框架的视图引擎。 + + diff --git a/docs/menu/examples/demo.md b/docs/menu/examples/demo.md new file mode 100644 index 000000000..e3ea9aaf4 --- /dev/null +++ b/docs/menu/examples/demo.md @@ -0,0 +1,118 @@ + + + + + 基础菜单 - Layui + + + + + + +
                        +
                          +
                        • + +
                        • +
                        • + +
                        • +
                        • +
                        • +
                          + menu group +
                          +
                            +
                          • +
                            menu item 3-1
                            +
                          • +
                          • +
                            menu group 2
                            +
                              +
                            • +
                              menu item 3-2-1
                              +
                            • +
                            • menu item 3-2-2
                            • +
                            +
                          • +
                          • menu item 3-3
                          • +
                          +
                        • +
                        • +
                        • menu item 4 1
                        • +
                        • menu item 5
                        • +
                        • menu item 6
                        • +
                        • +
                          + menu item 7 Children + +
                          +
                          +
                            +
                          • +
                            + menu item 7-1 + +
                            +
                            +
                              +
                            • menu item 7-2-1
                            • +
                            • menu item 7-2-2
                            • +
                            • menu item 7-2-3
                            • +
                            • menu item 7-2-4
                            • +
                            +
                            +
                          • +
                          • menu item 7-2
                          • +
                          • menu item 7-3
                          • +
                          +
                          +
                        • +
                        • menu item 8
                        • +
                        • +
                        • +
                          menu group 9
                          +
                            +
                          • menu item 9-1
                          • +
                          • +
                            + menu item 9-2 + +
                            +
                            +
                              +
                            • menu item 9-2-1
                            • +
                            • menu item 9-2-2
                            • +
                            • menu item 9-2-3
                            • +
                            +
                            +
                          • +
                          • menu item 9-31
                          • +
                          +
                        • +
                        • +
                        • menu item 10
                        • +
                        +
                        + + + + + + diff --git a/docs/menu/index.md b/docs/menu/index.md new file mode 100644 index 000000000..35e616b3c --- /dev/null +++ b/docs/menu/index.md @@ -0,0 +1,64 @@ +--- +title: 基础菜单 menu +toc: true +--- + +# 基础菜单 + +> 基础菜单 `menu` 是垂直导航菜单的另一个替代方案,它是基于 `dropdown` 组件驱动的静态元素结构。 + +

                        示例

                        + +
                        +  
                        +
                        + +

                        结构

                        + +基础菜单层级与样式结构如下: + +- 通过 `
                          ` 命名基础菜单容器 + - 追加 `className` 为 `lay-menu-lg` 可设置基础菜单的大尺寸风格 + - 追加 `lay-accordion` 属性可设置手风琴效果 2.8.18+ + - 通过 `
                        • ` 放置菜单列表项 + - 属性: + - 追加 `className` 为 `lay-menu-item-group` 可设置当前菜单为菜单组,即子菜单为纵向层级。 + - 或追加 `className` 为 `lay-menu-item-parent` 可设置当前菜单为父级菜单,即子菜单为横向层级。 + - 追加 `className` 为 `lay-menu-item-divider` 可设置分隔线。 + - 追加 `className` 为 `lay-menu-item-up` 或 `lay-menu-item-down` 可设置子菜单默认收缩或展开。 + - 追加 `className` 为 `lay-menu-item-checked` 可设置当前菜单为选中状态 + - 添加 `lay-options="{}"` 可设置对应菜单列表的基础属性 + - 内容: + - 通过 `
                          ` 放置菜单标题容器 + - 通过 `
                          ` 放置横向子菜单外层面板 + - 通过 `
                          ` 放置子菜单列表,其中 `
                        • ` 中的规则同父级。 +- 再将基础菜单放置在一个面板容器中,以更好地定义尺寸、边框或阴影等外观,详细可参考上述示例。 + + +

                          属性

                          + +属性即命名在基础菜单列表元素 `
                        • ` 中的 `lay-options` 属性值,如:`
                        • `,其支持的属性如下: + +| 属性 | 描述 | +| --- | --- | +| title | 设置菜单标题。默认读取标题容器内容中的文本。 | +| type | 设置菜单类型。可选值如下:
                          • 若不设定,则表示为常规菜单项
                          • `type:'group'` 菜单组,子菜单为纵向层级
                          • `type:'parent'` 父级菜单,子菜单为横向层级
                          | +| isAllowSpread | 子菜单是否允许展开收缩操作。默认 `true` | + +

                          事件

                          + +`dropdown.on('click(filter)', callback)` + +- 参数 `click(filter)` 是一个特定结构。 + - `click` 为基础菜单项点击事件固定值; + - `filter` 为基础菜单容器属性 `lay-filter` 对应的值。 +- 参数 `callback` 为事件执行时的回调函数,并返回一个 object 类型的参数。 + +点击菜单列表项时触发。用法:[#详见示例](#examples) + +## 贴士 + +基础菜单相当于是 `dropdown` 组件的一种静态化呈现,因此在事件等动态操作上需借助 `dropdown` 组件的 API 来完成。 + diff --git a/docs/modules.md b/docs/modules.md new file mode 100644 index 000000000..8864c8326 --- /dev/null +++ b/docs/modules.md @@ -0,0 +1,297 @@ +--- +title: 模块系统 +toc: true +--- + +

                          模块系统

                          + +> Layui 制定了一套适合自身应用场景的轻量级模块规范,以便在不同规模的项目中,也能对前端代码进行很好的管理或维护。 Layui 的轻量级模块系统,并非有意违背 CommonJS 和 ES Module ,而是试图以更简单的方式去诠释高效,这种对*返璞归真*的执念源于在主流标准尚未完全普及的前 ES5 时代,后来也成为 Layui 独特的表达方式,而沿用至今。 + +如下是一个关于模块的简单示例: + +``` +// 定义模块(通常单独作为一个 JS 文件) +layui.define([mods], function(exports){ + // … + + exports('mod1', api); // 输出模块 +}); + +// 使用模块 +layui.use(['mod1'], function(args){ + var mod1 = layui.mod1; + + // … +}); +``` + +我们可以将其视为「像使用普通 API 一样来管理模块」,在此前提下,组件的承载也变得轻松自如,我们完全可以游刃在以浏览器为宿主的原生态的 HTML/CSS/JavaScript 的开发模式中,而不必卷入层出不穷的主流框架的浪潮之中,给心灵一个栖息之所。 + +当然,Layui 自然也不是一个模块加载器,而是一套相对完整的 UI 解决方案,但与 Bootstrap 又并不相同,除了 HTML+CSS 本身的静态化处理,Layui 的组件更倾向于 JavaScript 的动态化渲染,并为之提供了相对丰富和统一的 API,使用时,只需稍加熟悉,便可在各种交互中应付自如。 + + +

                          定义模块

                          + +`layui.define([mods], callback);` + +- 参数 `mods` 可选,用于声明该模块所依赖的模块; +- 参数 `callback` 即为模块加载完毕的回调函数,它返回一个 `exports` 参数,用于输出该模块的接口。 + +``` +/** demo.js **/ +layui.define(function(exports){ + // do something + + // 输出 demo 模块 + exports('demo', { + msg: 'Hello Demo' + }); +}); + +// 若该模块需要依赖别的模块,则在 `mods` 参数中声明即可: +// layui.define(['layer', 'form'], callback); +``` + +如上所示,`callback` 返回的 `exports` 参数是一个函数,它接受两个参数:参数一为*模块名*,参数二为*模块接口*。 + +另外, `callback` 将会在初次加载该模块时被自动执行。而有时,在某些特殊场景中可能需要再次执行该 `callback`,那么可以通过 `layui.factory(mod)` 方法获得。如: + +``` +var demoCallback = layui.factory('demo'); // 得到定义 demo 模块时的 `callback` +``` + +- **模块命名空间** + +Layui 定义的模块将会被绑定在 `layui` 对象下,如:`var demo = layui.demo;` 每个模块都有一个特定命名,且无法被占用,所以你无需担心模块的命名空间被污染,除非通过 `layui.disuse([mods])` 方法弃用已定义的模块。 + +以下是定义一个「依赖 Layui 内置模块」的模块示例: + +``` +layui.define(['layer', 'laydate'], function(exports){ + var layer = layui.layer // 获得 layer 模块 + var laydate = layui.laydate; // 获得 laydate 模块 + + // 输出模块 + exports('demo', {}); // 模块名 demo 未被占用,此时模块定义成功 + // exports('layer', {}); // 模块名 layer 已经存在,此时模块定义失败 +}); +``` + +同样的,在「扩展模块」时,也同样不能命名已经存在的模块名。 + + +

                          使用模块

                          + +`layui.use([mods], callback);` + +- 参数 `mods` 若填写,必须是已被成功定义的模块名; +
                          2.6+:若 mods 不填,即只传一个 callback 参数时,则表示引用所有内置模块。 +- 参数 `callback` 即为使用模块成功后回调函数。 +
                          2.6+:该回调会在 html 文档加载完毕后再执行,确保你的代码在任何地方都能对元素进行操作。 + +``` +// 使用指定模块 +layui.use(['layer', 'table'], function(){ + var layer = layui.layer; + var table = layui.table; + + // do something +}); + +// 使用所有内置模块(layui v2.6 开始支持) +layui.use(function(){ + var layer = layui.layer; + var table = layui.table; + var laydate = layui.laydate; + // … + + // do something +}); +``` + +你还可以通过 `callback` 返回的参数得到模块对象,如: + +``` +layui.use(['layer', 'table'], function(layer, table){ + // 使用 layer + layer.msg('test'); + + // 使用 table + table.render({}); +}); +``` + +- **执行「定义模块」时的回调函数** + +在上文的定义模块中,我们提到一个特殊场景,即重新获取定义模块时的 `callback` 函数, 譬如在*单页面应用*开发中,我们在视图碎片中使用某个模块,由于定义模块时的 `callback` 只会在模块初次加载中被调用,而当视图碎片在每次被渲染时,又往往需要该 `callback` 被再次执行,那么则可以通过以下方式实现: + +``` +// 在单页面视图碎片渲染时,再次调用「定义模块」时的 `callback` +layui.use('demo', layui.factory('demo')); +``` + +

                          扩展模块

                          + +`layui.extend(settings);` + +- 参数 `settings` : 扩展模块的相关配置,如模块名、模块路径等。 + +除了 Layui 的内置模块,在实际项目开发时,必不可少也需要扩展模块。我们在前文的「模块命名空间」提到,模块名具有唯一性,即不可被占用,因此我们扩展的模块必须是一个未被定义过的模块名。 + +现在,让我们尝试扩展一个 Layui 第三方模块。 + +### 扩展遵循 Layui 规范的模块 + +1. **创建模块和定义模块** + +假设创建一个模块名为 `testModule` 的模块,新建 `testModule.js` 文件并放入项目的任意目录中(但应避免放入到 Layui 原始目录)。接着我们开始定义 `testModule` 模块,并编写该模块主体代码。 + +```js +/** + * 定义 testModule 模块 + **/ +layui.define(function(exports){ // 也可以依赖其他模块 + var obj = { + hello: function(str){ + alert('Hello '+ (str || 'TestModule')); + } + }; + + // 输出 testModule 接口 + exports('testModule', obj); +}); +``` + +2. **声明模块和使用模块** + +现在,我们只需声明模块名及模块文件路径,即完成模块扩展。 + +```js +// 假设 testModule 模块文件所在路径在:/js/layui_exts/testModule.js +layui.config({ + base: '/js/layui_exts/' // 设置用于扩展模块的基础路径 +}).extend({ + testModule: 'testModule', // 定义模块名和模块路径,会前置追加 base 基础路径 + // test1: 'test1' // 还可同时声明其他更多模块 +}); + +// 也可以不前置追加 base 基础路径,即设置单独路径 +layui.extend({ + testModule: '{/}/js/layui_exts/testModule' // 开头特定符 {/} 即代表采用单独路径 +}); + +// 然后我们就可以像使用内置模块一样使用扩展模块 +layui.use(['testModule', 'test1'], function(){ + var testModule = layui.testModule; + // var test1 = layui.test1; + + testModule.hello('World'); +}); +``` + +

                          扩展任意外部模块 2.11+

                          + +我们在 `2.11.0` 版本新增了无缝扩展任意外部模块的支持,即无需遵循 Layui 模块规范的第三方库也能通过 Layui 去加载,并且无需对外部模块做任何的代码改动,只需在 `layui.extend()` 方法中声明模块名、路径和接口即可。 + +当声明的模块接受的是一个 `object` 类型时,即意味着声明任意外部模块。声明外部模块的对象由以下选项组成: + +- `src` : 模块路径,可以是项目的相对路径,也可以是任意外部模块的公共 CDN 地址; +- `api` : 接口名称,通常是模块提供的全局对象 + +下面是一个扩展任意外部模块的示例: + +```js +// 扩展任意外部模块 +layui.extend({ + marked: { + src: 'https://cdnjs.cloudflare.com/ajax/libs/marked/15.0.7/marked.min.js', // 模块路径 + api: 'marked' // 接口名称 + }, + Prism: { + src: 'https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js', + api: 'Prism' + } +}); + +// 加载扩展模块 +layui.use(['marked', 'Prism'], function() { + console.log('任意外部模块 loaded: ') + console.log(' > marked: ', layui.marked); + console.log(' > Prism: ', layui.Prism); +}); +``` + +> 扩展模块是项目开发的重要环节,它既可以是工具性组件,也可以是纯业务组件,是 Layui 的延伸,也是项目的支撑。 + + +

                          建立模块入口

                          + +在不同的页面中,可能需要用到不同的业务模块。以首页为例: + +``` + + +``` + +上述的 `index` 模块即对应的模块文件 `/js/modules/index.js`,它同样也必须符合 Layui 模块规范。如: + +``` +/** + * index.js 首页业务模块 + */ +layui.define(['layer', 'form'], function(exports){ + var layer = layui.layer; + var form = layui.form; + + layer.msg('Hello Index'); + + exports('index', {}); // 输出模块名需和 use 和 extend 时的模块名一致 +}); +``` + +**合并模块入口** + +当项目存在许多不同的业务模块(且存在一定的依赖关系),我们又希望在页面中建立统一的入口模块。如: + +``` +// mod1.js +layui.define('layer', function(exports){ + // … + exports('mod1', {}); +}); + +// mod2.js,假设依赖 mod1 和 form +layui.define(['mod1', 'form'], function(exports){ + // … + exports('mod2', {}); +}); + +// mod3.js +// … + +// index.js 主入口模块 +layui.define('mod2', function(exports){ + // … + exports('main', {}); +}); +``` + +我们可以将上述模块合并为一个文件来加载,即借助构建工具(如 Gulp)将上述的 mod1、mod2、mod3、index 等业务模块合并到一个模块文件:`index.js`,此时只需在页面统一加载该模块即可。这样我们最多只需要加载两个 JS 文件:`layui.js、index.js`,这将大幅度减少静态资源的请求。 + + + +
                          + +## 小贴士 + +> 综上: Layui 轻量级模块系统,无非就是:定义模块、使用模块、弃用模块、扩展模块的相互呼应,翻译成 API 即: +> - `layui.define();` +> - `layui.use();` +> - `layui.disuse();` +> - `layui.extend();` +> --- +> 熟练运用,可让您的项目更利于维护。 diff --git a/docs/nav/examples/side.md b/docs/nav/examples/side.md new file mode 100644 index 000000000..4b0c6affd --- /dev/null +++ b/docs/nav/examples/side.md @@ -0,0 +1,43 @@ + + + + + 侧边垂直导航 - Layui + + + + + + + + + + + + + diff --git a/docs/nav/index.md b/docs/nav/index.md new file mode 100644 index 000000000..1e93ee320 --- /dev/null +++ b/docs/nav/index.md @@ -0,0 +1,348 @@ +--- +title: 导航菜单 nav +toc: true +--- + +# 导航菜单 + +> 导航菜单包含水平导航和垂直导航, 在 `2.x` 版本中,`nav` 组件属于 `element` 模块的子集。 + +

                          水平导航

                          + +一般用于页面头部菜单。样式规则如下: + +- 通过 `class="lay-nav"` 设置导航容器 +- 通过 `class="lay-nav-item"` 设置导航菜单项 + - 追加 `className` 为 `lay-this` 可设置菜单选中项 +- 通过 `class="lay-nav-child"` 设置导航子菜单项 + - 追加 `className` 为 `lay-nav-child-c` 和 `lay-nav-child-r` 可设置子菜单居中和向右对齐 + + +

                          常规用法

                          + +
                          +  
                          +
                          + +备注:滑块效果仅跟随不存在子菜单的菜单项。 + +

                          加入徽章等元素

                          + +
                          +  
                          +
                          + +

                          导航主题

                          + +给导航容器追加任意背景色 `class`,内置背景色参考:[#背景色公共类](../class/#bg) + +
                          +  
                          +
                          + + +

                          垂直导航

                          + +一般用于左侧侧边菜单。样式规则如下: + +- 在水平导航的 `class` 规则上,通过设置 `class="lay-nav lay-nav-tree"` 定义垂直导航容器。 +- 通过 `class="lay-nav-itemed"` 设置父菜单项为展开状态 +- 通过给导航容器追加 `class="lay-nav-side"` 可设置侧边垂直导航 +- 其余结构及填充内容与水平导航完全相同 + +
                          +  
                          +
                          + +

                          侧边垂直导航

                          + +
                          +  
                          +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var element = layui.element | 获得 `element` 模块。 | +| [element.render(\'nav\', \'filter\')](#render) | 导航菜单 `nav` 组件渲染。 | + +

                          渲染

                          + +`element.render('nav', filter);` + +- 参数 `'nav'` 是渲染导航的固定值 +- 参数 `filter` : 对应导航容器 `lay-filter` 的属性值或2.9.15+指定元素的 jQuery 对象 + +`nav` 组件会在元素加载完毕后,自动对导航完成一次渲染,因此该方法主要用于对动态插入的导航元素的初始化渲染。 + +``` +
                          + + + +``` + +

                          属性

                          + +| 属性 | 描述 | +| --- | --- | +| lay-accordion 2.8.18+ | 导航容器属性。用于开启垂直导航菜单展开时的手风琴效果。如:
                          `
                          ` | +| lay-bar | 导航容器属性。用于禁用滑块跟随功能。如:
                          `
                          ` | +| lay-unselect | 导航菜单项属性。 设置后,点击对应菜单项时,不会出现选中效果。 | + + +

                          事件

                          + +`element.on('nav(filter)', callback)` + +- 参数 `nav(filter)` 是一个特定结构。 + - `nav` 为导航事件固定值; + - `filter` 为导航容器属性 `lay-filter` 对应的值。 +- 参数 `callback` 为事件执行时的回调函数,并返回一个 `object` 类型的参数。 + +当点击导航父级菜单和二级菜单时触发。示例: + +
                          +  
                          +
                          + +

                          面包屑导航

                          + +面包屑导航主要用于指示当前页面所处的位置,并能返回到上级页面。 + +
                          +  
                          +
                          + +### **面包屑导航渲染** + +`element.render('breadcrumb', filter);` + +- 参数 `'breadcrumb'` 是渲染面包屑导航的固定值 +- 参数 `filter` : 对应面包屑导航容器 `lay-filter` 的属性值或2.9.15+指定元素的 jQuery 对象 + +该方法主要用于对动态插入的面包屑导航的初始化渲染,用法同上述导航菜单。 + diff --git a/docs/panel/index.md b/docs/panel/index.md new file mode 100644 index 000000000..d00466bad --- /dev/null +++ b/docs/panel/index.md @@ -0,0 +1,289 @@ +--- +title: 面板 panel,card,collapse +toc: true +--- + +# 面板 + +> 面板是一个包含普通面板(panel)、卡片面板(card)、折叠面板(collapse)的集合 + +

                          常规面板

                          + +常规面板通常作为包裹其他元素的形式存在,如与基础菜单 `menu` 经常搭配使用。 + +
                          +  
                          +
                          + +

                          卡片面板

                          + +
                          +  
                          +
                          + +

                          折叠面板

                          + +
                          +  
                          +
                          + + +

                          开启手风琴

                          + +在折叠面板容器上追加 `lay-accordion` 属性,开启手风琴效果,即点击展开当前面板的同时,折叠其他面板。 + +
                          +  
                          +
                          + +

                          折叠面板嵌套

                          + +折叠面板内部支持无限嵌套,即折叠面板中再放置无限层级的折叠面板,以实现树形折叠结构。如: + +
                          +  
                          +
                          + + +

                          折叠面板渲染

                          + + +`element.render('collapse', filter);` + +- 参数 `'collapse'` : 渲染折叠面板的固定值 +- 参数 `filter` : 对应折叠面板容器 `lay-filter` 的属性值或2.9.15+指定元素的 jQuery 对象 + +在元素加载完毕后,`element` 模块会自动对元素进行一次渲染。而当元素为动态插入时,需通过该方法完成初始化渲染。 + + +

                          折叠面板事件

                          + +`element.on('collapse(filter)', callback)` + +- 参数 `collapse(filter)` 是一个特定结构。 + - `collapse` 为折叠面板点击事件固定值; + - `filter` 为导航容器属性 `lay-filter` 对应的值。 +- 参数 `callback` 为事件执行时的回调函数,并返回一个 `object` 类型的参数。 + +
                          +  
                          +
                          + + + diff --git a/docs/progress/index.md b/docs/progress/index.md new file mode 100644 index 000000000..de2718ade --- /dev/null +++ b/docs/progress/index.md @@ -0,0 +1,236 @@ +--- +title: 进度条 progress +toc: true +--- + +# 进度条 + +> 进度条 `progress` 可应用于许多业务场景,如任务完成进度、loading 等等。 + +

                          示例

                          + +
                          +  
                          +
                          + +进度条宽度是 100% 适配于它的父级元素,如上面的进度条是在一个 300px 的父容器中。 + + +

                          进度条主题

                          + +
                          +  
                          +
                          + + +

                          大号进度条

                          + +通过对进度条容器追加 `className` 为 `lay-progress-big` 可设置大尺寸风格的进度条。 + +
                          +  
                          +
                          + + +

                          显示进度值

                          + +
                          +  
                          +
                          + + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var element = layui.element | 获得 `element` 模块。 | +| [element.render(\'progress\', filter)](#render) | 进度条 `progress` 组件渲染。 | +| [element.progress(filter, percent)](#progress) | 设置进度值 | + +

                          渲染

                          + +`element.render('progress', filter);` + +- 参数 `'progress'` : 渲染进度条的固定值 +- 参数 `filter` : 对应进度条容器 `lay-filter` 的属性值或2.9.15+指定元素的 jQuery 对象 + +在元素加载完毕后,element 模块会自动对元素进行一次渲染。而当元素为动态插入时,需通过该方法完成初始化渲染。 + +``` +
                          + + + +``` + + +

                          属性

                          + +| 属性 | 描述 | +| --- | --- | +| lay-percent | 用于设置进度条的值,进度条内层容器属性。支持 *百分比* 和 *分数* 形式。用法详见:[#示例](#examples) | +| lay-showpercent | 是否显示进度值,进度条外层容器属性,默认不显示。用法详见:[#示例](#showpercent) | + + +

                          设置进度值

                          + +`element.progress(filter, percent);` + +- 参数 `filter` : 对应进度条容器 `lay-filter` 的属性值 +- 参数 `'percent'` : 进度条的值 + +该方法用于动态改变进度条的值。示例: + +
                          +  
                          +
                          + + diff --git a/docs/rate/detail/demo.md b/docs/rate/detail/demo.md new file mode 100644 index 000000000..2e01e28e6 --- /dev/null +++ b/docs/rate/detail/demo.md @@ -0,0 +1,187 @@ +
                          +  
                          +
                          + +

                          显示文字

                          + +
                          +  
                          +
                          + +

                          半星效果

                          + +
                          +  
                          +
                          + +

                          自定义文本

                          + +
                          +  
                          +
                          + +

                          自定义长度

                          + +
                          +  
                          +
                          + +

                          只读

                          + +
                          +  
                          +
                          + +

                          自定义主题色

                          + +
                          +  
                          +
                          diff --git a/docs/rate/detail/options.md b/docs/rate/detail/options.md new file mode 100644 index 000000000..168f98166 --- /dev/null +++ b/docs/rate/detail/options.md @@ -0,0 +1,141 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          length + +评分的最大长度值,即星星的数量。 + +number + +`5` + +
                          value + +评分的初始值 + +number + +`0` + +
                          half + +是否可以选择半星。若开启,则 `value` 支持小数点,如: + +``` +value: '3.5' +``` + +boolean + +`false` + +
                          theme + +主题色 + +string + +`#FFB800` + +
                          text + +是否显示评分对应的文本 + +boolean + +`false` + +
                          readonly + +是否只读,即只用于展示,而不可点击 + +boolean + +`false` + +
                          setText + +初始设置自定义文本的回调函数。 并返回当前 `value` 参数。用法详见:[#自定义文本](#demo-setText) + +
                          choose + +选择评分后的回调函数。并返回当前 `value` 参数 + +``` +rate.render({ + elem: '#id', + choose: function(value){ + console.log(value); // 获得选中的评分值 + } +}); +``` + +
                          diff --git a/docs/rate/index.md b/docs/rate/index.md new file mode 100644 index 000000000..81cf7e1df --- /dev/null +++ b/docs/rate/index.md @@ -0,0 +1,58 @@ +--- +title: 评分组件 rate +toc: true +--- + +# 评分组件 + +> 评分组件 `rate` 一般用于等级展示或评价类操作。 + +

                          示例

                          + +
                          +{{- d.include("/rate/detail/demo.md") }} +
                          + +

                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var rate = layui.rate | 获得 `rate` 模块。 | +| [基础接口](../component/#export) 2.11+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [rate.render(options)](#render) | rate 组件渲染,核心方法。 | + +

                          渲染

                          + +`rate.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) +
                          2.8+ : 除 `elem` 属性外,其他基础属性也可以直接写在元素的 `lay-options="{}"` 属性中。 + +``` +
                          +
                          +
                          + + + +``` + +

                          属性

                          + +
                          +{{- d.include("/rate/detail/options.md") }} +
                          diff --git a/docs/slider/detail/demo.md b/docs/slider/detail/demo.md new file mode 100644 index 000000000..89d3399cd --- /dev/null +++ b/docs/slider/detail/demo.md @@ -0,0 +1,288 @@ +
                          +  
                          +
                          + +

                          定义初始值

                          + +
                          +  
                          +
                          + +

                          设置最大和最小值

                          + +
                          +  
                          +
                          + +

                          设置步长

                          + +
                          +  
                          +
                          + +

                          设置提示文本

                          + +
                          +  
                          +
                          + +

                          开启输入框

                          + +
                          +  
                          +
                          + +

                          开启范围选择

                          + +
                          +  
                          +
                          + +

                          垂直滑块

                          + +
                          +  
                          +
                          + +

                          自定义主题色

                          + +
                          +  
                          +
                          + +

                          禁用滑块

                          + +
                          +  
                          +
                          + diff --git a/docs/slider/detail/options.md b/docs/slider/detail/options.md new file mode 100644 index 000000000..e033a80f6 --- /dev/null +++ b/docs/slider/detail/options.md @@ -0,0 +1,268 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          type + +滑块类型,可选值有: + +- `default` 水平滑块(默认) +- `vertical`垂直滑块 + +string + +`default` + +
                          value + +滑块初始值。 + +- 默认可直接设置数值,如: `value: 50` +- 若滑块开启 `range: true` 区间选择,则值为数组,亦表示开始和结尾的区间,如: `value: [30, 60]` + +number
                          array
                          -
                          range + +是否开启滑块的区间选择。若开启,则滑块将出现两个可拖拽的点。 + +boolean + +`false` + +
                          min + +滑块的最小值 + +number + +`0` + +
                          max + +滑块的最大值 + +number + +`100` + +
                          step + +滑块单次拖动的步长 + +number + +`1` + +
                          showstep + +是否显示间断点 + +boolean + +`false` + +
                          tips + +鼠标移入当前圆点,是否显示当前值 + +boolean + +`true` + +
                          tipsAlways 2.9.3+ + +是否始终显示提示文本,要开启此功能,tips 必须设置为 `true` 才能生效 + +boolean + +`false` + +
                          input + +是否显示滑块的数字输入框。 注:若设置 `range: true` 则该属性强制无效。 + +boolean + +`false` + +
                          height + +滑动条高度。 必须设置 `type: 'vertical'` 属性,即垂直滑块时有效。 + +number + +`200` + +
                          theme + +滑块的主题色。 + +string-
                          disabled + +是否禁用滑块 + +boolean + +`false` + +
                          setTips + +滑块拖拽时设置提示文本的回调函数。并返回当前的 `value` 参数。用法详见:[#设置提示文本](#demo-setTips) + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          change + +滑块数值发生改变的回调函数。并返回当前的 `value` 参数。 + +``` +slider.render({ + elem: '#id', + change: function(value){ + console.log(value) // 滑块当前值 + // do something + } +}); +``` + +一般可在该回调中将 `value` 同步给表单隐藏域,或者进行一些其它操作。 + +
                          done 2.8+ + +滑块拖拽完毕的回调函数。并返回当前的 `value` 参数。滑块拖动过程中不会触发。 + +``` +slider.render({ + elem: '#id', + done: function(value){ + console.log(value) // 滑块当前值 + // do something + } +}); +``` + +若需将 `value` 异步发送给后端,一般采用 `done` 回调,而非 `change` 回调。 + +
                          + diff --git a/docs/slider/index.md b/docs/slider/index.md new file mode 100644 index 000000000..1bad6ff50 --- /dev/null +++ b/docs/slider/index.md @@ -0,0 +1,95 @@ +--- +title: 滑块组件 slider +toc: true +--- + +# 滑块组件 + +> 滑块组件 `slider` 是一个拖拽选值的交互性组件,常与 `form` 元素结合使用。 + +

                          示例

                          + + +
                          +{{- d.include("/slider/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var slider = layui.slider | 获得 `slider` 模块。 | +| [基础接口](../component/#export) 2.12+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [var inst = slider.render(options)](#render) | slider 组件渲染,核心方法。 | +| [inst.setValue(value)](#setValue) | 设置滑块值 | +| inst.config | 获得当前实例的属性选项 | + +

                          渲染

                          + +`slider.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) +
                          2.8+ : 除 `elem` 属性外,其他基础属性也可以直接写在元素的 `lay-options="{}"` 属性中。 + +``` +
                          +
                          +
                          + + + +``` + + +该方法返回一个实例对象,包含操作当前实例的相关方法成员。 + +``` +var inst = slider.render(options); +console.log(inst); // 得到当前实例对象 +``` + +

                          设置滑块值

                          + +`inst.setValue(value, index)` + +- 参数 `value` : 要设置的滑块数值 +- 参数 `index` : 滑块所在的区间开始值或结尾值的索引,开始值:`0` ; 结尾值:`1` + +``` +var slider = layui.slider; + +// 渲染 +var inst = slider.render({ + elem: '#id' + // … +}); + +// 设置滑块值 +inst.setValue(20); + +// 若滑块开启了范围,即: `range: true` +ins1.setValue(20, 0) // 设置开始值 +ins1.setValue(60, 1) // 设置结尾值 +``` + +

                          属性

                          + +
                          +{{- d.include("/slider/detail/options.md") }} +
                          + diff --git a/docs/table/detail/demo.md b/docs/table/detail/demo.md new file mode 100644 index 000000000..b489e38e1 --- /dev/null +++ b/docs/table/detail/demo.md @@ -0,0 +1,189 @@ +

                          综合演示 🔥

                          + +
                          +  
                          +
                          + +

                          静态表格

                          + +静态表格是指内容已经存在于页面中的 `` 元素,且可通过一些*特定属性*设定不同风格。 + +
                          +  
                          +
                          + +

                          模板配置渲染

                          + +在上文「[综合演示](#examples)」中,是通过组件核心方法完成的渲染。除此,还可以在模板上直接配置相关属性,让其自动完成渲染。 + +
                          +  
                          +
                          + +

                          静态表格转换

                          + +
                          +  
                          +
                          + +

                          已知数据渲染

                          + +
                          +  
                          +
                          + +

                          自定义模板

                          + +
                          +  
                          +
                          + +

                          自定义样式 2.7+

                          + +
                          +  
                          +
                          + +

                          自定义分页

                          + +
                          +  
                          +
                          + + + +
                          +  
                          +
                          + +

                          编辑的权限控制 2.7+

                          + +以下演示一个根据返回数据中某个字段来判断是否开启该行的编辑,*单击对应行*可进入单元格编辑。 + +
                          +  
                          +
                          + +

                          实现多样化编辑

                          + +
                          +  
                          +
                          + +

                          转换数据格式

                          + +
                          +  
                          +
                          + +

                          筛选列记忆功能

                          + +即点击当前表格右上角筛选图标后,对表头进行显示隐藏勾选,再刷新页面依然保留当前筛选状态。 + +
                          +  
                          +
                          + +

                          选中行操作

                          + +点击行任意处,通过行事件中执行相关选中方法,实现对整行的状态选中。*如下以「单选」行为例:* + +
                          +  
                          +
                          + +

                          多级表头

                          + +
                          +  
                          +
                          + + +

                          更多示例

                          + +> - 🎉 不定期分享在 [Gitee Issues](https://gitee.com/layui/layui/issues) + diff --git a/docs/table/detail/options.ajax.md b/docs/table/detail/options.ajax.md new file mode 100644 index 000000000..e86943aa0 --- /dev/null +++ b/docs/table/detail/options.ajax.md @@ -0,0 +1,226 @@ +
                          + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述
                          url + +发送异步请求的 URL。默认会自动传递两个参数:`?page=1&limit=30`(该参数可通过 `request` 属性自定义) +
                          `page` 代表当前页码、`limit` 代表每页数据条数。 + +
                          method + +请求的方式,默认:`get` + +
                          where + +请求的其他参数。如:`where: {token: 'sasasas', id: 123}` + +
                          headers + +请求的数据头参数。如:`headers: {token: 'sasasas'}` + +
                          contentType + +请求的内容编码类型。若要发送 `json` 内容,可设置:
                          +`contentType: 'application/json'` + +
                          dataType 2.7+ + +请求的数据类型,默认 `json`。 + +
                          jsonpCallback 2.7+ + +设置当 `dataType: 'jsonp'` 时的回调函数名。 + +
                          request + +用于对默认的分页相关的请求参数 `page,limit` 重新设定名称。如: + +``` +request: { + pageName: 'curr', // 页码的参数名称,默认:page + limitName: 'nums' // 每页数据条数的参数名,默认:limit +} +``` + +那么请求数据时的参数将会变为 `?curr=1&nums=30` + +
                          + +[**parseData**](#options.parseData) + + + +
                          + 数据格式解析的回调函数,用于将返回的任意数据格式解析成 table 组件规定的数据格式: +
                          + +``` +{ + "code": 0, + "msg": "", + "count": 1000, + "data": [{}, {}] +} +``` + +很多时候,您接口返回的数据格式并不一定都符合 table 默认规定的格式,比如: + +``` +{ + "status": 0, + "message": "", + "total": 180, + "data": { + "item": [{}, {}] + } +} +``` + +此时我们可以借助 `parseData` 回调函数将数据解析并转换为默认规定的格式: + +``` +table.render({ + elem: '', + url: '', + parseData: function(res){ // res 即为原始返回的数据 + return { + "code": res.status, // 解析接口状态 + "msg": res.message, // 解析提示文本 + "count": res.total, // 解析数据长度 + "data": res.data.item // 解析数据列表 + }; + }, + // … //其他参数 +}); +``` + +该函数非常实用 + + +
                          + +[**ajax**](#options.ajax) 2.12+ + + + +
                          + 自定义 ajax 请求,用于发送异步请求。 +
                          + +```js +table.render({ + // 自定义 ajax 请求 + // origOptions - 包含了原始的请求参数 + // type - 执行 ajax 请求的来源,'table' 或 'treeNodes' + ajax: function (origOptions, type) { + $.ajax({ + url: origOptions.url, + data: origOptions.data, + dataType: origOptions.dataType, + }) + .done(function (data) { + // 调用原始的 success 回调 + origOptions.success(data); + }) + .fail(function (xhr, status, error) { + // 调用原始的 error 回调 + origOptions.error(xhr, status, error); + }) + .always(function () { + // 调用原始的 complete 回调 + if (typeof origOptions.complete === "function") { + origOptions.complete(); + } + }); + } +}); + +``` + +
                          + +

                          返回数据中的特定字段

                          + +在返回的数据中,允许规定某些特定字段,以便 table 组件进行相应的特定解析。 + +| 特定字段名 | 描述 | 读写状态 | +| --- | --- | --- | +| LAY_CHECKED | 当前行的选中状态 | 可读可写 | +| LAY_DISABLED | 当前行是否禁止选择 | 可读可写 | +| LAY_INDEX | 当前行下标。每页重新从零开始计算 | 只读 | +| LAY_NUM | 当前行序号 | 只读 | +| LAY_COL | 当前列的表头属性选项 | 只读 | + +示例一: 在返回的数据中设置特定字段: + +``` +{ + "code": 0, + "count": 1000, + "data": [{},{ + LAY_DISABLED: true + }] +} +``` + +示例二: 在模板中读取特定字段示例: + +{{! +``` + +``` +!}} + diff --git a/docs/table/detail/options.cols.md b/docs/table/detail/options.cols.md new file mode 100644 index 000000000..6c88fe860 --- /dev/null +++ b/docs/table/detail/options.cols.md @@ -0,0 +1,482 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          field + +设置字段名。通常是表格数据列的唯一标识 + +string-
                          title + +设置列的标题。 + +string-
                          fieldTitle 2.8+ + +设置列的字段标题。该属性在筛选列和导出场景中优先级高于 `title` 属性 + +string-
                          width + +设置列宽。若不填写,则自动分配;若填写,则支持值为:*数字、百分比*。如: +`width: 200` / `width: '30%'` + +number/string-
                          minWidth + +设置当前列的最小宽度,一般用于列宽自动分配的情况。其优先级高于基础属性中的 `cellMinWidth` + +number + +`60` + +
                          maxWidth 2.8+ + +设置当前列的最大宽度。其优先级高于基础属性中的 `cellMaxWidth` + +number-
                          expandedWidth 2.8.15+ + +设置单元格被展开后的宽度。若设置的值的小于当前列宽,则展开后的列宽保持不变。注:当 `expandedMode` 属性为默认值时有效。 + +number-
                          expandedMode 2.8.17+ + +用于设置所有单元格默认展开方式,可选值有: + +- `tips` 悬浮展开方式 +- `default` 多行展开方式(默认) + +优先级高于 `cellExpandedMode` 基础属性 + +string-
                          type + +设置列类型。可选值有: +- `normal` 常规列,无需设定 +- `checkbox` 复选框列 +- `radio` 单选框列 +- `numbers` 序号列 +- `space` 空列 + +string + +`normal` + +
                          LAY_CHECKED + +设置全选状态,当列设置 `type: 'checkbox'` 时才有效。 + +boolean + +`false` + +
                          fixed + +设置固定列,即不跟随 table 横向滚动条而滚动。可选值有: +- `left` 固定在左 +- `right` 固定在右 + +多级表头设置固定列时,父列和子列均需设置。 + +string-
                          + +[templet](#cols.templet) + + + +
                          + 设置列的自定义模板,核心属性。模板遵循 laytpl 组件语法。 +
                          + + `templet` 提供了三种使用方式,选择任一用法即可: + +- **设置模版选择器** + +{{! +``` + + + +``` + +``` +table.render({ + cols: [[ + {field: 'title', templet: '#TPL-demo-title'} + // … + ]], + // … +}); +``` +!}} + +- **设置模板内容** + +{{! +``` +table.render({ + cols: [[ + {field: 'title', templet: ''} + // … + ]], + // … +}); +``` +!}} + +- **设置模板函数** + +函数将返回一个 `d` 参数,包含当前行数据及特定的额外字段。 +``` +table.render({ + cols: [[ + {field: 'title', templet: function(d){ + console.log(d); // 得到当前行数据 + console.log(this); // 得到表头当前列配置项 + console.log(d.LAY_NUM); // 得到序号。或其他特定字段 + + // 返回模板内容 + return ''+ d.title +'' + }} + // … + ]], + // … +}); +``` + +
                          exportTemplet 2.6.9+ + +
                          + +设置表格导出时的模板,用法同 `templet` 属性。当 `templet` 指向的模板内容较复杂时建议使用,如下以模板存在 `select` 元素为例: + +
                          + +``` +exportTemplet: function(d, obj){ + // 当前 td + var td = obj.td(this.field); + // 返回 select 选中值 + return td.find('select').val(); +} +``` + +
                          + + [totalRow](#cols.totalRow) + + + +
                          + 是否开启该列的自动合计功能,默认不开启。 +
                          + +- **采用前端合计** + +{{! +``` +// 开启并输出合计行前端合计结果 +totalRow: true + +// 开启并输出合计行自定义模板。此处 TOTAL_NUMS 即为合计结果的固定特定字段 +totalRow: '{{= d.TOTAL_NUMS }} 单位' +// 取整或其他运算 +totalRow: '{{= parseInt(d.TOTAL_NUMS) }}' +``` +!}} + +注意:*合计行模板仅支持字符写法,不支持函数写法,请勿与 `templet` 用法混淆。* + +- **采用后端合计** + +前端合计的数据有限,因此常需要后端直接返回合计结果,组件将优先读取。数据格式如下: + +``` +{ + "code": 0, + "totalRow": { + "score": "777", + "experience": "999" + }, + "data": [{}, {}], + "msg": "", + "count": 1000 +} +``` + +在合计行自定义模板中输出后端返回的合计数据 + +{{! +``` +// 获取后端接口返回数据中的统计字段。此处 TOTAL_ROW 即对应返回据中的 totalRow +totalRow: '分数:{{= d.TOTAL_ROW.score }}' +``` +!}} + +如上,在 `totalRow` 中返回所需统计的列字段名和值即可。 +`totalRow` 字段同样可以通过 `parseData` 回调来解析成为 table 组件所规定的数据格式。 + + +
                          + +[edit](#cols.edit) + + + +
                          + 用于对列所在的单元格开启编辑功能。可选值有: +
                          + +- `edit: 'text'` 单行输入模式 +- `edit: 'textarea'` 多行输入模式 2.7+ + +**函数写法** 2.7+ + +``` +edit: function(d){ + // d 即为当前行数据,此时可根据行相关字段来开启该行是否编辑的权限 + if(d.editable){ // editable 为任意字段名 + return 'text'; // 编辑模式 + } +} +``` + + +
                          string
                          function
                          + +`false` + +
                          hide + +是否初始隐藏列 + +boolean + +`false` + +
                          ignoreExport 2.8.3+ + +是否导出时忽略该列。支持以下可选值: + +- `true` : 忽略导出 +- `false` : 强制导出,对所有列适用 +- `null` : 只对常规列导出(默认) + +boolean-
                          escape + +是否对当前列进行内容编码(转义 html),优先级大于基础属性中的 `escape`。 + +boolean + +`true` + +
                          sort + +是否开启列的排序功能。
                          +注意:不推荐对值同时存在“数字和普通字符”的列开启排序,因为会进入字典序排序计算中,如:`'张三' > '2' > '100'`,这可能并不是你想要的结果,但字典序排列采用的是 `ASCII` 码比对。 + +
                          boolean + +`false` + +
                          unresize + +是否禁用拖拽列宽。默认情况下会根据列类型 `type` 属性来决定是否禁用,如复选框列,会自动禁用。而其它普通列,默认允许拖拽列宽,当然你也可以设置 true 来禁用该功能。 + +boolean + +`false` + +
                          event + +自定义单元格点击事件名,以便在 [单元格工具事件](#on-tool) 中完成对该单元格的事件处理。 + +string-
                          style + +自定义单元格样式。可传入任意的 CSS 内容,如:`style: 'font-size: 13px; color: red;'` + +string-
                          align + +单元格排列方式。可选值有:`left` | `center` | `right` + +string + +`left` + +
                          colspan + +单元格所占列数。一般用于多级表头 + +number + +`1` + +
                          rowspan + +单元格所占行数。一般用于多级表头 + +number + +`1` + +
                          + diff --git a/docs/table/detail/options.md b/docs/table/detail/options.md new file mode 100644 index 000000000..2bf543460 --- /dev/null +++ b/docs/table/detail/options.md @@ -0,0 +1,606 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem绑定原始 table 元素,方法渲染方式必填。string/DOM-
                          + +[url](#options.ajax) + + + +发送异步请求的 URL。更多异步相关属性见 : [#异步属性](#options.ajax) + +--
                          + +[cols](#options.cols) + + + +表头属性集,通过二维数组定义多级表头。方法渲染时必填。 更多表头属性见 : [#表头属性](#options.cols) + +array-
                          data + +直接赋值数据。既适用于只展示一页数据,也能对一段已知数据进行多页展示。该属性与 `url` 属性只能二选一。 + +
                          + +**注**:当设置 `data` 模式时,`count` 的值取 `data.length`,即对一段已知数据进行分页展示。 此时在 `page` 属性中设置 `count` 无效。 若要在同一页显示所有数据,可将 `limit` 设置成 `data.length`,即与 `count` 等同即可,那么默认的分页栏只会显示 1 页,若要自定义分页结构,可通过 `pagebar` 属性结合 `laypage` 组件来重新自定义分页排版。 + +
                          array-
                          id + +设定实例唯一索引,以便用于其他方法对 table 实例进行相关操作。若该属性未设置,则默认从 `elem` 属性绑定的原始 table 元素中的 `id` 属性值中获取。 + +string-
                          toolbar + +开启表格头部工具栏。支持以下几种值写法: + +- `toolbar: '#template-id'` 自定义工具栏模板选择器 +- `toolbar: '
                          xxx
                          '` 直接传入模板字符 +- `toolbar: true` 仅开启工具栏右侧,不显示左侧模板 +- `toolbar: 'default'` 开启工具栏并显示默认模板 + +
                          string
                          boolean
                          + +`false` + +
                          + +[defaultToolbar](#options.defaultToolbar) + + + +
                          + 设置头部工具栏右上角工具图标,值为一个数组,图标将根据数组值的顺序排列。 +
                          + +**默认内置工具**: + +```js +defaultToolbar: [ + 'filter', // 列筛选 + 'exports', // 导出 + 'print' // 打印 +] +``` + +**重写内置工具** 2.9.12+,以自定义导出为例: + +
                          + + +```js +defaultToolbar: [ + 'filter', + { + name: 'exports', + onClick: function(obj) { + // 获得数据并清除临时字段 + var data = table.clearCacheKey(obj.data); + // 当前示例配置项 + var options = obj.config; + + // 弹出面板 + obj.openPanel({ + list: [ // 列表 + '
                        • 导出 CSV 文件
                        • ', + '
                        • 导出 XLSX 文件
                        • ' + ].join(''), + done: function(panel, list) { // 操作列表 + list.on('click', function() { + var type = $(this).data('type') + if (type === 'csv') { + // 调用内置导出方法 + table.exportFile(options.id, null, type); + } else if(type === 'xlsx') { + // 自助处理导出 - 如借助 sheetjs 库或服务端导出 + // … + } + }); + } + }); + } + }, + 'print' +] +``` + +
                          + +**扩展工具图标**: + +```js +defaultToolbar: [ + 'filter', 'exports', 'print', // 内置工具 + { + // 扩展工具 + title: '提示', // 标题 + name: 'tips', // name + layEvent: 'LAYTABLE_TIPS', // 事件标识 + icon: 'lay-icon-tips', // 图标 className + onClick: function(obj) { // 点击事件 - 2.9.12+ + console.log(obj); // 查看返回的对象成员 + } + } +] +``` + +
                          width设置容器宽度,默认自适应。number-
                          + +[height](#options.height) + + + +
                          + 设置表格容器高度,默认自适应。其他可选值的规则如下: +
                          + +- `height: 315` 设置固定高度 +- `height: 'full-30'` 设置相对可视屏幕的高度铺满。这是一个特定的语法格式:`full` 表示铺满;后面的数字表示当前 table 之外的元素占用的高度,如:表格头部到页面最顶部*加*表格底部距离页面最底部的“距离和” +- `height: '#id-30'` 设置相对父元素的高度铺满,其中 `#id` 即父元素的 ID 选择器,其计算原理和上述 `full` 相同。 + +**函数写法** 2.9.1+ + +当需要动态改变表格高度时建议使用,如下以等效 `full-xx` 的写法为例: + +```js +height: function(){ + // 自定义其他区域的高度 + var otherHeight = $('#search-content').outerHeight(); + return $(window).height() - otherHeight; // 返回 number 类型 +} +``` + +
                          maxHeight 2.8+ + +设置表格容器的最大高度,设置该属性后,`height` 属性将被认定为默认的自适应值。 + +number-
                          cellMinWidth + +设置所有普通单元格的最小宽度,一般用于列宽自动分配的情况。其优先级低于表头属性中的 `minWidth` + +number + +`60` + +
                          cellMaxWidth 2.8+ + +设置所有普通单元格的最大宽度。其优先级低于表头属性中的 `maxWidth` + +number-
                          lineStyle 2.7+ + +用于定义表格的多行样式,如每行的高度等。该参数一旦设置,单元格将会开启多行模式,且鼠标 hover 时会通过显示滚动条的方式查看到更多内容。 请按实际场景使用。
                          示例:`lineStyle: 'height: 95px;'` + +
                          string-
                          syncFixedRowHeight 2.12+ 实验性 + +是否强制计算表格主区域的行高度并同步到固定列区域。开启后会对表格性能有一定的影响,仅适用于行高度自适应的场景。 +该功能使用 [ResizeObserver](https://developer.mozilla.org/zh-CN/docs/Web/API/ResizeObserver) 实现,如果你的浏览器不支持 `ResizeObserver`,可以尝试添加 [polyfill](https://github.com/que-etc/resize-observer-polyfill) 来解决兼容性问题。 + +boolean-
                          className 2.7+用于给表格主容器追加 css 类名,以便更好地扩展表格样式string-
                          css 2.7+ + +用于给当前表格主容器直接设定 css 样式,样式值只会对所在容器有效,不会影响其他表格实例。如:`css: '.lay-table-page{text-align: right;}'` + +string-
                          cellExpandedMode 2.8.17+ + +用于设置所有单元格默认展开方式,可选值有: + +- `tips` 悬浮展开方式 +- `default` 多行展开方式(默认) + +string-
                          cellExpandedWidth 2.8.17+ + +用于设置所有单元格默认展开后的宽度。当 `cellExpandedMode` 属性为默认值时有效。 + +number + +`60` + +
                          escape 2.6+是否开启对内容的编码(转义 html)boolean + +`true` + +
                          totalRow是否开启合计行区域string + +`false` + +
                          page + +用于开启分页。
                          +支持传入 [laypage](../laypage/#options) 组件的基础属性(jump,elem 除外) + +
                          boolean
                          object
                          + +`false` + +
                          pagebar 2.7+ + +用于开启分页区域的自定义模板,用法同 `toolbar` 属性。 + +string-
                          limit + +每页显示的条数。值需对应 limits 参数的选项。优先级低于 `page` 属性中的 `limit` 属性。 + +number + +`10` + +
                          limits每页条数的选择项。array + +`[10,…,90]` + +
                          loading + +设置数据请求时的加载动画,需开启 `url` 选项才生效。 + +- 若值为 `boolean` 类型,表示是否显示加载条,如: +``` +loading: true // 显示默认加载条 +loading: false // 禁用加载条 +``` + +- 若值为 `string` 类型 2.9.10+,表示自定义加载模板,此时可添加任意动画元素,如: +``` +loading: '' +``` + +boolean
                          string
                          + +`true` + +
                          scrollPos 2.7+ + +用于设置重载数据或切换分页时的滚动条位置状态。可选值: +- `fixed` 重载数据时,保持滚动条位置不变 +- `reset` 重载数据时,滚动条位置恢复置顶 +- `default` 默认方式,无需设置。即重载数据或切换分页时,纵向滚动条置顶,横向滚动条位置不变。 + +string-
                          editTrigger 2.7+ + +是用于设定单元格编辑的事件触发方式。如双击: `dblclick` + +string + +`click` + +
                          title定义 table 的大标题(在文件导出等地方会用到)string-
                          text自定义文本,如空数据时的异常提示等。object + +
                          `text: {none: '无数据'}`
                          +
                          autoSort + +是否由组件自动进行前端排序。若为 `false`,则需自主排序,即由后端直接返回排序好的数据。[#详细用法](#on-sort) + +boolean + +`true` + +
                          initSort + +初始排序状态。用于在数据表格渲染完毕时,按某个字段排序显示。它接受一个 `object` 类型的值,包含属性有: +- `field` 排序字段。对应 `cols` 设定的各字段名 +- `type` 排序方式。可选值 : `'asc','desc',null`,即:`升序、降序、默认` + +``` +initSort: { + field: 'id', // 按 id 字段排序 + type: 'desc' // 降序排序 +} +``` + +object-
                          skin + +设置表格边框风格。可选值:`grid`\|`line`\|`row`\|`nob` + +string + +`grid` + +
                          size + +设置表格其他尺寸。可选值:`sm`\|`md`|`lg` + +string + +`md` + +
                          even + +是否开启隔行背景。 + +string + +`false` + +
                          + +[before](#options.before) 2.7+ + + + +
                          +数据渲染之前的回调函数。 +
                          + +``` +table.render({ + before: function(options){ + console.log(options); // 当前实例属性选项 + options.where.abc = 123; // 修改或额外追加 where 属性 + }, + // … // 其它属性 +}); +``` + +
                          + +[done](#options.done) + + + +
                          + 数据渲染完毕的回调函数。返回的参数如下: +
                          + +``` +table.render({ + done: function(res, curr, count, origin){ + console.log(res); // 得到当前渲染的数据 + console.log(curr); // 得到当前页码 + console.log(count); // 得到数据总量 + console.log(origin); // 回调函数所执行的来源 --- 2.8.7+ + }, + // … // 其它属性 +}); +``` + +
                          error 2.6+ + +数据请求失败的回调函数。返回两个参数:错误对象、内容。 + +``` +error: function(e, msg) { + console.log(e, msg) +} +``` + +
                          complete 2.8.18+ + +数据接口请求完成后执行,无论成功还是失败均会触发 + +``` +complete: function(xhr, ts) { + console.log(xhr, ts) +} +``` + +
                          + diff --git a/docs/table/examples/autoRender.md b/docs/table/examples/autoRender.md new file mode 100644 index 000000000..32cf57e90 --- /dev/null +++ b/docs/table/examples/autoRender.md @@ -0,0 +1,17 @@ + + + + + + + + + + + + + +
                          ID用户名性别城市签名积分评分职业
                          + + + diff --git a/docs/table/examples/css.md b/docs/table/examples/css.md new file mode 100644 index 000000000..4b5e62002 --- /dev/null +++ b/docs/table/examples/css.md @@ -0,0 +1,84 @@ + + + + + table 自定义样式 - Layui + + + + + + + +
                          +
                          +
                          + + + + + + + + diff --git a/docs/table/examples/data.md b/docs/table/examples/data.md new file mode 100644 index 000000000..8b4f634b2 --- /dev/null +++ b/docs/table/examples/data.md @@ -0,0 +1,85 @@ +
                          + + + diff --git a/docs/table/examples/demo.md b/docs/table/examples/demo.md new file mode 100644 index 000000000..d717c1086 --- /dev/null +++ b/docs/table/examples/demo.md @@ -0,0 +1,379 @@ + + + + + table 组件综合演示 - Layui + + + + + + + + +
                          +
                          +
                          + + + + + + + + + + diff --git a/docs/table/examples/editModes.md b/docs/table/examples/editModes.md new file mode 100644 index 000000000..5cc6cbe50 --- /dev/null +++ b/docs/table/examples/editModes.md @@ -0,0 +1,170 @@ +
                          +{{! + + + + + + + +!}} + + + + diff --git a/docs/table/examples/editable.md b/docs/table/examples/editable.md new file mode 100644 index 000000000..27cee60a0 --- /dev/null +++ b/docs/table/examples/editable.md @@ -0,0 +1,59 @@ +
                          + + + + diff --git a/docs/table/examples/filter.md b/docs/table/examples/filter.md new file mode 100644 index 000000000..144b464b5 --- /dev/null +++ b/docs/table/examples/filter.md @@ -0,0 +1,49 @@ +
                          + + + + diff --git a/docs/table/examples/init.md b/docs/table/examples/init.md new file mode 100644 index 000000000..d87178393 --- /dev/null +++ b/docs/table/examples/init.md @@ -0,0 +1,48 @@ +
                          + +
                          + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          庄子华夏朴素而天下莫能与之争美
                          + + + diff --git a/docs/table/examples/onrowContextmenu.md b/docs/table/examples/onrowContextmenu.md new file mode 100644 index 000000000..00c51631a --- /dev/null +++ b/docs/table/examples/onrowContextmenu.md @@ -0,0 +1,59 @@ +
                          + + + + diff --git a/docs/table/examples/page.md b/docs/table/examples/page.md new file mode 100644 index 000000000..782c8f408 --- /dev/null +++ b/docs/table/examples/page.md @@ -0,0 +1,43 @@ +
                          + + + + + diff --git a/docs/table/examples/parse.md b/docs/table/examples/parse.md new file mode 100644 index 000000000..f691f9207 --- /dev/null +++ b/docs/table/examples/parse.md @@ -0,0 +1,41 @@ +> 假设这是一段数据源:/static/json/2/table/demo3.json
                          + 尽管它并不符合 table 组件默认规定的数据格式([#详见](#options-async-data)),但可以通过 parseData 回调将其进行转换。 + +
                          + + + + diff --git a/docs/table/examples/search.md b/docs/table/examples/search.md new file mode 100644 index 000000000..0521beb86 --- /dev/null +++ b/docs/table/examples/search.md @@ -0,0 +1,78 @@ +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          +
                          + +
                          +
                          +
                          +
                          +
                          + +
                          + +
                          +
                          +
                          + + +
                          +
                          + + + + + + diff --git a/docs/table/examples/setRowChecked.md b/docs/table/examples/setRowChecked.md new file mode 100644 index 000000000..93875a684 --- /dev/null +++ b/docs/table/examples/setRowChecked.md @@ -0,0 +1,62 @@ +
                          + + + + + diff --git a/docs/table/examples/static.md b/docs/table/examples/static.md new file mode 100644 index 000000000..6d39a95b8 --- /dev/null +++ b/docs/table/examples/static.md @@ -0,0 +1,207 @@ +默认风格: + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          + +行边框表格: + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          + +列边框表格: + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          + +无边框表格: + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          + +小尺寸表格: + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          + +大尺寸表格: + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          + +开启偶数行背景色: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          人物民族格言
                          孔子华夏有朋自远方来,不亦乐乎
                          孟子华夏穷则独善其身,达则兼济天下
                          庄子华夏朴素而天下莫能与之争美
                          diff --git a/docs/table/examples/templet.md b/docs/table/examples/templet.md new file mode 100644 index 000000000..03ab81020 --- /dev/null +++ b/docs/table/examples/templet.md @@ -0,0 +1,64 @@ +
                          + + + + + + + + + + diff --git a/docs/table/examples/theads.md b/docs/table/examples/theads.md new file mode 100644 index 000000000..ff444e07f --- /dev/null +++ b/docs/table/examples/theads.md @@ -0,0 +1,54 @@ +常用两级表头: + + + + + + + + + + + + + + + + +
                          联系人地址数量操作
                          + +更多级表头(支持无限极): + + + + + + + + + + + + + + + + + + + + + + + +
                          联系人数量地址1地址2操作
                          详细
                          街道小区单元
                          + + + + + diff --git a/docs/table/index.md b/docs/table/index.md new file mode 100644 index 000000000..4850b4e0e --- /dev/null +++ b/docs/table/index.md @@ -0,0 +1,1004 @@ +--- +title: 表格组件 table +toc: true +--- + +# 表格组件 🔥 + +> 表格组件 `table` 是 Layui 中使用率极高的一个组件,它以表格的承载方式对数据进行渲染、重载、排序、统计、分页等等一系列交互操作,并提供了丰富的 API 用于扩展,基本涵盖了日常业务所涉及的大部分需求。 + +

                          示例

                          + +以下所有示例中演示的数据均为「静态模拟数据」,实际使用时换成您的真实接口即可。 + +
                          + +
                          +{{- d.include("/table/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var table = layui.table | 获得 `table` 模块。 | +| [table.set(options)](#set) | 设定全局默认属性项。 | +| [table.render(options)](#render) | table 组件渲染,核心方法。 | +| [table.init(filter, options)](#table.init) | 初始化渲染静态表格。 | +| [table.reload(id, options, deep)](#table.reload) | 表格完整重载。 | +| [table.reloadData(id, options, deep)](#table.reloadData) 2.7+ | 表格数据重载。 | +| [table.renderData(id)](#table.renderData) 2.8.5+ | 重新渲染数据。 | +| [table.updateRow(id, opts)](#table.updateRow) 2.9.4+ | 更新指定行数据。 | +| [table.checkStatus(id)](#table.checkStatus) | 获取选中行相关数据。 | +| [table.setRowChecked(id, opts)](#table.setRowChecked) 2.8+ | 设置行选中状态。 | +| [table.getData(id)](#table.getData) | 获取当前页所有行表格数据。 | +| [table.cache](#table.cache) | 获取表格缓存数据集(包含特定字段)。 | +| [table.resize(id)](#table.resize) | 重置表格尺寸。 | +| [table.exportFile(id, data, opts)](#table.exportFile) | 导出表格数据到本地文件。 | +| [table.getOptions(id)](#table.getOptions) 2.8+ | 获取表格实例配置项。 | +| [table.hideCol(id, cols)](#table.hideCol) 2.8+ | 设置表格列的显示隐藏属性。 | +| [table.on(\'event(filter)\', callback)](#table.on) | table 相关事件。 | + + +

                          全局设置

                          + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法主要用于初始化设置属性默认值。实际应用时,必须先设置该方法,再执行渲染、重载等操作。 + +```js +layui.use(function(){ + var table = layui.table; + // 全局设置 + table.set({ + headers: {token: '123'} + }); + // 渲染 + table.render(options); +}); +``` + + +

                          渲染

                          + +table 提供了以下三种渲染模式,在实际使用时,一般按情况选择其中一种即可。 + +| 渲染方式 | 描述 | +| --- | --- | +| [方法配置渲染](#table.render) | 通过 table 组件提供的核心方法 `table.render(options)` 完成的渲染。推荐 | +| [模板配置渲染](#view-render) | 通过 `` 标签的 `lay-options="{}"` 属性定义模板,组件自动对其进行解析并完成渲染。 | +| [静态表格渲染](#table.init) | 对一段已经包含数据内容的静态表格进行动态化转换,使其具备 table 组件的相关功能。 | + + +

                          方法配置渲染

                          + +`table.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法返回当前实例对象,包含可操作当前表格的一些成员方法。 + +```html +
                          + + + +``` + +

                          模板配置渲染

                          + +在 `` 元素中直接书写 `lay-options="{}"` 属性,组件将自动对其进行解析并完成渲染。 + +``` + +
                          + + + + + + +
                          Title
                          +``` + +> 2.8 之前版本通过 `lay-data="{}"` 定义属性选项;
                          +> 2.8+ 版本推荐采用 `lay-options`,但同时兼容 `lay-data`。 + + +

                          静态表格渲染

                          + +`table.init(filter, options);` + +- 参数 `filter` : `` 元素对应的 `lay-filter` 属性值 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法用于将已输出在页面中的静态表格内容转换为动态 table 组件。[#参考相关示例](#demo-init) + +```html +
                          + 表格内容 +
                          + + + +``` + +

                          属性 🔥

                          + +属性是指 table *渲染、重载* 时的配置选项(`options`),它本身是一个 `object` 参数。如: + +``` +// 渲染 +table.render({ + // options + elem: '', + cols: [[]], + // … +}); +// 重载 +table.reload(id, { + // options +}); + +若为模板配置渲染,则 lay-options 或 lay-data 的属性值即为属性的配置选项(: + …
                          +``` + +table 的属性众多,我们大致分为以下几种: + +| 属性类别 | 描述 | +| --- | --- | +| [基础属性](#options) | - | +| [异步属性](#options.ajax) | 用于和异步数据请求相关的基础属性,由于相关属性成员较多,所以单独提取介绍。 | +| [表头属性](#options.cols) | 基础属性 `cols` 的子属性集。 | + +

                          基础属性

                          + +
                          +{{- d.include("/table/detail/options.md") }} +
                          + +

                          异步属性

                          + +异步属性本质也是基础属性,当开启 `url` 属性时才有效,由于相关属性成员较多,所以单独提取介绍。 + +
                          +{{- d.include("/table/detail/options.ajax.md") }} +
                          + +

                          表头属性

                          + +表头属性是基础属性 `cols` 的子集,其使用频率甚至超过基础属性本身。 + +
                          +{{- d.include("/table/detail/options.cols.md") }} +
                          + +

                          重载

                          + +即对一段已经渲染好的表格重新设置属性并渲染,可分为以下几种重载方式: + +| 重载方式 | API | +| --- | --- | +| [完整重载](#table.reload) | [table.reload(id, options, deep)](#table.reload) | +| [仅数据重载](#table.reloadData) | [table.reloadData(id, options, deep)](#table.reloadData) | + +重载的使用方式完全相同,区别只是在于参与重载时的属性差异及其对应的效果差异。一般按照实际需求选择使用。 + + +

                          完整重载

                          + +`table.reload(id, options, deep);` + +- 参数 `id` : table 渲染时的 `id` 属性值 +- 参数 `options` : 为基础属性选项 +- 参数 `deep` 2.6+ : 是否采用深度重载(即重载时始终携带初始时及上一次重载时的参数),默认 false。
                          + + + +该方法用于对表格的视图和数据在内的全部重载,所有属性均会参与到重载中,对应的表格会有一个直观的刷新效果。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 完整重载 - 所有属性属性(options)均可参与到重载中 +table.reload('test', { + where: { // 传递数据异步请求时携带的字段 + aaa: '111', + bbb: '222' + //… + }, + height: 1000 // 重设高度 +}); +``` + + +

                          仅数据重载 2.7+

                          + +`table.reloadData(id, options, deep);` + +- 参数同 `table.reload(id, options, deep)` 参数 + +该方法用于对表格的数据重载,与数据无关的属性不会参与到重载中。因此若只是更新数据,该方法可大幅提升体验。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 数据重载 - 仅与数据相关的属性(options)能参与到重载中 +table.reloadData('test', { + where: {}, // 数据异步请求时携带的字段集 --- 属性设置有效,因属于数据相关属性 + scrollPos: true, // 设定重载数据或切换分页时的滚动条的位置状态 --- 属性设置有效 + // … + height: 2000 // 高度 --- 属性设置无效,因不属于数据相关属性 +}); +``` + +

                          重新渲染数据 2.8.5+

                          + +`table.renderData(id);` +- 参数 `id` : table 渲染时的 `id` 属性值 + +该方法用于重新渲染数据,一般在修改 `table.cache` 后使用。 + +```js +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 获取当前实例的数据缓存 +var data = table.cache['test']; +// 获取某行数据,并从 data 中移除该行 +var item = data.splice(index, 1) // index 为当前行下标,一般可在事件中通过 obj.index 得到 +// 将某行数据移动到另外某行 +data.splice(newIndex, 0, item[0]); +// 根据 table.cache 重新渲染数据 +table.renderData('test'); +``` + +

                          更新指定行数据 2.9.4+

                          + +`table.updateRow(id, opts);` +- 参数 `id` : table 渲染时的 `id` 属性值 +- 参数 `opts` : 更新指定行时的可选属性,详见下表 + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| index | 行索引 | number | - | +| data | 行数据 | object | - | +| related | 是否更新其他包含自定义模板且可能有所关联的列视图 | boolean/function | - | + +该方法用于更新指定行数据。 + +```js +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 更新指定行数据 +table.updateRow('test', { + index: 0, + data: { + id: 1, + username: 'name' + } + // 是否更新关联的列视图 + related: function(field, index){ + return ['score', '5'].indexOf(field) !== -1; + } +}); +``` + +

                          获取选中行

                          + +`table.checkStatus(id);` +- 参数 `id` : table 渲染时的 `id` 属性值 + +该方法用于获取表格当前选中行相关数据 + +```js +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 获取选中行相关数据 +var tableStatus = table.checkStatus('test'); +console.log(tableStatus.data) // 选中行的数据 +console.log(tableStatus.data.length) // 选中行数量,可作为是否有选中行的条件 +console.log(tableStatus.dataCache) // 选中的原始缓存数据,包含内部特定字段 --- 2.9.17+ +console.log(tableStatus.isAll ) // 表格是否全选 +``` + +

                          设置行选中状态 2.8+

                          + +`table.setRowChecked(id, opts);` +- 参数 `id` : table 渲染时的 `id` 属性值 +- 参数 `opts` : 设置行选中时的可选属性,详见下表 + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| type | 选中方式。可选值: `checkbox,radio` | string | `checkbox` | +| index | 选中行的下标。支持以下几种情况:
                          • 若值为 `number` 类型,则表示行所在的数组下标(`0` 开头)
                          • 若值为 `array` 类型 2.9.1+,则表示多选下标。
                          • 若值为 `string` 类型,则可设置 `all` 操作全选。
                          | number
                          array
                          string | - | +| checked | 选中状态值。
                          • 若传递该属性,则赋值固定值。
                          • 若不传递该属性(默认),则 `checkbox` 将在 `true\|false` 中自动切换值,而 `radio` 将赋值 `true` 固定值。2.8.4+
                            **注意**:若 `index` 指定为多选或全选,`checked` 应当显式传递固定值
                          | boolean | - | + +该方法用于设置行的选中样式及相关的特定属性值 `LAY_CHECKED`。 + +```js +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 设置某行选中 +table.setRowChecked('test', { + index: 0, // 选中行的下标。 0 表示第一行 +}); + +// 批量选中行 +table.setRowChecked('test', { + index: [1,3,5] // 2.9.1+ +}); + +// 取消选中行 +table.setRowChecked('test', { + index: 'all', // 所有行 + checked: false // 此处若设置 true,则表示全选 +}); +``` + + +

                          获取当前页接口数据

                          + +`table.getData(id);` +- 参数 `id` : table 渲染时的 `id` 属性值 + +该方法用于获取表格当前页的数据,它对应的是接口返回的原始数据,不包含 table 组件内部的特定字段。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 获取当前页接口数据 +var data = table.getData('test'); +console.log(data); +``` + + +

                          获取表格缓存数据集

                          + +`var tableCache = table.cache;` + +`table.cache` 是一段存储当前页表格所有实例的当前页的临时数据,通过 id 作为索引,它包含接口返回的原始数据和组件内部的特定字段。 使用该静态属性可对表格数据进行*读写*操作。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 获取对应 table 的临时数据 +var thisCache = table.cache['test'] || {}; + +// 变更对应 table 的临时数据中的某个字段值 +thisCache.fieldName = 123; +``` + + +

                          重置尺寸

                          + +`table.resize(id);` +- 参数 `id` : table 渲染时的 `id` 属性值 + +该方法用于重置表格尺寸和结构,其内部完成了*固定列高度平铺、动态分配列宽、容器滚动条宽高补丁* 等适配。它一般用于修复特殊情况下导致的列宽适配异常(如浏览器窗口尺寸改变导致的表格父容器宽度变化),以保证表格尺寸依旧能友好展示。 + + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 重置对应 table 的尺寸,一般写在表格外部容器宽高发生变化后的段落 +table.resize('test'); +``` + + +

                          导出数据

                          + +`table.exportFile(id, data, opts);` +- 参数 `id` : table 渲染时的 `id` **或** 要导出的数据表头(当 `id` 为 `array` 类型时)。 +- 参数 `data` : 要导出的自定义数据,参数可选。 +- 参数 `opts` 2.7+: 导出数据时的属性选项,支持: `type,title`。 + +该方法用于外部导出对应 table 的数据和任意自定义数据。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 外部导出对应 table 的数据 +table.exportFile('test'); + +// 导出自定义数据 +table.exportFile(['名字','性别','年龄'], [ + ['张三','男','20'], + ['李四','女','18'], + ['王五','女','19'] +], { + type: 'csv', // 导出的文件格式,支持: csv,xls + title: '导出的文件标题' +}); +``` + +

                          获取配置项 2.8+

                          + +`table.getOptions(id);` +- 参数 `id` : table 渲染时的 `id` 属性值 + +该方法用于外部获取对应 table 实例的属性选项。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 获取配置项 +var thisOptions = table.getOptions('test'); +console.log(thisOptions); +``` + +

                          设置列显示或隐藏 2.8+

                          + +`table.hideCol(id, cols);` +- 参数 `id` : table 渲染时的 `id` 属性值 +- 参数 `cols` : 设置列(表头)显示或隐藏状态 + +该方法用于外部设置对应 table 列的显示与隐藏状态。 + +``` +// 渲染 +table.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 设置对应列的显示或隐藏 +table.hideCol('test', { + field: 'title', // 对应表头的 field 属性值 + hide: true // `true` or `false` +}); + +// 同时设置多列的显示或隐藏 +table.hideCol('test', [{ + field: 'title1', + hide: true +}, { + field: 'title2', + hide: false +}, { + field: 'title3', + hide: false +}]); + +// 显示或隐藏全部列 +table.hideCol('test', false); // `true` or `false` +``` + +

                          事件

                          + +`table.on('event(filter)', callback);` + +- 参数 `event(filter)` 是事件的特定结构。 `event` 为事件名,支持的事件见下表。`filter` 为元素属性 `lay-filter` 对应的值。 +- 参数 `callback` 为事件执行时的回调函数,并返回一个包含各项成员的 `object` 类型的参数。 + +| event | 描述 | +| --- | --- | +| [toolbar](#on-toolbar) | 头部工具栏事件 | +| [sort](#on-sort) | 表头排序切换事件 | +| [colTool](#on-colTool) 2.8.8+ | 表头自定义元素工具事件 | +| [colResized](#on-colResized) 2.8+ | 列拖拽宽度后的事件 | +| [colToggled](#on-colToggled) 2.8+ | 列筛选(显示或隐藏)后的事件 | +| [row / rowDouble](#on-row) | 行单击和双击事件 | +| [rowContextmenu](#on-rowContextmenu) 2.8+ | 行右键菜单事件 | +| [edit](#on-edit) | 单元格编辑事件 | +| [tool / toolDouble](#on-tool) 🔥 | 单元格工具事件。可在该事件中实现行的更新与删除操作。 | +| [checkbox](#on-checkbox) | 复选框事件 | +| [radio](#on-radio) | 单选框事件 | +| [pagebar](#on-pagebar) 2.7+ | 尾部分页栏事件 | + + +

                          头部工具栏事件

                          + +`table.on('toolbar(filter)', callback);` + +点击头部工具栏区域设定了属性为 `lay-event=""` 的元素时触发。如: + +```html + +
                          + + + + + + +``` + +

                          排序切换事件

                          + +`table.on('sort(filter)', callback);` + +点击表头排序时触发,它通常在设置 `autoSort: false ` 基础属性时使用,以呈现后端的排序,而不是默认的前端排序。 + +```js +var table = layui.table; + +// 禁用前端自动排序,以便由服务端直接返回排序好的数据 +table.render({ + elem: '#test', + autoSort: false, // 禁用前端自动排序。 + // … // 其他属性 +}); + +// 触发排序事件 +table.on('sort(test)', function(obj){ + console.log(obj.field); // 当前排序的字段名 + console.log(obj.type); // 当前排序类型:desc(降序)、asc(升序)、null(空对象,默认排序) + console.log(this); // 当前排序的 th 对象 + + // 尽管我们的 table 自带排序功能,但并没有请求服务端。 + // 有些时候,你可能需要根据当前排序的字段,重新向后端发送请求,从而实现服务端排序,如: + table.reload('test', { + initSort: obj, // 记录初始排序,如果不设的话,将无法标记表头的排序状态。 + where: { // 请求参数(注意:这里面的参数可任意定义,并非下面固定的格式) + field: obj.field, // 排序字段 + order: obj.type // 排序方式 + } + }); +}); +``` + +

                          表头自定义元素工具事件 2.8.8+

                          + +`table.on('colTool(filter)', callback);` + +点击表头单元格中带有 `lay-event` 属性的自定义元素触发,可充分借助该事件扩展 table 更多的操作空间。 + +```js +var table = layui.table; + +// 渲染 +table.render({ + elem: '#test', + cols: [[ + {field:'username', title:'用户名 ' + ]] + // … // 其他属性 +}); + +// 表头自定义元素工具事件 +table.on('colTool(test)', function(obj){ + var col = obj.col; // 获取当前列属性选项 + var options = obj.config; // 获取当前表格基础属性选项 + var layEvent = obj.event; // 获得自定义元素对应的 lay-event 属性值 + console.log(obj); // 查看对象所有成员 +}); +``` + +

                          列拖拽宽度后的事件 2.8+

                          + +`table.on('colResized(filter)', callback);` + +在表头列分割线拖拽宽度后触发。 + +```js +var table = layui.table; + +// 渲染 +table.render({ + elem: '#test', + // … // 其他属性 +}); + +// 列拖拽宽度后的事件 +table.on('colResized(test)', function(obj){ + var col = obj.col; // 获取当前列属性选项 + var options = obj.config; // 获取当前表格基础属性选项 + console.log(obj); // 查看对象所有成员 +}); +``` + +

                          列筛选(显示或隐藏)后的事件 2.8+

                          + +`table.on('colToggled(filter)', callback);` + +点击头部工具栏右上角的字段筛选列表时触发。 + +```js +var table = layui.table; + +// 渲染 +table.render({ + elem: '#test', + // … // 其他属性 +}); + +// 列筛选(显示或隐藏)后的事件 +table.on('colToggled(test)', function(obj){ + var col = obj.col; // 获取当前列属性选项 + var options = obj.config; // 获取当前表格基础属性选项 + console.log(obj); // 查看对象所有成员 +}); +``` + + +

                          行单击和双击事件

                          + +- 行单击事件:`table.on('row(filter)', callback);` +- 行双击事件:`table.on('rowDouble(filter)', callback);` + +单击或双击 table 行任意区域触发,两者用法相同。
                          +注2.8.4+:在 table 模板中或任意内部元素中设置 `lay-unrow` 属性,可阻止该元素执行 `row` 事件 + +```js +var table = layui.table; + +// 渲染 +table.render({ + elem: '#test', + // … // 其他属性 +}); + +// 行单击事件 +table.on('row(test)', function(obj) { + var data = obj.data; // 得到当前行数据 + var dataCache = obj.dataCache; // 得到当前行缓存数据,包含特定字段 --- 2.8.8+ + var index = obj.index; // 得到当前行索引 + var tr = obj.tr; // 得到当前行 元素的 jQuery 对象 + var options = obj.config; // 获取当前表格基础属性选项 + var e = obj.e; // 当前的 jQuery 事件对象 --- 2.9.14+ + + console.log('onrow', obj); // 查看返回对象的所有成员 + + // obj.del() // 删除当前行 + // obj.update(fields, related); // 修改行数据 + // obj.setRowChecked(opts); // 设置行选中状态 +}); + +// 行双击事件 +table.on('rowDouble(test)', function(obj) { + console.log('onrowDouble', obj); // 查看返回对象的所有成员 - 同 row 事件 +}); +``` + +

                          行右键菜单事件 2.8+

                          + +`table.on('rowContextmenu(filter)', callback);` + +右键单击行时触发。 + +
                          +  
                          +
                          + +

                          单元格编辑事件

                          + +`table.on('edit(filter)', callback);` + +单元格被编辑,且值发生改变时触发。 + +```js +var table = layui.table; +var layer = layui.layer; + +// 单元格编辑事件 +table.on('edit(test)', function(obj){ + var field = obj.field; // 得到修改的字段 + var value = obj.value // 得到修改后的值 + var oldValue = obj.oldValue // 得到修改前的值 -- v2.8.0 新增 + var data = obj.data // 得到所在行所有键值 + var col = obj.getCol(); // 得到当前列的表头配置属性 -- v2.8.0 新增 + console.log(obj); // 查看对象所有成员 + + // 值的校验 + if(value.replace(/\s/g, '') === ''){ + layer.tips('值不能为空', this, {tips: 1}); + return obj.reedit(); // 重新编辑 -- v2.8.0 新增 + } + + // 编辑后续操作,如提交更新请求,以完成真实的数据更新 + // … + + // 更新当前缓存数据 + var update = {}; + update[field] = value; + obj.update(update, true); // 参数 true 为 v2.7 新增功能,即同步更新其他包含自定义模板并可能存在关联的列视图 +}); + +``` + + +

                          单元格工具事件

                          + +- 单元格工具事件「单击触发」: `table.on('tool(filter)', callback);` +- 单元格工具事件「双击触发」: `table.on('toolDouble(filter)', callback);` + +单击或双击单元格中带有 `lay-event=""` 属性的元素时触发。在表格主体的单元格中,经常需要进行很多的动态操作,比如编辑、删除等操作,这些均可以在单元格工具事件中完成。 + +{{! +```html + + + +
                          + + + +``` +!}} + +

                          复选框事件

                          + +`table.on('checkbox(filter)', callback);` + +当 table 开启复选框,且点击复选框时触发。 + +```js +var table = layui.table; + +// 复选框事件 +table.on('checkbox(test)', function(obj){ + console.log(obj); // 查看对象所有成员 + console.log(obj.checked); // 当前是否选中状态 + console.log(obj.data); // 选中行的相关数据 + console.log(obj.type); // 若触发的是全选,则为:all;若触发的是单选,则为:one +}); +``` + + +

                          单选框事件

                          + +`table.on('radio(filter)', callback);` + +当 table 开启单选框,且点击单选框时触发。 + +```js +var table = layui.table; + +// 单选框事件 +table.on('radio(test)', function(obj){ + console.log(obj); // 当前行的一些常用操作集合 + console.log(obj.checked); // 当前是否选中状态 + console.log(obj.data); // 选中行的相关数据 +}); +``` + + +

                          尾部分页栏事件 2.7+

                          + +`table.on('pagebar(filter)', callback);` + +点击尾部分页栏自定义模板中属性为 `lay-event=""` 的元素时触发。用法跟 toolbar 完全一致。 + +```js +var table = layui.table; + +// 渲染 +table.render({ + elem: '#demo', + pagebar: '#pagebarDemo' // 分页栏模板所在的选择器 + // … // 其他参数 +}); + +// 分页栏事件 +table.on('pagebar(test)', function(obj){ + console.log(obj); // 查看对象所有成员 + console.log(obj.config); // 当前实例的配置信息 + console.log(obj.event); // 属性 lay-event 对应的值 +}); +``` + +## 小贴士 + +若表头数量太多及每页呈现的数据量太大,为了性能考虑,建议采用 [静态表格](#demo-static) 渲染,配合 [laypage](../laypage/#options) 组件实现分页。 + + + + + + diff --git a/docs/tabs/detail/demo.md b/docs/tabs/detail/demo.md new file mode 100644 index 000000000..33fde0635 --- /dev/null +++ b/docs/tabs/detail/demo.md @@ -0,0 +1,80 @@ +

                          动态操作

                          + +
                          +  
                          +
                          + +

                          方法渲染

                          + +即通过方法设置 tabs 标签,而非默认的自动渲染页面中的 `class="lay-tabs"` 的容器模板。 + +
                          +  
                          +
                          + +

                          卡片风格

                          + +
                          +  
                          +
                          + +

                          自定义事件

                          + +
                          +  
                          +
                          + +

                          打乱标签顺序

                          + +
                          +  
                          +
                          + +

                          通过 HASH 匹配选中标签

                          + +切换 tabs 标签项后,地址栏同步 `hash` 值,当页面刷新时,tabs 仍保持对应的切换状态。 + +
                          +  
                          +
                          + +

                          标签嵌套

                          + +
                          +  
                          +
                          + +

                          给任意元素绑定 tabs 切换功能

                          + +
                          +  
                          +
                          + diff --git a/docs/tabs/detail/options.md b/docs/tabs/detail/options.md new file mode 100644 index 000000000..e2994ed55 --- /dev/null +++ b/docs/tabs/detail/options.md @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +组件渲染指定的目标元素选择器或 DOM 对象 + +string/DOM-
                          id + +组件渲染的唯一实例 ID + +string-
                          className + +给主容器追加 CSS 类名,以便自定义样式 + +string-
                          trigger + +标签切换的触发事件 + +boolean + +`click` + +
                          headerMode + +标签头部的显示模式。可选值有: + +- `auto` 自动模式,根据标签头部是否溢出自动显示不同模式 +- `scroll` 始终滚动模式 +- `normal` 始终常规模式,不渲染头部滚动结构 + +string + +`auto` + +
                          index + +初始选中的标签索引或标签 `lay-id` 属性值 + +number-
                          closable + +是否开启标签项关闭功能 + +boolean + +`false` + +
                          header + +设置标签头部列表,通常在「非自动渲染」的场景下使用: + +**1. 方法渲染** + +若 `header` 传入一个数组,且成员值为对象,即为方法渲染时传入的头部列表数据。如: + +```js +header: [ + { title: 'Tab1' }, // 除 `title` 为必传项外,也可传入其他任意字段。 + { title: 'Tab2' } +] +``` + +**2. 任意元素渲染** + +若 `header` 传入一个数组,则成员值为元素选择器,即为绑定标签头部列表元素。如: + +```js +header: ['#tabsHeader', '>li'], +``` + +
                          body + +设置标签内容列表,通常在「非自动渲染」的场景下使用: + +**1. 方法渲染** + +若 `body` 传入一个数组,且成员值为对象,即为方法渲染时传入的标签内容列表数据。如: + +```js +body: [ + { content: 'Tab1' }, // `content` 为必传项 + { content: 'Tab2' } +] +``` + +**2. 任意元素渲染** + +若 `body` 传入一个数组,则成员值为元素选择器,即为绑定标签内容列表元素。如: + +```js +body: ['#tabsBody', '>div'], +``` + +
                          + diff --git a/docs/tabs/examples/beforeChange.md b/docs/tabs/examples/beforeChange.md new file mode 100644 index 000000000..270dc4c3c --- /dev/null +++ b/docs/tabs/examples/beforeChange.md @@ -0,0 +1,45 @@ +
                          +
                            +
                          • Tab1
                          • +
                          • Tab2
                          • +
                          • Tab3
                          • +
                          • Tab4
                          • +
                          • Tab5
                          • +
                          • Tab6
                          • +
                          +
                          +
                          Tab Content-1
                          +
                          Tab Content-2
                          +
                          Tab Content-3
                          +
                          Tab Content-4
                          +
                          Tab Content-5
                          +
                          Tab Content-6
                          +
                          +
                          + +本示例演示:切换标签时,弹出确认提示。 + + + + diff --git a/docs/tabs/examples/beforeClose.md b/docs/tabs/examples/beforeClose.md new file mode 100644 index 000000000..3a3ef045f --- /dev/null +++ b/docs/tabs/examples/beforeClose.md @@ -0,0 +1,45 @@ +
                          +
                            +
                          • Tab1
                          • +
                          • Tab2
                          • +
                          • Tab3
                          • +
                          • Tab4
                          • +
                          • Tab5
                          • +
                          • Tab6
                          • +
                          +
                          +
                          Tab Content-1
                          +
                          Tab Content-2
                          +
                          Tab Content-3
                          +
                          Tab Content-4
                          +
                          Tab Content-5
                          +
                          Tab Content-6
                          +
                          +
                          + +本示例演示:删除标签之前,弹出确认提示。 + + + + diff --git a/docs/tabs/examples/card.md b/docs/tabs/examples/card.md new file mode 100644 index 000000000..d382bf849 --- /dev/null +++ b/docs/tabs/examples/card.md @@ -0,0 +1,55 @@ +#### 普通卡片 + +
                          +
                            +
                          • 标题1
                          • +
                          • 标题2
                          • +
                          • 跳转项
                          • +
                          • 禁选项
                          • +
                          • 标题5
                          • +
                          • 标题6
                          • +
                          +
                          +
                          内容-1
                          +
                          内容-2
                          +
                          内容-3
                          +
                          内容-4
                          +
                          内容-5
                          +
                          内容-6
                          +
                          +
                          + +#### 边框卡片 + +
                          +
                            +
                          • 标题1
                          • +
                          • 标题2
                          • +
                          • 标题3
                          • +
                          • 标题4
                          • +
                          • 标题5
                          • +
                          • 标题6
                          • +
                          +
                          +
                          +
                          + +
                          +
                          +
                          2
                          +
                          3
                          +
                          4
                          +
                          5
                          +
                          6
                          +
                          +
                          + + + diff --git a/docs/tabs/examples/custom.md b/docs/tabs/examples/custom.md new file mode 100644 index 000000000..056d14960 --- /dev/null +++ b/docs/tabs/examples/custom.md @@ -0,0 +1,31 @@ +
                          + +
                          + + + +
                          +
                          +
                          内容 111
                          +
                          内容 222
                          +
                          内容 333
                          +
                          +
                          + + + + diff --git a/docs/tabs/examples/demo.md b/docs/tabs/examples/demo.md new file mode 100644 index 000000000..cde188ce8 --- /dev/null +++ b/docs/tabs/examples/demo.md @@ -0,0 +1,114 @@ +
                          +
                            +
                          • Tab1
                          • +
                          • Tab2
                          • +
                          • Tab3
                          • +
                          • Tab4
                          • +
                          • Tab5
                          • +
                          • Tab6
                          • +
                          +
                          +
                          Tab Content-1
                          +
                          Tab Content-2
                          +
                          Tab Content-3
                          +
                          Tab Content-4
                          +
                          Tab Content-5
                          +
                          Tab Content-6
                          +
                          +
                          + +🔔 操作提示:在「标签头部」点击鼠标右键,可开启标签操作的更多实用演示 + +
                          + + + + + +
                          + + + + diff --git a/docs/tabs/examples/hash.md b/docs/tabs/examples/hash.md new file mode 100644 index 000000000..7bd6f3342 --- /dev/null +++ b/docs/tabs/examples/hash.md @@ -0,0 +1,24 @@ + + + + + diff --git a/docs/tabs/examples/method.md b/docs/tabs/examples/method.md new file mode 100644 index 000000000..2e01892c9 --- /dev/null +++ b/docs/tabs/examples/method.md @@ -0,0 +1,27 @@ +
                          + + + + diff --git a/docs/tabs/examples/nest.md b/docs/tabs/examples/nest.md new file mode 100644 index 000000000..d01dd16b5 --- /dev/null +++ b/docs/tabs/examples/nest.md @@ -0,0 +1,41 @@ +
                          +
                            +
                          • 标题1
                          • +
                          • 标题2
                          • +
                          • 标题3
                          • +
                          +
                          +
                          +
                          +
                            +
                          • 标题 1-1
                          • +
                          • 标题 1-2
                          • +
                          +
                          +
                          1-1
                          +
                          1-2
                          +
                          +
                          +
                          +
                          +
                          +
                            +
                          • 标题 2-1
                          • +
                          • 标题 2-2
                          • +
                          • 标题 2-3
                          • +
                          +
                          +
                          2-1
                          +
                          2-2
                          +
                          2-3
                          +
                          +
                          +
                          +
                          3
                          +
                          4
                          +
                          5
                          +
                          +
                          + + + diff --git a/docs/tabs/examples/shuffle.md b/docs/tabs/examples/shuffle.md new file mode 100644 index 000000000..64c87e134 --- /dev/null +++ b/docs/tabs/examples/shuffle.md @@ -0,0 +1,23 @@ +
                          +
                            +
                          • Tab6
                          • +
                          • Tab5
                          • +
                          • Tab3
                          • +
                          • Tab2
                          • +
                          • Tab1
                          • +
                          • Tab4
                          • +
                          +
                          +
                          Tab Content-1
                          +
                          Tab Content-2
                          +
                          Tab Content-3
                          +
                          Tab Content-4
                          +
                          Tab Content-5
                          +
                          Tab Content-6
                          +
                          +
                          + +🔔 提示:即 tabs 能通过 `lay-id` 匹配对应的标签头和标签内容。 + + + diff --git a/docs/tabs/examples/trigger.md b/docs/tabs/examples/trigger.md new file mode 100644 index 000000000..8975f5a97 --- /dev/null +++ b/docs/tabs/examples/trigger.md @@ -0,0 +1,44 @@ +#### mouseenter 触发 + +
                          +
                            +
                          • 标题1
                          • +
                          • 标题2
                          • +
                          • 标题3
                          • +
                          • 标题4
                          • +
                          • 标题5
                          • +
                          • 标题6
                          • +
                          +
                          +
                          内容-1
                          +
                          内容-2
                          +
                          内容-3
                          +
                          内容-4
                          +
                          内容-5
                          +
                          内容-6
                          +
                          +
                          + +#### mousedown 触发 + +
                          +
                            +
                          • 标题1
                          • +
                          • 标题2
                          • +
                          • 标题3
                          • +
                          • 标题4
                          • +
                          • 标题5
                          • +
                          • 标题6
                          • +
                          +
                          +
                          内容-1
                          +
                          内容-2
                          +
                          内容-3
                          +
                          内容-4
                          +
                          内容-5
                          +
                          内容-6
                          +
                          +
                          + + + diff --git a/docs/tabs/index.md b/docs/tabs/index.md new file mode 100644 index 000000000..041423788 --- /dev/null +++ b/docs/tabs/index.md @@ -0,0 +1,364 @@ +--- +title: 标签页组件 tabs +toc: true +--- + +# 标签页组件 2.10+ + +> `tabs` 是 2.10 版本新增的加强型组件,可替代原 `element` 模块中的 `tab` 组件。tabs 广泛应用于 Web 页面。 + +

                          示例

                          + +
                          + +
                          +{{- d.include("/tabs/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var tabs = layui.tabs | 获得 `tabs` 模块。| +| [基础接口](../component/#export) | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [tabs.render(options)](#render) | tabs 组件渲染,核心方法。| +| [tabs.add(id, opts)](#add) | 新增一个标签项。| +| [tabs.close(id, index, force)](#close) | 关闭指定的标签项。| +| [tabs.closeMult(id, mode, index)](#closeMult) | 批量关闭标签项。| +| [tabs.change(id, index, force)](#change) | 切换到指定的标签项。| +| [tabs.data(id)](#data) | 获取当前标签页相关数据。| +| [tabs.getHeaderItem(id, index)](#getHeaderItem) | 获取指定的标签头部项。| +| [tabs.getBodyItem(id, index)](#getBodyItem) | 获取指定的标签内容项。| +| [tabs.refresh(id)](#refresh) | 刷新标签视图。 | + +

                          渲染

                          + +`tabs.render(options)` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +组件支持以下三种渲染方式: + +#### 1. 自动渲染 + +tabs 组件会在元素加载完毕后,自动对 `class="lay-tabs"` 目标元素完成一次渲染,若无法找到默认的目标元素(如:动态插入的标签元素的场景),则可通过该方法完成对标签页的初始化渲染。 + +```js +// 对 class="lay-tabs" 所在标签进行初始化渲染 +tabs.render(); +``` + +#### 2. 方法渲染 + +通过方法动态渲染一个 tabs 组件,无需在 HTML 中书写标签页的 HTML 结构。 + +```js +
                          + + +``` + +#### 3. 为任意元素渲染 tabs 功能 + +当 `header` 和 `body` 参数传入元素选择器时,可为任意元素绑定标签切换功能。 + +```js +// 给任意元素绑定 Tab 功能 +tabs.render({ + elem: '#demoTabs3', // 目标主容器选择器 + header: ['#demoTabsHeader', '>button'], // 标签头部主元素选择器、标签头部列表选择器 + body: ['#demoTabsBody', '>.test-item'] // 标签内容主元素选择器、标签内容列表选择器 +}); +``` + +具体用法可直接参考上述示例:[给任意元素绑定 tabs 切换功能](#demo-custom) + + +

                          属性

                          + +
                          +{{- d.include("/tabs/detail/options.md") }} +
                          + +

                          新增标签

                          + +`tabs.add(id, opts)` + +- 参数 `id` : 组件的实例 ID +- 参数 `opts` : 标签配置项。可选项详见下表 + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| title | 标签标题。必填项 | string | - | +| content | 标签内容。必填项 | string | - | +| id | 标签的 `lay-id` 属性值 | string | - | +| index | 活动标签的索引或 `lay-id` 属性值,默认取当前选中标签的索引 | number | - | +| mode | 标签的插入方式。支持以下可选值:
                          • `append` 插入标签到最后
                          • `prepend` 插入标签到最前
                          • `before` 在活动标签前插入
                          • `after` 在活动标签后插入
                          | string | `append` | +| active | 是否将新增项设置为活动标签 | boolean | `true` | +| closable | 标签是否可关闭。初始值取决于 `options.closable` | boolean | `false` | +| headerItem | 自定义标签头部元素,如 `headerItem: '
                        • '` | string | - | +| bodyItem | 自定义标签内容元素,如 `bodyItem: '
                          '` | string | - | +| done | 标签添加成功后执行的回调函数 | Function | - | + +该方法用于给对应的 tabs 实例新增一个标签 + +```js +tabs.add('test', { + title: 'New Tab 1', + content: 'New Tab Content 1', + done: function(data) { + console.log(data); // 标签相关数据 + + // 为新标签头添加任意属性 + data.headerItem.attr('lay-tips', '111'); + } +}); +``` + +

                          关闭标签

                          + +`tabs.close(id, index, force)` + +- 参数 `id` : 组件的实例 ID +- 参数 `index` : 若传入 number 类型,则为标签索引;若传入 string 类型,则为标签的 `lay-id` 属性值 +- 参数 `force` : 是否强制关闭。若设置 `true` 将忽略 `beforeClose` 事件行为。默认 `false` + +该方法用于关闭指定的标签项。 + +```js +tabs.close('test', 3); // 关闭索引为 3 的标签 +tabs.close('test', 3, true); // 强制关闭索引为 3 的标签 +tabs.close('test', 'abc'); // 关闭 lay-id="abc" 的标签 +``` + +

                          批量关闭标签

                          + +`tabs.closeMult(id, mode, index)` + +- 参数 `id` : 组件的实例 ID +- 参数 `mode` : 关闭方式。支持以下可选值: + +| mode | 描述 | +| --- | --- | +| other | 关闭除当前标签外的其他标签 | +| right | 关闭当前标签的右侧所有标签 | +| all | 关闭所有标签 | + +- 参数 `index` : 活动标签的索引或 `lay-id` 属性值,默认取当前选中标签的索引。一般用于标签右键事件。 + +该方法用于批量关闭标签,若标签项已设置不允许关闭(`lay-closable="false"`),则操作将被忽略。 + +```js +tabs.closeMult(id, 'other'); // 关闭除当前活动标签外的其他标签 +tabs.closeMult(id, 'other', 3); // 关闭除索引为 3 的标签外的其他标签 +tabs.closeMult(id, 'other', 'ccc'); // 关闭除 lay-id="ccc" 的标签外的其他标签 + +tabs.closeMult(id, 'right'); // 关闭当前活动标签的右侧所有标签 +tabs.closeMult(id, 'right', 3); // 关闭索引为 3 的标签的右侧所有标签 +tabs.closeMult(id, 'right', 'ccc'); // 关闭 lay-id="ccc" 的标签的右侧所有标签 + +tabs.closeMult(id, 'all'); // 关闭所有标签 +``` + +

                          切换标签

                          + +`tabs.change(id, index, force)` + +- 参数 `id` : 组件的实例 ID +- 参数 `index` : 标签索引或标签的 `lay-id` 属性值 +- 参数 `force` : 是否强制切换。若设置 `true` 将忽略 `beforeChange` 事件行为。默认 false + +该方法用于切换到指定的标签项。 + +```js +tabs.change('test', 3); // 切换到索引为 3 的标签 +tabs.change('test', 3, true); // 强制切换到索引为 3 的标签 +tabs.change('test', 'abc'); // 切换到 lay-id="abc" 的标签 +tabs.change('test', 'abc', true); // 强制切换到 lay-id="abc" 的标签 +``` + +

                          获取标签相关数据

                          + +`tabs.data(id)` + +- 参数 `id` : 组件的实例 ID + +该方法用于获取标签相关数据。 + +```js +var data = tabs.data('test'); +console.log(data); +``` + +返回的 `data` 包含以下字段: + +```js +{ + options, // 标签配置信息 + container, // 标签容器的相关元素 + thisHeaderItem, // 当前活动标签头部项 + thisBodyItem, // 当前活动标签内容项 + index, // 当前活动标签索引 + length, // 标签数量 +} +``` + +

                          获取标签头部项

                          + +`tabs.getHeaderItem(id, index)` + +- 参数 `id` : 组件的实例 ID +- 参数 `index` : 若传入 number 类型,则为标签索引;若传入 string 类型,则为标签的 `lay-id` 属性值 + +该方法用于获取标签头部项元素。 + +```js +var headerItem = tabs.getHeaderItem('test', 3); // 获取索引为 3 的标签头部项元素 +var headerItem = tabs.getHeaderItem('test', 'abc'); // 获取 lay-id="abc" 的标签头部项元素 +``` + +

                          获取标签内容项

                          + +`tabs.getBodyItem(id, index)` + +- 参数 `id` : 组件的实例 ID +- 参数 `index` : 若传入 number 类型,则为标签索引;若传入 string 类型,则为标签的 `lay-id` 属性值 2.11.2+ + +该方法用于获取标签内容项元素。 + +```js +var bodyItem = tabs.getBodyItem('test', 3); // 获取索引为 3 的标签内容项元素 +var bodyItem = tabs.getBodyItem('test', 'abc'); // 获取 lay-id="abc" 的标签内容项元素 +``` + +

                          刷新标签视图

                          + +`tabs.refresh(id)` + +- 参数 `id` : 组件的实例 ID + +该方法用于刷新标签视图,如标签头部的滚动结构等,一般通过非 API 方式对标签进行修改的场景中使用。 + +```js +tabs.refresh('test'); // 刷新标签视图 +``` + + +

                          事件

                          + +`tabs.on('event(id)', callback)` + +- 参数介绍详见 `component` 组件的[事件定义](../component/#on)。以下是组件提供的 `event` 事件列表 + +| event | 描述 | +| --- | --- | +| [afterRender](#on-afterRender) | 标签渲染后的事件 | +| [beforeChange](#on-beforeChange) | 标签切换前的事件 | +| [afterChange](#on-afterChange) | 标签切换后的事件 | +| [beforeClose](#on-beforeClose) | 标签关闭前的事件 | +| [afterClose](#on-afterClose) | 标签关闭后的事件 | + + +

                          标签渲染后的事件

                          + +`tabs.on('afterRender(id)', callback)` + +标签渲染成功后触发。 + +```js +tabs.on('afterRender(testID)', function(data){ + console.log(data); // 标签相关数据 +}); +``` + +

                          标签切换前的事件

                          + +`tabs.on('beforeChange(id)', callback)` + +标签在切换前触发,通过在事件中 `return false` 可阻止默认标签切换行为。通常和 `tabs.change()` 方法搭配使用。 + +```js +// tabs 切换前的事件 +tabs.on(`beforeChange(testID)`, function(data) { + console.log(data); // 标签相关数据 + console.log(data.from.index); // 切换前的选中标签索引 + console.log(data.from.headerItem); // 切换前的选中标签头部项 + console.log(data.to.index); // 切换后的选中标签索引 + console.log(data.to.headerItem); // 切换后的选中标签头部项 + + // 阻止标签默认关闭 + return false; +}); +``` + +示例演示: + +
                          +  
                          +
                          + +

                          标签切换后的事件

                          + +`tabs.on('afterChange(id)', callback)` + +标签成功切换后触发。 + +```js +// tabs 切换后的事件 +tabs.on('afterChange(testID)', function(data) { + console.log(data); +}); +``` + +

                          标签关闭前的事件

                          + +`tabs.on('beforeClose(id)', callback)` + +标签在切换前触发,通过在事件中 `return false` 可阻止默认标签切换行为。通常和 `tabs.close()` 方法搭配使用。 + +
                          +  
                          +
                          + +

                          标签关闭后的事件

                          + +`tabs.on('afterClose(id)', callback)` + +标签被成功关闭后触发。 + +```js +// tabs 关闭后的事件 +tabs.on('afterClose(testID)', function(data) { + console.log(data); +}); +``` + +## 💖 心语 + +tabs 是通过 component 重构的首个组件,它来自于最早试图发布的 Layui 3.0(后因为 3.0 技术路线的变化,而整理放至 2.10+ 版本中),目的是将 element 模块中的 tab 组件进行解耦,增强其可扩展性。为了给开发者必要的时间缓冲,我们会将旧 tab 组件仍然保留在后续的若干版本中,但会在合适的时机对旧 tab 组件进行剔除,建议开发者尽量提前过渡到当前新的 tabs 组件。 + + diff --git a/docs/timeline/index.md b/docs/timeline/index.md new file mode 100644 index 000000000..7807d8c11 --- /dev/null +++ b/docs/timeline/index.md @@ -0,0 +1,99 @@ +--- +title: 时间线 timeline +toc: true +--- + +# 时间线 + +> 时间线 `timeline` 用于将时间抽象到二维平面,垂直呈现一段从过去到现在的故事。 + +

                          常规时间线

                          + +
                          +  
                          +
                          + +时间线上的图标可任意定义,右侧内容区域可自由填充。 + +

                          简约时间线

                          + +
                          +  
                          +
                          + +透过这示例,见证 Layui 的起起伏伏。 diff --git a/docs/transfer/detail/demo.md b/docs/transfer/detail/demo.md new file mode 100644 index 000000000..68f52d848 --- /dev/null +++ b/docs/transfer/detail/demo.md @@ -0,0 +1,276 @@ +
                          +  
                          +
                          + +

                          定义标题及数据源

                          + +
                          +  
                          +
                          + +

                          初始右侧数据

                          + +
                          +  
                          +
                          + +

                          显示搜索框

                          + +
                          +  
                          +
                          + +

                          数据格式解析

                          + +
                          +  
                          +
                          + +

                          穿梭时的回调

                          + +
                          +  
                          +
                          + +

                          实例调用

                          + +
                          +  
                          +
                          diff --git a/docs/transfer/detail/options.data.md b/docs/transfer/detail/options.data.md new file mode 100644 index 000000000..eb0caae92 --- /dev/null +++ b/docs/transfer/detail/options.data.md @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          title + +数据标题 + +string-
                          value + +数据值 + +string-
                          checked + +是否选中状态 + +boolean + +`false` + +
                          disabled + +是否禁用状态 + +boolean + +`false` + +
                          diff --git a/docs/transfer/detail/options.md b/docs/transfer/detail/options.md new file mode 100644 index 000000000..7baf277e4 --- /dev/null +++ b/docs/transfer/detail/options.md @@ -0,0 +1,226 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          title + +穿梭框左右面板头部标题 + +array + + + +
                          data + +穿梭框的数据源。格式详见:[#data 格式](#options.data) + +array-
                          value + +初始选中的数据(右侧列表) + +array-
                          id + +设置实例唯一索引,用于其他方法传参使用。 + +string-
                          showSearch + +是否开启搜索。支持以下可选值: + +- `false` 不开启搜索(默认) +- `true` 开启搜索,且匹配时不区分大小写 +- `cs` 开启搜索,且匹配时区分大小写 2.7+ + +boolean
                          string
                          + +`false` + +
                          width + +定义左右穿梭框宽度 + +number + +`200` + +
                          height + +定义左右穿梭框高度 + +number + +`360` + +
                          text + +自定义默认文本, `object` 类型。支持以下属性: + +``` +text: { + none: '无数据', // 没有数据时的文案 + searchNone: '无匹配数据' // 搜索无匹配数据时的文案 +} +``` + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          onchange + +左右穿梭时的回调函数。返回的参数如下: + +``` +onchange: function(data, index){ + console.log(data); // 得到当前被穿梭的数据 + console.log(index); // 如果数据来自左边,index 为 0,否则为 1 +} +``` + +boolean + +`false` + +
                          dblclick 2.9.3+ + +双击时的回调函数。返回的参数如下: + +``` +dblclick: function(obj){ + console.log(obj.elem); // 点击的元素 + console.log(obj.data); // 得到点击项的数据 + console.log(obj.index); // 如果数据来自左边,index 为 0,否则为 1 + + return false // 返回 false 会阻止穿梭 +} +``` + +function + + `null` + +
                          + +[parseData](#options.parseData) + + + +
                          +数据格式解析的回调函数,用于将返回的任意数据格式解析成 transfer 组件规定的 data 格式 +
                          + +``` +transfer.render({ + elem: '', + data: [ // 任意数据 + {"id": "1", "name": "李白"}, + {"id": "2", "name": "杜甫"}, + {"id": "3", "name": "贤心"} + ], + parseData: function(res){ // 解析成规定的 data 格式 + return { + "value": res.id, // 数据值 + "title": res.name, // 数据标题 + "disabled": res.disabled, // 是否禁用 + "checked": res.checked // 是否选中 + }; + } +}); +``` + +
                          diff --git a/docs/transfer/index.md b/docs/transfer/index.md new file mode 100644 index 000000000..21fad1e89 --- /dev/null +++ b/docs/transfer/index.md @@ -0,0 +1,85 @@ +--- +title: 穿梭框组件 transfer +toc: true +--- + +# 穿梭框组件 + +> 穿梭框组件 `transfer` 以左右栏 `checkbox` 列表为表现形式,可对列表进行选择并移动到另一栏。 + +

                          示例

                          + +
                          +{{- d.include("/transfer/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var transfer = layui.transfer | 获得 `transfer` 模块。 | +| [基础接口](../component/#export) 2.13+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [transfer.render(options)](#render) | transfer 组件渲染,核心方法。 | +| [transfer.reload(id, options)](#reload) | 重载实例 | +| [transfer.getData(id)](#getData) | 获得右侧数据 | + +

                          渲染

                          + +`transfer.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +

                          属性

                          + +
                          +{{- d.include("/transfer/detail/options.md") }} +
                          + +

                          data 格式

                          + +
                          +{{- d.include("/transfer/detail/options.data.md") }} +
                          + +

                          重载

                          + +`transfer.reload(id, options);` + +- 参数 `id` : 对应渲染时定义的 `id` 属性值 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +``` +var transfer = layui.transfer; + +// 渲染 +transfer.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 重载 +transfer.reload('test', { // options + title: ['title 1', 'title 2'] +}); +``` + +

                          获得右侧数据

                          + +`transfer.getData(id);` + +- 参数 `id` : 对应渲染时定义的 `id` 属性值 + +穿梭框的右侧数据通常被认为是选中数据,因此你需要得到它,并进行提交等操作。 + +``` +var transfer = layui.transfer; + +// 渲染 +transfer.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 获得右侧数据 +var getData = transfer.getData('test'); +``` diff --git a/docs/tree/detail/demo.md b/docs/tree/detail/demo.md new file mode 100644 index 000000000..dd71e96d1 --- /dev/null +++ b/docs/tree/detail/demo.md @@ -0,0 +1,179 @@ +

                          综合演示

                          + + +
                          +  
                          +
                          + +

                          无连接线风格

                          + +
                          +  
                          +
                          + +

                          仅图标控制伸缩

                          + +
                          +  
                          +
                          + +

                          手风琴模式

                          + +
                          +  
                          +
                          + +

                          开启复选框

                          + +
                          +  
                          +
                          + diff --git a/docs/tree/detail/options.data.md b/docs/tree/detail/options.data.md new file mode 100644 index 000000000..202df1462 --- /dev/null +++ b/docs/tree/detail/options.data.md @@ -0,0 +1,110 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          title + +节点标题 + +string-
                          id + +节点唯一索引值,用于对指定节点进行各类操作 + +string-
                          field + +节点字段名 + +string-
                          children + +子节点。支持设定属性选项同父节点 + +array-
                          href + +点击节点弹出新窗口对应的 url。需开启 isJump 基础属性才有效。 + +string-
                          spread + +节点是否初始展开 + +boolean + +`false` + +
                          checked + +节点是否初始为选中状态。需开启 `showCheckbox` 基础属性时有效。 + +boolean + +`false` + +
                          disabled + +节点是否为禁用状态 + +boolean + +`false` + +
                          diff --git a/docs/tree/detail/options.md b/docs/tree/detail/options.md new file mode 100644 index 000000000..744d45f32 --- /dev/null +++ b/docs/tree/detail/options.md @@ -0,0 +1,246 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器 + +string/DOM-
                          data + +`tree` 的数据源。其格式详见:[#data 格式](#options.data) + +array-
                          id + +设置实例唯一索引,用于其他方法传参使用。 + +string-
                          showCheckbox + +是否显示复选框 + +boolean + +`false` + +
                          edit + +是否开启节点的右侧操作图标。支持以下可选值: + +- 若为 `true`,则默认显示「改删」图标 +- 若为 数组,则可自由配置操作图标,如:`edit:['add', 'update', 'del']` ,且图标将按照数组的顺序显示。 + +boolean
                          array
                          + +`false` + +
                          accordion + +是否开启手风琴模式 + +boolean + +`false` + +
                          onlyIconControl + +是否仅允许节点左侧图标控制展开伸缩。 + +- 默认为 `false`,即点击节点本身也可控制伸缩 +- 若值为 `true`,则只能通过节点左侧图标来展开收缩 + +boolean + +`false` + +
                          isJump + +是否允许点击节点时弹出新窗口跳转。若为 `true`,则需在对应的 data 中设定 href 属性(url 格式) + +boolean + +`false` + +
                          showLine + +是否开启节点连接线。若设为 `false`,则节点左侧出现三角图标。 + +boolean + +`true` + +
                          + +[customName](#options.customName) 2.8.14+ + + + +自定义 `data` 数据源中常用的字段名称。 + +object-
                          text + +自定义默认文本,`object` 类型。支持以下属性: + +``` +text: { + defaultNodeName: '未命名', // 节点默认名称 + none: '无数据' // 数据为空时的提示文本 +} +``` + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          click + +
                          + 节点被点击的回调函数。返回的参数如下: +
                          + +``` +click: function(obj){ + console.log(obj.data); // 得到当前点击的节点数据 + console.log(obj.state); // 得到当前节点的展开状态:open、close、normal + console.log(obj.elem); // 得到当前节点元素 + + console.log(obj.data.children); // 当前节点下是否有子节点 +} +``` + +
                          oncheck + +
                          + 点击复选框时的回调函数,返回的参数如下: +
                          + +``` +oncheck: function(obj){ + console.log(obj.data); // 得到当前点击的节点数据 + console.log(obj.checked); // 节点是否被选中 + console.log(obj.elem); // 得到当前节点元素 +} +``` + +
                          operate + +
                          + 点击节点的右侧操作图标的回调函数,返回的参数如下: +
                          + +``` +operate: function(obj){ + var type = obj.type; // 得到操作类型:add、edit、del + var data = obj.data; // 得到当前节点的数据 + var elem = obj.elem; // 得到当前节点元素 + + // Ajax 操作 + var id = data.id; // 得到节点索引 + if(type === 'add'){ // 增加节点 + //返回 key 值 + return 123; + } else if(type === 'update'){ // 修改节点 + console.log(elem.find('.lay-tree-txt').html()); // 得到修改后的内容 + } else if(type === 'del'){ // 删除节点 + // … + }; +} +``` + +
                          diff --git a/docs/tree/index.md b/docs/tree/index.md new file mode 100644 index 000000000..67ab9731b --- /dev/null +++ b/docs/tree/index.md @@ -0,0 +1,129 @@ +--- +title: 树组件 tree +toc: true +--- + +# 树组件 + +> 树组件 `tree` 是以树形为结构的菜单伸缩型组件,*当前版本中,`tree`主要用于树菜单展示,交互性相对较弱。* + +

                          示例

                          + +
                          +{{- d.include("/tree/detail/demo.md") }} +
                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var tree = layui.tree | 获得 `tree` 模块。 | +| [基础接口](../component/#export) 2.13+ | 该组件由 `component` 构建,因此继承其提供的基础接口。| +| [tree.render(options)](#render) | tree 组件渲染,核心方法。 | +| [tree.getChecked(id)](#getChecked) | 获取选中的节点数据 | +| [tree.setChecked(id, idArr)](#setChecked) | 设置对应 id 的节点选中 | +| [tree.reload(id, options)](#reload) | tree 实例重载 | + +

                          渲染

                          + +`tree.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +

                          属性

                          + +
                          +{{- d.include("/tree/detail/options.md") }} +
                          + +

                          data 格式

                          + +
                          +{{- d.include("/tree/detail/options.data.md") }} +
                          + +
                          + +您可以对上述 `data` 中常用的字段进行自定义名称 2.8.14+ : + +
                          + +``` +var tree = layui.tree; +// 渲染 +tree.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + data: [], // 数据源 + customName: { // 自定义 data 字段名 --- 2.8.14+ + id: 'id', + title: 'title', + children: 'children' + }, + // 其他属性 … +}); +``` + +

                          获取选中的节点数据

                          + +`tree.getChecked(id);` + +- 参数 `id` : 对应 tree 渲染时定义的 id 属性值 + +``` +var tree = layui.tree; + +// 渲染 +tree.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 获取选中的节点数据 +var checkData = tree.getChecked('test'); +``` + +

                          设置对应 id 的节点选中

                          + +`tree.setChecked(id, idArr);` + +- 参数 `id` : 对应 tree 渲染时定义的 id 属性值 +- 参数 `idArr` : 对应 tree 渲染时的 data 中的 id 属性值。数组格式,可设置多个。 + +``` +var tree = layui.tree; + +// 渲染 +tree.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 设置对应 id 的节点选中 +tree.setChecked('test', [1, 3]); // 批量勾选 id 为 1,3 的节点 +``` + +

                          重载

                          + +`tree.reload(id, idArr);` + +- 参数 `id` : 对应 tree 渲染时定义的 id 属性值 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +``` +var tree = layui.tree; + +// 渲染 +tree.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +// 重载 +tree.reload('test', { // options + data: [] +}); +``` diff --git a/docs/treeTable/detail/demo.md b/docs/treeTable/detail/demo.md new file mode 100644 index 000000000..790f817e0 --- /dev/null +++ b/docs/treeTable/detail/demo.md @@ -0,0 +1,18 @@ +

                          综合演示

                          + +
                          +  
                          +
                          + + + + + diff --git a/docs/treeTable/detail/options.md b/docs/treeTable/detail/options.md new file mode 100644 index 000000000..bcf11f8c9 --- /dev/null +++ b/docs/treeTable/detail/options.md @@ -0,0 +1,184 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述
                          tree + +treeTable 组件的特定属性集,包含以下「子成员集」: + +| 属性 | 描述 | +| --- | --- | +| [customName](#options.tree.customName) | 自定义属性名的集合 | +| [view](#options.tree.view) | 视图相关的属性集合 | +| [data](#options.tree.data) | 数据相关的属性集合 | +| [async](#options.tree.async) | 异步相关的属性集合 | +| [callback](#options.tree.callback) | 事件回调相关的属性集合 | + +用法如下: + +```js +treeTable.render({ + elem: '', + tree: { // treeTable 特定属性集 + customName: {}, + data: {}, + view: {}, + async: {}, + callback: {} + }, + // 其他 table 属性 +}); +```` + +
                          tree.customName + +
                          + +自定义属性名的集合,包含以下成员: + +
                          + +| 属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| children | 自定义「子节点集合」的属性名 | string | `children` | +| isParent | 自定义「是否属于父节点」的属性名 | string | `isParent` | +| name | 自定义「节点」属性名 | string | `name` | +| id | 自定义「节点索引」属性名 | string | `id` | +| pid | 自定义「父节点索引」属性名 | string | `parentId` | +| icon | 自定义图标的属性名称 | string | `icon` | + +
                          tree.view + +
                          + +视图相关的属性集合,包含以下成员: + +
                          + +| 属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| indent | 层级缩进量 | number | `14` | +| flexIconClose | 自定义关闭时的折叠按钮图标 | string | - | +| flexIconOpen | 自定义打开时的折叠按钮图标 | string | - | +| showIcon | 是否显示节点图标 | boolean | `true` | +| icon | 自定义节点图标。若设置了该属性或数据中有该字段信息,不管打开还是关闭都以这个图标的值为准 | string | - | +| iconClose | 自定义关闭时的节点图标 | string | - | +| iconOpen | 自定义打开时的节点图标 | string | - | +| iconLeaf | 自定义叶子节点的图标 | string | - | +| showFlexIconIfNotParent | 若非父节点时,是否显示折叠图标 | boolean | `false` | +| dblClickExpand | 双击节点时,是否自动展开父节点 | boolean | `true` | +| expandAllDefault 2.8.7+ | 是否默认展开全部节点 | boolean | `false` | + +自定义图标支持 HTML 字符串和图标类名。例如: + +- `''` +- `'lay-icon lay-icon-addition'` + +
                          tree.data + +
                          + +数据相关的属性集合,包含以下成员: + +
                          + +| 属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| isSimpleData | 是否使用平铺数据格式(Array) | boolean | `false` | +| rootPid | 用于设置根节点的 `pid` 属性值 | string | `null` | +| cascade | 用于设置复选的级联方式。支持以下可选值:
                          • all : 所有节点联动
                          • parent : 仅对父节点联动
                          • children : 仅对子节点联动
                          • none 2.8.16+ : 不做任何联动
                          | string | `all` | + +
                          tree.async + +
                          + +异步相关的属性集合,包含以下成员: + +
                          + +| 属性 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| enable | 是否开启异步加载模式。只有开启时 `async` 的其他属性选项才有效。 **注意:** 异步加载子节点不应跟 `simpleData` 同时开启,可以是 `url+simpleData` 的方式,获取完整的简单数据进行转换。若开启异步加载模式,即表示按需异步加载子节点。 | boolean | `false` | +| url | 异步加载的接口,可以根据需要设置与顶层接口不同的接口,若相同可不设置该属性 | string | - | +| [format](#options.tree.async.format) | 用于处理异步子节点数据的回调函数,该属性优先级高于 `async.url` 属性。用法详见下文。 | function | - | +| type | 请求的接口类型,设置可缺省同上 | string | - | +| contentType | 提交参数的数据类型,设置可缺省同上 | string | - | +| headers | 提交请求头,设置可缺省同上 | object | - | +| where | 提交参数的数据,设置可缺省同上 | object | - | +| autoParam | 自动参数,可以根据配置项以及当前节点的数据传参,如: `['type', 'age=age', 'parentId=id']` ,那么其请求参数将包含: `{type: '父节点 type', age: '父节点 age', parentId: '父节点 id'}` | array | - | + +
                          + +**format 示例** : + +
                          + +``` +treeTable.render({ + elem: '', + tree: { + enable: true, + async: { + format: function(trData, options, callback){ + // trData 为行数据、options 为 treeTable 属性选项 + // callbacck 为子节点的渲染函数 + // 可利用该函数对子节点数据进行异步请求或其他格式化处理 + var nodeList = [ + {id: 111, name: '子节点1'}, + {id: 333, name: '子节点3'} + ]; + callback(nodeList); + } + } + } +}) +``` + +
                          tree.callback + +
                          + +事件回调相关的属性集合,包含以下成员: + +
                          + +| 属性 | 描述 | +| --- | --- | +| beforeExpand | 展开前回调函数。可以在展开或者关闭之前调用,传入当前表格 `id` ,当前操作的行数据以及要展开或关闭的状态,若回调返回 `false` 则取消该次操作。 返回的参数包含: `function(tableId, trData, expandFlag){ console.log(arguments); }` | +| onExpand | 展开或关闭后的回调函数,返回参数同 `beforeExpand` | + +
                          + diff --git a/docs/treeTable/examples/demo.md b/docs/treeTable/examples/demo.md new file mode 100644 index 000000000..e710b128b --- /dev/null +++ b/docs/treeTable/examples/demo.md @@ -0,0 +1,121 @@ +
                          + + + + + + + + diff --git a/docs/treeTable/index.md b/docs/treeTable/index.md new file mode 100644 index 000000000..a6b89ac4f --- /dev/null +++ b/docs/treeTable/index.md @@ -0,0 +1,387 @@ +--- +title: 树表组件 treeTable +toc: true +--- + +# 树表组件 2.8+ + +> 树表组件 `treeTable` 是基于 `table` 组件延伸的树形表格组件,支持常见的树组件功能。
                          +> 注意:*该组件不支持 IE8,若要支持,可自行添加 polyfill实现兼容。* + +

                          示例

                          + +以下所有示例中演示的数据均为「静态模拟数据」,实际使用时换成您的真实接口即可。 + +
                          +{{- d.include("/treeTable/detail/demo.md") }} +
                          + +

                          + +

                          API

                          + +`table` 组件的所有 `API` 均适用于 `treeTable` 组件。在此基础上,`treeTable` 还专门提供了以下方法: + +| API | 描述 | +| --- | --- | +| var treeTable = layui.treeTable; | 获得 `treeTable` 模块。 | +| [treeTable.render(options)](#render) | treeTable 组件渲染,核心方法。 | +| [treeTable.reload(id, options)](#reload) | 树表完整重载。 | +| [treeTable.reloadData(id, options)](#reload) | 树表数据重载。 | +| [treeTable.reloadAsyncNode(id, index)](#reloadAsyncNode) | 重载异步子节点 | +| [treeTable.getData(id, isSimpleData)](#getData) | 获取树表数据。 | +| [treeTable.getNodeById(id, dataId)](#getNodeById) | 获取节点信息集 | +| [treeTable.getNodesByFilter(id, filter, opts)](#getNodesByFilter) | 获取符合过滤规则的节点信息集 | +| [treeTable.getNodeDataByIndex(id, index)](#getNodeDataByIndex) | 通过行元素对应的 `data-index` 属性获取对应行数据。 | +| [treeTable.updateNode(id, index, data)](#updateNode) | 更新行数据。 | +| [treeTable.removeNode(id, index)](#removeNode) | 删除行记录。 | +| [treeTable.addNodes(id, opts)](#addNodes) | 新增行记录。 | +| [treeTable.expandNode(id, opts)](#expandNode) | 展开或关闭节点。 | +| [treeTable.expandAll(id, expandFlag)](#expandAll) | 展开或关闭全部节点。 | +| [treeTable.setRowChecked(id, opts)](#setRowChecked) | 设置行选中状态 | +| [treeTable.checkAllNodes(id, checked)](#checkAllNodes) | 全选或取消全选 | +| [treeTable.checkStatus(id, includeHalfCheck)](#checkStatus) | 获取选中行相关数据 | +| [treeTable.on(\'event(filter)\', callback)](#on) | treeTable 相关事件 | + +

                          渲染

                          + +`treeTable.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该组件渲染的使用方式与 `table` 组件完全相同。 + +

                          属性

                          + +`table` 组件的所有基础属性均适用于 `treeTable` 组件。在此基础上,`treeTable` 还专门提供了 `tree` 属性集: + +
                          +{{- d.include("/treeTable/detail/options.md") }} +
                          + +

                          重载

                          + +即对一段已经渲染好的表格重新设置属性并渲染,可分为以下几种重载方式: + +| 重载方式 | API | +| --- | --- | +| 完整重载 | treeTable.reload(id, options) | +| 仅数据重载 | treeTable.reloadData(id, options) | + +- 参数 `id` : treeTable 渲染时的 id 属性值 +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +使用方式与 `table` 组件完全相同,具体用法可参考:[table 重载](../table/#reload) + + +

                          重载异步子节点

                          + +`treeTable.reloadAsyncNode(id, index)` + +- 参数 `id` : treeTable 渲染时的 id 属性值 +- 参数 `index` : 节点对应的行下标,一般可通过 `` 元素的 `data-index` 属性获得 + +该方法用于在异步模式下,对节点进行重载。 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + async: { + enable: true // 开启异步加载模式 + } + // 其他属性 … +}); +// 重载子节点 +treeTable.reloadAsyncNode('test', 0); // 第一行 +``` + + +

                          获取树表数据

                          + +`treeTable.getData(id, isSimpleData);` + +- 参数 `id` : treeTable 渲染时的 id 属性值 +- 参数 `isSimpleData` : 是否为简单数据,为 `true` 时返回简单数据结构的数据,否则则为带层级的数据 + +该方法用于获取表格当前页的全部数据,它对应的是接口返回的原始数据,不包含 `treeTable` 组件内部的特定字段。 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 获取当前页接口的树表数据 +var data = treeTable.getData('test'); // 获取第一行的数据 +console.log(data); +``` + +

                          获取节点信息集

                          + +`treeTable.getNodeById(id, dataId)` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `dataId` : 数据项的 `id` 属性值 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 获取节点信息集 +var obj = treeTable.getNodeById('test', 1); +console.log(obj); +``` + +

                          获取符合过滤规则的节点信息集

                          + +`treeTable.getNodesByFilter(id, filter, opts)` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `filter` : 过滤函数 +- 参数 `opts` : 该方法的属性选项,详见下表: + +| 属性名 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| isSingle | 是否只找到第一个 | boolean | `false` | +| parentNode | 在指定在某个父节点下的子节点中搜索 | object | - | + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 获取节点信息集 +var obj = treeTable.getNodesByFilter('test', function(item){ + // 自定义过滤条件 + return item.id > 1000; +}); +console.log(obj); +``` + + +

                          获取树表对应下标的数据

                          + +`treeTable.getNodeDataByIndex(id, index);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `index` : 节点对应的行下标,一般可通过 `` 元素的 `data-index` 属性获得 + +该方法用于获取表格当前页对应下表的数据,返回的数据格式同 `treeTable.getData()` 方法。 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 获取树表对应下标的数据 +var obj = treeTable.getNodeDataByIndex('test', 0); // 获取第一行的数据 +console.log(obj); +``` + +

                          更新行数据

                          + +`treeTable.updateNode(id, index, data);` + +- 参数 `id` : treeTable 渲染时的 id 属性值 +- 参数 `index` : 节点对应的行下标,一般可通过 `` 元素的 `data-index` 属性获得 +- 参数 `data` : 更新的数据项,可包含要更新的各种字段 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 更新行数据 +var data = treeTable.updateNode('test', 0, { // 更新第一行的数据 + title: '123' +}); +``` + +

                          删除行记录

                          + +`treeTable.removeNode(id, index);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `index/node` : 要删除的节点数据,也可以是节点对应的行下标( `data-index`) + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 删除行记录 +treeTable.removeNode('test', 0); // 删除第一行 +``` + + +

                          新增行数据

                          + +`treeTable.addNodes(id, opts);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `opts` : 该方法可支持的可选属性项,详见下表: + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | -- | --- | +| parentIndex | 父节点数据下标 | number | - | +| index | 节点对应的行下标。若为 `-1` 表示插入到最后,否则则插入到对应下标。 | number | `-1`| +| data | 新增的节点数据项。若新增的是多个节点,则用数组的形式。若只有一个节点可以是普通对象形式 | object | - | +| focus | 是否聚焦到新增的节点。若存在多个,则聚焦到第一个新增的节点 | boolean | `false` | + +该方法可返回新增后的数据项。详细用法可参考:[#示例](#examples) + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 新增行数据 +treeTable.addNodes('test', { + parentIndex: 0, // 一般在 tool 事件中,可通过对应数据项中的 `LAY_DATA_INDEX` 特定属性获得 + index: 1, + data: { + title: '新节点-1' + } +}); +``` + + +

                          展开或关闭节点

                          + +`treeTable.expandNode(id, opts);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `opts` : 该方法可支持的可选属性项,详见下表: + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | -- | --- | +| index | 节点对应的行下标,一般可通过 `` 元素的 `data-index` 属性获得 | number | - | +| expandFlag | 设置展开或关闭状态,若为 `true` 则表示展开;`false` 则为关闭;`null` 则表示切换 | boolean/null | - | +| inherit | 子节点是否继承父节点的展开或关闭状态,`expandFlag` 属性必须为 `boolean` 型时才有效。 | boolean | `false` | +| callbackFlag | 是否触发 tree.callback 事件(`beforeExpand,onExpand`) | boolean | `false` | +| done 2.11.3+| 节点操作完成后的回调函数 | (tableId, trData, trExpand) => void | - | + +若操作的节点不是一个父节点,则返回 `null`,否则返回操作之后的折叠状态。 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 展开或关闭对应节点 +treeTable.expandNode('test', { + index: 0, // 第一行 + expandFlag: true // 展开 +}); +``` + +

                          展开或关闭全部节点

                          + +`treeTable.expandAll(id, expandFlag);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `expandFlag` : 折叠状态。 `true` 展开;`false` 关闭 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 展开或关闭全部节点 +treeTable.expandAll('test', false); // 关闭全部节点 +``` + +

                          设置行选中状态

                          + +`treeTable.setRowChecked(id, opts);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `opts` : 该方法可支持的可选属性项,详见下表: + +| opts | 描述 | 类型 | 默认值 | +| --- | --- | -- | --- | +| index | 要设置选中状态的行下标或行数据 | number/object | - | +| checked | 选中状态。`true` 选中;`false` 取消选中;`null` 切换。 其中,若为 `radio` 框,则不支持 `null`(切换)。 | boolean | - | +| callbackFlag | 是否触发事件,若为 `true`,则 `checked: false` 无效。其对应的事件跟 `table` 的 `radio,checkbox` 事件用法一样 | boolean | `false` | + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 勾选或取消勾选单个节点 +treeTable.setRowChecked('test', { + index: 0, + checked: true // 选中 +}); +``` + +

                          设置全选或取消全选

                          + +`treeTable.checkAllNodes(id, checked);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `checked` : 选中状态。`true` 选中;`false` 取消选中;`null` 复选框模式时的切换。 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); +// 勾选或取消勾选单个节点 +treeTable.checkAllNodes('test', true); // 全选 +``` + +

                          获取行选中相关数据

                          + +`treeTable.checkStatus(id, includeHalfCheck);` + +- 参数 `id` : treeTable 渲染时的 `id` 属性值 +- 参数 `includeHalfCheck` : 是否包含半选数据 + +```js +// 渲染 +treeTable.render({ + elem: '', // 绑定元素选择器 + id: 'test', // 自定义 id 索引 + // 其他属性 … +}); + +treeTable.checkStatus('test', true); // 包含半选 +``` + + +

                          事件

                          + +`treeTable.on('event(filter)', callback);` + +`treeTable` 事件继承于 `table` 事件,具体使用方法可参考:[#table 事件](../table/#table.on) + + +## 贴士 + +> `treeTable` 基于 `table` 组件扩展而来,因此,熟练运用 `treeTable` 的前提是熟悉 `table` 组件。 亦可通过 `table` 提供的基础 `API` 操作 `treeTable` 组件,但 `treeTable` 无法操作 `table`。 diff --git a/docs/upload/detail/demo.md b/docs/upload/detail/demo.md new file mode 100644 index 000000000..7795ba762 --- /dev/null +++ b/docs/upload/detail/demo.md @@ -0,0 +1,62 @@ +

                          图片上传

                          + +
                          +  
                          +
                          + +

                          制作多文件上传表格

                          + +
                          +  
                          +
                          + + +

                          过滤文件类型

                          + +
                          +  
                          +
                          + + +

                          限制文件大小

                          + +
                          +  
                          +
                          + +

                          选择后手动上传

                          + +
                          +  
                          +
                          + + +

                          拖拽上传

                          + +
                          +  
                          +
                          + + +

                          绑定原始文件域

                          + +
                          +  
                          +
                          diff --git a/docs/upload/detail/options.md b/docs/upload/detail/options.md new file mode 100644 index 000000000..eb23927cf --- /dev/null +++ b/docs/upload/detail/options.md @@ -0,0 +1,535 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                          属性名描述类型默认值
                          elem + +绑定元素选择器或 DOM 对象 + +string/DOM-
                          url + +上传接口 + +string-
                          field + +文件域的字段名 + +string + +`file` + +
                          + +[data](#options.data) + + + +
                          +传递给上传接口的额外参数,支持静态赋值和动态赋值两种写法。 +
                          + +- 静态赋值 : + +``` +data: { + id: '123' +} +``` + +- 动态赋值 : + +``` +data: { + id: function(){ + return $('#id').val(); + }, + id2: function(index, file){ // 参数支持。2.9.3+ + // 注:当 unified:true 和 ie8/9 下,参数无效 + console.log(index); // 得到文件索引 + console.log(file); // 得到文件对象 + } +} +``` + +
                          object-
                          headers + +上传接口的请求头。如 `headers: {token: 'abc123'}` + +object-
                          dataType 2.8.17+ + +服务端返回的数据类型,如:`text,json,xml` 等 + +string + +`json` + +
                          + +[accept](#options.accept) + + + +
                          +指定允许上传时校验的文件类型。可选值有: +
                          + +- `images` 图片类型 +- `file` 所有文件类型 +- `video` 视频类型 +- `audio` 音频类型 + +
                          string + +`images` + +
                          acceptMime + +规定打开系统的文件选择框时,筛选出的文件类型,多个 `MIME` 类型可用逗号隔开。示例: + +``` +acceptMime: 'image/*'` // 筛选所有图片类型 +acceptMime: 'image/jpeg, image/png` // 只筛选 jpg,png 格式图片 +``` + +更多可选值参考: MIME 类型 + +string-
                          + +[exts](#options.exts) + + + +
                          + +允许上传的文件后缀。一般结合 `accept` 属性来设定。 + +
                          + +- 假设 `accept: 'file'` 类型时,那么设置 `exts: 'zip|rar|7z'` 即代表只允许上传压缩格式的文件。 +- 默认为常见图片后缀,即 `jpg|png|gif|bmp|jpeg|svg` + +
                          string + +见左 + +
                          auto + +是否选完文件后自动上传。若为 `false`,则需设置 `bindAction` 属性来指向其它按钮提交上传。参考:[#示例](#demo-auto) + +boolean + +`true` + +
                          bindAction + +设置触发上传的元素选择器或 DOM 对象。 +
                          一般配合 `auto: false` 来使用。详细用法参考:[#示例](#demo-auto) + +
                          string/DOM-
                          force 2.6.9+ + +规定强制返回的数据格式。 + +- 若值为 `'json'`,则强制校验 JSON 数据格式 + +string + +`null` + +
                          size + +设置文件最大可允许上传的大小,单位 `KB` 。默认不限制。 +
                          不支持 `ie8/9` + +
                          number + +`0` + +
                          multiple + +是否允许多文件上传。不支持 `ie8/9` + +boolean + +`false` + +
                          unified 2.8.8+ + +选择多文件时,是否统一上传,即只发送一次请求。 + +boolean + +`false` + +
                          number + +同时可上传的文件数量,一般当 `multiple: true` 时使用。 + +number-
                          drag + +是否接受拖拽的文件上传。 + +boolean + +`true` + +
                          + +[text](#options.text) 2.8.9+ + + + +
                          + +自定义内部各类场景下的提示文本 + +
                          + +``` +text: { // 自定义提示文本 + "data-format-error": "", // 数据格式错误的提示 + "check-error": "", // 文件格式校验失败的提示 + "error": "", // 上传失败的提示 + "limit-number": null, // 限制 number 属性的提示。若设置,需为函数写法 + "limit-size": null, // 限制 size 属性的提示。若设置,需为函数写法 + "cross-domain": "", // IE 下跨域的提示 +} +``` + +
                          + + +
                          + +[回调函数](#options.callback) + +
                          + +
                          + +[choose](#options.choose) + + + +
                          +选择文件后的回调函数。返回的参数如下 +
                          + +``` +choose: function(obj){ + // 将每次选择的文件追加到文件队列 + var files = obj.pushFile(); + + // 预读本地文件,如果是多文件,则会遍历。(不支持ie8/9) + obj.preview(function(index, file, result){ + console.log(index); // 得到文件索引 + console.log(file); // 得到文件对象 + console.log(result); // 得到文件base64编码,比如图片 + + // obj.resetFile(index, file, '123.jpg'); // 重命名文件名 + + // 这里还可以做一些 append 文件列表 DOM 的操作 + + // obj.upload(index, file); // 对上传失败的单个文件重新上传,一般在某个事件中使用 + // delete files[index]; //删除列表中对应的文件,一般在某个事件中使用 + }); +} + +// 获取本次选取的文件,大文件建议用此方法获取文件信息(2.9.9+) +obj.getChooseFiles(); +``` + +详细用法参考:[#示例](#demo-files-table) + +
                          + +[before](#options.before) + + + +
                          +文件提交上传前的回调函数。返回的参数同 choose +
                          + +``` +before: function(obj){ // obj 参数同 choose + layer.load(); // 上传 loading + + // 若返回 false,则表明阻止上传 + /* + if(true){ + return false; + } + */ +} + +// 返回 jQuery Deferred 对象或 JS 原生 Promise 对象,false 或 Promise.reject 表明阻止上传(2.9.11+) +// Promise +/** @type {(obj: object) => boolean | JQueryDeferred | Promise} */ +before: function(obj){ + return new Promise(function(resolve, reject){ + setTimeout(function(){ + console.log('before_async_task', obj); + resolve(true); + }, 1000) + }) +} + +// Deferred +before: function(obj){ + return $.Deferred(function(defer){ + setTimeout(function(){ + console.log('before_async_task', obj); + defer.resolve(true); + }, 1000) + }).promise(); +} + +// Deferred2 +before: function(obj){ + var defer = $.Deferred(); + setTimeout(function(){ + console.log('before_async_task', obj); + defer.resolve(true); + }, 1000) + return defer.promise(); +} +``` + +
                          + +[progress](#options.progress) + + + +
                          +执行上传请求后的回调函数。返回的参数如下: +
                          + +``` +progress: function(n, elem, res, index){ + var percent = n + '%' // 获取进度百分比 + element.progress('demo', percent); // 可配合 layui 进度条元素使用 + + // 得到当前触发的元素 DOM 对象 + console.log(elem); // 可通过该元素定义的属性值匹配到对应的进度条。 + console.log(res); // 得到 progress 响应信息 + + console.log(index); // 得到当前上传文件的索引,多文件上传时的进度条控制 + element.progress('demo-'+ index, n + '%'); // 进度条 +} +``` + +详细用法参考:[#示例](#examples) +
                          + +[done](#options.done) + + + +
                          +执行单次文件上传请求后的回调函数。返回的参数如下: +
                          + +``` +done: function(res, index, upload){ + // 假设 `code: 0` 代表上传成功 + if(res.code == 0){ + // do something // 比如将 res 返回的图片链接保存到隐藏域 + } + + // 获取当前触发上传的元素,一般用于 elem 绑定 class 的情况 + var item = this.item; + + // … +} +``` + +详细用法参考:[#示例](#examples) + +
                          + +[allDone](#options.allDone) + + + +
                          + +当开启多文件 (`multiple: true` ) 且所有文件均上传完毕后的状态回调函数。 + +
                          + +``` +allDone: function(obj){ + console.log(obj.total); // 上传的文件总数 + console.log(obj.successful); // 上传成功的文件数 + console.log(obj.failed); // 上传失败的文件数 +} +``` + +
                          error + +执行上传请求出现异常的回调(一般为网络异常、URL 404等)。返回三个参数如下: +- `index`: 当前文件的索引 +- `upload`: 重新上传的方法 +- `res`: 返回值(纯文本)2.9.12+ +- `xhr`: jQuery XHR 对象 2.9.15+ + +``` +error: function(index, upload, res, xhr){ + console.log(index); // 当前文件的索引 + // upload(); 重新上传的方法 + console.log(res); // 返回值(纯文本) + console.log(JSON.parse(res)); // 返回值(json) + console.log(xhr); +} +``` + +
                          + diff --git a/docs/upload/examples/accept.md b/docs/upload/examples/accept.md new file mode 100644 index 000000000..85ca16fe8 --- /dev/null +++ b/docs/upload/examples/accept.md @@ -0,0 +1,40 @@ +
                          + + + + +
                          + + + diff --git a/docs/upload/examples/auto.md b/docs/upload/examples/auto.md new file mode 100644 index 000000000..a13020177 --- /dev/null +++ b/docs/upload/examples/auto.md @@ -0,0 +1,24 @@ +
                          + + +
                          + + + diff --git a/docs/upload/examples/drag.md b/docs/upload/examples/drag.md new file mode 100644 index 000000000..beb67bb28 --- /dev/null +++ b/docs/upload/examples/drag.md @@ -0,0 +1,28 @@ +
                          + +
                          点击上传,或将文件拖拽到此处
                          +
                          +
                          上传成功后渲染 +
                          +
                          + + + + diff --git a/docs/upload/examples/files.table.md b/docs/upload/examples/files.table.md new file mode 100644 index 000000000..2aa8bba52 --- /dev/null +++ b/docs/upload/examples/files.table.md @@ -0,0 +1,100 @@ +
                          + +
                          + + + + + + + + + + + + + + +
                          文件名大小上传进度操作
                          +
                          + +
                          + + + + diff --git a/docs/upload/examples/form.file.md b/docs/upload/examples/form.file.md new file mode 100644 index 000000000..2b7cc9df7 --- /dev/null +++ b/docs/upload/examples/form.file.md @@ -0,0 +1,19 @@ + + + + \ No newline at end of file diff --git a/docs/upload/examples/image.md b/docs/upload/examples/image.md new file mode 100644 index 000000000..3a4a137b5 --- /dev/null +++ b/docs/upload/examples/image.md @@ -0,0 +1,88 @@ + +
                          +
                          + +
                          +
                          +
                          +
                          +
                          +
                          +
                          +
                          + +
                          + 预览图: +
                          +
                          +
                          + + + diff --git a/docs/upload/index.md b/docs/upload/index.md new file mode 100644 index 000000000..6ee35b986 --- /dev/null +++ b/docs/upload/index.md @@ -0,0 +1,128 @@ +--- +title: 上传组件 upload +toc: true +--- + +# 上传组件 + +> 上传组件 `upload` 是用于处理文件上传的前端交互逻辑,可以更好地协助后端实现文件从本地到服务端上传的对接。 + +

                          示例

                          + +以下示例均没有设置上传接口,因此每次上传都会报异常提示,这属于正常现象。实际使用时设置成您的真实上传接口即可。 + +
                          + +
                          +{{- d.include("/upload/detail/demo.md") }} +
                          + +

                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var upload = layui.upload | 获得 `upload` 模块。 | +| [var inst = upload.render(options)](#render) | upload 组件渲染,核心方法。 | +| [inst.upload()](#upload) | 对当前实例提交上传 | +| [inst.reload(options)](#reload) | 对当前实例进行重载 | +| inst.config | 获得当前实例的属性选项 | + +

                          渲染

                          + +`upload.render(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) +
                          注 : 除 `elem` 属性外,其他基础属性也可以直接写在元素的 `lay-options="{}"` 属性中。 + +``` + + + + + + +``` + +该方法返回一个实例对象,包含操作当前实例的相关方法成员。 + +``` +var inst = upload.render(options); +console.log(inst); // 得到当前实例对象 +``` + +

                          提交上传

                          + +`inst.upload();` + +- 无需传递参数 + +文件在进行选择后,会自动提交上传。而若文件*上传失败*,则可以使用该方法来重新上传, + +``` +// 渲染 +var inst = upload.render({ + elem: '#id', + error: function(){ // 上传失败的回调 + // 当上传失败时,可在此处生成「重新上传」按钮,并执行该方法重新触发上传提交 + /* + $('#btn').on('click', function(){ + inst.upload(); + }) + */ + } + // … +}); +``` + +

                          重载

                          + +`inst.reload(options);` + +- 参数 `options` : 基础属性选项。[#详见属性](#options) + +该方法用于对当前的上传实例进行完整重载,所有属性均可参与到重载中。 + +``` +// 渲染 +var inst = upload.render({ + elem: '#id', + // … +}); + +// 重载 +inst.reload({ + field: 'AAA', + // … +}) +``` + +

                          属性

                          + +
                          +{{- d.include("/upload/detail/options.md") }} +
                          + +

                          跨域方案

                          + +`upload` 组件支持跨域上传,一般有以下两种场景 + +- 自建上传服务。在服务端配置 `CORS` 开启跨资源共享。 即对接口所在的服务器设置 `Access-Control-Allow-Origin ` 相关 `header` 信息。 + +- 第三方上传服务。如:阿里云、腾讯云等,只需按照不同平台对应的上传 SDK 进行操作即可。 + diff --git a/docs/util/detail/demo.md b/docs/util/detail/demo.md new file mode 100644 index 000000000..ad2933c25 --- /dev/null +++ b/docs/util/detail/demo.md @@ -0,0 +1,129 @@ +
                          +  
                          +
                          + diff --git a/docs/util/index.md b/docs/util/index.md new file mode 100644 index 000000000..c5ad55dd2 --- /dev/null +++ b/docs/util/index.md @@ -0,0 +1,265 @@ +--- +title: 工具模块 util +toc: true +--- + +# 工具模块 + +> 工具模块 `util` 是由工具类方法和小组件组成的集合。 + +

                          示例

                          + +
                          +{{- d.include("/util/detail/demo.md") }} +
                          + +

                          + +

                          API

                          + +| API | 描述 | +| --- | --- | +| var util = layui.util | 获得 `util` 模块。 | +| [util.fixbar(options)](../fixbar/) | 固定条组件 | +| [util.countdown(options)](#countdown) | 倒计时组件 | +| [util.timeAgo(time, onlyDate)](#timeAgo) | 某个时间在多久前 | +| [util.toDateString(time, format, options)](#toDateString) | 将毫秒数或日期对象转换成日期格式字符 | +| [util.digit(num, length)](#digit) | 数字前置补零 | +| [util.escape(str)](#escape) | 转义 HTML 字符 | +| [util.unescape(str)](#escape) | 还原 HTML 字符 | +| [util.openWin(options)](#openWin) 2.8+ | 打开浏览器新标签页 | +| [util.on(attr, events, options)](#on) | 批量事件处理 | + +

                          倒计时

                          + +`util.countdown(options);` + +- 参数 `options` 2.8.9+: 属性选项。可选项详见下表: + +| 属性 | 描述 | +| --- | --- | +| date | 目标时间值。值可以为毫秒数或 `Date` 对象 | +| now | 当前时间值,一般为当前服务器时间。值可以为毫秒数或 `Date` 对象 | +| ready | 倒计时初始时的回调函数。 | +| clock | 倒计时计时中的回调函数,每秒触发一次,直到计时完成。 | +| done | 倒计时计时完成的回调函数,即到达目标时间值时触发 | + +- 注: 2.8.9 之前的版本写法为:`util.countdown(date, now, clock);` + +该方法返回的实例对象成员如下 2.8.9+: + +```js +var countdown = util.countdown(options); +countdown.clear(); // 清除当前倒计时 +countdown.reload(options); // 重载当前倒计时。 +countdown.timer; // 当前倒计时计时器 ID +``` + +相关用法可参考:[#示例](#examples) + +```js +layui.use('util', function(){ + var util = layui.util; + // 示例 + util.countdown({ + date: '2099-1-1', // 目标时间值 + now: new Date(), // 当前时间,一般为服务器时间,此处以本地时间为例 + clock: function(obj, countdown){ // 计时中 + console.log(obj); // 得到当前计时器的「天、时、分、秒」值 + console.log(countdown); // 得到当前实例对象 + }, + done: function(obj, countdown){ // 计时完成 + console.log('time is up'); + } + }); +}); +``` + +

                          某个时间在多久前

                          + +`var result = util.timeAgo(time, onlyDate);` + +- 参数 `time` : 某个时间的毫秒数或日期对象 +- 参数 `onlyDate` : 是否在超过 30 天后,只返回日期字符,而不返回时分秒 + +返回结果 + +- 若 `time` 在 3 分钟以内,返回: 刚刚 +- 若 `time` 在 30 天以内,返回: 若干分钟前、若干小时前、若干天前,如:5 分钟前 +- 若 `time` 在 30 天以上,返回: 日期字符,如: 2023-01-01 + +``` +var result = util.timeAgo(1672531200000); // 2023-01-01 00:00:00 +``` + +相关效果见:[#示例](#examples) + + +

                          转换日期格式字符

                          + +`var result = util.toDateString(time, format, options);` + +- 参数 `time` : 毫秒数或日期对象 +- 参数 `format` : 日期字符格式。默认格式:`yyyy-MM-dd HH:mm:ss` 。可自定义,如: `yyyy年MM月dd日` +- 参数 `options` 2.8.13+ : 该方法的属性选项,详见下表: + +| 属性名 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| customMeridiem | 自定义 meridiem 格式 | Function | - | + +``` +var result = util.toDateString(1672531200000, 'yyyy-MM-dd'); // 2023-01-01 + +// 中括号中的字符会原样保留 2.8.13+ +var result2 = util.toDateString(new Date('2023-01-01 11:35:25'), 'ss[s]'); // 25s + +// 自定义 meridiem +var result3 = util.toDateString( + '2023-01-01 11:35:25', + 'hh:mm:ss A', + { + customMeridiem: function(hours, minutes){ + return (hours < 12 ? 'AM' : 'PM') + //.split('').join('.') // 有句点,A.M. + //.toLowerCase() // 小写,a.m. + } + } +); // 11:35:25 AM +``` + +参数 `format` 所有可用的格式列表 : + +| 格式 | 示例 | 描述 | +| --- | --- | --- | +| yy 2.8.13+ | 23 | 年,两位数 | +| yyyy | 2023 | 年,四位数 | +| M 2.8.13+ | 1-12 | 月 | +| MM | 01-12 | 月,两位数 | +| d 2.8.13+ | 1-31 | 日 | +| dd | 01-31 | 日,两位数 | +| H 2.8.13+ | 0-23 | 小时 | +| HH | 00-23 | 小时,两位数 | +| h 2.8.13+ | 1-12 | 小时,12 小时制 | +| hh 2.8.13+ | 01-12 | 小时,12 小时制,两位数 | +| A 2.8.13+ | 凌晨/早上/上午/中午/下午/晚上 | meridiem | +| m 2.8.13+ | 0-59 | 分钟 | +| mm | 00-59 | 分钟,两位数 | +| s 2.8.13+ | 0-59 | 秒 | +| ss | 00-59 | 秒,两位数 | +| SSS 2.8.13+ | 000-999 | 毫秒,三位数 | + +

                          数字前置补零

                          + +`util.digit(num, length);` + +- 参数 `num` : 原始数字 +- 参数 `length` : 数字长度,如果原始数字长度小于 length,则前面补零 + +该方法返回一个 `string` 类型的结果,如: + +``` +var rs1 = util.digit(6, 2); // "06" +var rs2 = util.digit(7, 3); // "007" +``` + + +

                          转义和还原 HTML

                          + +- `util.escape(str);` 转义 HTML +- `util.unescape(str);` 还原被转义的 HTML + +参数 `str` : 任意 HTML 字符 + +``` +var str1 = util.escape('
                          123
                          '); // 返回: <div>123</div> +var str2 = util.unescape('<div>123</div>'); // 返回:
                          123
                          +``` + +

                          打开浏览器新标签页 2.8+

                          + +`util.openWin(options);` + +- 参数 `options` : 属性选项。可选项详见下表 + +| 属性 | 描述 | +| --- | --- | +| url | 要打开页面 `URL` | +| target | 打开页面的方式或窗口 `name` | +| content | 打开的页面内容。若设置了 `url` 属性,则该属性无效 | +| specs | 窗口的相关配置,同 `window.open()` 的 `specs` | +| window | 当前所在的窗口对象,默认 `self` | + +该方法基于原生 `window.open()` 的二次封装,以提升打开浏览器窗口的灵活性。 + +``` +// 打开一个 url +util.openWin({ + url: 'https://cn.bing.com' +}); +// 打开一个自定义内容窗口 +util.openWin({ + content: 'Hello World.' +}); +``` + +

                          批量事件处理

                          + +`util.on(attr, events, options);` + +| 参数 | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| attr | 触发事件的元素属性名。可省略2.9+ | `string` | `lay-on` | +| events | 事件集合。包含 `attr` 对应的属性值和事件回调函数的键值对 | `object` | - | +| options 2.9+ | 参数的更多选项。详见下表。 | `object` | - | + +参数 `options` 可选项: + +| options | 描述 | 类型 | 默认值 | +| --- | --- | --- | --- | +| elem | 触发事件的委托元素 | string \| HTMLElement \| JQuery | - | +| trigger | 事件触发的方式 | string | `click` | + +
                          +  
                          +
                          + diff --git a/docs/versions.md b/docs/versions.md new file mode 100644 index 000000000..4b6a63a47 --- /dev/null +++ b/docs/versions.md @@ -0,0 +1,65 @@ +--- +title: 更新日志 +toc: true +--- + +# 更新日志 + +> 导读:📑 [Layui 不同版本的浏览器兼容说明](/notes/browser-support.html) · 📑 [Layui 2.x 系列版本主要升级变化](/notes/share/2x-major-upgrade-changes.html) · 📑 [Layui 2.8+ 《升级指南》](/notes/2.8/upgrade-guide.html) + +
                          + + +

                          + +

                          + v3.0.0-alpha +

                          + +- https://github.com/layui/layui/releases/tag/v3.0.0-alpha.3 +- https://github.com/layui/layui/releases/tag/v3.0.0-alpha.2 +- https://github.com/layui/layui/releases/tag/v3.0.0-alpha.1 +- https://github.com/layui/layui/releases/tag/v3.0.0-alpha.0 + +--- + + + +

                          + 2.x +

                          + +查看 2.x 系列版本更新日志 diff --git a/docs/versions/2.8.x.md b/docs/versions/2.8.x.md new file mode 100644 index 000000000..37187a84e --- /dev/null +++ b/docs/versions/2.8.x.md @@ -0,0 +1,699 @@ +--- +title: 2.8.x 更新日志 +toc: true +--- + +# 更新日志 + +> 导读:📑 [Layui 2.8+ 《升级指南》](/notes/2.8/upgrade-guide.html) · 📑 [Layui 新版文档站上线初衷](/notes/2.8/news.html) + +

                          + 2.10+ +

                          + +查看 2.10+ 及最新版更新日志 + +--- + +

                          + 2.9.x +

                          + +查看 2.9.x 系列版本更新日志 + +--- + +

                          + +

                          + 2.8.18 + 2023-10-31 +

                          + +- #### form + - 新增 `input` 数字输入框组件的特定属性 `lay-precision`,用于设置数值精度 # 1375/I81SY4 + - 优化 `input` 数字输入框组件的失去焦点对值的有效范围约束 # 1375/I7KU6V + - 优化 `input` 数字输入框组件当值达到临界点时加减按钮的禁用视觉效果 # 1375 + - 优化 `input` 数字输入框当表单验证失败时的边框颜色 # 1371 +- #### nav + - 新增 垂直导航菜单展开和收缩时的过渡动画 # 1407 + - 新增 `lay-accordion` 属性支持,用于开启手风琴,兼容旧版 `lay-shrink="all"` # 1384 +- #### layer + - 新增 `photos` 层的鼠标滚轮缩放功能 # I7ZAE8 + - 优化 移动端定位 # 1376 +- #### table + - 新增 `complete` 属性,当数据接口请求完成后执行,无论成功还是失败均会触发 # 1379 + - 修复 `ignoreExport` 表头属性值效果与文档不符的问题 # I86DBY + - 修复 `type: 'radio'` 且为右侧固定列时,选择效果无效的问题 # 1406 + - 优化 鼠标在固定列滚轮时无法触发滚动条的问题 # I8CGZH + - 优化 某些情况在 Firefox 的报错问题 +- #### treeTable + - 修复 `treeTable.removeNode()` 在开启 `data` 模式时删除异常问题 # I7Z0AB/I82E2S + - 修复 `treeTable.setRowChecked()` 方法未逐层展开上级节点的问题 # 1385/I84RUT + - 修复 `treeTable.addNodes()` 新增根节点时出现的报错问题 # 1414 + - 修复 数据格式为简单类型时 IE9+ 兼容问题 # 1415/I8C04Y +- #### upload + - 修复 `unified: true` 时的报错问题 # 1391 + - 优化 渲染入口逻辑,以解决因重复渲染导致的若干问题 # 1391 + - 优化 实例的 `reload` 方法,可更好地进行完整重载 # 1391 +- #### dropdown / menu + - 新增 `accordion` 属性,开启手风琴效果(menu: 主容器设置 `lay-accordion` 属性) # 1397 + - 新增 折叠展开动画效果 # 1397 +- #### laydate + - 优化 `rangeLinked` 属性开启时,点击目标元素可重新渲染的问题 # 1391 + - 优化 `type` 为 `time,datetime` 选择器时,「现在」按钮的禁用状态判断条件 # I828CD +- #### laypage + - 新增 `limitTemplet` 属性,用于自定义条目模板 # I80AHZ + - 新增 `skipText` 属性,用于自定义跳页区域文本 # I80AHZ +- #### carousel + - 优化 轮播切换时的动画效果 # 1378/I82STP +- #### rate / slider + - 优化 代码细节 # 1374 +- #### code + - 新增 `code` 属性,用于设置原始 code 值,优先级高于目标元素中的内容 # 1391 + - 优化 预览区域显示效果 # 1398 + - 优化 其他若干小问题 # 1391 +- #### 其他 + - 新增 Source Maps 支持 # 1404/I89W5P + - 新增 lay 模块部分函数 JSDoc 注释和示例 #1401 + - 优化 `
                          ` 全局样式优先级 # I86R6G + +### 下载: [layui-v2.8.18.zip](https://gitee.com/layui/layui/attach_files/1570299/download) + +--- + +

                          + 2.8.17 + 2023-09-11 +

                          + +- #### table + - 新增 `cellExpandedMode` 基础属性,用于设置所有单元格默认展开方式 # I7XW28 [8bd8415] + - 新增 `cellExpandedWidth` 基础属性,用于设置所有单元格默认展开后的宽度 [8bd8415] + - 新增 `expandedMode` 表头属性,用于设置当前表头单元格展开方式,优先级高于 `cellExpandedMode` [8bd8415] + - 修复 导出来自 treeTable 数据的顺序错乱问题 # I7YOXZ [3123adf] +- #### form + - 优化 验证机制,以确保自定义验证规则的灵活性,内置规则若为必填项,依旧需叠加 `required` 规则 [a00ecf2] + - 剔除 `verIncludeRequired` 全局属性,因为会造成不必要的歧义 [a00ecf2] +- #### laydate + - 修复 开启 `rangeLinked` 属性后,done 函数第二个参数未能正确返回开始日期的问题 #I7XBOA/I7YCHW [4d9365e] + - 修复 开启 `rangeLinked` 且 `range` 为数组时,当初始值格式不符而自动校正导致的开始日期表单赋值异常问题 [4d9365e] +- #### upload + - 新增 `dataType` 属性,用于定义服务端返回的数据类型 [58e675c] + - 优化 多文件模式中,正在上传中的文件会被再次触发上传的问题 # I7XXTW/I4C6XE [9a6b85f] +- #### code + - 重构 主体结构,以更好地适配第三方语法高亮库 # 1352 [ad5935c] + - 新增 实例返回的对象,包含对当前实例进行重载等方法成员 [ad5935c] + - 新增 `codeRender` 函数,用于重新渲染 code,譬如代码高亮处理 # 1352 + - 新增 `highlighter` 属性,用于指定语法高亮器,支持 `hljs,prism,shiki` 等流行库 # 1352 + - 新增 `lang` 属性,用于指定语言类型 # 1352 + - 新增 `langMarker` 属性,用于是否在代码域右上角显示语言类型 # 1352 + - 新增 `wordWrap` 属性,用于设置文字是否自动换行 [ad5935c] + - 加强 `tools` 属性,进一步提升可扩展性 [ad5935c] + - 优化 `dark` 模式主题,与 vscode 保持一致 [ad5935c] +- #### lay + - 新增 `lay.clipboard.writeText(options)` 方法,用于写入剪切板(复制) [5a00d0a] +- #### 公共类 + - 新增 `layui-padding-*` 和 `layui-margin-*` 内外边距样式类名 [5e0d71d] + +### 下载: [layui-v2.8.17.zip](https://gitee.com/layui/layui/attach_files/1523966/download) + +--- + +

                          + 2.8.16 + 2023-08-30 +

                          + +- #### layer + - 新增 `photos` 的 `toolbar` 属性,用于开启图片旋转 放大 缩小 还原等头部工具栏 # 1339 + - 调整 `photos` 的 属性名: `hideFooter → footer`,用于是否开启底部栏 +- #### table + - 优化 初始化时的样式渲染及多行模式的内容结构 + - 优化 `size` 为 `sm` / `lg` 时的展开状态 + - 优化 无数据时的导出和打印功能提示 # 1337 + - 优化 数据项为禁用状态的选中状态 # 1328 + - 优化 `table.renderData()` 方法执行了多余排序的问题 # 1358 +- #### treeTable + - 修复 部分操作之后 `radio` 列选中状态丢失的问题 # 1358 + - 修复 `data` 模式下排序之后出现节点结构错乱的问题 # 1358/I7TXXL + - 优化 `data.cascade` 属性,新增 `none` 可选值,即操作节点时不做任何联动 # 1358 + - 优化 数据项为禁用状态时的全选复选框的状态 # 1329 + - 优化 异步加载子节点为空时的展开状态 # 1326 +- #### laydate + - 优化 `shortcuts.value` 快捷选项的赋值属性,支持函数类型 # 1324 +- #### rate + - 优化 代码书写格式 # 1343 +- #### code + - 修复 自定义工具栏出现的报错问题 # 1342 + - 优化 复制功能,以兼容非安全域下复制失败的问题 #1356 + - 优化 预览区未能显示滚动条的问题 # 1359 + +### 下载: [layui-v2.8.16.zip](https://gitee.com/layui/layui/attach_files/1511975/download) + +--- + +

                          + 2.8.15 + 2023-08-16 +

                          + +- #### table + - 新增 `expandedWidth` 表头属性,用于设置单元格被展开后的宽度 + - 优化 单元格内容下拉展开状态面板,以解决此前因展开后内容不可操作等问题 # I7RS8S + - 优化 `table.reload()` 造成 `window resize` 事件重复绑定的问题 # I7RJWY + - 优化 多行模式在 Firefox 的内容显示问题 +- #### layer + - 优化 开启默认动画弹出层后,鼠标移入按钮出现往上偏移的问题 # I7QVVP + - 优化 弹层右上角关闭按钮因上个版本更新导致的主题样式异常问题 # I7TP11 +- #### dropdown + - 新增 `customName` 属性,用于自定义 `data` 属性中常用的字段名称 + - 修复 在某些特殊情况下调整浏览器窗口尺寸时出现的 `resize` 事件报错问题 +- #### tree + - 新增 `customName` 属性,用于自定义 `data` 中常用的字段名称 +- #### lay + - 新增 `lay.style()` 方法,用于向页面创建 style 样式 + - 优化 `lay.position()` 方法,可让下拉弹出元素的定位更智能 + +### 下载: [layui-v2.8.15.zip](https://gitee.com/layui/layui/attach_files/1499232/download) + +--- + +因 `2.8.14` 版本存在 layer 主题样式异常问题,`2.8.14` 已被跳过。 + +--- + +

                          + 2.8.13 + 2023-08-08 +

                          + +- #### table + - 优化 在自定义模板中放置 `checkbox` 时对应的文字显示异常问题 # I7LQNO + - 优化 `totalRow` 属性在 `table.reloadData()` 数据重载时的支持 # I7R6VY +- #### treeTable + - 修复 执行 `treeTable.addNodes()` 增加节点导致当前节点选中状态丢失的问题 # I7Q6IP + - 优化 删除节点时,对容器尺寸重新进行自动适配 +- #### tree + - 优化 容器样式,以解决用于其他组件内部可能造成的样式异常问题 # I7QAO3 +- #### dropdown + - **调整** `data.title` 属性对 HTML 的转义处理。若不转义,可通过 `templet` 属性实现 # I7Q6IV +- #### util + - 重构 `util.toDateString()` 转换日期格式字符组件,以提供更强大的占位符支持 # 1314 + - 修复 `util.fixbar()` 组件因 `default` 属性在 IE8 出现的保留字报错问题 + +### 下载: [layui-v2.8.13.zip](https://gitee.com/layui/layui/attach_files/1490273/download) + +--- + + +

                          + 2.8.12 + 2023-08-01 +

                          + +- #### form + - 优化 `input` 数字输入框在前置后置结构中的样式 # I7KTQB +- #### layer + - 修复 设置 `scrollbar` 属性禁用页面滚动条时,点击最大化再还原导致滚动条又重新出现的问题 # I7NTGX + - 修复 弹层容器中的 `id` 值与其他弹层索引值相同时,导致关闭弹层存在冲突问题 # I7PF0O +- #### upload + - 修复 `auto: false` 时,打开文件选择框并点击取消后,导致文件上传失效的问题 # I7NU31 +- #### treeTable + - 新增 `tree.data.cascade` 属性,用于设置复选的级联方式,默认 `all` # 1309 + - 修复 右侧固定列选中背景色没有和主体选中状态保持同步的问题 # I7NVCU + - 调整 树形转平铺的方法,保留节点的 `children` 信息 # 1309 + - 调整 重载时的参数拷贝,由默认深拷贝换成默认浅拷贝,以便与 table 组件保持一致 # 1309/I7NN0O +- #### tree + - 优化 `checked` 属性赋值机制,若初始数据源存在该属性,才对其进行动态赋值 + - 优化 `spread` 属性赋值机制,若初始数据源存在该属性,则展开和收缩时,自动对其更新状态值 +- #### 其他 + - 修正 code 中部分单词拼写错误 # 1310 + +### 下载: [layui-v2.8.12.zip](https://gitee.com/layui/layui/attach_files/1482367/download) + +--- + +

                          + 2.8.11 + 2023-07-13 +

                          + +- #### form + - 修复 `radio` 标题模板中若存在图标,选中时该图标被强制更改的问题 # I7IERB + - 优化 `input` 数字输入框的精度问题 # I7I7J2 + - 修正 `verIncludelRequired` 属性名为 `verIncludeRequired` # 1305 +- #### table + - 修复 导出统计行中若存在逗号出现的内容分隔异常问题 # I7IDA3 + - 修复 当点击筛选显示隐藏固定列时出现的未对齐的问题 # I7KQ0O +- #### menu + - 修复 `menu` 标题项自定义图标在展开收缩后被强制更改的问题 # 1303/I7JAPU +- #### tree + - 修复 点击复选框时未将对应的数据中的 `checked` 属性值进行同步的问题 + +### 下载: [layui-v2.8.11.zip](https://gitee.com/layui/layui/attach_files/1464525/download) + +--- + +

                          + 2.8.10 + 2023-07-03 +

                          + +- 修复 `layui.js` 在 IE 和 Safari 等「古董浏览器」存在一个正则零宽断言报错的问题 # I7HZCZ/I7I0TO + +### 下载: [layui-v2.8.10.zip](https://gitee.com/layui/layui/attach_files/1455365/download) + +--- + +

                          + 2.8.9 + 2023-07-03 +

                          + +- #### form + - 新增 `input` 数字输入框组件,通过动态点缀 `lay-affix="number"` 属性开启 + - 优化 `input,textarea` 禁用状态时的样式 # I7GN5Z +- #### table + - 优化 点击单元格出现编辑框时,不触发行事件 +- #### treeTable + - 修复 选中和取消选中时,父节点和子节点的选中背景色未能正确同步的问题 # I7FUD6 +- #### upload + - 新增 `text` 属性,用于自定义内部各类场景下的提示文本 +- #### util + - 重构 `countdown` 倒计时组件,采用 `options` 参数写法,但仍对旧版兼容 + - 新增 `countdown` 的 `date,now,clock,done` 等属性 + - 新增 `countdown` 的 `clear,reload` 等实例方法,用于清除和重置倒计时等操作 + +### 下载: [~~layui-v2.8.9.zip~~](https://gitee.com/layui/layui/attach_files/1454465/download) + +--- + +

                          + 2.8.8 + 2023-06-20 +

                          + +- #### form + - 新增 `input` 获取焦点时的光环效果,以提升当前活动输入框的辨别度 + - 取消 上个版本对 `select` 开启搜索时 `value` 的改动,由于存在若干不可控的影响 +- #### table + - 新增 `colTool` 事件,点击表头自定义元素触发,并返回当前列的相关信息,提升 table 的可玩性 + - 新增 `row,tool,checkbox,radio` 事件返回的 `dataCache` 属性,可获得当前行缓存数据,包含特定字段 +- #### upload + - 新增 `unified` 属性,用于选择多文件时是否统一上传,即只发送一次请求 # I6Z171 +- #### 其他 + - 优化 `layui.js,layer.js` 部分代码细节 # 1285 + +### 下载: [layui-v2.8.8.zip](https://gitee.com/layui/layui/attach_files/1444541/download) + +--- + +

                          + 2.8.7 + 2023-06-16 +

                          + +- #### form + - ~~优化 `select` 开启搜索时输入状态,将值转移到 `placeholder`,便于输入~~ # 1280 +
                          *注:由于存在若干影响,该项功能已在 `2.8.8` 中取消* +- #### table + - 新增 表头复选框的半选效果,当数据项部分选中且未全选时显示 + - 优化 `table.setRowChecked()` 方法,新增当前行选中背景色,便于与 hover 等活动背景色区分 + - 剔除 `table.setRowChecked()` 方法中的 `selectedStyle` 属性,因为没有实质意义 + - 优化 表头部分字段为 `hide` 在数据异常的情况下可能出现的表头错位的问题 # 1281 + - 优化 `done` 回调函数,新增参数 `origin` 用于区分重载和重新渲染数据 # 1281 + - 加强 `ignoreExport` 表头属性,允许指定不排除哪些字段 # 1281 +- #### treeTable + - 新增 `view.expandAllDefault` 属性,用于设置是否默认展开全部节点 # 1281 + - 修复 开启排序且在 `done` 回调中执行了 `expandAll` 展开全部导致死循环问题 # 1281 + - 修复 执行 `treeTable.reload(id)` 若 `id` 未匹配到对应实例时出现的报错问题 # 1281/I7CXLN +- #### grid + - 修复 space30 和 space32 边距相同的问题 # I7D7YP + +### 下载: [layui-v2.8.7.zip](https://gitee.com/layui/layui/attach_files/1441026/download) + +--- + +

                          + 2.8.6 + 2023-06-08 +

                          + +- #### table + - 新增 `table.renderData(id)` 方法,用于重新渲染数据,可搭配 `table.cache` 使用 # 1273 + - 修复 `table.hideCol(id, cols)` 第二个参数为普通对象时的异常问题 # 1270/I7AAUN + - 修复 多级表头在某些缩放比例的情况下出现表头跟表体错位问题 # 1273/I7A33T + - 修复 `table.getTrHtml()` 方法 `tr` 节点代码中的 `numbers` 列信息错误问题 + - 优化 `table setRowChecked()` 方法中标注当前选中行样式的判断逻辑 # 1273 +- #### treeTable + - 修复 `treeTable.expandAll()` 展开全部之后节点的折叠状态没有记忆的问题 # 1273 + - 修复 无主键的树表 reloadData 之后节点被展开的问题 # 1273 + - 修复 部分情况下父节点展开之后子节点中的单选复选列和其他表单元素没有渲染的问题 1273/I7AWNV + - 修复 初始化无数据时出现的数据报错的问题 # 1273 +- #### tab + - 修复 删除选项卡时,若标题栏存在其他元素,下标获取异常的问题 # 1271/I7AO7F + - 优化 `element.tabAdd()` 方法,第二个参数中新增 `change` 属性支持,以支持添加即自动切换功能 + - 优化 折叠功能,切换选项时不自动折叠选项卡,且添加选项时若处于折叠状态则自动展开 # I79HUD +- #### util + - 修复 fixbar 中添加了无效样式问题 # I79JTH + +### 下载: [layui-v2.8.6.zip](https://gitee.com/layui/layui/attach_files/1432770/download) + +--- + +因 `2.8.5` 版本中存在一个 tab 删除时下标的异常问题,`2.8.5` 已被跳过。 + +--- + +

                          + 2.8.4 + 2023-05-30 +

                          + +- #### form + - 新增 `verIncludelRequired` 全局属性,用于设置验证规则中是否同时包含必填 # I737EW + - 修复 checkbox 开关标题和半选图标未垂直居中的问题 # 1255 + - 修复 checkbox 在初始设置半选时,点击复选框时图标未恢复成非半选状态的问题 + - 修复 checkbox 被重新渲染时,标题模版未正确获取的问题 # 1257 + - 修复 select 经浏览器翻译成别的语言后,点击选项出现的显示异常问题 # 1256 + - 优化 checkbox 元素的 `lay-skin` ,当设置非内置风格时,不再强制显示为默认风格 +- #### table + - 新增 对 table 内元素的 `lay-unrow` 属性的识别,点击该元素时,可阻止执行 `row` 行单击事件 + - 修复 `table.setRowChecked()` 方法导致 `checkbox,radio` 事件失效的问题 # I73MLV/I76KBX/I78VI3 + - 修复 打印功能在 Edge 中可能出现的闪退问题 # 1264 + - 优化 `table.setRowChecked()` 方法,若未传 `checked` 属性,则自动对 `checkbox` 进行选中状态值切换 + - 优化 `row` 事件机制,若目标元素为 `checkbox,radio`,则不触发 `row` 事件 + - 优化 外层容器的高度,不再设置一个固定值,内部元素将根据 `height` 属性值自动撑满 + - 优化 底部边框问题 +- #### treeTable + - 新增 节点折叠状态记忆功能 # 1260/I777CJ + - 新增 `customName.icon` 属性,用于自定义图标的属性名称 # 1260/I73BQU + - 新增 `async.format` 回调函数,用于处理异步子节点数据,优先级高于 `async.url` # 1260 + - 新增 `treeTable.reloadAsyncNode(id, index)` 方法,用于重载异步子节点 # 1260 + - 新增 `treeTable.getNodeById(id)` 方法,用于获取节点信息集 # 1260 + - 新增 `treeTable.getNodesByFilter(id, filter, opts)` 方法,用于获取符合过滤规则的节点信息集 # 1260 + - 修复 `isSimpleData` 模式渲染后的默认数据排序异常问题 # 1260 + - 修复 展开全部节点排序失效的问题 # 1260/I73M2K + - 修复 折叠叶子节点时,图标没有变化的问题 # 1260 + - 修复 节点选中状态判断异常问题 # 1260 + - 优化 `treeTable.checkStatus()` 方法,可通过设置第二个参数,用于是否返回半选状态的数据 # 1260/I73JAW + - 优化 重新排序和视图内表单初始化的调用逻辑 # 1260 + - 优化 节点渲染方法 # 1260 +- #### layer + - 修复 `skin:'layui-layer-lan'` 时,导致 `btnAlign` 属性无效的问题 # I73PD1 +- #### laydate + - 优化 `theme` 属性,当其为数组格式,且第一个成员为 `hex` 格式主色值,则第二个成员为辅色值 # 1265 +- #### upload + - 新增 `exts` 属性对于图片类型时的 `.svg` 扩展名支持 +- #### code + - 优化 `copy` 属性开启时, 对 `tools` 属性的初始化配置 # I72QGO + - 优化 `preview: 'iframe'` 时的 `', + ); + } + + // 执行预览 + var runPreview = function (thisItemBody) { + var iframe = thisItemBody.children('iframe')[0]; + + // 是否 iframe 方式预览 + if (isIframePreview && iframe) { + iframe.srcdoc = finalCode(options.code); + } else { + thisItemBody.html(options.code); + } + + // 当前实例预览完毕后的回调 + setTimeout(function () { + typeof options.done === 'function' && + options.done({ + container: thisItemBody, + options: options, + render: function () { + form.render(thisItemBody.find('.lay-form')); + element.render(); + tabs.render({ + elem: ['.' + CONST.ELEM_PREVIEW, '.lay-tabs'].join(' '), + }); + }, + }); + }, 3); + }; + + if (layout[0] === 'preview') { + elemPreviewView.addClass(CONST.ELEM_SHOW); + othis.before(elemPreviewView); + runPreview(elemPreviewView); + } else { + othis.addClass(CONST.ELEM_SHOW).after(elemPreviewView); + } + + // 内容项初始化样式 + options.previewStyle = [options.style, options.previewStyle].join(''); + elemPreviewView.attr('style', options.previewStyle); + + // 初始化 tabs + tabs.render({ + elem: elemTabsView, + id: TABS_ID, + }); + + // 标签切换后的事件 + tabs.on(`afterChange(${TABS_ID})`, function (data) { + var { thisHeaderItem } = data; + var thisElem = thisHeaderItem.closest('.' + CONST.ELEM_PREVIEW); + var elemItemBody = thisElem.find('.' + CONST.ELEM_ITEM); + var thisItemBody = elemItemBody.eq(data.index); + + elemItemBody.removeClass(CONST.ELEM_SHOW); + thisItemBody.addClass(CONST.ELEM_SHOW); + + if (thisHeaderItem.attr('lay-id') === 'preview') { + runPreview(thisItemBody); + } + + setCodeLayout(); + }); + } + + // 创建 code 容器 + var codeElem = $(''); + + // 添加主容器 className + othis.addClass( + (function (arr) { + if (!options.wordWrap) arr.push('lay-code-nowrap'); + return arr.join(' '); + })(['lay-code-view lay-border-box']), + ); + + // code 主题风格 + var theme = options.theme || options.skin; + if (theme) { + othis.removeClass('lay-code-theme-dark lay-code-theme-light'); + othis.addClass('lay-code-theme-' + theme); + } + + // 添加高亮必要的 className + if (options.highlighter) { + othis.addClass(`${options.highlighter} lay-code-hl`); + if (options.highlighter === 'prism') { + othis.addClass(`language-${options.lang}`); + } + } + + // 获取 code 行结构 + var createCodeRst = createCode( + options.encode ? lay.escape(finalCode(rawCode)) : rawCode, // 是否编码 + ); + var lines = createCodeRst.lines; + + // 插入 code + othis.html(codeElem.html(createCodeRst.html)); + + // 插入行号边栏 + if (options.ln) { + othis.append('
                          '); + } + + // 兼容旧版本 height 属性 + if (options.height) { + codeElem.css('max-height', options.height); + } + + // code 区域样式 + options.codeStyle = [options.style, options.codeStyle].join(''); + if (options.codeStyle) { + codeElem.attr('style', function (i, val) { + return (val || '') + options.codeStyle; + }); + } + + // 动态设置样式 + var cssRules = [ + { + selector: '>.lay-code-wrap>.lay-code-line{}', + setValue: function (item, value) { + item.style['padding-left'] = value + 'px'; + }, + }, + { + selector: '>.lay-code-wrap>.lay-code-line>.lay-code-line-number{}', + setValue: function (item, value) { + item.style.width = value + 'px'; + }, + }, + { + selector: '>.lay-code-ln-side{}', + setValue: function (item, value) { + item.style.width = value + 'px'; + }, + }, + ]; + + // 生成初始 style 元素 + var styleElem = lay.style({ + target: othis[0], + id: 'DF-code-' + index, + text: $.map( + $.map(cssRules, function (val) { + return val.selector; + }), + function (val) { + return ['.lay-code-view[lay-code-index="' + index + '"]', val].join( + ' ', + ); + }, + ).join(''), + }); + + // 动态设置 code 布局 + var setCodeLayout = (function fn() { + if (options.ln) { + var multiLine = Math.floor(lines.length / 100); + var lineElem = codeElem.children('.' + CONST.ELEM_LINE); + var width = lineElem + .last() + .children('.' + CONST.ELEM_LINE_NUM) + .outerWidth(); + + othis.addClass(CONST.ELEM_LN_MODE); + + // 若超出 100 行 + if (multiLine && width > CONST.LINE_RAW_WIDTH) { + lay.getStyleRules(styleElem, function (item, i) { + try { + cssRules[i].setValue(item, width); + } catch { + // ignore + } + }); + } + } + + return fn; + })(); + + // 创建 code header + if (options.header) { + var headerElem = $('
                          '); + headerElem.html(options.title || options.text.code); + othis.prepend(headerElem); + } + + // 创建 code 区域固定条 + var elemFixbar = $('
                          '); + + // 若开启复制,且未开启预览,则单独生成复制图标 + if (options.copy && !options.preview) { + var copyElem = $( + [ + '', + '', + '', + ].join(''), + ); + + // 点击复制 + copyElem.on('click', function () { + toolkit.copy.onClick(); + }); + + elemFixbar.append(copyElem); + } + + // 创建 language marker + if (options.langMarker) { + elemFixbar.append( + '' + options.lang + '', + ); + } + + // 创建 about 自定义内容 + if (options.about) { + elemFixbar.append(options.about); + } + + // 生成 code fixbar + othis.append(elemFixbar); + + // code 渲染完毕后的回调 + if (!options.preview) { + setTimeout(function () { + typeof options.done === 'function' && options.done({}); + }, 3); + } + + // 所有实例渲染完毕后的回调 + if (options.elem.length === index + 1) { + typeof options.allDone === 'function' && options.allDone(); + } + + return ret; +} diff --git a/src/components/collapse.js b/src/components/collapse.js new file mode 100644 index 000000000..d24b9a132 --- /dev/null +++ b/src/components/collapse.js @@ -0,0 +1,110 @@ +/** + * collapse + * 折叠面板组件 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +var SUPER_MOD_NAME = 'element'; // 所属的超级模块名,确保向下兼容 + +// 创建组件 +var component = componentBuilder({ + name: 'collapse', // 组件名 + + // 默认配置 + config: { + elem: '.lay-collapse', + }, + + render: function () { + var that = this; + var options = that.config; + + options.elem.each(function () { + var elemItem = $(this).find('.lay-collapse-item'); + elemItem.each(function () { + var othis = $(this); + var elemTitle = othis.find('.lay-collapse-title'); + var elemCont = othis.find('.lay-collapse-content'); + var isNone = elemCont.css('display') === 'none'; + var clickEventName = 'click.lay_collapse_click'; + + // 初始状态 + elemTitle.find('.lay-collapse-icon').remove(); + elemTitle.append( + '', + ); + othis[isNone ? 'removeClass' : 'addClass'](CONST.CLASS_SHOW); + + // 兼容旧版( < 2.11.3) + if (elemCont.hasClass(CONST.CLASS_SHOW)) { + elemCont.removeClass(CONST.CLASS_SHOW); + } + + // 点击标题 + elemTitle + .off(clickEventName, event.titleClick) + .on(clickEventName, event.titleClick); + }); + }); + }, +}); + +// 基础事件体 +var event = { + // 点击面板标题项 + titleClick: function () { + var othis = $(this); + var wrapper = othis.closest('.lay-collapse'); + var filter = wrapper.attr('lay-filter'); + + var ANIM_MS = 200; // 动画过渡毫秒数 + var CLASS_ITEM = '.lay-collapse-item'; + var CLASS_CONTENT = '.lay-collapse-content'; + + var thisItemElem = othis.parent(CLASS_ITEM); + var thisContentElem = othis.siblings(CLASS_CONTENT); + var isNone = thisContentElem.css('display') === 'none'; + var isAccordion = typeof wrapper.attr('lay-accordion') === 'string'; + + // 动画执行完成后的操作 + var complete = function () { + $(this).css('display', ''); // 剔除动画生成的 style display,以适配外部样式的状态重置 + }; + + // 是否正处于动画中的状态 + if (thisContentElem.is(':animated')) return; + + // 展开或收缩 + if (isNone) { + // 先执行 slideDown 动画,再标注展开状态样式,避免元素 `block` 状态导致动画无效 + thisContentElem.slideDown(ANIM_MS, complete); + thisItemElem.addClass(CONST.CLASS_SHOW); + } else { + // 先取消展开状态样式,再将元素临时显示,避免 `none` 状态导致 slideUp 动画无效 + thisItemElem.removeClass(CONST.CLASS_SHOW); + thisContentElem.show().slideUp(ANIM_MS, complete); + } + + // 是否开启手风琴 + if (isAccordion) { + var itemSiblings = thisItemElem.siblings('.' + CONST.CLASS_SHOW); + itemSiblings.removeClass(CONST.CLASS_SHOW); + itemSiblings.children(CLASS_CONTENT).show().slideUp(ANIM_MS, complete); + } + + // 事件 + lay.event.call(this, SUPER_MOD_NAME, 'collapse(' + filter + ')', { + title: othis, + content: thisContentElem, + show: isNone, + }); + }, +}; + +var CONST = component.CONST; + +// export +export { component as collapse }; diff --git a/src/components/colorpicker.js b/src/components/colorpicker.js new file mode 100644 index 000000000..4ac5cc670 --- /dev/null +++ b/src/components/colorpicker.js @@ -0,0 +1,904 @@ +/** + * colorpicker + * 颜色选择组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +var device = lay.device(); +var clickOrMousedown = device.mobile ? 'click' : 'mousedown'; + +// 创建组件 +var component = componentBuilder({ + name: 'colorpicker', + + // 默认配置 + config: { + color: '', // 默认颜色,默认没有 + size: null, // 选择器大小 + alpha: false, // 是否开启透明度 + format: 'hex', // 颜色显示/输入格式,可选 rgb,hex + predefine: false, // 预定义颜色是否开启 + colors: [ + // 默认预定义颜色列表 + '#16baaa', + '#16b777', + '#1E9FFF', + '#FF5722', + '#FFB800', + '#01AAED', + '#999', + '#c00', + '#ff8c00', + '#ffd700', + '#90ee90', + '#00ced1', + '#1e90ff', + '#c71585', + '#393D49', + 'rgb(0, 186, 189)', + 'rgb(255, 120, 0)', + 'rgb(250, 212, 0)', + 'rgba(0,0,0,.5)', + 'rgba(255, 69, 0, 0.68)', + 'rgba(144, 240, 144, 0.5)', + 'rgba(31, 147, 255, 0.73)', + ], + }, + + CONST: { + ELEM: 'lay-colorpicker', + ELEM_MAIN: '.lay-colorpicker-main', + ICON_PICKER_DOWN: 'lay-icon-down', + ICON_PICKER_CLOSE: 'lay-icon-close', + PICKER_TRIG_SPAN: 'lay-colorpicker-trigger-span', + PICKER_TRIG_I: 'lay-colorpicker-trigger-i', + PICKER_SIDE: 'lay-colorpicker-side', + PICKER_SIDE_SLIDER: 'lay-colorpicker-side-slider', + PICKER_BASIS: 'lay-colorpicker-basis', + PICKER_ALPHA_BG: 'lay-colorpicker-alpha-bgcolor', + PICKER_ALPHA_SLIDER: 'lay-colorpicker-alpha-slider', + PICKER_BASIS_CUR: 'lay-colorpicker-basis-cursor', + PICKER_INPUT: 'lay-colorpicker-main-input', + }, + + // 初始化之前 + beforeInit: function () { + var that = this; + that.stopClickOutsideEvent = $.noop; + that.stopResizeEvent = $.noop; + CONST.PICKER_OPENED = CONST.MOD_ID + '-opened'; + }, + + // 渲染之前 + beforeRender: function () { + var that = this; + var options = that.config; + options.target = $('body'); // 后续考虑开放 target 元素 + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 颜色选择框对象 + var elemColorBox = $( + [ + '
                          ', + '', + '', + '', + '', + '', + '
                          ', + ].join(''), + ); + + // 初始化颜色选择框尺寸 + var elem = options.elem; + options.size && elemColorBox.addClass('lay-colorpicker-' + options.size); + + // 插入颜色选择框 + elem.addClass('lay-inline').html((that.elemColorBox = elemColorBox)); + + // 获取背景色值 + that.color = that.elemColorBox.find( + '.' + CONST.PICKER_TRIG_SPAN, + )[0].style.background; + }, +}); + +// RGB 转 HSB +var RGBToHSB = function (rgb) { + var hsb = { h: 0, s: 0, b: 0 }; + var min = Math.min(rgb.r, rgb.g, rgb.b); + var max = Math.max(rgb.r, rgb.g, rgb.b); + var delta = max - min; + hsb.b = max; + hsb.s = max !== 0 ? (255 * delta) / max : 0; + if (hsb.s !== 0) { + if (rgb.r == max) { + // 因 rgb 中返回的数字为 string 类型 + hsb.h = (rgb.g - rgb.b) / delta; + } else if (rgb.g == max) { + hsb.h = 2 + (rgb.b - rgb.r) / delta; + } else { + hsb.h = 4 + (rgb.r - rgb.g) / delta; + } + } else { + hsb.h = -1; + } + if (max === min) { + hsb.h = 0; + } + hsb.h *= 60; + if (hsb.h < 0) { + hsb.h += 360; + } + hsb.s *= 100 / 255; + hsb.b *= 100 / 255; + return hsb; +}; + +// HEX 转 HSB +var HEXToHSB = function (hex) { + hex = hex.indexOf('#') > -1 ? hex.substring(1) : hex; + if (hex.length === 3) { + var num = hex.split(''); + hex = num[0] + num[0] + num[1] + num[1] + num[2] + num[2]; + } + hex = parseInt(hex, 16); + var rgb = { r: hex >> 16, g: (hex & 0x00ff00) >> 8, b: hex & 0x0000ff }; + return RGBToHSB(rgb); +}; + +// HSB 转 RGB +var HSBToRGB = function (hsb) { + var rgb = {}; + var h = hsb.h; + var s = (hsb.s * 255) / 100; + var b = (hsb.b * 255) / 100; + + if (s === 0) { + rgb.r = rgb.g = rgb.b = b; + } else { + var t1 = b; + var t2 = ((255 - s) * b) / 255; + var t3 = ((t1 - t2) * (h % 60)) / 60; + if (h === 360) h = 0; + if (h < 60) { + rgb.r = t1; + rgb.b = t2; + rgb.g = t2 + t3; + } else if (h < 120) { + rgb.g = t1; + rgb.b = t2; + rgb.r = t1 - t3; + } else if (h < 180) { + rgb.g = t1; + rgb.r = t2; + rgb.b = t2 + t3; + } else if (h < 240) { + rgb.b = t1; + rgb.r = t2; + rgb.g = t1 - t3; + } else if (h < 300) { + rgb.b = t1; + rgb.g = t2; + rgb.r = t2 + t3; + } else if (h < 360) { + rgb.r = t1; + rgb.g = t2; + rgb.b = t1 - t3; + } else { + rgb.r = 0; + rgb.g = 0; + rgb.b = 0; + } + } + return { r: Math.round(rgb.r), g: Math.round(rgb.g), b: Math.round(rgb.b) }; +}; + +// HSB 转 HEX +var HSBToHEX = function (hsb) { + var rgb = HSBToRGB(hsb); + var hex = [rgb.r.toString(16), rgb.g.toString(16), rgb.b.toString(16)]; + $.each(hex, function (nr, val) { + if (val.length === 1) { + hex[nr] = '0' + val; + } + }); + return hex.join(''); +}; + +// 转化成所需 rgb 格式 +var RGBSTo = function (rgbs) { + var regexp = /[0-9]{1,3}/g; + var re = rgbs.match(regexp) || []; + return { r: re[0], g: re[1], b: re[2] }; +}; + +var $win = $(window); +// var $doc = $(document); + +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 渲染颜色选择器 +Class.prototype.renderPicker = function () { + var that = this; + var options = that.config; + + // 颜色选择器对象 + var elemPicker = (that.elemPicker = $( + [ + '
                          ', + //颜色面板 + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + //透明度条块 + '
                          ', + '
                          ', + '
                          ', + '
                          ', + '
                          ', + //预设颜色列表 + (function () { + if (options.predefine) { + var list = ['
                          ']; + options.colors.forEach(function (v) { + list.push( + [ + '
                          ', + '
                          ', + '
                          ', + ].join(''), + ); + }); + list.push('
                          '); + return list.join(''); + } else { + return ''; + } + })(), + //底部表单元素区域 + '
                          ', + '
                          ', + '', + '
                          ', + '
                          ', + '', + '', + '', + '
                          ', + ].join(''), + )); + + that.removePicker(options.id); // 若已存在则先移除 + options.target.append(elemPicker); + options.elem.data(CONST.PICKER_OPENED, true); // 面板已打开的标记 + + that.position(); + that.pickerEvents(); + that.onClickOutside(); + that.autoUpdatePosition(); +}; + +// 颜色选择器移除 +Class.prototype.removePicker = function (index) { + var that = this; + var options = that.config; + var elem = $('#lay-colorpicker' + (index || that.index)); + + that.stopClickOutsideEvent(); + that.stopResizeEvent(); + + if (elem[0]) { + elem.remove(); + options.elem.removeData(CONST.PICKER_OPENED); + + // 面板关闭后的回调 + typeof options.close === 'function' && options.close(that.color); + } + + return that; +}; + +// 面板定位 +Class.prototype.position = function () { + var that = this; + var options = that.config; + lay.position(that.bindElem || that.elemColorBox[0], that.elemPicker[0], { + position: options.position, + align: 'center', + }); + return that; +}; + +// 颜色选择器赋值 +Class.prototype.val = function () { + var that = this, + // options = that.config, + elemColorBox = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN), + elemPickerInput = that.elemPicker.find('.' + CONST.PICKER_INPUT), + e = elemColorBox[0], + bgcolor = e.style.backgroundColor; + + // 判断是否有背景颜色 + if (bgcolor) { + // 转化成 hsb 格式 + var hsb = RGBToHSB(RGBSTo(bgcolor)); + var type = elemColorBox.attr('lay-type'); + + // 同步滑块的位置及颜色选择器的选择 + that.select(hsb.h, hsb.s, hsb.b); + + // 若格式要求为rgb + if (type === 'torgb') { + elemPickerInput.find('input').val(bgcolor); + } else if (type === 'rgba') { + // 若格式要求为 rgba + var rgb = RGBSTo(bgcolor); + + // 若开启透明度而没有设置,则给默认值 + if ((bgcolor.match(/[0-9]{1,3}/g) || []).length === 3) { + elemPickerInput + .find('input') + .val('rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', 1)'); + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', 280); + } else { + elemPickerInput.find('input').val(bgcolor); + var left = + bgcolor.slice(bgcolor.lastIndexOf(',') + 1, bgcolor.length - 1) * 280; + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', left); + } + + // 设置 span 背景色 + that.elemPicker.find('.' + CONST.PICKER_ALPHA_BG)[0].style.background = + 'linear-gradient(to right, rgba(' + + rgb.r + + ', ' + + rgb.g + + ', ' + + rgb.b + + ', 0), rgb(' + + rgb.r + + ', ' + + rgb.g + + ', ' + + rgb.b + + '))'; + } else { + elemPickerInput.find('input').val('#' + HSBToHEX(hsb)); + } + } else { + // 若没有背景颜色则默认到最初始的状态 + that.select(0, 100, 100); + elemPickerInput.find('input').val(''); + that.elemPicker.find('.' + CONST.PICKER_ALPHA_BG)[0].style.background = ''; + that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER).css('left', 280); + } +}; + +// 颜色选择器滑动 / 点击 +Class.prototype.side = function () { + var that = this, + options = that.config, + span = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN), + type = span.attr('lay-type'), + side = that.elemPicker.find('.' + CONST.PICKER_SIDE), + slider = that.elemPicker.find('.' + CONST.PICKER_SIDE_SLIDER), + basis = that.elemPicker.find('.' + CONST.PICKER_BASIS), + choose = that.elemPicker.find('.' + CONST.PICKER_BASIS_CUR), + alphacolor = that.elemPicker.find('.' + CONST.PICKER_ALPHA_BG), + alphaslider = that.elemPicker.find('.' + CONST.PICKER_ALPHA_SLIDER), + _h = (slider[0].offsetTop / 180) * 360, + _b = 100 - (choose[0].offsetTop / 180) * 100, + _s = (choose[0].offsetLeft / 260) * 100, + _a = Math.round((alphaslider[0].offsetLeft / 280) * 100) / 100, + i = that.elemColorBox.find('.' + CONST.PICKER_TRIG_I), + pre = that.elemPicker.find('.lay-colorpicker-pre').children('div'), + change = function (x, y, z, a) { + that.select(x, y, z); + var rgb = HSBToRGB({ h: x, s: y, b: z }); + var color = HSBToHEX({ h: x, s: y, b: z }); + var elemInput = that.elemPicker + .find('.' + CONST.PICKER_INPUT) + .find('input'); + + i.addClass(CONST.ICON_PICKER_DOWN).removeClass(CONST.ICON_PICKER_CLOSE); + span[0].style.background = + 'rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'; + + if (type === 'torgb') { + elemInput.val('rgb(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ')'); + } else if (type === 'rgba') { + var left = a * 280; + alphaslider.css('left', left); + elemInput.val( + 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + a + ')', + ); + span[0].style.background = + 'rgba(' + rgb.r + ', ' + rgb.g + ', ' + rgb.b + ', ' + a + ')'; + alphacolor[0].style.background = + 'linear-gradient(to right, rgba(' + + rgb.r + + ', ' + + rgb.g + + ', ' + + rgb.b + + ', 0), rgb(' + + rgb.r + + ', ' + + rgb.g + + ', ' + + rgb.b + + '))'; + } else { + elemInput.val('#' + color); + } + + //回调更改的颜色 + options.change && + options.change( + that.elemPicker + .find('.' + CONST.PICKER_INPUT) + .find('input') + .val() + .trim(), + ); + }, + //拖拽元素 + elemMove = $( + [ + '
                          ', + ].join(''), + ), + createMoveElem = function (call) { + $('#LAY-colorpicker-moving')[0] || $('body').append(elemMove); + elemMove.on('mousemove', call); + elemMove + .on('mouseup', function () { + elemMove.remove(); + }) + .on('mouseleave', function () { + elemMove.remove(); + }); + }; + // 移动端滑动模拟事件中 + // 1. 不触发游标上绑定的事件,以提高性能,使滑动更流畅 + // 2. 游标上的事件需要冒泡到颜色拾取区域,用来模拟拖动游标的效果 + var needTrigger = true; + var needStopPropagation = true; + + //右侧主色选择 + slider.on('mousedown', function (e, triggerEvent) { + var oldtop = this.offsetTop; + var oldy = e.clientY === undefined ? triggerEvent.clientY : e.clientY; + var move = function (e) { + var top = oldtop + (e.clientY - oldy), + maxh = side[0].offsetHeight; + if (top < 0) top = 0; + if (top > maxh) top = maxh; + var h = (top / 180) * 360; + _h = h; + change(h, _s, _b, _a); + e.preventDefault(); + }; + needStopPropagation && e.stopPropagation(); + createMoveElem(move); + e.preventDefault(); + }); + + side.on('mousedown', function (e) { + var top = e.clientY - $(this).offset().top + $win.scrollTop(); + if (top < 0) top = 0; + if (top > this.offsetHeight) top = this.offsetHeight; + var h = (top / 180) * 360; + _h = h; + change(h, _s, _b, _a); + e.preventDefault(); + needTrigger && slider.trigger('mousedown', e); + }); + + //中间小圆点颜色选择 + choose.on('mousedown', function (e, triggerEvent) { + var oldtop = this.offsetTop; + var oldleft = this.offsetLeft; + var oldy = e.clientY === undefined ? triggerEvent.clientY : e.clientY; + var oldx = e.clientX === undefined ? triggerEvent.clientX : e.clientX; + var move = function (e) { + var top = oldtop + (e.clientY - oldy), + left = oldleft + (e.clientX - oldx), + maxh = basis[0].offsetHeight, + maxw = basis[0].offsetWidth; + if (top < 0) top = 0; + if (top > maxh) top = maxh; + if (left < 0) left = 0; + if (left > maxw) left = maxw; + var s = (left / 260) * 100, + b = 100 - (top / 180) * 100; + _b = b; + _s = s; + change(_h, s, b, _a); + e.preventDefault(); + }; + needStopPropagation && e.stopPropagation(); + createMoveElem(move); + e.preventDefault(); + }); + + basis.on('mousedown', function (e) { + var top = e.clientY - $(this).offset().top + $win.scrollTop(), + left = e.clientX - $(this).offset().left + $win.scrollLeft(); + if (top < 0) top = 0; + if (top > this.offsetHeight) top = this.offsetHeight; + if (left < 0) left = 0; + if (left > this.offsetWidth) left = this.offsetWidth; + var s = (left / 260) * 100, + b = 100 - (top / 180) * 100; + _b = b; + _s = s; + change(_h, s, b, _a); + e.stopPropagation(); + e.preventDefault(); + needTrigger && choose.trigger('mousedown', e); + }); + + //底部透明度选择 + alphaslider.on('mousedown', function (e, triggerEvent) { + var oldleft = this.offsetLeft; + var oldx = e.clientX === undefined ? triggerEvent.clientX : e.clientX; + var move = function (e) { + var left = oldleft + (e.clientX - oldx), + maxw = alphacolor[0].offsetWidth; + if (left < 0) left = 0; + if (left > maxw) left = maxw; + var a = Math.round((left / 280) * 100) / 100; + _a = a; + change(_h, _s, _b, a); + e.preventDefault(); + }; + + needStopPropagation && e.stopPropagation(); + createMoveElem(move); + e.preventDefault(); + }); + alphacolor.on('mousedown', function (e) { + var left = e.clientX - $(this).offset().left; + if (left < 0) left = 0; + if (left > this.offsetWidth) left = this.offsetWidth; + var a = Math.round((left / 280) * 100) / 100; + _a = a; + change(_h, _s, _b, a); + e.preventDefault(); + needTrigger && alphaslider.trigger('mousedown', e); + }); + + // 预定义颜色选择 + pre.each(function () { + $(this).on('click', function () { + $(this) + .parent('.lay-colorpicker-pre') + .addClass('selected') + .siblings() + .removeClass('selected'); + var color = this.style.backgroundColor, + hsb = RGBToHSB(RGBSTo(color)), + a = color.slice(color.lastIndexOf(',') + 1, color.length - 1); + // var left; + _h = hsb.h; + _s = hsb.s; + _b = hsb.b; + if ((color.match(/[0-9]{1,3}/g) || []).length === 3) a = 1; + _a = a; + // left = a * 280; + change(hsb.h, hsb.s, hsb.b, a); + }); + }); + + if (!lay.touchEventsSupported()) return; + // 触摸事件模拟 + [ + { elem: side, eventType: 'mousedown' }, + { elem: alphacolor, eventType: 'mousedown' }, + { elem: basis, eventType: 'mousedown' }, + ].forEach(function (obj) { + lay.touchSwipe(obj.elem, { + onTouchStart: function () { + needTrigger = false; + needStopPropagation = false; + }, + onTouchMove: function (e) { + touchHandler(e, obj.eventType); + }, + onTouchEnd: function () { + elemMove.remove(); + needTrigger = true; + needStopPropagation = true; + }, + }); + }); + function touchHandler(event, eventType) { + var pointer = event.touches[0]; + var simulatedEvent = document.createEvent('MouseEvent'); + + simulatedEvent.initMouseEvent( + eventType, + true, + true, + window, + 1, + pointer.screenX, + pointer.screenY, + pointer.clientX, + pointer.clientY, + false, + false, + false, + false, + 0, + null, + ); + pointer.target.dispatchEvent(simulatedEvent); + } +}; + +// 颜色选择器hsb转换 +Class.prototype.select = function (h, s, b) { + var that = this; + // var options = that.config; + var hex = HSBToHEX({ h: h, s: 100, b: 100 }); + // var color = HSBToHEX({ h: h, s: s, b: b }); + var sidetop = (h / 360) * 180; + var top = 180 - (b / 100) * 180; + var left = (s / 100) * 260; + var basisElem = that.elemPicker.find('.' + CONST.PICKER_BASIS)[0]; + + that.elemPicker.find('.' + CONST.PICKER_SIDE_SLIDER).css('top', sidetop); //滑块的top + basisElem.style.background = '#' + hex; //颜色选择器的背景 + + //选择器的top left + that.elemPicker.find('.' + CONST.PICKER_BASIS_CUR).css({ + top: (top / basisElem.offsetHeight) * 100 + '%', + left: (left / basisElem.offsetWidth) * 100 + '%', + }); + + // if(type === 'change') return; + + // 选中的颜色 + // that.elemPicker.find('.' + CONST.PICKER_INPUT).find('input').val('#'+ color); +}; + +Class.prototype.pickerEvents = function () { + var that = this; + var options = that.config; + + var elemColorBoxSpan = that.elemColorBox.find('.' + CONST.PICKER_TRIG_SPAN); //颜色盒子 + var elemPickerInput = that.elemPicker.find( + '.' + CONST.PICKER_INPUT + ' input', + ); //颜色选择器表单 + + var pickerEvents = { + // 清空 + clear: function () { + elemColorBoxSpan[0].style.background = ''; + that.elemColorBox + .find('.' + CONST.PICKER_TRIG_I) + .removeClass(CONST.ICON_PICKER_DOWN) + .addClass(CONST.ICON_PICKER_CLOSE); + that.color = ''; + + options.done && options.done(''); + that.removePicker(); + }, + + //确认 + confirm: function (othis, change) { + var value = elemPickerInput.val().trim(), + colorValue, + hsb; + + if (value.indexOf(',') > -1) { + hsb = RGBToHSB(RGBSTo(value)); + that.select(hsb.h, hsb.s, hsb.b); + elemColorBoxSpan[0].style.background = colorValue = '#' + HSBToHEX(hsb); + + if ( + (value.match(/[0-9]{1,3}/g) || []).length > 3 && + elemColorBoxSpan.attr('lay-type') === 'rgba' + ) { + var left = + value.slice(value.lastIndexOf(',') + 1, value.length - 1) * 280; + that.elemPicker + .find('.' + CONST.PICKER_ALPHA_SLIDER) + .css('left', left); + elemColorBoxSpan[0].style.background = value; + colorValue = value; + } + } else { + hsb = HEXToHSB(value); + elemColorBoxSpan[0].style.background = colorValue = '#' + HSBToHEX(hsb); + that.elemColorBox + .find('.' + CONST.PICKER_TRIG_I) + .removeClass(CONST.ICON_PICKER_CLOSE) + .addClass(CONST.ICON_PICKER_DOWN); + } + + if (change === 'change') { + that.select(hsb.h, hsb.s, hsb.b, change); + options.change && options.change(colorValue); + return; + } + that.color = value; + + options.done && options.done(value); + that.removePicker(); + }, + }; + + // 选择器面板点击事件 + that.elemPicker.on('click', '*[colorpicker-events]', function () { + var othis = $(this), + attrEvent = othis.attr('colorpicker-events'); + pickerEvents[attrEvent] && pickerEvents[attrEvent].call(this, othis); + }); + + // 输入框事件 + elemPickerInput.on('keyup', function (e) { + var othis = $(this); + pickerEvents.confirm.call(this, othis, e.keyCode === 13 ? null : 'change'); + }); +}; + +// 事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 弹出颜色选择器 + that.elemColorBox.on('click', function () { + // 主面板是否已打开 + var opened = options.elem.data(CONST.PICKER_OPENED); + + // 根据主面板状态,自动切换打开与关闭 + if (opened) { + that.removePicker(); + } else { + that.renderPicker(); + that.val(); + that.side(); + } + }); +}; + +/** + * 点击面板外部时的事件 + */ +Class.prototype.onClickOutside = function () { + var that = this; + var options = that.config; + + that.stopClickOutsideEvent(); + + var stop = lay.onClickOutside( + that.elemPicker[0], + function () { + var elemColorBoxSpan = that.elemColorBox.find( + '.' + CONST.PICKER_TRIG_SPAN, + ); + + if (that.color) { + var hsb = RGBToHSB(RGBSTo(that.color)); + that.select(hsb.h, hsb.s, hsb.b); + } else { + that.elemColorBox + .find('.' + CONST.PICKER_TRIG_I) + .removeClass(CONST.ICON_PICKER_DOWN) + .addClass(CONST.ICON_PICKER_CLOSE); + } + + elemColorBoxSpan[0].style.background = that.color || ''; + + // 取消选择的回调 + typeof options.cancel === 'function' && options.cancel(that.color); + + // 移除面板 + that.removePicker(); + }, + { + ignore: [options.elem[0]], + event: clickOrMousedown, + capture: false, + }, + ); + + that.stopClickOutsideEvent = function () { + stop(); + that.stopClickOutsideEvent = $.noop; + }; +}; + +/** + * 窗口大小变化时自动更新位置 + */ +Class.prototype.autoUpdatePosition = function () { + var that = this; + // var options = that.config; + var RESIZE_EVENT_NAME = 'resize.lay_colorpicker_resize'; + + that.stopResizeEvent(); + + var windowResizeHandler = function () { + that.position(); + }; + + $win.on(RESIZE_EVENT_NAME, windowResizeHandler); + + that.stopResizeEvent = function () { + $win.off(RESIZE_EVENT_NAME, windowResizeHandler); + that.stopResizeEvent = $.noop; + }; +}; + +export { component as colorpicker }; diff --git a/src/components/dropdown.js b/src/components/dropdown.js new file mode 100644 index 000000000..41907362d --- /dev/null +++ b/src/components/dropdown.js @@ -0,0 +1,817 @@ +/** + * dropdown + * 下拉菜单组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; +import { laytpl } from '../core/laytpl.js'; + +var device = lay.device(); +var clickOrMousedown = device.mobile ? 'touchstart' : 'mousedown'; + +// 模块名 +var MOD_NAME = 'dropdown'; +var MOD_INDEX = 'layui_' + MOD_NAME + '_index'; // 模块索引名 +var MOD_INDEX_OPENED = MOD_INDEX + '_opened'; +var MOD_ID = 'lay-' + MOD_NAME + '-id'; + +var resizeObserver = lay.createSharedResizeObserver(MOD_NAME); + +// 外部接口 +var dropdown = { + config: { + customName: { + // 自定义 data 字段名 + id: 'id', + title: 'title', + children: 'child', + }, + }, + + // 设置全局项 + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + + // 事件 + on: function (events, callback) { + return lay.onevent.call(this, MOD_NAME, events, callback); + }, +}; + +// 操作当前实例 +var thisModule = function () { + var that = this; + var options = that.config; + var id = options.id; + + return { + config: options, + // 重置实例 + reload: function (options) { + that.reload.call(that, options); + }, + reloadData: function (options) { + dropdown.reloadData(id, options); + }, + close: function () { + that.remove(); + }, + open: function () { + that.render(); + }, + }; +}; + +// 字符常量 +var STR_ELEM = 'lay-dropdown'; +// var STR_HIDE = 'lay-hide'; +var STR_DISABLED = 'lay-disabled'; +// var STR_NONE = 'lay-none'; +var STR_ITEM_UP = 'lay-menu-item-up'; +var STR_ITEM_DOWN = 'lay-menu-item-down'; +var STR_MENU_TITLE = 'lay-menu-body-title'; +var STR_ITEM_GROUP = 'lay-menu-item-group'; +var STR_ITEM_PARENT = 'lay-menu-item-parent'; +var STR_ITEM_DIV = 'lay-menu-item-divider'; +var STR_ITEM_CHECKED = 'lay-menu-item-checked'; +var STR_ITEM_CHECKED2 = 'lay-menu-item-checked2'; +var STR_MENU_PANEL = 'lay-menu-body-panel'; +var STR_MENU_PANEL_L = 'lay-menu-body-panel-left'; +var STR_ELEM_SHADE = 'lay-dropdown-shade'; + +var STR_GROUP_TITLE = '.' + STR_ITEM_GROUP + '>.' + STR_MENU_TITLE; + +// 构造器 +var Class = function (options) { + var that = this; + that.index = dropdown.index = lay.autoIncrementer('dropdown'); + that.config = $.extend({}, that.config, dropdown.config, options); + that.stopClickOutsideEvent = $.noop; + that.stopResizeEvent = $.noop; + that.init(); +}; + +// 默认配置 +Class.prototype.config = { + trigger: 'click', // 事件类型 + content: '', // 自定义菜单内容 + className: '', // 自定义样式类名 + style: '', // 设置面板 style 属性 + show: false, // 是否初始即显示菜单面板 + isAllowSpread: true, // 是否允许菜单组展开收缩 + isSpreadItem: true, // 是否初始展开子菜单 + data: [], // 菜单数据结构 + delay: [200, 300], // 延时显示或隐藏的毫秒数,若为 number 类型,则表示显示和隐藏的延迟时间相同,trigger 为 hover 时才生效 + shade: 0, // 遮罩 + accordion: false, // 手风琴效果,仅菜单组生效。基础菜单需要在容器上追加 'lay-accordion' 属性。 + closeOnClick: true, // 面板打开后,再次点击目标元素时是否关闭面板。行为取决于所使用的触发事件类型 +}; + +// 重载实例 +Class.prototype.reload = function (options, type) { + var that = this; + that.config = $.extend({}, that.config, options); + that.init(true, type); +}; + +// 初始化准备 +Class.prototype.init = function (rerender, type) { + var that = this; + var options = that.config; + + // 若 elem 非唯一 + var elem = $(options.elem); + if (elem.length > 1) { + elem.each(function () { + dropdown.render( + $.extend({}, options, { + elem: this, + }), + ); + }); + return that; + } + + // 合并 lay-options 属性上的配置信息 + $.extend(options, lay.options(elem[0])); + + // 若重复执行 render,则视为 reload 处理 + if (!rerender && elem.attr(MOD_ID)) { + var newThat = thisModule.getThis(elem.attr(MOD_ID)); + if (!newThat) return; + return newThat.reload(options, type); + } + + options.elem = $(options.elem); + options.target = $('body'); // 后续考虑开放 target 元素 + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + options.id = 'id' in options ? options.id : elem.attr('id') || that.index; + + thisModule.that[options.id] = that; // 记录当前实例对象 + elem.attr(MOD_ID, options.id); // 目标元素已渲染过的标记 + + // 初始化自定义字段名 + options.customName = $.extend( + {}, + dropdown.config.customName, + options.customName, + ); + + // 若传入 hover,则解析为 mouseenter + if (options.trigger === 'hover') { + options.trigger = 'mouseenter'; + } + + // 初始即显示或者面板弹出之后执行了刷新数据 + if ( + options.show || + (type === 'reloadData' && + that.mainElem && + options.target.find(that.mainElem.get(0)).length) + ) + that.render(type); + + // 若面板已经打开,则无需再绑定目标元素事件,避免 render 重复执行 + if (!elem.data(MOD_INDEX_OPENED)) { + that.events(); // 事件 + } +}; + +// 渲染 +Class.prototype.render = function (type) { + var that = this; + var options = that.config; + var customName = options.customName; + + // 默认菜单内容 + var getDefaultView = function () { + var elemUl = $('
                            '); + if (options.data.length > 0) { + eachItemView(elemUl, options.data); + } else { + elemUl.html( + '
                          • ' + + i18n.$t('dropdown.noData') + + '
                          • ', + ); + } + return elemUl; + }; + + // 遍历菜单项 + var eachItemView = function (views, data) { + // var views = []; + + data.forEach(function (item) { + // 是否存在子级 + var isChild = + item[customName.children] && item[customName.children].length > 0; + var isSpreadItem = + 'isSpreadItem' in item ? item.isSpreadItem : options.isSpreadItem; + var title = (function (title) { + var templet = item.templet || options.templet; + if (templet) { + title = + typeof templet === 'function' + ? templet(item) + : laytpl(templet).render(item); + } + return title; + })(lay.escape(item[customName.title])); + + // 初始类型 + var type = (function () { + if (isChild) { + item.type = item.type || 'parent'; + } + if (item.type) { + return ( + { + group: 'group', + parent: 'parent', + '-': '-', + }[item.type] || 'parent' + ); + } + return ''; + })(); + + if ( + type !== '-' && + !item[customName.title] && + !item[customName.id] && + !isChild + ) + return; + + //列表元素 + var viewLi = $( + [ + '', + //标题区 + (function () { + //是否超文本 + var viewText = + 'href' in item + ? '' + + title + + '' + : title; + + //是否存在子级 + if (isChild) { + return ( + '
                            ' + + viewText + + (function () { + if (type === 'parent') { + return ''; + } else if (type === 'group' && options.isAllowSpread) { + return ( + '' + ); + } else { + return ''; + } + })() + + '
                            ' + ); + } + return '
                            ' + viewText + '
                            '; + })(), + '', + ].join(''), + ); + + viewLi.data('item', item); + + //子级区 + if (isChild) { + var elemPanel = $('
                            '); + var elemUl = $('
                              '); + + if (type === 'parent') { + elemPanel.append(eachItemView(elemUl, item[customName.children])); + viewLi.append(elemPanel); + } else { + viewLi.append(eachItemView(elemUl, item[customName.children])); + } + } + + views.append(viewLi); + }); + return views; + }; + + // 主模板 + var TPL_MAIN = [ + '
                              ', + '
                              ', + ].join(''); + + // 重载或插入面板内容 + var mainElem; + var content = options.content || getDefaultView(); + var mainElemExisted = thisModule.findMainElem(options.id); + if (type === 'reloadData' && mainElemExisted.length) { + // 是否仅重载数据 + mainElem = that.mainElem = mainElemExisted; + mainElemExisted.html(content); + } else { + // 常规渲染 + mainElem = that.mainElem = $(TPL_MAIN); + mainElem.append(content); + + // 初始化某些属性 + mainElem.addClass(options.className); + mainElem.attr('style', options.style); + + // 辞旧迎新 + that.remove(options.id); + options.target.append(mainElem); + options.elem.data(MOD_INDEX_OPENED, true); // 面板已打开的标记 + + // 遮罩 + var shade = options.shade + ? '
                              ' + : ''; + var shadeElem = $(shade); + // 处理移动端点击穿透问题 + if (clickOrMousedown === 'touchstart') { + shadeElem.on(clickOrMousedown, function (e) { + e.preventDefault(); + }); + } + mainElem.before(shadeElem); + + // 如果是鼠标移入事件,则鼠标移出时自动关闭 + if (options.trigger === 'mouseenter') { + mainElem + .on('mouseenter', function () { + clearTimeout(that.timer); + }) + .on('mouseleave', function () { + that.delayRemove(); + }); + } + } + + that.position(); // 定位坐标 + + // 阻止全局事件 + mainElem.find('.lay-menu').on(clickOrMousedown, function (e) { + e.stopPropagation(); + }); + + // 触发菜单列表事件 + mainElem.find('.lay-menu li').on('click', function (e) { + var othis = $(this); + var data = othis.data('item') || {}; + var isChild = + data[customName.children] && data[customName.children].length > 0; + var isClickAllScope = options.clickScope === 'all'; // 是否所有父子菜单均触发点击事件 + + if (data.disabled) return; // 菜单项禁用状态 + + // 普通菜单项点击后的回调及关闭面板 + if ((!isChild || isClickAllScope) && data.type !== '-') { + var ret = + typeof options.click === 'function' + ? options.click(data, othis, e) + : null; + + ret === false || isChild || that.remove(); + e.stopPropagation(); + } + }); + + // 触发菜单组展开收缩 + mainElem.find(STR_GROUP_TITLE).on('click', function () { + var othis = $(this); + var elemGroup = othis.parent(); + var data = elemGroup.data('item') || {}; + + if (data.type === 'group' && options.isAllowSpread) { + thisModule.spread(elemGroup, options.accordion); + } + }); + + that.onClickOutside(); + that.autoUpdatePosition(); + + // 组件打开完毕的事件 + typeof options.ready === 'function' && options.ready(mainElem, options.elem); +}; + +// 位置定位 +Class.prototype.position = function () { + var that = this; + var options = that.config; + + lay.position(options.elem[0], that.mainElem[0], { + position: options.position, + e: that.e, + clickType: options.trigger === 'contextmenu' ? 'right' : null, + align: options.align || null, + }); +}; + +// 移除面板 +Class.prototype.remove = function (id) { + id = id || this.config.id; + var that = thisModule.getThis(id); // 根据 id 查找对应的实例 + if (!that) return; + + var options = that.config; + var mainElem = thisModule.findMainElem(id); + that.stopClickOutsideEvent(); + that.stopResizeEvent(); + + // 若存在已打开的面板元素,则移除 + if (mainElem[0]) { + mainElem.prev('.' + STR_ELEM_SHADE).remove(); // 先移除遮罩 + mainElem.remove(); + options.elem.removeData(MOD_INDEX_OPENED); + typeof options.close === 'function' && options.close(options.elem); + } +}; + +Class.prototype.normalizedDelay = function () { + var that = this; + var options = that.config; + var delay = [].concat(options.delay); + + return { + show: delay[0], + hide: delay[1] !== undefined ? delay[1] : delay[0], + }; +}; + +// 延迟移除面板 +Class.prototype.delayRemove = function () { + var that = this; + // var options = that.config; + clearTimeout(that.timer); + + that.timer = setTimeout(function () { + that.remove(); + }, that.normalizedDelay().hide); +}; + +// 事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 是否鼠标移入时触发 + var isMouseEnter = options.trigger === 'mouseenter'; + var trigger = options.trigger + '.lay_dropdown_render'; + + // 始终先解除上一个触发元素的事件(如重载时改变 elem 的情况) + if (that.thisEventElem) that.thisEventElem.off(trigger); + that.thisEventElem = options.elem; + + // 触发元素事件 + options.elem.off(trigger).on(trigger, function (e) { + clearTimeout(that.timer); + that.e = e; + + // 主面板是否已打开 + var opened = options.elem.data(MOD_INDEX_OPENED); + + // 若为鼠标移入事件,则延迟触发 + if (isMouseEnter) { + if (!opened) { + that.timer = setTimeout(function () { + that.render(); + }, that.normalizedDelay().show); + } + } else { + // 若为 click 事件,则根据主面板状态,自动切换打开与关闭 + if (options.closeOnClick && opened && options.trigger === 'click') { + that.remove(); + } else { + that.render(); + } + } + + e.preventDefault(); + }); + + // 如果是鼠标移入事件 + if (isMouseEnter) { + // 执行鼠标移出事件 + options.elem.on('mouseleave', function () { + that.delayRemove(); + }); + } +}; + +/** + * 点击面板外部时的事件 + */ +Class.prototype.onClickOutside = function () { + var that = this; + var options = that.config; + var isCtxMenu = options.trigger === 'contextmenu'; + var isTopElem = lay.isTopElem(options.elem[0]); + + that.stopClickOutsideEvent(); + + var stop = lay.onClickOutside( + that.mainElem[0], + function (e) { + // 点击面板外部时的事件 + if (typeof options.onClickOutside === 'function') { + var shouldClose = options.onClickOutside(e); + if (shouldClose === false) return; + } + + that.remove(); + }, + { + ignore: isCtxMenu || isTopElem ? null : [options.elem[0]], + event: clickOrMousedown, + capture: false, + detectIframe: true, + }, + ); + + that.stopClickOutsideEvent = function () { + stop(); + that.stopClickOutsideEvent = $.noop; + }; +}; + +/** + * 窗口大小变化时自动更新位置 + */ +Class.prototype.autoUpdatePosition = function () { + var that = this; + var options = that.config; + + that.stopResizeEvent(); + + var windowResizeHandler = function () { + if (that.mainElem && (!that.mainElem[0] || !that.mainElem.is(':visible'))) + return; + if (options.trigger === 'contextmenu') { + that.remove(); + } else { + that.position(); + } + }; + $(window).on('resize.lay_dropdown_resize', windowResizeHandler); + + var shouldObserveResize = resizeObserver && options.trigger !== 'contextmenu'; + var triggerEl = options.elem[0]; + var contentEl = that.mainElem[0]; + if (shouldObserveResize) { + resizeObserver.observe(triggerEl, $.proxy(that.position, that)); + resizeObserver.observe(contentEl, $.proxy(that.position, that)); + } + + that.stopResizeEvent = function () { + $(window).off('resize.lay_dropdown_resize', windowResizeHandler); + if (shouldObserveResize) { + resizeObserver.unobserve(triggerEl); + resizeObserver.unobserve(contentEl); + } + + that.stopResizeEvent = $.noop; + }; +}; + +// 记录所有实例 +thisModule.that = {}; // 记录所有实例对象 + +// 获取当前实例对象 +thisModule.getThis = function (id) { + if (id === undefined) { + throw new Error('ID argument required'); + } + return thisModule.that[id]; +}; + +// 根据 id 从页面查找组件主面板元素 +thisModule.findMainElem = function (id) { + return $('.' + STR_ELEM + '[' + MOD_ID + '="' + id + '"]'); +}; + +// 设置菜单组展开和收缩状态 +thisModule.spread = function (othis, isAccordion) { + var contentElem = othis.children('ul'); + var needSpread = othis.hasClass(STR_ITEM_UP); + var ANIM_MS = 200; + + // 动画执行完成后的操作 + var complete = function () { + $(this).css({ display: '' }); // 剔除临时 style,以适配外部样式的状态重置; + }; + + // 动画是否正在执行 + if (contentElem.is(':animated')) return; + + // 展开 + if (needSpread) { + othis.removeClass(STR_ITEM_UP).addClass(STR_ITEM_DOWN); + contentElem.hide().stop().slideDown(ANIM_MS, complete); + } else { + // 收缩 + contentElem.stop().slideUp(ANIM_MS, complete); + othis.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP); + } + + // 手风琴 + if (needSpread && isAccordion) { + var groupSibs = othis.siblings('.' + STR_ITEM_DOWN); + groupSibs.children('ul').stop().slideUp(ANIM_MS, complete); + groupSibs.removeClass(STR_ITEM_DOWN).addClass(STR_ITEM_UP); + } +}; + +// 全局事件 +(function () { + var _WIN = $(window); + var _DOC = $(document); + + // 基础菜单的静态元素事件 + var ELEM_LI = '.lay-menu:not(.lay-dropdown-menu) li'; + _DOC.on('click', ELEM_LI, function () { + var othis = $(this); + var parent = othis.parents('.lay-menu').eq(0); + var isChild = + othis.hasClass(STR_ITEM_GROUP) || othis.hasClass(STR_ITEM_PARENT); + var filter = parent.attr('lay-filter') || parent.attr('id'); + var options = lay.options(this); + + // 非触发元素 + if (othis.hasClass(STR_ITEM_DIV)) return; + + // 非菜单组 + if (!isChild) { + // 选中 + parent.find('.' + STR_ITEM_CHECKED).removeClass(STR_ITEM_CHECKED); // 清除选中样式 + parent.find('.' + STR_ITEM_CHECKED2).removeClass(STR_ITEM_CHECKED2); // 清除父级菜单选中样式 + othis.addClass(STR_ITEM_CHECKED); //添加选中样式 + othis.parents('.' + STR_ITEM_PARENT).addClass(STR_ITEM_CHECKED2); // 添加父级菜单选中样式 + + options.title = + options.title || + othis + .children('.' + STR_MENU_TITLE) + .text() + .trim(); + + // 触发事件 + lay.event.call(this, MOD_NAME, 'click(' + filter + ')', options); + } + }); + + // 基础菜单的展开收缩事件 + _DOC.on('click', ELEM_LI + STR_GROUP_TITLE, function () { + var othis = $(this); + var elemGroup = othis.parents('.' + STR_ITEM_GROUP + ':eq(0)'); + var options = lay.options(elemGroup[0]); + var isAccordion = + typeof othis.parents('.lay-menu').eq(0).attr('lay-accordion') === + 'string'; + + if ('isAllowSpread' in options ? options.isAllowSpread : true) { + thisModule.spread(elemGroup, isAccordion); + } + }); + + // 判断子级菜单是否超出屏幕 + var ELEM_LI_PAR = '.lay-menu .' + STR_ITEM_PARENT; + _DOC + .on('mouseenter', ELEM_LI_PAR, function () { + var othis = $(this); + var elemPanel = othis.find('.' + STR_MENU_PANEL); + + if (!elemPanel[0]) return; + var rect = elemPanel[0].getBoundingClientRect(); + + // 是否超出右侧屏幕 + if (rect.right > _WIN.width()) { + elemPanel.addClass(STR_MENU_PANEL_L); + // 不允许超出左侧屏幕 + rect = elemPanel[0].getBoundingClientRect(); + if (rect.left < 0) { + elemPanel.removeClass(STR_MENU_PANEL_L); + } + } + + // 是否超出底部屏幕 + if (rect.bottom > _WIN.height()) { + elemPanel.eq(0).css('margin-top', -(rect.bottom - _WIN.height() + 5)); + } + }) + .on('mouseleave', ELEM_LI_PAR, function () { + var othis = $(this); + var elemPanel = othis.children('.' + STR_MENU_PANEL); + + elemPanel.removeClass(STR_MENU_PANEL_L); + elemPanel.css('margin-top', 0); + }); +})(); + +// 关闭面板 +dropdown.close = function (id) { + var that = thisModule.getThis(id); + if (!that) return this; + + that.remove(); + return thisModule.call(that); +}; + +// 打开面板 +dropdown.open = function (id) { + var that = thisModule.getThis(id); + if (!that) return this; + + that.render(); + return thisModule.call(that); +}; + +// 重载实例 +dropdown.reload = function (id, options, type) { + var that = thisModule.getThis(id); + if (!that) return this; + + that.reload(options, type); + return thisModule.call(that); +}; + +// 仅重载数据 +dropdown.reloadData = function () { + var args = $.extend([], arguments); + args[2] = 'reloadData'; + + // 重载时,与数据相关的参数 + var dataParams = new RegExp( + '^(' + ['data', 'templet', 'content'].join('|') + ')$', + ); + + // 过滤与数据无关的参数 + Object.keys(args[1] || {}).forEach(function (key) { + if (!dataParams.test(key)) { + delete args[1][key]; + } + }); + + return dropdown.reload.apply(null, args); +}; + +// 核心入口 +dropdown.render = function (options) { + var inst = new Class(options); + return thisModule.call(inst); +}; + +export { dropdown }; diff --git a/src/components/element.js b/src/components/element.js new file mode 100644 index 000000000..6b70d9058 --- /dev/null +++ b/src/components/element.js @@ -0,0 +1,76 @@ +/** + * element + * 常用元素操作 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; +import { nav } from './nav.js'; +import { breadcrumb } from './breadcrumb.js'; +import { progress } from './progress.js'; +import { collapse } from './collapse.js'; + +const elements = { nav, breadcrumb, progress, collapse }; + +// 创建组件 +const component = componentBuilder({ + name: 'element', // 模块名 + + CONST: { + MOD_NAME: 'element', + }, +}); + +// const CONST = component.CONST; + +// 保留原接口,确保向下兼容 +$.extend(component, { + render(type, filter) { + const elemFilter = (function () { + if (typeof filter === 'string' && filter) { + return '[lay-filter="' + filter + '"]'; + } + return ''; + })(); + const components = { + nav: '.lay-nav' + elemFilter, + breadcrumb: '.lay-breadcrumb' + elemFilter, + progress: '.lay-progress' + elemFilter, + collapse: '.lay-collapse' + elemFilter, + }; + + // 仅允许渲染指定组件 + if (type && !components[type]) return; + + // 若 filter 为 jQuery 对象 + if (type && typeof filter === 'object' && filter instanceof $) { + return elements[type].render({ + elem: filter, + }); + } + + if (components[type]) { + return elements[type].render({ + elem: components[type], + }); + } + + Object.keys(components).forEach(function (componentName) { + elements[componentName].render({ + elem: components[componentName], + }); + }); + }, + + progress: progress.setValue, +}); + +component.init = component.render; + +// 自动渲染 +lay.use(() => { + component.render(); +}); + +export { component as element }; diff --git a/src/components/floatbar.js b/src/components/floatbar.js new file mode 100644 index 000000000..b410a753d --- /dev/null +++ b/src/components/floatbar.js @@ -0,0 +1,148 @@ +/** + * floatbar + * 悬浮条组件 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +// 创建组件 +const component = componentBuilder({ + name: 'floatbar', // 组件名 + + // 默认配置 + config: { + target: 'body', // floatbar 的插入目标选择器 + bars: [], // bar 配置项 + showDefaultBar: true, // 是否显示默认 bar + scrollThreshold: 160, // 出现 top bar 的滚动条位置临界值 + }, + + CONST: { + ELEM: 'lay-floatbar', + }, + + render() { + const options = this.config; + + // 目标元素对象 + const $target = $(options.target); + + // 滚动条所在元素对象 + const $scroll = options.scroll + ? $(options.scroll) + : $(options.target === 'body' ? window : $target); + + // 是否提供默认图标 + if (options.showDefaultBar) { + // 是否已存在 top bar + const hasTopBar = options.bars.some((item) => item.type === 'top'); + + // 追加默认 top bar + if (!hasTopBar) { + options.bars.push({ + type: 'top', + icon: 'lay-icon-top', + }); + } + } + + const elem = $('
                              ').attr(CONST.MOD_ID, options.id).addClass(CONST.ELEM); + let topBarElem; + + // 自定义样式 + if (options.css) { + lay.style({ + target: elem[0], + id: `DF-${CONST.MOD_NAME}-${this.index}`, + text: `.${CONST.ELEM}[${CONST.MOD_ID}="${options.id}"] { ${options.css} }`, + }); + } + + // 生成 bars 节点 + options.bars.forEach(function (item) { + const barElem = $('
                              '); + + // 设置 bar 相关属性 + barElem + .attr({ + 'data-type': item.type, + style: item.style, + }) + .html(item.content); + + // bar 内置点击事件 + barElem.on('click', function () { + const type = $(this).data('type'); + // 回到顶部 + if (type === 'top') { + $scroll[0]?.scrollTo({ + top: 0, + behavior: 'smooth', + }); + } + }); + + // 自定义任意事件 + if (lay.type(options.on) === 'object') { + Object.entries(options.on).forEach(([eventName, callback]) => { + barElem.on(eventName, function () { + const type = $(this).data('type'); + typeof callback === 'function' && callback.call(this, type); + }); + }); + } + + // 获得 top bar 节点 + if (item.type === 'top') { + barElem.addClass('lay-floatbar-top'); + topBarElem = barElem; + } + + // 插入 bar 图标节点 + if (item.icon) { + const iconElem = $('').addClass(item.icon); + barElem.append(iconElem); + } + + elem.append(barElem); // 插入 bar 图标节点 + }); + + // 若目标元素已存在 floatbar, 则移除旧的节点 + $target.find('.' + CONST.ELEM).remove(); + + // 向目标元素插入 floatbar 节点 + $target.append(elem); + + // top bar 的显示隐藏 + let setTopBar; + if (topBarElem) { + let locked; + setTopBar = (function fn() { + const top = $scroll.scrollTop(); + if (top >= options.scrollThreshold) { + locked || (topBarElem.show(), (locked = 1)); + } else { + locked && (topBarElem.hide(), (locked = 0)); + } + return fn; + })(); + } + + // 根据 scrollbar 设置 floatbar 相关状态 + let timer; + const scrollEventName = 'scroll.lay_floatbar_scroll'; + $scroll.off(scrollEventName).on(scrollEventName, function () { + if (!setTopBar) return; + clearTimeout(timer); + timer = setTimeout(() => { + setTopBar(); + }, 100); + }); + }, +}); + +const CONST = component.CONST; + +export { component as floatbar }; diff --git a/src/components/flow.js b/src/components/flow.js new file mode 100644 index 000000000..d1e2c4dc3 --- /dev/null +++ b/src/components/flow.js @@ -0,0 +1,250 @@ +/** + * flow + * 流加载组件 + */ + +import { loader } from '../core/loader.js'; +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +// 创建组件 +var component = componentBuilder({ + name: 'flow', + + CONST: { + ELEM_LOAD: + '', + ELEM_MORE: 'lay-flow-more', + FLOW_SCROLL_EVENTS: 'scroll.lay_flow_scroll', + LAZYIMG_SCROLL_EVENTS: 'scroll.lay_flow_lazyimg_scroll', + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + var page = 0; + var locked; + var finished; + + var elem = options.elem; + if (!elem[0]) return; + + var scrollElem = $(options.scrollElem || document); // 滚动条所在元素 + var threshold = 'mb' in options ? options.mb : 50; // 临界距离 + var isAuto = 'isAuto' in options ? options.isAuto : true; // 否自动滚动加载 + var moreText = options.moreText || i18n.$t('flow.loadMore'); // 手动加载时,加载更多按钮文案 + var endText = options.end || i18n.$t('flow.noMore'); // “末页”显示文案 + var direction = options.direction || 'bottom'; + var isTop = direction === 'top'; + + // 滚动条所在元素是否为 document + var notDocument = options.scrollElem && options.scrollElem !== document; + + // 加载更多 + var ELEM_TEXT = '' + moreText + ''; + var $more = $( + '', + ); + + elem.find('.' + CONST.ELEM_MORE).remove(); // 清除旧的「加载更多」元素 + elem[isTop ? 'prepend' : 'append']($more); + + // 加载下一个元素 + var next = function (content, status) { + var scrollHeightStart = notDocument + ? scrollElem.prop('scrollHeight') + : document.documentElement.scrollHeight; + var scrollTopStart = scrollElem.scrollTop(); + + $more[isTop ? 'after' : 'before'](content); + status = status == 0 ? true : null; + status ? $more.html(endText) : $moreBtn.html(ELEM_TEXT); + finished = status; + locked = null; + + // 如果允许图片懒加载 + if (options.isLazyimg) { + component.lazyimg({ + elem: options.elem.find('img[lay-src]'), + scrollElem: options.scrollElem, + direction: options.direction, + id: options.id, + }); + } + + if (isTop) { + var scrollHeightEnd = notDocument + ? scrollElem.prop('scrollHeight') + : document.documentElement.scrollHeight; + if (page === 1) { + // 首次渲染后滑动到底部 + scrollElem.scrollTop(scrollHeightEnd); + } else if (page > 1) { + var nextElementHeight = scrollHeightEnd - scrollHeightStart; + scrollElem.scrollTop(scrollTopStart + nextElementHeight); + } + } + }; + var $moreBtn = $more.find('a'); + + // 触发请求 + var done = (function fn() { + locked = true; + $moreBtn.html(CONST.ELEM_LOAD); + typeof options.done === 'function' && options.done(++page, next); + return fn; + })(); + + // 不自动滚动加载 + $moreBtn.on('click', function () { + if (finished) return; + locked || done(); + }); + + if (!isAuto) return that; + + // 滚动条滚动事件 + var timer; + var FLOW_SCROLL_EVENTS = CONST.FLOW_SCROLL_EVENTS + '_' + options.id; + scrollElem.off(FLOW_SCROLL_EVENTS).on(FLOW_SCROLL_EVENTS, function () { + var othis = $(this), + top = othis.scrollTop(); + + if (timer) clearTimeout(timer); + + // 如果已经结束,或者元素处于隐藏状态,则不执行滚动加载 + if (finished || !elem.width()) return; + + timer = setTimeout(function () { + // 计算滚动所在容器的可视高度 + var height = notDocument ? othis.height() : $(window).height(); + + // 计算滚动所在容器的实际高度 + var scrollHeight = notDocument + ? othis.prop('scrollHeight') + : document.documentElement.scrollHeight; + + // 临界点 + if ( + !isTop ? scrollHeight - top - height <= threshold : top <= threshold + ) { + locked || done(); + } + }, 100); + }); + }, +}); + +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +// 保留原接口,确保向下兼容 +$.extend(component, { + load: function (options) { + return component.render(options); + }, + + // 图片懒加载 + lazyimg: function (options) { + options = options || {}; + + var scrollElem = $(options.scrollElem || document); // 滚动条所在元素 + var elem = options.elem || 'img'; + var direction = options.direction || 'bottom'; + var isTop = direction === 'top'; + var index = 0; + + // 滚动条所在元素是否为 document + var notDocument = options.scrollElem && options.scrollElem !== document; + + // 显示图片 + var render = (function fn(othis) { + var $elem = $(elem); + + // 计算滚动所在容器的可视高度 + var height = notDocument ? scrollElem.height() : $(window).height(); + var start = scrollElem.scrollTop(); + var end = start + height; + + var show = function (item) { + var elemTop = notDocument + ? (function () { + return item.offset().top - scrollElem.offset().top + start; + })() + : item.offset().top; + + /* 始终只加载在当前屏范围内的图片 */ + if ( + (isTop ? elemTop + item.height() : elemTop) >= start && + elemTop <= end + ) { + if (item.attr('lay-src')) { + var src = item.attr('lay-src'); + loader.image(src, { + success() { + var next = $elem.eq(index); + item.attr('src', src).removeAttr('lay-src'); + + /* 当前图片加载就绪后,检测下一个图片是否在当前屏 */ + next[0] && fn(next); + index++; + }, + error() { + item.removeAttr('lay-src'); + }, + }); + } + } + }; + + if (othis) { + show(othis); + } else { + // 计算未加载过的图片 + for (var i = 0; i < $elem.length; i++) { + var item = $elem.eq(i), + elemTop = notDocument + ? (function () { + return item.offset().top - scrollElem.offset().top + start; + })() + : item.offset().top; + + show(item); + index = i; + + // 如果图片的 top 坐标,超出了当前屏,则终止后续图片的遍历 + if (elemTop > end) break; + } + } + + return fn; + })(); + + // 滚动事件 + var timer; + var id = options.id || ''; + var LAZYIMG_SCROLL_EVENTS = CONST.LAZYIMG_SCROLL_EVENTS + '_' + id; + scrollElem + .off(LAZYIMG_SCROLL_EVENTS) + .on(LAZYIMG_SCROLL_EVENTS, function () { + if (timer) clearTimeout(timer); + timer = setTimeout(function () { + render(); + }, 50); + }); + + return render; + }, +}); + +export { component as flow }; diff --git a/src/components/form.js b/src/components/form.js new file mode 100644 index 000000000..ca34d6787 --- /dev/null +++ b/src/components/form.js @@ -0,0 +1,1756 @@ +/** + * form 表单组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { log } from '../core/logger.js'; +import { $ } from 'jquery'; +import { layer } from './layer.js'; + +var MOD_NAME = 'form'; +var ELEM = '.lay-form'; +var THIS = 'lay-this'; +// var SHOW = 'lay-show'; +var HIDE = 'lay-hide'; +var DISABLED = 'lay-disabled'; +var OUT_OF_RANGE = 'lay-input-number-out-of-range'; +var BAD_INPUT = 'lay-input-number-invalid'; + +var resizeObserver = lay.createSharedResizeObserver(MOD_NAME); + +// AppleWebKit/537.36 无法获取 input 元素任意属性的属性描述符(包括lookupGetter),但可以重新定义 getter/setter +var needCheckboxFallback = + typeof Object.getOwnPropertyDescriptor( + HTMLInputElement.prototype, + 'checked', + ) === 'undefined'; + +var Form = function () { + this.config = { + // 内置的验证规则 + verify: { + required: function (value) { + if (!/[\S]+/.test(value) || value === undefined || value === null) { + return i18n.$t('form.validateMessages.required'); + } + }, + phone: function (value) { + var EXP = /^1\d{10}$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.phone'); + } + }, + email: function (value) { + var EXP = /^([a-zA-Z0-9_.-])+@(([a-zA-Z0-9-])+\.)+([a-zA-Z0-9]{2,4})+$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.email'); + } + }, + url: function (value) { + var EXP = /^(#|(http(s?)):\/\/|\/\/)[^\s]+\.[^\s]+$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.url'); + } + }, + number: function (value) { + if (value && isNaN(value)) { + return i18n.$t('form.validateMessages.number'); + } + }, + date: function (value) { + var EXP = + /^(\d{4})[-/](\d{1}|0\d{1}|1[0-2])([-/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.date'); + } + }, + identity: function (value) { + var EXP = /(^\d{15}$)|(^\d{17}(x|X|\d)$)/; + if (value && !EXP.test(value)) { + return i18n.$t('form.validateMessages.identity'); + } + }, + }, + autocomplete: null, // 全局 autocomplete 状态。 null 表示不干预 + }; +}; + +// 全局设置 +Form.prototype.set = function (options) { + var that = this; + $.extend(true, that.config, options); + return that; +}; + +// 验证规则设定 +Form.prototype.verify = function (settings) { + var that = this; + $.extend(true, that.config.verify, settings); + return that; +}; + +// 获取指定表单对象 +Form.prototype.getFormElem = function (filter) { + return $( + ELEM + + (function () { + return filter ? '[lay-filter="' + filter + '"]' : ''; + })(), + ); +}; + +// 表单事件 +Form.prototype.on = function (events, callback) { + return lay.onevent.call(this, MOD_NAME, events, callback); +}; + +// 赋值/取值 +Form.prototype.val = function (filter, object) { + var that = this; + var formElem = that.getFormElem(filter); + + // 遍历 + formElem.each(function () { + var itemForm = $(this); + + // 赋值 + for (var key in object) { + if (!lay.hasOwn(object, key)) continue; + + var type; + var value = object[key]; + var itemElem = itemForm.find('[name="' + key + '"]'); + + // 如果对应的表单不存在,则不执行 + if (!itemElem[0]) continue; + type = itemElem[0].type; + + // 如果为复选框 + if (type === 'checkbox') { + itemElem[0].checked = value; + } else if (type === 'radio') { + // 如果为单选框 + itemElem.each(function () { + this.checked = this.value == value + ''; + }); + } else { + // 其它类型的表单 + itemElem.val(value); + } + } + }); + + form.render(null, filter); + + // 返回值 + return that.getValue(filter); +}; + +// 取值 +Form.prototype.getValue = function (filter, itemForm) { + itemForm = itemForm || this.getFormElem(filter); + + var nameIndex = {}, // 数组 name 索引 + field = {}, + fieldElem = itemForm.find('input,select,textarea'); // 获取所有表单域 + + fieldElem.each(function (_, item) { + var othis = $(this), + init_name; // 初始 name + + item.name = (item.name || '').replace(/^\s*|\s*&/, ''); + if (!item.name) return; + + // 用于支持数组 name + if (/^.*\[\]$/.test(item.name)) { + var key = item.name.match(/^(.*)\[\]$/g)[0]; + nameIndex[key] = nameIndex[key] | 0; + init_name = item.name.replace( + /^(.*)\[\]$/, + '$1[' + nameIndex[key]++ + ']', + ); + } + + if (/^(checkbox|radio)$/.test(item.type) && !item.checked) return; // 复选框和单选框未选中,不记录字段 + // select 多选用 jQuery 方式取值,未选中 option 时, + // jQuery v2.2.4 及以下版本返回 null,以上(3.x) 返回 []。 + // 统一规范化为 [],参考 https://github.com/jquery/jquery/issues/2562 + field[init_name || item.name] = + this.tagName === 'SELECT' && + typeof this.getAttribute('multiple') === 'string' + ? othis.val() || [] + : this.value; + }); + + return field; +}; + +// 表单控件渲染 +Form.prototype.render = function (type, filter) { + var that = this; + var options = that.config; + var elemForm = $( + ELEM + + (function () { + return filter ? '[lay-filter="' + filter + '"]' : ''; + })(), + ); + var items = { + // 输入框 + input: function (elem) { + var inputs = elem || elemForm.find('input,textarea'); + + // 初始化全局的 autocomplete + options.autocomplete && inputs.attr('autocomplete', options.autocomplete); + + var handleInputNumber = function (elem, eventType) { + var that = this; + var rawValue = elem.val(); + var value = Number(rawValue); + var step = Number(elem.attr('step')) || 1; // 加减的数字间隔 + var min = Number(elem.attr('min')); + var max = Number(elem.attr('max')); + var precision = Number(elem.attr('lay-precision')); + var noAction = eventType !== 'click' && rawValue === ''; // 初始渲染和失焦时空值不作处理 + var isInit = eventType === 'init'; + var isBadInput = isNaN(value); + var isStepStrictly = typeof elem.attr('lay-step-strictly') === 'string'; + + elem.toggleClass(BAD_INPUT, isBadInput); + if (isBadInput) return; // 若非数字,则不作处理 + + if (eventType === 'click') { + // 兼容旧版行为,2.10 以前 readonly 不禁用控制按钮 + if ( + elem[0].type === 'text' && + typeof elem.attr('readonly') === 'string' + ) + return; + var isDecrement = !!$(that).index(); // 0: icon-up, 1: icon-down + value = isDecrement ? value - step : value + step; + } + + // 获取小数点后位数 + var decimals = function (step) { + var decimals = (step.toString().match(/\.(\d+$)/) || [])[1] || ''; + return decimals.length; + }; + + precision = + precision >= 0 + ? precision + : Math.max(decimals(step), decimals(rawValue)); + + // 赋值 + if (!noAction) { + // 初始渲染时只处理数字精度 + if (!isInit) { + if (isStepStrictly) { + value = Math.round(value / step) * step; + } + if (value <= min) value = min; + if (value >= max) value = max; + } + // 若 `lay-precision` 为 0, 则表示只保留整数 + if (precision === 0) { + value = parseInt(value); + } else if (precision > 0) { + // 小数位精度 + value = value.toFixed(precision); + } + + elem.val(value); + elem.attr('lay-input-mirror', elem.val()); + } + + // 超出范围的样式 + var outOfRange = value < min || value > max; + elem[outOfRange && !noAction ? 'addClass' : 'removeClass']( + OUT_OF_RANGE, + ); + + if (isInit) return; + + // 更新按钮状态 + var controlBtn = { + increment: elem.next().find('.lay-icon-up'), + decrement: elem.next().find('.lay-icon-down'), + }; + controlBtn.increment[ + value >= max && !noAction ? 'addClass' : 'removeClass' + ](DISABLED); + controlBtn.decrement[ + value <= min && !noAction ? 'addClass' : 'removeClass' + ](DISABLED); + }; + + // 初始化输入框动态点缀 + elemForm.find('input[lay-affix],textarea[lay-affix]').each(function () { + var othis = $(this); + var affix = othis.attr('lay-affix'); + var CLASS_WRAP = 'lay-input-wrap'; + var CLASS_SUFFIX = 'lay-input-suffix'; + var CLASS_AFFIX = 'lay-input-affix'; + var disabled = othis.is('[disabled]') || othis.is('[readonly]'); + + // 根据是否空值来显示或隐藏元素 + var showAffix = function (elem, value) { + elem = $(elem); + if (!elem[0]) return; + var normalizedValue = String(value ?? '').trim(); + elem[normalizedValue ? 'removeClass' : 'addClass'](HIDE); + }; + + // 渲染动态点缀内容 + var renderAffix = function (opts) { + opts = $.extend( + {}, + affixOptions[affix] || { + value: affix, + }, + opts, + lay.options(othis[0]), + ); + var elemAffix = $('
                              '); + var value = lay.isArray(opts.value) ? opts.value : [opts.value]; + var elemIcon = $( + (function () { + var arr = []; + value.forEach(function (item) { + arr.push( + '', + ); + }); + return arr.join(''); + })(), + ); + + elemAffix.append(elemIcon); // 插入图标元素 + + // 追加 className + if (opts.split) elemAffix.addClass('lay-input-split'); + if (opts.className) elemAffix.addClass(opts.className); + + // 移除旧的元素 + var hasElemAffix = othis.next('.' + CLASS_AFFIX); + if (hasElemAffix[0]) hasElemAffix.remove(); + + // 是否在规定的容器中 + if (!othis.parent().hasClass(CLASS_WRAP)) { + othis.wrap('
                              '); + } + + // 是否已经存在后缀元素 + var hasElemSuffix = othis.next('.' + CLASS_SUFFIX); + if (hasElemSuffix[0]) { + hasElemAffix = hasElemSuffix.find('.' + CLASS_AFFIX); + if (hasElemAffix[0]) hasElemAffix.remove(); + + hasElemSuffix.prepend(elemAffix); + + othis.css('padding-right', function () { + var paddingRight = othis.closest('.lay-input-group')[0] + ? 0 + : hasElemSuffix.outerWidth(); + return paddingRight + elemAffix.outerWidth(); + }); + } else { + elemAffix.addClass(CLASS_SUFFIX); + othis.after(elemAffix); + } + + opts.show === 'auto' && showAffix(elemAffix, othis.val()); + + typeof opts.init === 'function' && opts.init.call(this, othis, opts); + + // 输入事件 + othis.on('input', function () { + var value = this.value; + opts.show === 'auto' && showAffix(elemAffix, value); + }); + + // 失去焦点事件 + othis.on('blur', function () { + typeof opts.blur === 'function' && + opts.blur.call(this, othis, opts); + }); + + // 点击动态后缀事件 + elemIcon.on('click', function () { + var inputFilter = othis.attr('lay-filter'); + if ($(this).hasClass(DISABLED)) return; + + typeof opts.click === 'function' && + opts.click.call(this, othis, opts); + + // 对外事件 + lay.event.call(this, MOD_NAME, 'input-affix(' + inputFilter + ')', { + elem: othis[0], + affix: affix, + options: opts, + }); + }); + }; + + // 动态点缀配置项 + var affixOptions = { + eye: { + // 密码显隐 + value: 'eye-invisible', + click: function (elem) { + // 事件 + var SHOW_NAME = 'LAY_FORM_INPUT_AFFIX_SHOW'; + var isShow = elem.data(SHOW_NAME); + + elem + .attr('type', isShow ? 'password' : 'text') + .data(SHOW_NAME, !isShow); + + renderAffix({ + value: isShow ? 'eye-invisible' : 'eye', + }); + }, + }, + clear: { + // 内容清除 + value: 'clear', + click: function (elem) { + elem.val('').focus(); + showAffix($(this).parent(), null); + }, + show: 'auto', // 根据输入框值是否存在来显示或隐藏点缀图标 + disabled: disabled, // 跟随输入框禁用状态 + }, + number: { + // 数字输入框 + value: ['up', 'down'], + split: true, + className: 'lay-input-number', + disabled: othis.is('[disabled]'), // 跟随输入框禁用状态 + init: function (elem) { + // 旧版浏览器不支持更改 input 元素的 type 属性,需要主动设置 text + if (elem.attr('type') === 'text' || elem[0].type === 'text') { + var ns = '.lay_input_number'; + var skipCheck = false; + var isComposition = false; + var isReadonly = typeof elem.attr('readonly') === 'string'; + var isMouseWheel = typeof elem.attr('lay-wheel') === 'string'; + var btnElem = elem.next('.lay-input-number').children('i'); + // 旧版浏览器不支持 beforeInput 事件,需要设置一个 attr 存储输入前的值 + elem.attr('lay-input-mirror', elem.val()); + elem.off(ns); + // 旧版浏览器不支持 event.inputType 属性,需要用 keydown 事件来判断是否跳过输入检查 + elem.on('keydown' + ns, function (e) { + skipCheck = false; + if (e.keyCode === 8 || e.keyCode === 46) { + // Backspace || Delete + skipCheck = true; + } + // Up & Down 键盘事件处理 + if ( + !isReadonly && + btnElem.length === 2 && + (e.keyCode === 38 || e.keyCode === 40) + ) { + e.preventDefault(); + btnElem.eq(e.keyCode === 38 ? 0 : 1).click(); + } + }); + elem.on('input' + ns, function () { + if (isComposition) return; + if (skipCheck || canInputNumber(this.value)) { + elem.attr('lay-input-mirror', this.value); + } else { + // 恢复输入前的值 + this.value = elem.attr('lay-input-mirror'); + } + elem.toggleClass(BAD_INPUT, isNaN(Number(this.value))); + }); + elem.on('compositionstart' + ns, function () { + isComposition = true; + }); + elem.on('compositionend' + ns, function () { + isComposition = false; + elem.trigger('input'); + }); + // 响应鼠标滚轮或触摸板 + if (isMouseWheel) { + elem.on( + ['wheel', 'mousewheel', 'DOMMouseScroll'].join(ns + ' ') + + ns, + function (e) { + if (!btnElem.length) return; + if (!$(this).is(':focus')) return; + var direction = 0; + e.preventDefault(); + if (e.type === 'wheel') { + e.deltaX = e.originalEvent.deltaX; + e.deltaY = e.originalEvent.deltaY; + direction = + Math.abs(e.deltaX) >= Math.abs(e.deltaY) + ? e.deltaX + : e.deltaY; + } else if (e.type === 'mousewheel') { + direction = -e.originalEvent.wheelDelta; + } else if (e.type === 'DOMMouseScroll') { + direction = e.originalEvent.detail; + } + btnElem.eq(direction > 0 ? 1 : 0).click(); + }, + ); + } + + if (isReadonly) { + btnElem.addClass(DISABLED); + } + } + handleInputNumber.call(this, elem, 'init'); + }, + click: function (elem) { + handleInputNumber.call(this, elem, 'click'); + }, + blur: function (elem) { + handleInputNumber.call(this, elem, 'blur'); + }, + }, + }; + + renderAffix(); + }); + }, + + // 下拉选择框 + select: function (elem) { + var TIPS = i18n.$t('form.select.placeholder'); + var CLASS = 'lay-form-select'; + var TITLE = 'lay-select-title'; + var NONE = 'lay-select-none'; + var CREATE_OPTION = 'lay-select-create-option'; + var PANEL_WRAP = 'lay-select-panel-wrap'; + var PANEL_ELEM_DATA = 'lay-select-panel-elem-data'; + var selects = elem || elemForm.find('select'); + + // 各种事件 + var events = function ( + reElem, + titleElem, + disabled, + isSearch, + isCreatable, + isAppendTo, + ) { + var select = $(this); + var title = titleElem; + var input = title.find('input'); + var dl = reElem.find('dl'); + // var dds = dl.children('dd'); + var dts = dl.children('dt'); // select 分组dt元素 + var index = this.selectedIndex; // 当前选中的索引 + var initValue = ''; + var removeClickOutsideEvent; + + if (disabled) return; + + /** + * 搜索项 + * @typedef searchOption + * @prop {boolean} [caseSensitive=false] 是否区分大小写 + * @prop {boolean} [fuzzy=false] 是否开启模糊匹配,开启后将会忽略模式出现在字符串中的位置。 + */ + /** @type {searchOption} */ + var laySearch = + select.attr('lay-search') === 'cs' + ? { caseSensitive: true } + : lay.options(select, { attr: 'lay-search' }); + // 目前只支持 body + var appendTarget = select.attr('lay-append-to') || 'body'; + var appendPosition = select.attr('lay-append-position'); + + // 展开下拉 + var showDown = function () { + if (isAppendTo) { + // 如果追加面板元素后出现滚动条,触发元素宽度可能会有变化,所以先追加面板元素 + reElem.appendTo(appendTarget).css({ width: title.width() + 'px' }); + + var updatePosition = function () { + lay.position(title[0], reElem[0], { + position: appendPosition, + allowBottomOut: true, + offset: [0, 5], + }); + }; + + updatePosition(); + $(window).on('resize.lay_select_resize', updatePosition); + if (resizeObserver) { + resizeObserver.observe(reElem[0], updatePosition); + } + } + var top = + reElem.offset().top + reElem.outerHeight() + 5 - $win.scrollTop(); + var dlHeight = dl.outerHeight(); + var dds = dl.children('dd'); + + index = select[0].selectedIndex; // 获取最新的 selectedIndex + title.parent().addClass(CLASS + 'ed'); + dds.removeClass(HIDE); + dts.removeClass(HIDE); + + // 初始选中样式 + dds.removeClass(THIS); + index >= 0 && dds.eq(index).addClass(THIS); + + // 上下定位识别 + if (top + dlHeight > $win.height() && top >= dlHeight) { + reElem.addClass(CLASS + 'up'); + } + + followScroll(); + + removeClickOutsideEvent = lay.onClickOutside( + isAppendTo ? reElem[0] : dl[0], + function () { + hideDown(); + initValue && input.val(initValue); + }, + { ignore: title, detectIframe: true, capture: false }, + ); + }; + + // 隐藏下拉 + var hideDown = function (choose) { + title.parent().removeClass(CLASS + 'ed ' + CLASS + 'up'); + input.blur(); + isCreatable && dl.children('.' + CREATE_OPTION).remove(); + if (typeof removeClickOutsideEvent === 'function') { + removeClickOutsideEvent(); + removeClickOutsideEvent = null; + } + if (isAppendTo) { + reElem.detach(); + $(window).off('resize.lay_select_resize'); + if (resizeObserver) { + resizeObserver.unobserve(reElem[0]); + } + } + + if (choose) return; + + notOption(input.val(), function (none) { + var selectedIndex = select[0].selectedIndex; + + // 未查询到相关值 + if (none) { + initValue = $(select[0].options[selectedIndex]).prop('text'); // 重新获得初始选中值 + + // 如果是第一项,且文本值等于 placeholder,则清空初始值 + if ( + selectedIndex === 0 && + initValue === input.attr('placeholder') + ) { + initValue = ''; + } + + // 如果有选中值,则将输入框纠正为该值。否则清空输入框 + input.val(initValue || ''); + } + }); + }; + + // 定位下拉滚动条 + var followScroll = function () { + var thisDd = dl.children('dd.' + THIS); + + if (!thisDd[0]) return; + + var posTop = thisDd.position().top; + var dlHeight = dl.height(); + var ddHeight = thisDd.height(); + + // 若选中元素在滚动条不可见底部 + if (posTop > dlHeight) { + dl.scrollTop(posTop + dl.scrollTop() - dlHeight + ddHeight - 5); + } + + // 若选择元素在滚动条不可见顶部 + if (posTop < 0) { + dl.scrollTop(posTop + dl.scrollTop() - 5); + } + }; + + // 点击标题区域 + title.on('click', function () { + title.parent().hasClass(CLASS + 'ed') ? hideDown() : showDown(); + dl.find('.' + NONE).remove(); + }); + + // 点击箭头获取焦点 + title.find('.lay-edge').on('click', function () { + input.focus(); + }); + + // select 中 input 键盘事件 + input + .on('keyup', function (e) { + // 键盘松开 + var keyCode = e.keyCode; + + // Tab键展开 + if (keyCode === 9) { + showDown(); + } + }) + .on('keydown', function (e) { + // 键盘按下 + var keyCode = e.keyCode; + + // Tab键隐藏 + if (keyCode === 9) { + hideDown(); + } + + // 标注 dd 的选中状态 + var setThisDd = function (prevNext) { + e.preventDefault(); + var allDisplayedElem = dl.children( + 'dd:not(.' + HIDE + ',.' + DISABLED + ')', + ); + if (!allDisplayedElem.length) return; + var firstIndex = 0; + var lastIndex = allDisplayedElem.length - 1; + var selectedIndex = -1; + + allDisplayedElem.each(function (index, el) { + if ($(el).hasClass(THIS)) { + selectedIndex = index; + return false; + } + }); + + var nextIndex = + prevNext === 'prev' + ? selectedIndex - 1 < firstIndex + ? lastIndex + : selectedIndex - 1 + : selectedIndex + 1 > lastIndex + ? firstIndex + : selectedIndex + 1; + + var selectedElem = allDisplayedElem.eq(nextIndex); + selectedElem.addClass(THIS).siblings().removeClass(THIS); // 标注样式 + followScroll(); // 定位滚动条 + }; + + if (keyCode === 38) setThisDd('prev'); // Up 键 + if (keyCode === 40) setThisDd('next'); // Down 键 + + // Enter 键 + if (keyCode === 13) { + e.preventDefault(); + dl.children('dd.' + THIS).trigger('click'); + } + }) + .on('paste', function () { + showDown(); + }); + + // 检测值是否不属于 select 项 + var notOption = function (value, callback, origin) { + var num = 0; + var dds = dl.children('dd'); + var hasEquals = false; + var rawValue = value; + var fuzzyMatchRE; + if (!laySearch.caseSensitive) { + value = value.toLowerCase(); + } + if (laySearch.fuzzy) { + fuzzyMatchRE = fuzzyMatchRegExp(value, laySearch.caseSensitive); + } + dds.each(function () { + var othis = $(this); + var text = othis.text(); + var isCreateOption = isCreatable && othis.hasClass(CREATE_OPTION); + + // 需要区分大小写 + if (isCreatable && !isCreateOption && text === rawValue) { + hasEquals = true; + } + + // 是否区分大小写 + if (!laySearch.caseSensitive) { + text = text.toLowerCase(); + } + + // 匹配 + var not = laySearch.fuzzy + ? !fuzzyMatchRE.test(text) + : text.indexOf(value) === -1; + + if (value === '' || origin === 'blur' ? value !== text : not) num++; + origin === 'keyup' && + othis[ + (isCreatable ? not && !isCreateOption : not) + ? 'addClass' + : 'removeClass' + ](HIDE); + }); + // 处理 select 分组元素 + origin === 'keyup' && + dts.each(function () { + var othis = $(this); + var thisDds = othis.nextUntil('dt').filter('dd'); // 当前分组下的dd元素 + if (isCreatable) thisDds = thisDds.not('.' + CREATE_OPTION); + var allHide = thisDds.length == thisDds.filter('.' + HIDE).length; // 当前分组下所有dd元素都隐藏了 + othis[allHide ? 'addClass' : 'removeClass'](HIDE); + }); + var none = num === dds.length; + return (callback(none, hasEquals), none); + }; + + // 搜索匹配 + var search = function (e) { + var value = this.value, + keyCode = e.keyCode; + + if ( + keyCode === 9 || + keyCode === 13 || + keyCode === 37 || + keyCode === 38 || + keyCode === 39 || + keyCode === 40 + ) { + return false; + } + + notOption( + value, + function (none, hasEquals) { + if (isCreatable) { + if (hasEquals) { + dl.children('.' + CREATE_OPTION).remove(); + } else { + var createOptionElem = dl.children('.' + CREATE_OPTION); + if (createOptionElem[0]) { + createOptionElem.attr('lay-value', value).text(value); + } else { + // 临时显示在顶部 + var ddElem = $('
                              ') + .addClass(CREATE_OPTION) + .attr('lay-value', value) + .text(value); + var firstOptionELem = dl.children().eq(0); + var hasTips = firstOptionELem.hasClass('lay-select-tips'); + firstOptionELem[hasTips ? 'after' : 'before'](ddElem); + } + } + } else { + if (none) { + dl.find('.' + NONE)[0] || + dl.append( + '

                              ' + + i18n.$t('form.select.noMatch') + + '

                              ', + ); + } else { + dl.find('.' + NONE).remove(); + } + } + }, + 'keyup', + ); + + // 当搜索值清空时 + if (value === '') { + // 取消选中项 + select.val(''); + dl.find('.' + THIS).removeClass(THIS); + (select[0].options[0] || {}).value || + dl.children('dd:eq(0)').addClass(THIS); + dl.find('.' + NONE).remove(); + isCreatable && dl.children('.' + CREATE_OPTION).remove(); + } + + followScroll(); // 定位滚动条 + }; + + if (isSearch) { + input.on('input', lay.debounce(search, 50)).on('blur', function () { + var selectedIndex = select[0].selectedIndex; + + initValue = $(select[0].options[selectedIndex]).prop('text'); // 重新获得初始选中值 + + // 如果是第一项,且文本值等于 placeholder,则清空初始值 + if ( + selectedIndex === 0 && + initValue === input.attr('placeholder') + ) { + initValue = ''; + } + + setTimeout(function () { + notOption( + input.val(), + function () { + initValue || input.val(''); // none && !initValue + }, + 'blur', + ); + }, 200); + }); + } + + // 选择 + dl.on('click', 'dd', function () { + var othis = $(this), + value = othis.attr('lay-value'); + var filter = select.attr('lay-filter'); // 获取过滤器 + + if (othis.hasClass(DISABLED)) return false; + + // 将新增的 option 元素添加到末尾 + if (isCreatable && othis.hasClass(CREATE_OPTION)) { + var optionElem = $('
                              '); + if (index === 0 && !item.value && tagName !== 'optgroup') { + dd.addClass('lay-select-tips'); + dd.text(item.text || TIPS); + arr.push(dd.prop('outerHTML')); + } else if (tagName === 'optgroup') { + var dt = $('
                              '); + dt.text(item.label); + arr.push(dt.prop('outerHTML')); + } else { + dd.attr('lay-value', item.value); + if (value === item.value) { + dd.addClass(THIS); + } + if (item.disabled) { + dd.addClass(DISABLED); + } + dd.text(item.text); + arr.push(dd.prop('outerHTML')); + } + }); + if (arr.length === 0) { + arr.push( + '
                              ' + + i18n.$t('form.select.noData') + + '
                              ', + ); + } + return arr.join(''); + })(); + elem.html(content); + return elem; + })(); + + // 如果已经渲染,则 Rerender + if (hasRender[0]) { + if (isAppendTo) { + var panelWrapElem = hasRender.data(PANEL_ELEM_DATA); + panelWrapElem && panelWrapElem.remove(); + } + hasRender.remove(); + } + if (isAppendTo) { + selectWrapper.append(titleElem); + othis.after(selectWrapper); + var contentWrapElem = $( + '
                              ', + ).append(contentElem); + selectWrapper.data(PANEL_ELEM_DATA, contentWrapElem); // 将面板元素对象记录在触发元素 data 中,重新渲染时需要清理旧面板元素 + events.call( + this, + contentWrapElem, + titleElem, + disabled, + isSearch, + isCreatable, + isAppendTo, + ); + } else { + selectWrapper.append(titleElem).append(contentElem); + othis.after(selectWrapper); + events.call( + this, + selectWrapper, + titleElem, + disabled, + isSearch, + isCreatable, + isAppendTo, + ); + } + }); + }, + + // 复选框/开关 + checkbox: function (elem) { + var CLASS = { + checkbox: ['lay-form-checkbox', 'lay-form-checked', 'checkbox'], + switch: ['lay-form-switch', 'lay-form-onswitch', 'switch'], + SUBTRA: 'lay-icon-indeterminate', + ICON: 'lay-icon', + ICON_OK: 'lay-icon-ok', + }; + var clickEventName = 'click.lay_checkbox_click'; + var checks = elem || elemForm.find('input[type=checkbox]'); + // 风格 + /* var skins = { + primary: true, // 默认风格 + tag: true, // 标签风格 + switch: true, // 开关风格 + }; */ + // 事件 + var events = function (reElem, RE_CLASS) { + var check = $(this); + var skin = check.attr('lay-skin') || 'primary'; + var isSwitch = skin === 'switch'; + var isPrimary = skin === 'primary'; + + // 勾选 + // 通过重新赋值触发美化元素样式更新 + check.off(clickEventName).on(clickEventName, function () { + var filter = check.attr('lay-filter'); // 获取过滤器 + var checked = check[0].checked; + var indeterminate = check[0].indeterminate; + + // 禁用 + if (check[0].disabled) return; + + // 半选 + check[0].indeterminate = indeterminate; + + // 开关 + check[0].checked = checked; + + // 事件 + lay.event.call(check[0], MOD_NAME, RE_CLASS[2] + '(' + filter + ')', { + elem: check[0], + value: check[0].value, + othis: reElem, + }); + }); + + reElem.on('click', function () { + var hasLabel = check.closest('label').length; + if (!hasLabel) { + check.trigger('click'); + } + }); + + that.syncAppearanceOnPropChanged(this, 'checked', function () { + if (isSwitch) { + var title = ( + reElem.next('*[lay-checkbox]')[0] + ? reElem.next().html() + : check.attr('title') || '' + ).split('|'); + reElem + .children('div') + .html(this.checked ? title[0] : title[1] || title[0]); + } + reElem.toggleClass(RE_CLASS[1], this.checked); + }); + + if (isPrimary) { + that.syncAppearanceOnPropChanged(this, 'indeterminate', function () { + if (this.indeterminate) { + reElem + .children('.' + CLASS.ICON) + .removeClass(CLASS.ICON_OK) + .addClass(CLASS.SUBTRA); + } else { + reElem + .children('.' + CLASS.ICON) + .removeClass(CLASS.SUBTRA) + .addClass(CLASS.ICON_OK); + } + }); + } + }; + + // 遍历复选框 + checks.each(function (index, check) { + var othis = $(this); + var skin = othis.attr('lay-skin') || 'primary'; + var title = lay.escape( + ( + check.title || + (function () { + // 向下兼容 lay-text 属性 + return (check.title = othis.attr('lay-text') || ''); + })() + ).trim(), + ); + var disabled = this.disabled; + + // if(!skins[skin]) skin = 'primary'; // 若非内置风格,则强制为默认风格 + var RE_CLASS = CLASS[skin] || CLASS.checkbox; + + // 替代元素 + var hasRender = othis.next('.' + RE_CLASS[0]); + hasRender[0] && hasRender.remove(); // 若已经渲染,则 Rerender + + // 若存在标题模板,则优先读取标题模板 + var titleTplAttrs = []; + if (othis.next('[lay-checkbox]')[0]) { + var titleTplElem = othis.next(); + title = titleTplElem.html() || ''; + if (titleTplElem[0].attributes.length > 1) { + Array.from(titleTplElem[0].attributes).forEach(function (attr) { + if (attr.name !== 'lay-checkbox') { + titleTplAttrs.push(attr.name + '="' + attr.value + '"'); + } + }); + } + } + titleTplAttrs = titleTplAttrs.join(' '); + + // 若为开关,则对 title 进行分隔解析 + title = skin === 'switch' ? title.split('|') : [title]; + + if (othis.closest('[lay-ignore]').length) return othis.show(); + + if (needCheckboxFallback) { + toggleAttribute.call(check, 'lay-form-sync-checked', check.checked); + !check.checked && + toggleAttribute.call( + check, + 'lay-form-sync-indeterminate', + check.indeterminate, + ); + } + + // 替代元素 + var reElem = $( + [ + '
                              ', + (function () { + // 不同风格的内容 + var type = { + // 复选框 + checkbox: [ + title[0] + ? '
                              ' + title[0] + '
                              ' + : skin === 'primary' + ? '' + : '
                              ', + '', + ].join(''), + // 开关 + switch: + '
                              ' + + ((check.checked ? title[0] : title[1] || title[0]) || '') + + '
                              ', + }; + return type[skin] || type['checkbox']; + })(), + '
                              ', + ].join(''), + ); + + othis.after(reElem); + events.call(this, reElem, RE_CLASS); + }); + }, + + // 单选框 + radio: function (elem) { + var CLASS = 'lay-form-radio'; + var ICON = ['lay-icon-radio', 'lay-icon-circle']; + var radios = elem || elemForm.find('input[type=radio]'); + var clickEventName = 'click.lay_radio_click'; + + // 事件 + var events = function (reElem) { + var radio = $(this); + var ANIM = 'lay-anim-scaleSpring'; + + radio.off(clickEventName).on(clickEventName, function () { + var filter = radio.attr('lay-filter'); // 获取过滤器 + + if (radio[0].disabled) return; + + radio[0].checked = true; + + lay.event.call(radio[0], MOD_NAME, 'radio(' + filter + ')', { + elem: radio[0], + value: radio[0].value, + othis: reElem, + }); + }); + + reElem.on('click', function () { + var hasLabel = radio.closest('label').length; + if (!hasLabel) { + radio.trigger('click'); + } + }); + + that.syncAppearanceOnPropChanged(this, 'checked', function () { + var radioEl = this; + if (radioEl.checked) { + reElem.addClass(CLASS + 'ed'); + reElem.children('.lay-icon').addClass(ANIM + ' ' + ICON[0]); + var forms = radio.parents(ELEM); + var sameRadios = forms.find( + 'input[name=' + + radioEl.name.replace(/(\.|#|\[|\])/g, '\\$1') + + ']', + ); // 找到相同name的兄弟 + sameRadios.each(function () { + if (radioEl === this) return; + this.checked = false; + }); + } else { + reElem.removeClass(CLASS + 'ed'); + reElem + .children('.lay-icon') + .removeClass(ANIM + ' ' + ICON[0]) + .addClass(ICON[1]); + } + }); + }; + + // 初始渲染 + radios.each(function (index, radio) { + var othis = $(this), + hasRender = othis.next('.' + CLASS); + var disabled = this.disabled; + var skin = othis.attr('lay-skin'); + + if (othis.closest('[lay-ignore]').length) return othis.show(); + + if (needCheckboxFallback) { + toggleAttribute.call(radio, 'lay-form-sync-checked', radio.checked); + } + + hasRender[0] && hasRender.remove(); // 如果已经渲染,则Rerender + + var title = lay.escape(radio.title || ''); + var titleTplAttrs = []; + if (othis.next('[lay-radio]')[0]) { + var titleTplElem = othis.next(); + title = titleTplElem.html() || ''; + if (titleTplElem[0].attributes.length > 1) { + Array.from(titleTplElem[0].attributes).forEach(function (attr) { + if (attr.name !== 'lay-radio') { + titleTplAttrs.push(attr.name + '="' + attr.value + '"'); + } + }); + } + } + titleTplAttrs = titleTplAttrs.join(' '); + + // 替代元素 + var reElem = $( + [ + '
                              ', + '', + '
                              ' + title + '
                              ', + '
                              ', + ].join(''), + ); + + othis.after(reElem); + events.call(this, reElem); + }); + }, + }; + + // 执行所有渲染项 + var renderItem = function () { + Object.values(items).forEach(function (item) { + item(); + }); + }; + + // jquery 对象 + if (lay.type(type) === 'object') { + // 若对象为表单域容器 + if ($(type).is(ELEM)) { + elemForm = $(type); + renderItem(); + } else { + // 对象为表单项 + type.each(function (index, item) { + var elem = $(item); + if (!elem.closest(ELEM).length) { + return; // 若不在 lay-form 容器中直接跳过 + } + if (item.tagName === 'SELECT') { + items['select'](elem); + } else if (item.tagName === 'INPUT') { + var itemType = item.type; + if (itemType === 'checkbox' || itemType === 'radio') { + items[itemType](elem); + } else { + items['input'](elem); + } + } + }); + } + } else { + type + ? items[type] + ? items[type]() + : log('[form] "' + type + '" is an unsupported form element type') + : renderItem(); + } + return that; +}; + +/** + * checkbox 和 radio 指定属性变化时自动更新 UI + * 只能用于 boolean 属性 + * @param {HTMLInputElement} elem - HTMLInput 元素 + * @param {'checked' | 'indeterminate'} propName - 属性名 + * @param {() => void} handler - 属性值改变时执行的回调 + * @see https://learn.microsoft.com/zh-cn/previous-versions//ff382725(v=vs.85)?redirectedfrom=MSDN + */ +Form.prototype.syncAppearanceOnPropChanged = (function () { + // 此处性能敏感,不希望每次赋值取值时都判断是否需要 fallback + if (needCheckboxFallback) { + return function (elem, propName, handler) { + var originProps = Object.getOwnPropertyDescriptor( + HTMLInputElement.prototype, + propName, + ); + + Object.defineProperty( + elem, + propName, + lay.extend({}, originProps, { + get: function () { + return ( + typeof this.getAttribute('lay-form-sync-' + propName) === 'string' + ); + }, + set: function (newValue) { + toggleAttribute.call(this, 'lay-form-sync-' + propName, newValue); + handler.call(this); + }, + }), + ); + }; + } + return function (elem, propName, handler) { + var originProps = Object.getOwnPropertyDescriptor( + HTMLInputElement.prototype, + propName, + ); + + Object.defineProperty( + elem, + propName, + lay.extend({}, originProps, { + get: function () { + return originProps.get.call(this); + }, + set: function (newValue) { + originProps.set.call(this, newValue); + handler.call(this); + }, + }), + ); + }; +})(); + +/** + * 主动触发验证 + * @param {(string|HTMLElement|JQuery)} elem - 要验证的区域表单元素 + * @return {boolean} 返回结果。若验证通过,返回 `true`, 否则返回 `false` + */ +Form.prototype.validate = function (elem) { + var that = this; + var intercept; // 拦截标识 + var options = that.config; // 获取全局配置项 + var verify = options.verify; // 验证规则 + var DANGER = 'lay-form-danger'; // 警示样式 + + elem = $(elem); + + // 节点不存在可视为 true + if (!elem[0]) return !0; + + // 若节点不存在特定属性,则查找容器内有待验证的子节点 + if (elem.attr('lay-verify') === undefined) { + // 若校验的是一个不带验证规则的容器,校验内部的 lay-verify 节点 + if (that.validate(elem.find('*[lay-verify]')) === false) { + return false; + } + } + + // 开始校验 + elem.each(function (_, item) { + var othis = $(this); + var verifyStr = othis.attr('lay-verify') || ''; + var vers = verifyStr.split('|'); + var verType = othis.attr('lay-vertype'); // 提示方式 + var value = othis.val(); + value = typeof value === 'string' ? value.trim() : value; + + othis.removeClass(DANGER); // 移除警示样式 + + // 遍历元素绑定的验证规则 + for (const thisVer of vers) { + var verst; // 校验结果 + var errorText = ''; // 错误提示文本 + var rule = verify[thisVer]; // 获取校验规则 + + // 匹配验证规则 + if (rule) { + verst = + typeof rule === 'function' + ? (errorText = rule(value, item)) + : !rule[0].test(value); // 兼容早期数组中的正则写法 + + // 是否属于美化替换后的表单元素 + var isForm2Elem = + item.tagName.toLowerCase() === 'select' || + /^(checkbox|radio)$/.test(item.type); + + errorText = errorText || rule[1]; + + // 获取自定义必填项提示文本 + if (thisVer === 'required') { + errorText = othis.attr('lay-reqtext') || errorText; + } + + // 若命中校验规则 + if (verst) { + // 提示层风格 + if (verType === 'tips') { + layer.tips( + errorText, + (function () { + if (!othis.closest('[lay-ignore]').length) { + if (isForm2Elem) { + return othis.next(); + } + } + return othis; + })(), + { tips: 1 }, + ); + } else if (verType === 'alert') { + layer.alert(errorText, { + title: i18n.$t('form.verifyErrorPromptTitle'), + shadeClose: true, + }); + } + // 若返回的为字符或数字,则自动弹出默认提示框;否则由 verify 方法中处理提示 + else if (/\b(string|number)\b/.test(typeof errorText)) { + layer.msg(errorText, { icon: 5, shift: 6 }); + } + + setTimeout(function () { + (isForm2Elem ? othis.next().find('input') : item).focus(); + }, 7); + + othis.addClass(DANGER); + intercept = true; + break; + } + } + } + + if (intercept) return false; + }); + + return !intercept; +}; + +// 提交表单并校验 +var submit = (Form.prototype.submit = function (filter, callback) { + var field = {}; // 字段集合 + var button = $(this); // 当前触发的按钮 + + // 表单域 lay-filter 属性值 + var layFilter = + typeof filter === 'string' ? filter : button.attr('lay-filter'); + + // 当前所在表单域 + var elem = this.getFormElem + ? this.getFormElem(layFilter) + : button.parents(ELEM).eq(0); + + // 获取需要校验的元素 + var verifyElem = elem.find('*[lay-verify]'); + + // 开始校验 + if (!form.validate(verifyElem)) return false; + + // 获取当前表单值 + field = form.getValue(null, elem); + + // 返回的参数 + var params = { + elem: this.getFormElem ? window.event && window.event.target : this, // 触发事件的对象 + form: this.getFormElem ? elem[0] : button.parents('form')[0], // 当前所在的 form 元素,如果存在的话 + field: field, // 当前表单数据 + }; + + // 回调 + typeof callback === 'function' && callback(params); + + // 事件 + return lay.event.call(this, MOD_NAME, 'submit(' + layFilter + ')', params); +}); + +function fuzzyMatchRegExp(keyword, caseSensitive) { + var wordMap = {}; + var regexPattern = ['^']; + var escapeRegExp = function (str) { + return str.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'); + }; + + if (!caseSensitive) keyword = keyword.toLowerCase(); + + var i; + + // 统计关键字中各字符出现次数 + var wordArr = keyword.trim().split(''); + for (i = 0; i < wordArr.length; i++) { + var c = wordArr[i]; + wordMap[c] = (wordMap[c] || 0) + 1; + } + + // 构建正则表达式模式 + for (c in wordMap) { + regexPattern.push('(?=.*'); + for (i = 0; i < wordMap[c]; i++) { + regexPattern.push(escapeRegExp(c)); + if (i !== wordMap[c] - 1) { + regexPattern.push('.*'); // 在字符之间添加任意字符匹配 + } + } + regexPattern.push(')'); + } + regexPattern.push('.*'); + + return new RegExp(regexPattern.join(''), !caseSensitive ? 'i' : undefined); +} + +// 引用自 https://github.com/msn0/mdn-polyfills/blob/master/src/Element.prototype.toggleAttribute/toggleattribute.js +function toggleAttribute(name, force) { + var forcePassed = arguments.length === 2; + var forceOn = !!force; + var forceOff = forcePassed && !force; + + if (this.getAttribute(name) !== null) { + if (forceOn) return true; + + this.removeAttribute(name); + return false; + } else { + if (forceOff) return false; + + this.setAttribute(name, ''); + return true; + } +} + +// 修改自 https://github.com/Tencent/tdesign-common/blob/53786c58752401e648cc45918f2a4dbb9e8cecfa/js/input-number/number.ts#L209 +var specialCode = ['-', '.', 'e', 'E', '+']; +function canInputNumber(number) { + if (number === '') return true; + // 数字最前方不允许出现连续的两个 0 + if (number.slice(0, 2) === '00') return false; + // 不能出现空格 + if (number.match(/\s/g)) return false; + // 只能出现一个点(.) + var tempMatched = number.match(/\./g); + if (tempMatched && tempMatched.length > 1) return false; + // 只能出现一个e(e) + tempMatched = number.match(/e/g); + if (tempMatched && tempMatched.length > 1) return false; + // 只能出现一个负号(-)或 一个正号(+),并且在第一个位置;但允许 3e+10 这种形式 + var tempNumber = number.slice(1); + tempMatched = tempNumber.match(/(\+|-)/g); + if (tempMatched && (!/e(\+|-)/i.test(tempNumber) || tempMatched.length > 1)) + return false; + // 允许输入数字字符 + var isNumber = !isNaN(Number(number)); + if (!isNumber && !(specialCode.indexOf(number.slice(-1)) !== -1)) + return false; + if (/e/i.test(number) && (!/\de/i.test(number) || /e\./.test(number))) + return false; + return true; +} + +var form = new Form(); +var $dom = $(document); +var $win = $(window); + +// 初始自动完成渲染 +lay.use(function () { + form.render(); +}); + +// 表单 reset 重置渲染 +$dom.on('reset', ELEM, function () { + var filter = $(this).attr('lay-filter'); + setTimeout(function () { + form.render(null, filter); + }, 50); +}); + +// 表单提交事件 +$dom.on('submit', ELEM, submit).on('click', '*[lay-submit]', submit); + +export { form }; diff --git a/src/components/laydate.js b/src/components/laydate.js new file mode 100644 index 000000000..74c2f0df4 --- /dev/null +++ b/src/components/laydate.js @@ -0,0 +1,3273 @@ +/** + * laydate + * 日期与时间组件 + */ + +import { lay } from '../core/lay.js'; +import { log } from '../core/logger.js'; +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; + +// 模块名 +var MOD_NAME = 'laydate'; +var MOD_ID = 'lay-' + MOD_NAME + '-id'; // 已渲染过的索引标记名 +var zhCN = 'zh-CN'; // 简体中文语言码 +var YearBeforeMonthLocale = [ + 'eu-ES', + 'ja-JP', + 'km-KH', + 'ko-KR', + 'pt-BR', + 'si-LK', + 'ms-MY', + 'ug-CN', + 'zh-CN', + 'zh-HK', + 'zh-TW', +]; // 年份在前的语言 + +function addSpaceBetweenChars(str) { + if (typeof str !== 'string' || str.length <= 1) { + return str; + } + + var result = ''; + for (var i = 0; i < str.length - 1; i++) { + var char = str[i]; + var nextChar = str[i + 1]; + result += char; + + // 判断当前字符和下一个字符的类型 + var isCharDigit = isDigit(char); + var isNextCharDigit = isDigit(nextChar); + + // 在数字和非数字(非空格)之间添加空格 + if ( + (isCharDigit && !isNextCharDigit && nextChar !== ' ') || // 数字 → 非数字(非空格) + (char !== ' ' && !isCharDigit && isNextCharDigit) // 非空格非数字 → 数字 + ) { + result += ' '; + } + } + result += str[str.length - 1]; // 添加最后一个字符 + return result; +} + +function isDigit(char) { + var code = char.charCodeAt(0); + return code >= 48 && code <= 57; // '0' 到 '9' 的 ASCII 码范围 +} + +// 对象合并时,让数组覆盖,而非合并 +function overwriteArray(objValue, srcValue) { + // 数组覆盖而非合并 + if (Array.isArray(objValue) && Array.isArray(srcValue)) { + return srcValue; + } +} + +// 外部调用 +var laydate = { + config: { + weekStart: 0, // 默认周日一周的开始 + }, // 全局配置项 + + // 设置全局项 + set: function (options) { + var that = this; + that.config = lay.extend({}, that.config, options, overwriteArray); + return that; + }, +}; + +// 操作当前实例 +var thisModule = function () { + var that = this; + var options = that.config; + var id = options.id; + + thisModule.that[id] = that; // 记录当前实例对象 + + return (that.inst = { + // 提示框 + hint: function (content) { + that.hint.call(that, content); + }, + // 重载实例 + reload: function (options) { + that.reload.call(that, options); + }, + config: that.config, + }); +}; + +// 字符常量 +var ELEM = '.lay-laydate'; +var THIS = 'lay-this'; +// var SHOW = 'lay-show'; +// var HIDE = 'lay-hide'; +var DISABLED = 'laydate-disabled'; +var LIMIT_YEAR = [100, 200000]; + +var ELEM_STATIC = 'lay-laydate-static'; +var ELEM_LIST = 'lay-laydate-list'; +var ELEM_SELECTED = 'laydate-selected'; +var ELEM_HINT = 'lay-laydate-hint'; +var ELEM_DAY_NOW = 'laydate-day-now'; +var ELEM_PREV = 'laydate-day-prev'; +var ELEM_NEXT = 'laydate-day-next'; +var ELEM_FOOTER = 'lay-laydate-footer'; +var ELEM_SHORTCUT = 'lay-laydate-shortcut'; +var ELEM_NOW = '.laydate-btns-now'; +var ELEM_CONFIRM = '.laydate-btns-confirm'; +var ELEM_TIME_TEXT = 'laydate-time-text'; +var ELEM_TIME_BTN = 'laydate-btns-time'; +var ELEM_PREVIEW = 'lay-laydate-preview'; +var ELEM_MAIN = 'lay-laydate-main'; +var ELEM_SHADE = 'lay-laydate-shade'; + +// 组件构造器 +var Class = function (options) { + var that = this; + that.index = laydate.index = lay.autoIncrementer('laydate'); + that.config = lay.extend( + {}, + that.config, + laydate.config, + options, + overwriteArray, + ); + + // 若 elem 非唯一,则拆分为多个实例 + var elem = $(options.elem || that.config.elem); + if (elem.length > 1) { + elem.each(function () { + laydate.render( + lay.extend({}, that.config, { + elem: this, + }), + overwriteArray, + ); + }); + return that; + } + + // 初始化属性 + options = lay.extend(that.config, lay.options(elem[0]), overwriteArray); // 继承节点上的属性 + + // 更新 i18n 消息对象 + that.i18nMessages = that.getI18nMessages(); + + // 处理日期面板顶部年月顺序 + // 这是一个变通的方法,因为 i18nMessages.monthBeforeYear 不存在 + if (typeof that.i18nMessages.monthBeforeYear !== 'boolean') { + if (!window.Intl) { + that.i18nMessages.monthBeforeYear = !( + YearBeforeMonthLocale.indexOf(options.lang) > -1 + ); + } else { + var formatter = new Intl.DateTimeFormat(options.lang, { + year: 'numeric', + month: 'short', + }); + var parts = formatter.formatToParts(new Date(1970, 0)); + var order = []; + parts.map(function (part) { + if (part.type === 'year' || part.type === 'month') { + order.push(part.type); + } + }); + that.i18nMessages.monthBeforeYear = order[0] === 'month'; + } + } + + // 若重复执行 render,则视为 reload 处理 + if (elem[0] && elem.attr(MOD_ID)) { + var newThat = thisModule.getThis(elem.attr(MOD_ID)); + if (!newThat) return; + return newThat.reload(options); + } + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + options.id = 'id' in options ? options.id : elem.attr('id') || that.index; + + // 自增索引 + options.index = that.index; + + // 初始化 + that.init(); +}; + +// 日期格式字符 +var dateType = 'yyyy|y|MM|M|dd|d|HH|H|mm|m|ss|s'; + +// 将日期格式字符转换为数组 +thisModule.formatArr = function (format) { + return (format || '').match(new RegExp(dateType + '|.', 'g')) || []; +}; + +/* + 组件操作 +*/ + +// 是否闰年 +Class.isLeapYear = function (year) { + return (year % 4 === 0 && year % 100 !== 0) || year % 400 === 0; +}; + +// 默认配置 +Class.prototype.config = { + type: 'date', // 控件类型,支持:year/month/date/time/datetime + range: false, // 是否开启范围选择,即双控件 + format: 'yyyy-MM-dd', // 默认日期格式 + value: null, // 默认日期,支持传入new Date(),或者符合format参数设定的日期格式字符 + isInitValue: true, // 用于控制是否自动向元素填充初始值(需配合 value 参数使用) + min: '1900-1-1', // 有效最小日期,年月日必须用“-”分割,时分秒必须用“:”分割。注意:它并不是遵循 format 设定的格式。 + max: '2099-12-31', // 有效最大日期,同上 + trigger: 'click', // 呼出控件的事件 + show: false, // 是否直接显示,如果设置 true,则默认直接显示控件 + showBottom: true, // 是否显示底部栏 + isPreview: true, // 是否显示值预览 + btns: ['clear', 'now', 'confirm'], // 右下角显示的按钮,会按照数组顺序排列 + // 为实现 lang 选项就近生效,去除此处的默认值,$t 设置了英文回退值 + lang: '', // 语言,只支持 cn/en,即中文和英文 + theme: 'default', // 主题 + position: null, // 控件定位方式定位, 默认absolute,支持:fixed/absolute/static + calendar: false, // 是否开启公历重要节日,仅支持中文版 + mark: {}, // 日期备注,如重要事件或活动标记 + holidays: null, // 标注法定节假日或补假上班 + zIndex: null, // 控件层叠顺序 + done: null, // 控件选择完毕后的回调,点击清空/现在/确定也均会触发 + change: null, // 日期时间改变后的回调 + autoConfirm: true, // 是否自动确认(日期|年份|月份选择器非range下是否自动确认) + shade: 0, +}; + +Class.prototype.getI18nMessages = function () { + var that = this; + var options = that.config; + var locale = i18n.config.locale; + + // 纠正旧版「简体中文」语言码 + if (options.lang === 'cn') { + options.lang = zhCN; + } else if (!options.lang) { + options.lang = i18n.config.locale; + } + locale = options.lang; + + return { + months: i18n.$t('laydate.months', null, { + locale: locale, + default: [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], + }), + weeks: i18n.$t('laydate.weeks', null, { + locale: locale, + default: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + }), + time: i18n.$t('laydate.time', null, { + locale: locale, + default: ['Hour', 'Minute', 'Second'], + }), + literal: { + year: i18n.$t('laydate.literal.year', null, { + locale: locale, + default: '', + }), + }, + monthBeforeYear: i18n.$t('laydate.monthBeforeYear', null, { + locale: locale, + default: null, + }), + selectDate: i18n.$t('laydate.selectDate', null, { + locale: locale, + default: 'Select Date', + }), + selectTime: i18n.$t('laydate.selectTime', null, { + locale: locale, + default: 'Select Time', + }), + startTime: i18n.$t('laydate.startTime', null, { + locale: locale, + default: 'Start Time', + }), + endTime: i18n.$t('laydate.endTime', null, { + locale: locale, + default: 'End Time', + }), + tools: { + confirm: i18n.$t('laydate.tools.confirm', null, { + locale: locale, + default: 'Confirm', + }), + clear: i18n.$t('laydate.tools.clear', null, { + locale: locale, + default: 'Clear', + }), + now: i18n.$t('laydate.tools.now', null, { + locale: locale, + default: 'Now', + }), + reset: i18n.$t('laydate.tools.reset', null, { + locale: locale, + default: 'Reset', + }), + }, + rangeOrderPrompt: i18n.$t('laydate.rangeOrderPrompt', null, { + locale: locale, + default: 'End time cannot be less than start Time\nPlease re-select', + }), + invalidDatePrompt: i18n.$t('laydate.invalidDatePrompt', null, { + locale: locale, + default: 'Invalid date\n', + }), + formatErrorPrompt: function (format) { + return i18n.$t( + 'laydate.formatErrorPrompt', + { format: format }, + { + locale: locale, + default: + 'Date format is invalid\nMust follow the format:\n{format}\n', + }, + ); + }, + autoResetPrompt: i18n.$t('laydate.autoResetPrompt', null, { + locale: locale, + default: 'It has been reset', + }), + preview: i18n.$t('laydate.preview', null, { + locale: locale, + default: 'The selected result', + }), + }; +}; + +// 仅简体中文生效,不做国际化 +Class.prototype.markerOfChineseFestivals = { + '0-1-1': '元旦', + '0-2-14': '情人', + '0-3-8': '妇女', + '0-3-12': '植树', + '0-4-1': '愚人', + '0-5-1': '劳动', + '0-5-4': '青年', + '0-6-1': '儿童', + '0-9-10': '教师', + '0-10-1': '国庆', + '0-12-25': '圣诞', +}; + +// 重载实例 +Class.prototype.reload = function (options) { + var that = this; + that.config = lay.extend({}, that.config, options, overwriteArray); + that.init(); +}; + +//初始准备 +Class.prototype.init = function () { + var that = this, + options = that.config, + isStatic = options.position === 'static', + format = { + year: 'yyyy', + month: 'yyyy-MM', + date: 'yyyy-MM-dd', + time: 'HH:mm:ss', + datetime: 'yyyy-MM-dd HH:mm:ss', + }; + + options.elem = $(options.elem); + options.eventElem = $(options.eventElem); + + if (!options.elem[0]) return; + + lay.type(options.theme) !== 'array' && (options.theme = [options.theme]); + // 设置了全面版模式 + if (options.fullPanel) { + if (options.type !== 'datetime' || options.range) { + // 目前只支持datetime的全面版 + delete options.fullPanel; + } + } + + //日期范围分隔符 + that.rangeStr = options.range + ? typeof options.range === 'string' + ? options.range + : '-' + : ''; + + //日期范围的日历面板是否联动 + that.rangeLinked = !!( + options.range && + options.rangeLinked && + (options.type === 'date' || options.type === 'datetime') + ); + + //切换日历联动方式 + that.autoCalendarModel = function () { + var state = that.rangeLinked; + that.rangeLinked = + options.range && + (options.type === 'date' || options.type === 'datetime') && + (!that.startDate || + !that.endDate || + (that.startDate && + that.endDate && + that.startDate.year === that.endDate.year && + that.startDate.month === that.endDate.month)); + $(that.elem)[that.rangeLinked ? 'addClass' : 'removeClass']( + 'lay-laydate-linkage', + ); + return that.rangeLinked != state; // 返回发生了变化 + }; + + //是否自动切换 + that.autoCalendarModel.auto = + that.rangeLinked && options.rangeLinked === 'auto'; + + //若 range 参数为数组,则表示为开始日期和结束日期的 input 对象 + if (lay.type(options.range) === 'array') { + that.rangeElem = [$(options.range[0]), $(options.range[1])]; + } + + //若 type 设置非法,则初始化为 date 类型 + if (!format[options.type]) { + window.console && + console.error && + console.error( + "laydate type error:'" + options.type + "' is not supported", + ); + options.type = 'date'; + } + + //根据不同 type,初始化默认 format + if (options.format === format.date) { + options.format = format[options.type] || format.date; + } + + //将日期格式转化成数组 + that.format = thisModule.formatArr(options.format); + + // 设置了一周的开始是周几,此处做一个控制 + if (options.weekStart) { + if (!/^[0-6]$/.test(options.weekStart)) { + var lang = that.i18nMessages; + options.weekStart = lang.weeks.indexOf(options.weekStart); + if (options.weekStart === -1) options.weekStart = 0; + } + } + + //生成正则表达式 + that.EXP_IF = ''; + that.EXP_SPLIT = ''; + that.format.forEach(function (item, i) { + var EXP = new RegExp(dateType).test(item) + ? '\\d{' + + (function () { + if ( + new RegExp(dateType).test( + that.format[i === 0 ? i + 1 : i - 1] || '', + ) + ) { + if (/^yyyy|y$/.test(item)) return 4; + return item.length; + } + if (/^yyyy$/.test(item)) return '1,4'; + if (/^y$/.test(item)) return '1,308'; + return '1,2'; + })() + + '}' + : '\\' + item; + that.EXP_IF = that.EXP_IF + EXP; + that.EXP_SPLIT = that.EXP_SPLIT + '(' + EXP + ')'; + }); + //验证日期格式正则 + that.EXP_IF_ONE = new RegExp('^' + that.EXP_IF + '$'); //验证单个日期格式 + that.EXP_IF = new RegExp( + '^' + + (options.range + ? that.EXP_IF + '\\s\\' + that.rangeStr + '\\s' + that.EXP_IF + : that.EXP_IF) + + '$', + ); + that.EXP_SPLIT = new RegExp('^' + that.EXP_SPLIT + '$', ''); + + //如果不是 input|textarea 元素,则默认采用 click 事件 + if (!that.isInput(options.elem[0])) { + if (options.trigger === 'focus') { + options.trigger = 'click'; + } + } + + // 设置唯一 KEY + options.elem.attr('lay-key', that.index); + options.eventElem.attr('lay-key', that.index); + options.elem.attr(MOD_ID, options.id); // 渲染过的标记 + + //获取限制内日期 + ['min', 'max'].forEach(function (item, i) { + var ymd = []; + var hms = []; + if (typeof options[item] === 'number') { + //如果为数字 + var day = options[item], + tDate = new Date(), + time = that + .newDate({ + //今天的最大毫秒数 + year: tDate.getFullYear(), + month: tDate.getMonth(), + date: tDate.getDate(), + hours: i ? 23 : 0, + minutes: i ? 59 : 0, + seconds: i ? 59 : 0, + }) + .getTime(), + STAMP = 86400000, //代表一天的毫秒数 + thisDate = new Date( + day + ? day < STAMP + ? time + day * STAMP + : day //如果数字小于一天的毫秒数,则数字为天数,否则为毫秒数 + : time, + ); + ymd = [ + thisDate.getFullYear(), + thisDate.getMonth() + 1, + thisDate.getDate(), + ]; + hms = [thisDate.getHours(), thisDate.getMinutes(), thisDate.getSeconds()]; + } else if (typeof options[item] === 'string') { + ymd = (options[item].match(/\d+-\d+-\d+/) || [''])[0].split('-'); + hms = (options[item].match(/\d+:\d+:\d+/) || [''])[0].split(':'); + } else if (typeof options[item] === 'object') { + return options[item]; + } + options[item] = { + year: ymd[0] | 0 || new Date().getFullYear(), + month: ymd[1] ? (ymd[1] | 0) - 1 : new Date().getMonth(), + date: ymd[2] | 0 || new Date().getDate(), + hours: hms[0] | 0, + minutes: hms[1] | 0, + seconds: hms[2] | 0, + }; + }); + + that.elemID = 'lay-laydate' + options.elem.attr('lay-key'); + + if (options.show || isStatic) that.render(); + isStatic || that.events(); + + // 重定义 input 元素的 get set + if (typeof options.formatToDisplay === 'function') { + if (that.isInput(options.elem[0])) { + that.formatToDisplay(options.elem[0], options.formatToDisplay); + } else { + var rangeElem = that.rangeElem; + if (rangeElem) { + that.formatToDisplay(rangeElem[0][0], options.formatToDisplay); + that.formatToDisplay(rangeElem[1][0], options.formatToDisplay); + } + } + } + + //默认赋值 + if (options.value && options.isInitValue) { + if (lay.type(options.value) === 'date') { + that.setValue(that.parse(0, that.systemDate(options.value))); + } else { + that.setValue(options.value); + } + } +}; + +//控件主体渲染 +Class.prototype.render = function () { + var that = this, + options = that.config, + lang = that.i18nMessages, + isStatic = options.position === 'static', + //主面板 + elem = (that.elem = lay.elem('div', { + id: that.elemID, + class: [ + 'lay-laydate', + options.range ? ' lay-laydate-range' : '', + that.rangeLinked ? ' lay-laydate-linkage' : '', + isStatic ? ' ' + ELEM_STATIC : '', + options.fullPanel ? ' laydate-theme-fullpanel' : '', // 全面版 + // ,options.theme && options.theme !== 'default' && !/^#/.test(options.theme) ? (' laydate-theme-' + options.theme) : '' + (function () { + var themeStr = ''; + options.theme.forEach(function (theme) { + if (theme !== 'default' && !/^#/.test(theme)) { + themeStr += ' laydate-theme-' + theme; + } + }); + return themeStr; + })(), + ].join(''), + })), + //主区域 + elemMain = (that.elemMain = []), + elemHeader = (that.elemHeader = []), + elemCont = (that.elemCont = []), + elemTable = (that.table = []), + //底部区域 + divFooter = (that.footer = lay.elem('div', { + class: ELEM_FOOTER, + })), + //快捷栏 + divShortcut = (that.shortcut = lay.elem('ul', { + class: ELEM_SHORTCUT, + })); + + if (options.zIndex) elem.style.zIndex = options.zIndex; + + //单双日历区域 + for (var i = 0; i < 2; i++) { + if (!options.range && i > 0) { + break; + } + + //头部区域 + var divHeader = lay.elem('div', { + class: 'lay-laydate-header', + }), + //左右切换 + headerChild = [ + (function () { + //上一年 + var elem = lay.elem('i', { + class: 'lay-icon laydate-icon laydate-prev-y', + }); + elem.innerHTML = ''; + return elem; + })(), + (function () { + //上一月 + var elem = lay.elem('i', { + class: 'lay-icon laydate-icon laydate-prev-m', + }); + elem.innerHTML = ''; + return elem; + })(), + (function () { + //年月选择 + var elem = lay.elem('div', { + class: 'laydate-set-ym', + }); + elem.appendChild(lay.elem('span')); + elem.appendChild(lay.elem('span')); + return elem; + })(), + (function () { + //下一月 + var elem = lay.elem('i', { + class: 'lay-icon laydate-icon laydate-next-m', + }); + elem.innerHTML = ''; + return elem; + })(), + (function () { + //下一年 + var elem = lay.elem('i', { + class: 'lay-icon laydate-icon laydate-next-y', + }); + elem.innerHTML = ''; + return elem; + })(), + ], + //日历内容区域 + divContent = lay.elem('div', { + class: 'lay-laydate-content', + }), + table = lay.elem('table'), + thead = lay.elem('thead'), + theadTr = lay.elem('tr'); + + //生成年月选择 + headerChild.forEach(function (item) { + divHeader.appendChild(item); + }); + + //生成表格 + thead.appendChild(theadTr); + for (var rowIndex = 0; rowIndex < 6; rowIndex++) { + //表体 + var tr = table.insertRow(0); + for (var j = 0; j < 7; j++) { + if (rowIndex === 0) { + var th = lay.elem('th'); + th.innerHTML = lang.weeks[(j + options.weekStart) % 7]; + theadTr.appendChild(th); + } + tr.insertCell(j); + } + } + table.insertBefore(thead, table.children[0]); //表头 + divContent.appendChild(table); + + elemMain[i] = lay.elem('div', { + class: ELEM_MAIN + ' laydate-main-list-' + i, + }); + + elemMain[i].appendChild(divHeader); + elemMain[i].appendChild(divContent); + + elemHeader.push(headerChild); + elemCont.push(divContent); + elemTable.push(table); + } + + //生成底部栏 + $(divFooter).html( + (function () { + var html = [], + btns = []; + if (options.type === 'datetime') { + html.push( + '' + + lang.selectTime + + '', + ); + } + if ( + !(!options.range && options.type === 'datetime') || + options.fullPanel + ) { + html.push( + '', + ); + } + + options.btns.forEach(function (item) { + var title = lang.tools[item] || 'btn'; + if (options.range && item === 'now') return; + if (isStatic && item === 'clear') { + title = lang.tools.reset; + } + btns.push( + '' + + title + + '', + ); + }); + html.push(''); + return html.join(''); + })(), + ); + + // 生成快捷键栏 + if (options.shortcuts) { + elem.appendChild(divShortcut); + $(divShortcut) + .html( + (function () { + var shortcutBtns = []; + options.shortcuts.forEach(function (item, i) { + shortcutBtns.push( + '
                            • ' + item.text + '
                            • ', + ); + }); + return shortcutBtns.join(''); + })(), + ) + .find('li') + .on('click', function () { + var btnSetting = options.shortcuts[this.dataset['index']] || {}; + var value = + (typeof btnSetting.value === 'function' + ? btnSetting.value() + : btnSetting.value) || []; + if (!lay.isArray(value)) { + value = [value]; + } + var type = options.type; + value.forEach(function (item, i) { + var dateTime = [options.dateTime, that.endDate][i]; + if (type === 'time' && lay.type(item) !== 'date') { + if (that.EXP_IF.test(item)) { + item = (item.match(that.EXP_SPLIT) || []).slice(1); + lay.extend(dateTime, { + hours: item[0] | 0, + minutes: item[2] | 0, + seconds: item[4] | 0, + }); + } + } else { + lay.extend( + dateTime, + that.systemDate( + lay.type(item) === 'date' ? item : new Date(item), + ), + ); + } + + if (type === 'time' || type === 'datetime') { + that[['startTime', 'endTime'][i]] = { + hours: dateTime.hours, + minutes: dateTime.minutes, + seconds: dateTime.seconds, + }; + } + if (i === 0) { + // 第一个值作为startDate + that.startDate = lay.extend({}, dateTime); + } else { + that.endState = true; + } + if (type === 'year' || type === 'month' || type === 'time') { + that.listYM[i] = [dateTime.year, dateTime.month + 1]; + } else if (i) { + that.autoCalendarModel.auto && that.autoCalendarModel(); + } + }); + that.checkDate('limit').calendar(null, null, 'init'); + + var timeBtn = $(that.footer) + .find('.' + ELEM_TIME_BTN) + .removeClass(DISABLED); + timeBtn && timeBtn.attr('lay-type') === 'date' && timeBtn[0].click(); + that.done(null, 'change'); + + $(this).addClass(THIS); + + // 自动确认 + if (options.position !== 'static') { + that.setValue(that.parse()).done().remove(); + } + /* + if (options.position !== 'static' && !options.range && options.autoConfirm) { + if (type === 'date') { + that.choose($(elem).find('td.lay-this')) + } else if (type === 'year' || type === 'month') { + if($(elemMain[0]).find('.' + ELEM_MAIN + ' li.' + THIS + ':not(.laydate-disabled)')[0]) { + that.setValue(that.parse()).done().remove(); + } + } + } + */ + }); + } + + //插入到主区域 + elemMain.forEach(function (main) { + elem.appendChild(main); + }); + options.showBottom && elem.appendChild(divFooter); + + // 生成自定义主题 + var style = lay.elem('style'); + var styleText = []; + var colorTheme; + var isPrimaryColor = true; + options.theme.forEach(function (theme) { + // 主色 + if (isPrimaryColor && /^#/.test(theme)) { + colorTheme = true; + isPrimaryColor = false; + styleText.push( + [ + '#{{id}} .lay-laydate-header{background-color:{{theme}};}', + '#{{id}} li.lay-this,#{{id}} td.lay-this>div{background-color:{{theme}} !important;}', + options.theme.indexOf('circle') !== -1 + ? '' + : '#{{id}} .lay-this{background-color:{{theme}} !important;}', + '#{{id}} .laydate-day-now{color:{{theme}} !important;}', + '#{{id}} .laydate-day-now:after{border-color:{{theme}} !important;}', + ] + .join('') + .replace(/{{id}}/g, that.elemID) + .replace(/{{theme}}/g, theme), + ); + return; + } + // 第二个自定义颜色作为辅色 + if (!isPrimaryColor && /^#/.test(theme)) { + styleText.push( + [ + '#{{id}} .laydate-selected>div{background-color:{{theme}} !important;}', + '#{{id}} .laydate-selected:hover>div{background-color:{{theme}} !important;}', + ] + .join('') + .replace(/{{id}}/g, that.elemID) + .replace(/{{theme}}/g, theme), + ); + } + }); + //快捷栏样式 + if (options.shortcuts && options.range) { + styleText.push( + '#{{id}}.lay-laydate-range{width: 628px;}'.replace( + /{{id}}/g, + that.elemID, + ), + ); + } + if (styleText.length) { + styleText = styleText.join(''); + style.innerHTML = styleText; + + colorTheme && $(elem).addClass('laydate-theme-molv'); + elem.appendChild(style); + } + + //移除上一个控件 + that.remove(Class.thisElemDate); + + //记录当前执行的实例索引 + laydate.thisId = options.id; + + //如果是静态定位,则插入到指定的容器中,否则,插入到body + isStatic + ? options.elem.append(elem) + : (document.body.appendChild(elem), that.position()); //定位 + + var shade = options.shade + ? '
                              ' + : ''; + elem.insertAdjacentHTML('beforebegin', shade); + + that.checkDate().calendar(null, 0, 'init'); //初始校验 + that.changeEvent(); //日期切换 + + Class.thisElemDate = that.elemID; + + that.renderAdditional(); + typeof options.ready === 'function' && + options.ready( + lay.extend({}, options.dateTime, { + month: options.dateTime.month + 1, + }), + ); + + that.preview(); +}; + +//控件移除 +Class.prototype.remove = function (prev) { + var that = this, + options = that.config, + elem = $('#' + (prev || that.elemID)); + if (!elem[0]) return that; + + if (!elem.hasClass(ELEM_STATIC)) { + that.checkDate(function () { + elem.remove(); + //delete options.dateTime; + delete that.startDate; + delete that.endDate; + delete that.endState; + delete that.startTime; + delete that.endTime; + delete laydate.thisId; + typeof options.close === 'function' && options.close(that); + }); + } + $('.' + ELEM_SHADE).remove(); + return that; +}; + +//定位算法 +Class.prototype.position = function () { + var that = this, + options = that.config; + lay.position(options.elem[0], that.elem, { + position: options.position, + }); + return that; +}; + +// 提示 +Class.prototype.hint = function (opts) { + var that = this; + // var options = that.config; + var div = lay.elem('div', { + class: ELEM_HINT, + }); + + if (!that.elem) return; + + // 兼容旧版参数 + if (typeof opts === 'object') { + opts = opts || {}; + } else { + opts = { + content: opts, + }; + } + + div.innerHTML = opts.content || ''; + $(that.elem) + .find('.' + ELEM_HINT) + .remove(); + that.elem.appendChild(div); + + clearTimeout(that.hinTimer); + that.hinTimer = setTimeout( + function () { + $(that.elem) + .find('.' + ELEM_HINT) + .remove(); + }, + 'ms' in opts ? opts.ms : 3000, + ); +}; + +//获取递增/减后的年月 +Class.prototype.getAsYM = function (Y, M, type) { + type ? M-- : M++; + if (M < 0) { + M = 11; + Y--; + } + if (M > 11) { + M = 0; + Y++; + } + return [Y, M]; +}; + +//系统日期 +Class.prototype.systemDate = function (newDate) { + var thisDate = newDate || new Date(); + return { + year: thisDate.getFullYear(), //年 + month: thisDate.getMonth(), //月 + date: thisDate.getDate(), //日 + hours: newDate ? newDate.getHours() : 0, //时 + minutes: newDate ? newDate.getMinutes() : 0, //分 + seconds: newDate ? newDate.getSeconds() : 0, //秒 + }; +}; + +//日期校验 +Class.prototype.checkDate = function (fn) { + var that = this, + // thisDate = new Date(), + options = that.config, + lang = that.i18nMessages, + dateTime = (options.dateTime = options.dateTime || that.systemDate()), + thisMaxDate, + error, + elem = options.elem[0], + // valType = that.isInput(elem) ? 'val' : 'html', + value = (function () { + //如果传入了开始和结束日期的 input 对象,则将其拼接为日期范围字符 + if (that.rangeElem) { + var vals = [that.rangeElem[0].val(), that.rangeElem[1].val()]; + + if (vals[0] && vals[1]) { + return vals.join(' ' + that.rangeStr + ' '); + } + } + return that.isInput(elem) + ? elem.value + : options.position === 'static' + ? '' + : $(elem).attr('lay-date'); + })(), + //校验日期有效数字 + checkValid = function (dateTime) { + if (!dateTime) { + return; + } + if (dateTime.year > LIMIT_YEAR[1]) + ((dateTime.year = LIMIT_YEAR[1]), (error = true)); //不能超过20万年 + if (dateTime.month > 11) ((dateTime.month = 11), (error = true)); + if (dateTime.seconds > 59) + ((dateTime.seconds = 0), dateTime.minutes++, (error = true)); + if (dateTime.minutes > 59) + ((dateTime.minutes = 0), dateTime.hours++, (error = true)); + if (dateTime.hours > 23) ((dateTime.hours = 0), (error = true)); + + //计算当前月的最后一天 + thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); + if (dateTime.date > thisMaxDate) + ((dateTime.date = thisMaxDate), (error = true)); + }, + //获得初始化日期值 + initDate = function (dateTime, value, index) { + var startEnd = ['startTime', 'endTime']; + value = (value.match(that.EXP_SPLIT) || []).slice(1); + index = index || 0; + + if (options.range) { + that[startEnd[index]] = that[startEnd[index]] || {}; + } + that.format.forEach(function (item, i) { + var thisv = parseFloat(value[i]); + if (value[i].length < item.length) error = true; + if (/yyyy|y/.test(item)) { + //年 + if (thisv < LIMIT_YEAR[0]) ((thisv = LIMIT_YEAR[0]), (error = true)); //年不能低于100年 + dateTime.year = thisv; + } else if (/MM|M/.test(item)) { + //月 + if (thisv < 1) ((thisv = 1), (error = true)); + dateTime.month = thisv - 1; + } else if (/dd|d/.test(item)) { + //日 + if (thisv < 1) ((thisv = 1), (error = true)); + dateTime.date = thisv; + } else if (/HH|H/.test(item)) { + //时 + if (thisv < 0) ((thisv = 0), (error = true)); + if (thisv > 23) ((thisv = 23), (error = true)); + dateTime.hours = thisv; + options.range && (that[startEnd[index]].hours = thisv); + } else if (/mm|m/.test(item)) { + //分 + if (thisv < 0) ((thisv = 0), (error = true)); + if (thisv > 59) ((thisv = 59), (error = true)); + dateTime.minutes = thisv; + options.range && (that[startEnd[index]].minutes = thisv); + } else if (/ss|s/.test(item)) { + //秒 + if (thisv < 0) ((thisv = 0), (error = true)); + if (thisv > 59) ((thisv = 59), (error = true)); + dateTime.seconds = thisv; + options.range && (that[startEnd[index]].seconds = thisv); + } + }); + checkValid(dateTime); + }; + + if (fn === 'limit') { + if (options.range) { + checkValid(that.rangeLinked ? that.startDate : dateTime); // 校验开始时间 + that.endDate && checkValid(that.endDate); // 校验结束时间 + } else { + checkValid(dateTime); + } + return that; + } + + value = value || options.value; + if (typeof value === 'string') { + value = value.replace(/\s+/g, ' ').replace(/^\s|\s$/g, ''); + } + + //如果开启范围,则计算结束日期 + var getEndDate = function () { + if (options.range) { + that.endDate = + that.endDate || + lay.extend( + {}, + options.dateTime, + (function () { + var obj = {}, + dateTime = options.dateTime, + EYM = that.getAsYM(dateTime.year, dateTime.month); + + //初始右侧面板的年月 + if (options.type === 'year') { + obj.year = dateTime.year + 1; + } else if (options.type !== 'time') { + obj.year = EYM[0]; + obj.month = EYM[1]; + } + + //初始右侧面板的时间 + if (options.type === 'datetime' || options.type === 'time') { + obj.hours = 23; + obj.minutes = obj.seconds = 59; + } + + return obj; + })(), + ); + } + }; + getEndDate(); + + if (typeof value === 'string' && value) { + if (that.EXP_IF.test(value)) { + //校验日期格式 + if (options.range) { + value = value.split(' ' + that.rangeStr + ' '); + [options.dateTime, that.endDate].forEach(function (item, i) { + initDate(item, value[i], i); + }); + } else { + initDate(dateTime, value); + } + } else { + //格式不合法 + that.hint( + lang.formatErrorPrompt( + options.range + ? options.format + ' ' + that.rangeStr + ' ' + options.format + : options.format, + ) + lang.autoResetPrompt, + ); + error = true; + } + } else if (value && lay.type(value) === 'date') { + //若值为日期对象 + options.dateTime = that.systemDate(value); + } else { + //重置开始日期 + options.dateTime = that.systemDate(); + delete that.startTime; + + //重置结束日期 + delete that.endDate; //删除原有的结束日期 + getEndDate(); //并重新获得新的结束日期 + delete that.endTime; + } + + //从日期范围表单中获取初始值 + (function () { + if (that.rangeElem) { + var vals = [that.rangeElem[0].val(), that.rangeElem[1].val()], + arrDate = [options.dateTime, that.endDate]; + vals.forEach(function (_v, _i) { + if (that.EXP_IF_ONE.test(_v)) { + //校验日期格式 + initDate(arrDate[_i], _v, _i); + } + }); + } + })(); + + // 校验日期有效数字 + checkValid(dateTime); + if (options.range) checkValid(that.endDate); + + // 如果初始值格式错误,则纠正初始值 + if (error && value) { + that.setValue( + options.range ? (that.endDate ? that.parse() : '') : that.parse(), + ); + } + + //如果当前日期不在设定的最大小日期区间,则自动纠正在可选区域 + //校验主面板是否在可选日期区间 + var minMaxError; + if (that.getDateTime(dateTime) > that.getDateTime(options.max)) { + //若超出最大日期 + dateTime = options.dateTime = lay.extend({}, options.max); + minMaxError = true; + } else if (that.getDateTime(dateTime) < that.getDateTime(options.min)) { + //若少于最小日期 + dateTime = options.dateTime = lay.extend({}, options.min); + minMaxError = true; + } + + //校验右侧面板是否在可选日期区间 + if (options.range) { + if ( + that.getDateTime(that.endDate) < that.getDateTime(options.min) || + that.getDateTime(that.endDate) > that.getDateTime(options.max) + ) { + that.endDate = lay.extend({}, options.max); + minMaxError = true; + } + // 有时间范围的情况下初始化startTime和endTime + that.startTime = { + hours: options.dateTime.hours, + minutes: options.dateTime.minutes, + seconds: options.dateTime.seconds, + }; + that.endTime = { + hours: that.endDate.hours, + minutes: that.endDate.minutes, + seconds: that.endDate.seconds, + }; + // 如果是年月范围,将对应的日期统一成当月的1日进行比较,避免出现同一个月但是开始日期大于结束日期的情况 + if (options.type === 'month') { + options.dateTime.date = 1; + that.endDate.date = 1; + } + } + + // 初始值不在最大最小范围内 + if (minMaxError && value) { + that.setValue(that.parse()); + that.hint('value ' + lang.invalidDatePrompt + lang.autoResetPrompt); + } + + // 初始赋值 startDate,endState + that.startDate = + that.startDate || (value && lay.extend({}, options.dateTime)); // 有默认值才初始化startDate + that.autoCalendarModel.auto && that.autoCalendarModel(); + that.endState = + !options.range || !that.rangeLinked || !!(that.startDate && that.endDate); // 初始化选中范围状态 + + fn && fn(); + return that; +}; + +/** + * 渲染备注 + * @param {JQuery} tdElem td 元素 + * @param {[number, number, number]} YMD 年月日 + * @param {object | string} markers 备注信息 + */ +Class.prototype.markRender = function (tdElem, YMD, markers) { + var markText; + + if (typeof markers === 'object') { + Object.entries(markers || {}).forEach(function ([key, title]) { + var keys = key.split('-'); + if ( + (keys[0] == YMD[0] || keys[0] == 0) && //每年的每月 + (keys[1] == YMD[1] || keys[1] == 0) && //每月的每日 + keys[2] == YMD[2] + ) { + //特定日 + markText = title || YMD[2]; + } + }); + } else if (typeof markers === 'string') { + markText = markers || YMD[2]; + } + + markText && + tdElem + .find('div') + .html('' + markText + ''); +}; + +/** + * 公历重要日期与自定义备注 + * @param {JQuery} td + * @param {[number, number, number]} YMD + * @returns Class + */ +Class.prototype.mark = function (td, YMD) { + var that = this; + var options = that.config; + + var render = function (markers) { + that.markRender(td, YMD, markers); + }; + + // chineseFestivals 仅简体中文生效 + if (options.calendar) { + if (options.lang === zhCN) { + render(that.markerOfChineseFestivals); + } + } + + if (typeof options.mark === 'function') { + options.mark({ year: YMD[0], month: YMD[1], date: YMD[2] }, render); + } else if (typeof options.mark === 'object') { + render(options.mark); + } + + return that; +}; + +/** + * 渲染法定节假日或补假上班标记 + * @param {JQuery} tdElem td 元素 + * @param {[number, number, number]} YMD 年月日 + * @param {[Array, Array] | string} markers 标记信息 + */ +Class.prototype.holidaysRender = function (tdElem, YMD, markers) { + var type = ['holidays', 'workdays']; + + var isEquals = function (ymdStr1, ymdStr2) { + var ymd1 = ymdStr1.split('-'); + var ymd2 = ymdStr2.split('-'); + + ymd1.forEach(function (v, i) { + ymd1[i] = parseInt(v, 10); + }); + ymd2.forEach(function (v, i) { + ymd2[i] = parseInt(v, 10); + }); + + return ymd1.join('-') === ymd2.join('-'); + }; + + var insertHtml = function (el, type, text) { + el.find('div').html( + [ + '', + text, + '', + ].join(''), + ); + }; + + if (lay.type(markers) === 'array') { + markers.forEach(function (item, idx) { + (item || []).forEach(function (dayStr) { + if (isEquals(dayStr, tdElem.attr('lay-ymd'))) { + insertHtml(tdElem, type[idx], YMD[2]); + } + }); + }); + } else if (typeof markers === 'string') { + if (type.indexOf(markers) !== -1) { + insertHtml(tdElem, markers, YMD[2]); + } + } +}; + +/** + * 标注法定节假日或补假上班 + * @param {JQuery} td + * @param {[number, number, number]} YMD + * @returns Class + */ +Class.prototype.holidays = function (td, YMD) { + var that = this; + var options = that.config; + + var render = function (markers) { + that.holidaysRender(td, YMD, markers); + }; + + if (typeof options.holidays === 'function') { + options.holidays({ year: YMD[0], month: YMD[1], date: YMD[2] }, render); + } else if (lay.type(options.holidays) === 'array') { + render(options.holidays); + } + + return that; +}; + +/** + * 自定义单元格 + * @param {HTMLElement|Array} el - 单元格元素 + * @param {{year:number, month:number, date:number}} dateObj - 当前单元格对应的日期信息 + * @param {'year' | 'month' | 'date'} panelMode - 面板模式 + * @returns + */ +Class.prototype.cellRender = function (el, dateObj, panelMode) { + var that = this; + var options = that.config; + + if (typeof options.cellRender === 'function') { + var render = function (content) { + if (typeof content === 'string') { + $(el).html(content); + } else if (typeof content === 'object') { + $(el).html('').append($(content)[0]); + } + }; + options.cellRender(dateObj, render, { originElem: el, type: panelMode }); + } + + return that; +}; + +/** + * 给定年份的开始日期 + * @param {Date} date + */ +Class.prototype.startOfYear = function (date) { + var newDate = new Date(date); + newDate.setFullYear(newDate.getFullYear(), 0, 1); + newDate.setHours(0, 0, 0, 0); + return newDate; +}; + +/** + * 给定年份的结束日期 + * @param {Date} date + */ +Class.prototype.endOfYear = function (date) { + var newDate = new Date(date); + var year = newDate.getFullYear(); + newDate.setFullYear(year + 1, 0, 0); + newDate.setHours(23, 59, 59, 999); + return newDate; +}; + +/** + * 给定月份的开始日期 + * @param {Date} date + */ +Class.prototype.startOfMonth = function (date) { + var newDate = new Date(date); + newDate.setDate(1); + newDate.setHours(0, 0, 0, 0); + return newDate; +}; + +/** + * 给定月份的结束日期 + * @param {Date} date + */ +Class.prototype.endOfMonth = function (date) { + var newDate = new Date(date); + var month = newDate.getMonth(); + newDate.setFullYear(newDate.getFullYear(), month + 1, 0); + newDate.setHours(23, 59, 59, 999); + return newDate; +}; + +/** + * 将指定的天数添加到给定日期 + * @param {Date} date 要更改的日期 + * @param {number} amount 天数 + */ +Class.prototype.addDays = function (date, amount) { + var newDate = new Date(date); + if (!amount) return newDate; + newDate.setDate(newDate.getDate() + amount); + return newDate; +}; + +/** + * 不可选取的年或月。年或月中的所有日期都禁用时,才判定为不可选取。 + * @param {Date} date 要检测的年或月 + * @param {'year' | 'month'} type 面板类型 + * @param {'start' | 'end'} position 面板位置 + */ +Class.prototype.isDisabledYearOrMonth = function (date, type, position) { + var that = this; + var options = that.config; + var millisecondsInDay = 24 * 60 * 60 * 1000; + + var startDay = + type === 'year' ? that.startOfYear(date) : that.startOfMonth(date); + var endDay = type === 'year' ? that.endOfYear(date) : that.endOfMonth(date); + var numOfDays = + Math.floor((endDay.getTime() - startDay.getTime()) / millisecondsInDay) + 1; + var disabledCount = 0; + + for (var i = 0; i < numOfDays; i++) { + var day = that.addDays(startDay, i); + if (options.disabledDate.call(options, day, position)) { + disabledCount++; + } + } + + return disabledCount === numOfDays; +}; + +/** + * @typedef limitOptions + * @prop {JQuery} [elem] - 检测的元素, 例如面板中年月日时分秒元素,“现在”,“确认” 按钮等 + * @prop {number} [index] - 元素集合中,当前检测元素的索引,years:0,month:0,date:0-41,hms:0 + * @prop {['hours', 'minutes', 'seconds'] | ['hours', 'minutes'] | ['hours']} [time] - 是否比较时分秒 + * @prop {'year'|'month'|string} [type] - 面板类型? + * @prop {0 | 1} [rangeType] - 面板索引, 0 表示 start, 1 表示 end + * @prop {Partial<{year:number,month: number,date:number,hours:number,minutes:number,seconds:number}>} [date] - 检测的日期时间对象 + * @prop {'date' | 'time' | 'datetime'} disabledType - 禁用类型,按钮应使用 datetime + */ +/** + * 不可选取的日期 + * @param {number} date 当前检测的日期的时间戳 + * @param {limitOptions} opts + * @returns {boolean} + */ +Class.prototype.isDisabledDate = function (date, opts) { + opts = opts || {}; + + var that = this; + var options = that.config; + var position = options.range + ? opts.rangeType === 0 + ? 'start' + : 'end' + : 'start'; + + if (!options.disabledDate) return false; + if (options.type === 'time') return false; + if (!(opts.disabledType === 'date' || opts.disabledType === 'datetime')) + return false; + + // 不需要时分秒 + var normalizedDate = new Date(date); + normalizedDate.setHours(0, 0, 0, 0); + + return opts.type === 'year' || opts.type === 'month' + ? that.isDisabledYearOrMonth(normalizedDate, opts.type, position) + : options.disabledDate.call(options, normalizedDate, position); +}; + +/** + * 不可选取的时间 + * @param {number} date 当前检测的日期的时间戳 + * @param {limitOptions} opts + * @returns {boolean} + */ +Class.prototype.isDisabledTime = function (date, opts) { + opts = opts || {}; + + var that = this; + var options = that.config; + var position = options.range + ? opts.rangeType === 0 + ? 'start' + : 'end' + : 'start'; + + if (!options.disabledTime) return false; + if (!(options.type === 'time' || options.type === 'datetime')) return false; + if (!(opts.disabledType === 'time' || opts.disabledType === 'datetime')) + return false; + + var isDisabledItem = function (compareVal, rangeFn, rangeFnParam) { + return function () { + return ( + ( + (typeof rangeFn === 'function' && + rangeFn.apply(options, rangeFnParam)) || + [] + ).indexOf(compareVal) !== -1 + ); + }; + }; + + var dateObj = that.systemDate(new Date(date)); + var disabledTime = + options.disabledTime.call(options, that.newDate(dateObj), position) || {}; + + // 面板中的时分秒 HTML 元素需要分别检测是否禁用 + // 按钮检测任意一项是否禁用即可 + return opts.disabledType === 'datetime' + ? isDisabledItem(dateObj.hours, disabledTime.hours)() || + isDisabledItem(dateObj.minutes, disabledTime.minutes, [ + dateObj.hours, + ])() || + isDisabledItem(dateObj.seconds, disabledTime.seconds, [ + dateObj.hours, + dateObj.minutes, + ])() + : [ + isDisabledItem(dateObj.hours, disabledTime.hours), + isDisabledItem(dateObj.minutes, disabledTime.minutes, [dateObj.hours]), + isDisabledItem(dateObj.seconds, disabledTime.seconds, [ + dateObj.hours, + dateObj.minutes, + ]), + ][opts.time.length - 1](); +}; + +/** + * 不可选取的日期时间 + * @param {number} timestamp 当前检测的日期的时间戳 + * @param {limitOptions} opts + * @returns + */ +Class.prototype.isDisabledDateTime = function (timestamp, opts) { + opts = opts || {}; + + var that = this; + // var options = that.config; + + return ( + that.isDisabledDate(timestamp, opts) || that.isDisabledTime(timestamp, opts) + ); +}; + +/** + * 无效日期范围的标记 + * @param {limitOptions} opts + * + */ +Class.prototype.limit = function (opts) { + opts = opts || {}; + + var that = this; + var options = that.config; + var timestamp = {}; + var dateTime = + opts.index > (opts.time ? 0 : 41) ? that.endDate : options.dateTime; + var isOut; + + Object.entries({ + now: lay.extend({}, dateTime, opts.date || {}), + min: options.min, + max: options.max, + }).forEach(function ([key, item]) { + timestamp[key] = that + .newDate( + lay.extend( + { + year: item.year, + month: opts.type === 'year' ? 0 : item.month, // 年份的时候只比较年 + date: opts.type === 'year' || opts.type === 'month' ? 1 : item.date, // 年月只比较年月不与最大最小比日期 + }, + (function () { + var hms = {}; + (opts.time || []).forEach(function (keys) { + hms[keys] = item[keys]; + }); + return hms; + })(), + ), + ) + .getTime(); //time:是否比较时分秒 + }); + + isOut = + timestamp.now < timestamp.min || + timestamp.now > timestamp.max || + that.isDisabledDateTime(timestamp.now, opts); + opts.elem && opts.elem[isOut ? 'addClass' : 'removeClass'](DISABLED); + + return isOut; +}; + +//当前日期对象 +Class.prototype.thisDateTime = function (index) { + var that = this, + options = that.config; + return index ? that.endDate : options.dateTime; +}; + +//日历表 +Class.prototype.calendar = function (value, index, type) { + index = index ? 1 : 0; + var that = this, + options = that.config, + dateTime = value || that.thisDateTime(index), + thisDate = new Date(), + startWeek, + prevMaxDate, + thisMaxDate, + lang = that.i18nMessages, + isAlone = options.type !== 'date' && options.type !== 'datetime', + tds = $(that.table[index]).find('td'), + elemYM = $(that.elemHeader[index][2]).find('span'); + + if (dateTime.year < LIMIT_YEAR[0]) + ((dateTime.year = LIMIT_YEAR[0]), that.hint(lang.invalidDatePrompt)); + if (dateTime.year > LIMIT_YEAR[1]) + ((dateTime.year = LIMIT_YEAR[1]), that.hint(lang.invalidDatePrompt)); + + //记录初始值 + if (!that.firstDate) { + that.firstDate = lay.extend({}, dateTime); + } + + //计算当前月第一天的星期 + thisDate.setFullYear(dateTime.year, dateTime.month, 1); + startWeek = (thisDate.getDay() + (7 - options.weekStart)) % 7; + + prevMaxDate = laydate.getEndDate(dateTime.month || 12, dateTime.year); //计算上个月的最后一天 + thisMaxDate = laydate.getEndDate(dateTime.month + 1, dateTime.year); //计算当前月的最后一天 + + //赋值日 + tds.each(function (index_, item) { + var YMD = [dateTime.year, dateTime.month], + st; + item = $(item); + item.removeAttr('class'); + if (index_ < startWeek) { + st = prevMaxDate - startWeek + index_; + item.addClass('laydate-day-prev'); + YMD = that.getAsYM(dateTime.year, dateTime.month, 'sub'); + } else if (index_ >= startWeek && index_ < thisMaxDate + startWeek) { + st = index_ - startWeek; + if (!that.rangeLinked) { + st + 1 === dateTime.date && item.addClass(THIS); + } + } else { + st = index_ - thisMaxDate - startWeek; + item.addClass('laydate-day-next'); + YMD = that.getAsYM(dateTime.year, dateTime.month); + } + YMD[1]++; + YMD[2] = st + 1; + item.attr('lay-ymd', YMD.join('-')).html('
                              ' + YMD[2] + '
                              '); + that + .mark(item, YMD) + .holidays(item, YMD) + .limit({ + elem: item, + date: { + year: YMD[0], + month: YMD[1] - 1, + date: YMD[2], + }, + index: index_, + rangeType: index, + disabledType: 'date', // 日面板,检测当前日期是否禁用 + }); + that.cellRender( + item, + { year: YMD[0], month: YMD[1], date: YMD[2] }, + 'date', + ); + }); + + //同步头部年月 + $(elemYM[0]).attr('lay-ym', dateTime.year + '-' + (dateTime.month + 1)); + $(elemYM[1]).attr('lay-ym', dateTime.year + '-' + (dateTime.month + 1)); + if (!that.panelYM) that.panelYM = {}; + that.panelYM[index] = { year: dateTime.year, month: dateTime.month }; + + var normalizedYearStr = addSpaceBetweenChars( + dateTime.year + lang.literal.year, + ); + var normalizedMonthStr = addSpaceBetweenChars(lang.months[dateTime.month]); + if (!lang.monthBeforeYear) { + $(elemYM[0]).attr('lay-type', 'year').html(normalizedYearStr); + $(elemYM[1]).attr('lay-type', 'month').html(normalizedMonthStr); + } else { + $(elemYM[0]).attr('lay-type', 'month').html(normalizedMonthStr); + $(elemYM[1]).attr('lay-type', 'year').html(normalizedYearStr); + } + + //初始默认选择器 + if (isAlone) { + //年、月等独立选择器 + if (options.range) { + if (value || type !== 'init') { + // 判断是否需要显示年月时间列表 + that.listYM = [ + [ + (that.startDate || options.dateTime).year, + (that.startDate || options.dateTime).month + 1, + ], + [that.endDate.year, that.endDate.month + 1], + ]; + that.list(options.type, 0).list(options.type, 1); + + //同步按钮可点状态 + options.type === 'time' + ? that.setBtnStatus( + true, + lay.extend({}, that.systemDate(), that.startTime), + lay.extend({}, that.systemDate(), that.endTime), + ) + : that.setBtnStatus(true); + } + } else { + that.listYM = [[dateTime.year, dateTime.month + 1]]; + that.list(options.type, 0); + } + } + + //初始赋值双日历 + if (options.range && type === 'init') { + //执行渲染第二个日历 + if (that.rangeLinked) { + var EYM = that.getAsYM( + dateTime.year, + dateTime.month, + index ? 'sub' : null, + ); + that.calendar( + lay.extend({}, dateTime, { + year: EYM[0], + month: EYM[1], + }), + 1 - index, + ); // 渲染另外一个 + } else { + that.calendar(null, 1 - index); + } + } + + // 通过检测当前有效日期,来设定底部按钮状态 + if (!options.range) { + var timeParams = ['hours', 'minutes', 'seconds']; + + // 现在按钮 + that.limit({ + elem: $(that.footer).find(ELEM_NOW), + date: that.systemDate( + /^(datetime|time)$/.test(options.type) ? new Date() : null, + ), + index: 0, + time: timeParams, + disabledType: 'datetime', // 按钮,检测日期和时间 + }); + // 确认按钮 + that.limit({ + elem: $(that.footer).find(ELEM_CONFIRM), + index: 0, + time: timeParams, + disabledType: 'datetime', // 按钮,检测日期和时间 + }); + } + + //同步按钮可点状态 + that.setBtnStatus(); + + // 重置快捷栏选中状态 + $(that.shortcut) + .find('li.' + THIS) + .removeClass(THIS); + + //标记选择范围 + if (options.range && !isAlone && type !== 'init') that.stampRange(); + + return that; +}; + +//生成年月时分秒列表 +Class.prototype.list = function (type, index) { + var that = this, + options = that.config, + dateTime = that.rangeLinked + ? options.dateTime + : [options.dateTime, that.endDate][index], + lang = that.i18nMessages, + isAlone = + options.range && options.type !== 'date' && options.type !== 'datetime', //独立范围选择器 + ul = lay.elem('ul', { + class: + ELEM_LIST + + ' ' + + { + year: 'laydate-year-list', + month: 'laydate-month-list', + time: 'laydate-time-list', + }[type], + }), + elemHeader = that.elemHeader[index], + elemYM = $(elemHeader[2]).find('span'), + elemCont = that.elemCont[index || 0], + haveList = $(elemCont).find('.' + ELEM_LIST)[0], + isMonthBeforeYear = lang.monthBeforeYear, + text = lang.literal.year, + listYM = that.listYM[index] || {}, + hms = ['hours', 'minutes', 'seconds'], + startEnd = ['startTime', 'endTime'][index]; + + if (listYM[0] < 1) listYM[0] = 1; + + //生成年列表 + if (type === 'year') { + var yearNum, + startY = (yearNum = listYM[0] - 7); + if (startY < 1) startY = yearNum = 1; + for (var yearIndex = 0; yearIndex < 15; yearIndex++) { + var li = lay.elem('li', { + 'lay-ym': yearNum, + }), + ymd = { + year: yearNum, + month: 0, + date: 1, + }; + + yearNum == listYM[0] && $(li).addClass(THIS); + li.innerHTML = yearNum + text; + ul.appendChild(li); + + /* + if(yearNum < that.firstDate.year){ + ymd.month = options.min.month; + ymd.date = options.min.date; + } else if(yearNum >= that.firstDate.year){ + ymd.month = options.max.month; + ymd.date = options.max.date; + } + */ + + that.limit({ + elem: $(li), + date: ymd, + index: index, + type: type, + rangeType: index, + disabledType: 'date', // 年面板,检测当前年份中的所有日期是否禁用 + }); + that.cellRender(li, { year: yearNum, month: 1, date: 1 }, 'year'); + yearNum++; + } + + $(elemYM[!isMonthBeforeYear ? 0 : 1]) + .attr('lay-ym', yearNum - 8 + '-' + listYM[1]) + .html(startY + text + ' - ' + (yearNum - 1 + text)); + } + + //生成月列表 + else if (type === 'month') { + for (var i = 0; i < 12; i++) { + const li = lay.elem('li', { + 'lay-ym': i, + }); + const ymd = { + year: listYM[0], + month: i, + date: 1, + }; + + i + 1 == listYM[1] && $(li).addClass(THIS); + li.innerHTML = lang.months[i]; + ul.appendChild(li); + + /* + if(listYM[0] < that.firstDate.year){ + ymd.date = options.min.date; + } else if(listYM[0] >= that.firstDate.year){ + ymd.date = options.max.date; + } + */ + + that.limit({ + elem: $(li), + date: ymd, + index: index, + type: type, + rangeType: index, + disabledType: 'date', // 月面板,检测当前月份中的所有日期是否禁用 + }); + that.cellRender(li, { year: listYM[0], month: i + 1, date: 1 }, 'month'); + } + + $(elemYM[!isMonthBeforeYear ? 0 : 1]) + .attr('lay-ym', listYM[0] + '-' + listYM[1]) + .html(listYM[0] + text); + } + + //生成时间列表 + else if (type === 'time') { + //检测时分秒状态是否在有效日期时间范围内 + var setTimeStatus = function () { + $(ul) + .find('ol') + .each(function (i, ol) { + $(ol) + .find('li') + .each(function (ii, li) { + that.limit({ + elem: $(li), + date: [ + { + hours: ii, + }, + { + hours: that[startEnd].hours, + minutes: ii, + }, + { + hours: that[startEnd].hours, + minutes: that[startEnd].minutes, + seconds: ii, + }, + ][i], + index: index, + rangeType: index, + disabledType: 'time', // 时间面板,分别检测时分秒列表是否禁用 + time: [ + ['hours'], + ['hours', 'minutes'], + ['hours', 'minutes', 'seconds'], + ][i], + }); + }); + }); + if (!options.range) { + that.limit({ + elem: $(that.footer).find(ELEM_CONFIRM), + date: that[startEnd], + index: 0, + time: ['hours', 'minutes', 'seconds'], + disabledType: 'datetime', // 确认按钮,检测时分秒列表任意一项是否禁用 + }); + } + }; + + var setTimeListVisibility = function () { + var showHour = options.format.indexOf('H') !== -1; + var showMinute = options.format.indexOf('m') !== -1; + var showSecond = options.format.indexOf('s') !== -1; + var liElem = ul.children; + var hideCount = 0; + + [showHour, showMinute, showSecond].forEach(function (isShow, i) { + if (!isShow) { + liElem[i].className += ' lay-hide'; + hideCount++; + } + }); + ul.className += ' laydate-time-list-hide-' + hideCount; + }; + + //初始化时间对象 + if (options.range) { + if (!that[startEnd]) { + that[startEnd] = startEnd === 'startTime' ? dateTime : that.endDate; + } + } else { + that[startEnd] = dateTime; + } + + //生成时分秒 + [24, 60, 60].forEach(function (item, i) { + var li = lay.elem('li'), + childUL = ['

                              ' + lang.time[i] + '

                                ']; + for (var ii = 0; ii < item; ii++) { + childUL.push( + '' + + lay.digit(ii, 2) + + '', + ); + } + li.innerHTML = childUL.join('') + '
                              '; + ul.appendChild(li); + }); + setTimeStatus(); + setTimeListVisibility(); + } + + //插入容器 + if (haveList) elemCont.removeChild(haveList); + elemCont.appendChild(ul); + + //年月面板 - 选择事件 + if (type === 'year' || type === 'month') { + //显示切换箭头 + $(that.elemMain[index]).addClass('laydate-ym-show'); + + //选中 + $(ul) + .find('li') + .on('click', function () { + var ym = $(this).attr('lay-ym') | 0; + if ($(this).hasClass(DISABLED)) return; + if (that.rangeLinked) { + lay.extend(dateTime, { + year: type === 'year' ? ym : listYM[0], + month: type === 'year' ? listYM[1] - 1 : ym, + }); + } else { + dateTime[type] = ym; + } + + //当为年选择器或者年月选择器 + var isYearOrMonth = ['year', 'month'].indexOf(options.type) !== -1; + var isChangeMonth = + type === 'year' && ['date', 'datetime'].indexOf(options.type) !== -1; + if (isYearOrMonth || isChangeMonth) { + $(ul) + .find('.' + THIS) + .removeClass(THIS); + $(this).addClass(THIS); + + //如果为年月选择器,点击了年列表,则切换到月选择器 + if ((options.type === 'month' && type === 'year') || isChangeMonth) { + that.listYM[index][0] = ym; + isAlone && ((index ? that.endDate : dateTime).year = ym); + that.list('month', index); + } + } else { + that.checkDate('limit').calendar(dateTime, index, 'init'); // 重新渲染一下两个面板 + that.closeList(); + } + + if (!options.range) { + that.limit({ + type: type, + elem: $(that.footer).find(ELEM_CONFIRM), + date: dateTime, + disabledType: 'datetime', // 按钮,检测日期和时间 + }); + } + + that.setBtnStatus(); //同步按钮可点状态 + + //若为月选择器,只有当选择月份时才自动关闭; + //若为年选择器,选择年份即自动关闭 + //且在范围未开启时 + if (!options.range && options.autoConfirm) { + if ( + (options.type === 'month' && type === 'month') || + (options.type === 'year' && type === 'year') + ) { + that.setValue(that.parse()).done().remove(); + } + } + + that.autoCalendarModel.auto && !that.rangeLinked + ? that.choose($(elemCont).find('td.lay-this'), index) + : that.endState && that.done(null, 'change'); + $(that.footer) + .find('.' + ELEM_TIME_BTN) + .removeClass(DISABLED); + }); + } else { + //时间选择面板 - 选择事件 + var span = lay.elem('span', { + class: ELEM_TIME_TEXT, + }), + //滚动条定位 + scroll = function () { + $(ul) + .find('ol') + .each(function (i) { + var ol = this, + li = $(ol).find('li'); + ol.scrollTop = 30 * (that[startEnd][hms[i]] - 2); + if (ol.scrollTop <= 0) { + li.each(function (ii) { + if (!$(this).hasClass(DISABLED)) { + ol.scrollTop = 30 * (ii - 2); + return false; + } + }); + } + }); + }, + haveSpan = $(elemHeader[2]).find('.' + ELEM_TIME_TEXT); + + scroll(); + span.innerHTML = options.range + ? [lang.startTime, lang.endTime][index] + : lang.selectTime; + $(that.elemMain[index]).addClass('laydate-time-show'); + + if (haveSpan[0]) haveSpan.remove(); + elemHeader[2].appendChild(span); + + var olElem = $(ul).find('ol'); + olElem.each(function (i) { + var ol = this; + //选择时分秒 + $(ol) + .find('li') + .on('click', function () { + var value = this.innerHTML | 0; + if ($(this).hasClass(DISABLED)) return; + + if (options.range) { + that[startEnd][hms[i]] = value; + } else { + dateTime[hms[i]] = value; + } + $(ol) + .find('.' + THIS) + .removeClass(THIS); + $(this).addClass(THIS); + + setTimeStatus(); + scroll(); + (that.endDate || + options.type === 'time' || + options.type === 'datetime') && + that.done(null, 'change'); + + //同步按钮可点状态 + that.setBtnStatus(); + }); + }); + + if (lay.device().mobile) { + olElem.css({ + overflowY: 'auto', + touchAction: 'pan-y', + }); + } + } + + return that; +}; + +//记录列表切换后的年月 +Class.prototype.listYM = []; + +//关闭列表 +Class.prototype.closeList = function () { + var that = this; + // var options = that.config; + + that.elemCont.forEach(function (item, index) { + $(item) + .find('.' + ELEM_LIST) + .remove(); + $(that.elemMain[index]).removeClass('laydate-ym-show laydate-time-show'); + }); + $(that.elem) + .find('.' + ELEM_TIME_TEXT) + .remove(); +}; + +//检测结束日期是否超出开始日期 +Class.prototype.setBtnStatus = function (tips, start, end) { + var that = this, + options = that.config, + lang = that.i18nMessages, + isOut, + elemBtn = $(that.footer).find(ELEM_CONFIRM), + timeParams = + options.type === 'datetime' || options.type === 'time' + ? ['hours', 'minutes', 'seconds'] + : undefined; + if (options.range) { + start = start || (that.rangeLinked ? that.startDate : options.dateTime); + end = end || that.endDate; + isOut = + !that.endState || + that.newDate(start).getTime() > that.newDate(end).getTime(); + + //如果不在有效日期内,直接禁用按钮,否则比较开始和结束日期 + that.limit({ + date: start, + disabledType: 'datetime', // 按钮,检测日期和时间 + time: timeParams, + rangeType: 0, + }) || + that.limit({ + date: end, + disabledType: 'datetime', // 按钮,检测日期和时间 + time: timeParams, + rangeType: 1, + }) + ? elemBtn.addClass(DISABLED) + : elemBtn[isOut ? 'addClass' : 'removeClass'](DISABLED); + + // 是否异常提示 + if (tips && isOut) { + that.hint(lang.rangeOrderPrompt); + } + } +}; + +// 转义为规定格式的日期字符 +Class.prototype.parse = function (state, date) { + var that = this; + var options = that.config; + var startDate = that.rangeLinked ? that.startDate : options.dateTime; + var dateTime = + date || + (state == 'end' + ? lay.extend({}, that.endDate, that.endTime) + : options.range + ? lay.extend({}, startDate || options.dateTime, that.startTime) + : options.dateTime); + var format = laydate.parse(dateTime, that.format, 1); + + // 返回日期范围字符 + if (options.range && state === undefined) { + return format + ' ' + that.rangeStr + ' ' + that.parse('end'); + } + + return format; +}; + +//创建指定日期时间对象 +Class.prototype.newDate = function (dateTime) { + dateTime = dateTime || {}; + return new Date( + dateTime.year || 1, + dateTime.month || 0, + dateTime.date || 1, + dateTime.hours || 0, + dateTime.minutes || 0, + dateTime.seconds || 0, + ); +}; + +// 获得指定日期时间对象的毫秒数 +Class.prototype.getDateTime = function (obj) { + return this.newDate(obj).getTime(); +}; + +/** + * 格式化输入框显示值 + * @param {HTMLInputElement} elem HTML input 元素 + * @param {(value: string) => string} displayValueCallback + */ +Class.prototype.formatToDisplay = function (elem, displayValueCallback) { + var that = this; + var props = Object.getOwnPropertyDescriptor( + HTMLInputElement.prototype, + 'value', + ); + + Object.defineProperty( + elem, + 'value', + lay.extend({}, props, { + get: function () { + return this.getAttribute('lay-date'); + }, + set: function (value) { + props.set.call(this, displayValueCallback.call(that, value)); + this.setAttribute('lay-date', value); + }, + }), + ); +}; + +//赋值 +Class.prototype.setValue = function (value) { + var that = this, + options = that.config, + elem = options.elem[0]; + + //静态展现则不作默认赋值 + if (options.position === 'static') return that; + + value = value || ''; + + //绑定的元素是否为 input + if (that.isInput(elem)) { + $(elem).val(value); + } else { + //如果 range 传入了开始和结束的 input 对象,则分别对其赋值 + var rangeElem = that.rangeElem; + if (rangeElem) { + if (lay.type(value) !== 'array') { + value = value.split(' ' + that.rangeStr + ' '); + } + rangeElem[0].val(value[0] || ''); + rangeElem[1].val(value[1] || ''); + } else { + if ($(elem).find('*').length === 0) { + var displayValue = + typeof options.formatToDisplay === 'function' + ? options.formatToDisplay(value) + : value; + $(elem).html(displayValue); + } + $(elem).attr('lay-date', value); + } + } + + return that; +}; + +//预览 +Class.prototype.preview = function () { + var that = this, + options = that.config; + + if (!options.isPreview) return; + + var elemPreview = $(that.elem).find('.' + ELEM_PREVIEW), + value = options.range + ? (that.rangeLinked ? that.endState : that.endDate) + ? that.parse() + : '' + : that.parse(); + + // 显示预览 + elemPreview.html(value); + + // 预览颜色渐变 + var oldValue = elemPreview.html(); + if (oldValue) { + var color = + lay.type(options.theme) === 'array' ? options.theme[0] : options.theme; + elemPreview.css({ + color: /^#/.test(String(color)) ? color : '#16b777', + }); + + setTimeout(function () { + elemPreview.css({ + color: '#777', + }); + }, 300); + } +}; + +// 附加的渲染处理,在 ready 和 change 的时候调用 +Class.prototype.renderAdditional = function () { + var that = this; + var options = that.config; + + // 处理全面板 + if (options.fullPanel) { + that.list('time', 0); + } +}; + +// 标记范围内的日期 +Class.prototype.stampRange = function () { + var that = this, + options = that.config, + startTime = that.rangeLinked ? that.startDate : options.dateTime, + endTime, + tds = $(that.elem).find('td'); + + if (options.range && !that.endState) + $(that.footer).find(ELEM_CONFIRM).addClass(DISABLED); + // if(!that.endState) return; + + startTime = + startTime && + that + .newDate({ + year: startTime.year, + month: startTime.month, + date: startTime.date, + }) + .getTime(); + + endTime = + that.endState && + that.endDate && + that + .newDate({ + year: that.endDate.year, + month: that.endDate.month, + date: that.endDate.date, + }) + .getTime(); + + // if(startTime > endTime) return that.hint(TIPS_OUT); + + tds.each(function (i, item) { + var ymd = $(item).attr('lay-ymd').split('-'); + var thisTime = that + .newDate({ + year: ymd[0], + month: ymd[1] - 1, + date: ymd[2], + }) + .getTime(); + + // 标记当天 + if (options.rangeLinked && !that.startDate) { + if (thisTime === that.newDate(that.systemDate()).getTime()) { + $(item).addClass( + $(item).hasClass(ELEM_PREV) || $(item).hasClass(ELEM_NEXT) + ? '' + : ELEM_DAY_NOW, + ); + } + } + + /* + * 标注区间 + */ + + $(item).removeClass(ELEM_SELECTED + ' ' + THIS); + + if (thisTime === startTime || thisTime === endTime) { + (that.rangeLinked || + (!that.rangeLinked && + (i < 42 ? thisTime === startTime : thisTime === endTime))) && + $(item).addClass( + $(item).hasClass(ELEM_PREV) || $(item).hasClass(ELEM_NEXT) + ? ELEM_SELECTED + : THIS, + ); + } + if (thisTime > startTime && thisTime < endTime) { + $(item).addClass(ELEM_SELECTED); + } + }); +}; + +// 执行 done/change 回调 +Class.prototype.done = function (param, type) { + var that = this; + var options = that.config; + var start = lay.extend( + {}, + lay.extend( + that.rangeLinked ? that.startDate : options.dateTime, + that.startTime, + ), + ); + var end = lay.extend({}, lay.extend(that.endDate, that.endTime)); + + [start, end].forEach(function (item) { + if (!('month' in item)) return; + lay.extend(item, { + month: item.month + 1, + }); + }); + + that.preview(); + + param = param || [that.parse(), start, end]; + type === 'change' && that.renderAdditional(); + typeof options[type || 'done'] === 'function' && + options[type || 'done'].apply(options, param); + + return that; +}; + +/** + * 判断日期是否存在面板,用于处理日期范围选择的一些边缘情况 + * @param {object} datetime 日期时间对象 + * @param {number} index - 面板索引 + * @returns + */ +Class.prototype.checkPanelDate = function (datetime, index) { + var that = this; + var options = that.config; + // 年月范围选择不需要处理 + if (options.type !== 'date' && options.type !== 'datetime') return; + + var startPanel = index === 0; + var month = datetime.month + 1; // 点击的日期所在月份 + var panelMonth = that.panelYM[index].month + 1; // 当前面板头部月份 + + // 边缘日期的处理 + var firstRenderIndex = that.endState + ? // 二次点击(一般为结束日期)任意一侧面板时: + // 1. 左侧面板中,点击的月份属于下一个月时,应渲染右侧面板而不是左侧面板; + // 2. 左侧面板中,点击的月份属于上一个月时,应将两个面板都重新渲染(等效点击 prevMonth); + // 3. 右侧面板同理。 + (function () { + return (startPanel && month > panelMonth) || + (!startPanel && month < panelMonth) + ? 1 - index + : index; + })() + : // 初次点击(一般为开始日期)任意一侧面板时: + // 1. 让该面板自行切换,以保持日期的「选中状态」在该侧; + // 2. 另一侧面板则根据点击的面板进行响应式切换,以保持左右面板始终为连续月份。 + index; + + // 为简化实现,只要点击的月份不等于当前面板顶部显示的月份时,就重新渲染两侧面板 + return { + needFullRender: month !== panelMonth, + index: firstRenderIndex, + }; +}; + +//选择日期 +Class.prototype.choose = function (td, index) { + if (td.hasClass(DISABLED)) return; + + var that = this, + options = that.config, + panelIndex = index; // 记录点击的是哪一个面板的 + + if (that.rangeLinked) { + if (that.endState || !that.startDate) { + // 重新选择或者第一次选择 + index = 0; + that.endState = false; + } else { + index = 1; + that.endState = true; + } + } + + var dateTime = that.thisDateTime(index), + // tds = $(that.elem).find('td'), + YMD = td.attr('lay-ymd').split('-'); + + YMD = { + year: YMD[0] | 0, + month: (YMD[1] | 0) - 1, + date: YMD[2] | 0, + }; + + lay.extend(dateTime, YMD); //同步 dateTime + + //范围选择 + if (options.range) { + //补充时分秒 + ['startTime', 'endTime'].forEach(function (item, i) { + that[item] = that[item] || { + hours: i ? 23 : 0, + minutes: i ? 59 : 0, + seconds: i ? 59 : 0, + }; + if (index === i) { + // 判断选择之后的是否在范围内,超出则需要调整时分秒 + if ( + that.getDateTime(lay.extend({}, dateTime, that[item])) < + that.getDateTime(options.min) + ) { + that[item] = { + hours: options.min.hours, + minutes: options.min.minutes, + seconds: options.min.seconds, + }; + lay.extend(dateTime, that[item]); + } else if ( + that.getDateTime(lay.extend({}, dateTime, that[item])) > + that.getDateTime(options.max) + ) { + that[item] = { + hours: options.max.hours, + minutes: options.max.minutes, + seconds: options.max.seconds, + }; + lay.extend(dateTime, that[item]); + } + } + }); + if (!index) { + that.startDate = lay.extend({}, dateTime); // 同步startDate + } + // 校验另外一个日期是否在有效的范围内 + // 此处为范围选择的日期面板点击选中处理,所以 disabledType 为 date + if ( + that.endState && + !that.limit({ + date: that.rangeLinked ? that.startDate : that.thisDateTime(1 - index), + disabledType: 'date', + }) + ) { + // 根据选择之后判断是否需要切换模式 + var isChange; + if (that.endState && that.autoCalendarModel.auto) { + isChange = that.autoCalendarModel(); + } + // 判断是否反选 + var needSwapDate = + (isChange || (that.rangeLinked && that.endState)) && + that.newDate(that.startDate) > that.newDate(that.endDate); + if (needSwapDate) { + var isSameDate = + that.startDate.year === that.endDate.year && + that.startDate.month === that.endDate.month && + that.startDate.date === that.endDate.date; + var startDate; + // 如果是同一天并且出现了反选证明是时分秒出现开始时间大于结束时间的现象 + if (isSameDate) { + startDate = that.startTime; + that.startTime = that.endTime; + that.endTime = startDate; + } + // 当出现反向选择时(即“后点击”的日期比“先点击”的日期小),重新提取区间 + startDate = that.startDate; + that.startDate = lay.extend({}, that.endDate, that.startTime); + options.dateTime = lay.extend({}, that.startDate); + that.endDate = lay.extend({}, startDate, that.endTime); + } + isChange && (options.dateTime = lay.extend({}, that.startDate)); + } + if (that.rangeLinked) { + // 处理日期范围选择的一些边缘情况 + var checkState = that.checkPanelDate(dateTime, panelIndex); + var dateTimeTemp = lay.extend({}, dateTime); + var renderMode = + isChange || (checkState && checkState.needFullRender) ? 'init' : null; + var panelIdx = checkState ? checkState.index : panelIndex; + that.calendar(dateTimeTemp, panelIdx, renderMode); + } else { + that.calendar(null, index, isChange ? 'init' : null); + } + that.endState && that.done(null, 'change'); + } else if (options.position === 'static') { + //直接嵌套的选中 + that.calendar().done().done(null, 'change'); //同时执行 done 和 change 回调 + } else if (options.type === 'date') { + options.autoConfirm + ? that.setValue(that.parse()).done().remove() + : that.calendar().done(null, 'change'); + } else if (options.type === 'datetime') { + that.calendar().done(null, 'change'); + } +}; + +//底部按钮 +Class.prototype.tool = function (btn, type) { + var that = this, + options = that.config, + lang = that.i18nMessages, + dateTime = options.dateTime, + isStatic = options.position === 'static', + active = { + //选择时间 + datetime: function () { + if ($(btn).hasClass(DISABLED)) return; + that.list('time', 0); + options.range && that.list('time', 1); + $(btn).attr('lay-type', 'date').html(that.i18nMessages.selectDate); + }, + + //选择日期 + date: function () { + that.closeList(); + $(btn).attr('lay-type', 'datetime').html(that.i18nMessages.selectTime); + }, + + //清空、重置 + clear: function () { + isStatic && (lay.extend(dateTime, that.firstDate), that.calendar()); + options.range && + (delete options.dateTime, + delete that.endDate, + delete that.startTime, + delete that.endTime); + that.setValue(''); + that.done(null, 'onClear').done(['', {}, {}]).remove(); + }, + + // 现在 + now: function () { + var thisDate = new Date(); + + // 当前系统时间未在 min/max 范围内,则不可点击 + if ($(btn).hasClass(DISABLED)) { + return that.hint(lang.tools.now + ', ' + lang.invalidDatePrompt); + } + + lay.extend(dateTime, that.systemDate(), { + hours: thisDate.getHours(), + minutes: thisDate.getMinutes(), + seconds: thisDate.getSeconds(), + }); + + that.setValue(that.parse()); + isStatic && that.calendar(); + that.done(null, 'onNow').done().remove(); + }, + + //确定 + confirm: function () { + if (options.range) { + if ($(btn).hasClass(DISABLED)) { + var isTimeout = + options.type === 'time' + ? that.startTime && + that.endTime && + that.newDate(that.startTime) > that.newDate(that.endTime) + : that.startDate && + that.endDate && + that.newDate( + lay.extend({}, that.startDate, that.startTime || {}), + ) > + that.newDate( + lay.extend({}, that.endDate, that.endTime || {}), + ); + + return that.hint( + isTimeout ? lang.rangeOrderPrompt : lang.invalidDatePrompt, + ); + } + } else { + if ($(btn).hasClass(DISABLED)) + return that.hint(lang.invalidDatePrompt); + } + + that.setValue(that.parse()); + that.done(null, 'onConfirm').done().remove(); + }, + }; + active[type] && active[type](); +}; + +//统一切换处理 +Class.prototype.change = function (index) { + var that = this, + options = that.config, + dateTime = that.thisDateTime(index), + isAlone = + options.range && (options.type === 'year' || options.type === 'month'), + elemCont = that.elemCont[index || 0], + listYM = that.listYM[index], + addSubYear = function (type) { + var isYear = $(elemCont).find('.laydate-year-list')[0], + isMonth = $(elemCont).find('.laydate-month-list')[0]; + + //切换年列表 + if (isYear) { + listYM[0] = type ? listYM[0] - 15 : listYM[0] + 15; + that.list('year', index); + } + + if (isMonth) { + //切换月面板中的年 + type ? listYM[0]-- : listYM[0]++; + that.list('month', index); + } + + if (isYear || isMonth) { + lay.extend(dateTime, { + year: listYM[0], + }); + if (isAlone) dateTime.year = listYM[0]; + options.range || that.done(null, 'change'); + options.range || + that.limit({ + elem: $(that.footer).find(ELEM_CONFIRM), + date: { + year: listYM[0], + month: isYear ? 0 : listYM[1] - 1, + }, + disabledType: 'datetime', // 按钮,检测日期和时间 + }); + } + + that.setBtnStatus(); + return isYear || isMonth; + }; + + return { + prevYear: function () { + if (addSubYear('sub')) return; + if (that.rangeLinked) { + options.dateTime.year--; + that.checkDate('limit').calendar(null, null, 'init'); + } else { + dateTime.year--; + that.checkDate('limit').calendar(null, index); + // 面板自动切换的模式下重新判定是否发生模式转换等细节处理 + that.autoCalendarModel.auto + ? that.choose($(elemCont).find('td.lay-this'), index) + : that.done(null, 'change'); + } + }, + prevMonth: function () { + var YM; + // rangeLinked 模式非实时选择日期,不需要同步 options.dateTime,应根据面板显示日期切换 + if (that.rangeLinked) { + var panelYM = that.panelYM[0]; + var dateTimeTemp; + YM = that.getAsYM(panelYM.year, panelYM.month, 'sub'); + dateTimeTemp = lay.extend({}, options.dateTime, that.panelYM[0], { + year: YM[0], + month: YM[1], + }); + that.checkDate('limit').calendar(dateTimeTemp, null, 'init'); + } else { + YM = that.getAsYM(dateTime.year, dateTime.month, 'sub'); + lay.extend(dateTime, { + year: YM[0], + month: YM[1], + }); + + that.checkDate('limit').calendar(null, null, 'init'); + that.autoCalendarModel.auto + ? that.choose($(elemCont).find('td.lay-this'), index) + : that.done(null, 'change'); + } + }, + nextMonth: function () { + var YM; + + if (that.rangeLinked) { + var panelYM = that.panelYM[0]; + YM = that.getAsYM(panelYM.year, panelYM.month); + var dateTimeTemp = lay.extend({}, options.dateTime, that.panelYM[0], { + year: YM[0], + month: YM[1], + }); + that.checkDate('limit').calendar(dateTimeTemp, null, 'init'); + } else { + YM = that.getAsYM(dateTime.year, dateTime.month); + + lay.extend(dateTime, { + year: YM[0], + month: YM[1], + }); + + that.checkDate('limit').calendar(null, null, 'init'); + that.autoCalendarModel.auto + ? that.choose($(elemCont).find('td.lay-this'), index) + : that.done(null, 'change'); + } + }, + nextYear: function () { + if (addSubYear()) return; + if (that.rangeLinked) { + options.dateTime.year++; + that.checkDate('limit').calendar(null, 0, 'init'); + } else { + dateTime.year++; + that.checkDate('limit').calendar(null, index); + that.autoCalendarModel.auto + ? that.choose($(elemCont).find('td.lay-this'), index) + : that.done(null, 'change'); + } + }, + }; +}; + +// 日期切换事件 +Class.prototype.changeEvent = function () { + var that = this; + // var options = that.config; + + //日期选择事件 + $(that.elem) + .on('click', function (e) { + e.stopPropagation(); + }) + .on('mousedown', function (e) { + e.stopPropagation(); + }); + + //年月切换 + that.elemHeader.forEach(function (header, i) { + //上一年 + $(header[0]).on('click', function () { + that.change(i).prevYear(); + }); + + //上一月 + $(header[1]).on('click', function () { + that.change(i).prevMonth(); + }); + + //选择年月 + $(header[2]) + .find('span') + .on('click', function () { + var othis = $(this), + layYM = othis.attr('lay-ym'), + layType = othis.attr('lay-type'); + + if (!layYM) return; + + layYM = layYM.split('-'); + + that.listYM[i] = [layYM[0] | 0, layYM[1] | 0]; + that.list(layType, i); + $(that.footer) + .find('.' + ELEM_TIME_BTN) + .addClass(DISABLED); + }); + + //下一月 + $(header[3]).on('click', function () { + that.change(i).nextMonth(); + }); + + //下一年 + $(header[4]).on('click', function () { + that.change(i).nextYear(); + }); + }); + + //点击日期 + that.table.forEach(function (table, i) { + var tds = $(table).find('td'); + tds.on('click', function () { + that.choose($(this), i); + }); + }); + + //点击底部按钮 + $(that.footer) + .find('span') + .on('click', function () { + var type = $(this).attr('lay-type'); + that.tool(this, type); + }); +}; + +//是否输入框 +Class.prototype.isInput = function (elem) { + return ( + /input|textarea/.test(elem.tagName.toLocaleLowerCase()) || + /INPUT|TEXTAREA/.test(elem.tagName) + ); +}; + +//绑定的元素事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + if (!options.elem[0] || options.elem[0].eventHandler) return; + + var showEvent = function () { + // 已经打开的面板避免重新渲染 + if (laydate.thisId === options.id) return; + that.render(); + }; + + //绑定呼出控件事件 + options.elem.on(options.trigger, showEvent); + options.elem[0].eventHandler = true; + options.eventElem.on(options.trigger, showEvent); + + // 元素解绑 + that.unbind = function () { + that.remove(); + options.elem.off(options.trigger, showEvent); + options.elem.removeAttr('lay-key'); + options.elem.removeAttr(MOD_ID); + options.elem[0].eventHandler = false; + options.eventElem.off(options.trigger, showEvent); + options.eventElem.removeAttr('lay-key'); + delete thisModule.that[options.id]; + }; +}; + +// 绑定关闭控件事件 +$(document) + .on('mousedown', function (e) { + if (!laydate.thisId) return; + var that = thisModule.getThis(laydate.thisId); + if (!that) return; + + var options = that.config; + + if ( + e.target === options.elem[0] || + e.target === options.eventElem[0] || + e.target === $(options.closeStop)[0] || + (options.elem[0] && options.elem[0].contains(e.target)) + ) + return; + + that.remove(); + }) + .on('keydown', function (e) { + if (!laydate.thisId) return; + var that = thisModule.getThis(laydate.thisId); + if (!that) return; + + // 回车触发确认 + if (that.config.position === 'static') return; + if (e.keyCode === 13) { + if ($('#' + that.elemID)[0] && that.elemID === Class.thisElemDate) { + e.preventDefault(); + $(that.footer).find(ELEM_CONFIRM)[0].click(); + } + } + }); + +//自适应定位 +$(window).on('resize', function () { + if (!laydate.thisId) return; + var that = thisModule.getThis(laydate.thisId); + if (!that) return; + + if (!that.elem || !$(ELEM)[0]) { + return false; + } + + that.position(); +}); + +// 记录所有实例 +thisModule.that = {}; //记录所有实例对象 + +// 获取当前实例对象 +thisModule.getThis = function (id) { + var that = thisModule.that[id]; + if (!that) { + log( + id + ? MOD_NAME + " instance with ID '" + id + "' not found" + : 'ID argument required', + ); + } + return that; +}; + +// 渲染 - 核心接口 +laydate.render = function (options) { + var inst = new Class(options); + return thisModule.call(inst); +}; + +// 重载 +laydate.reload = function (id, options) { + var that = thisModule.getThis(id); + if (!that) return; + return that.reload(options); +}; + +// 获取对应 ID 的实例 +laydate.getInst = function (id) { + var that = thisModule.getThis(id); + if (that) { + return that.inst; + } +}; + +// 面板提示 +laydate.hint = function (id, opts) { + var that = thisModule.getThis(id); + if (!that) return; + return that.hint(opts); +}; + +// 解绑实例 +laydate.unbind = function (id) { + var that = thisModule.getThis(id); + if (!that) return; + return that.unbind(); +}; + +// 关闭日期面板 +laydate.close = function (id) { + var that = thisModule.getThis(id || laydate.thisId); + if (!that) return; + return that.remove(); +}; + +// 将指定对象转化为日期值 +laydate.parse = function (dateTime, format, one) { + dateTime = dateTime || {}; + + //如果 format 是字符型,则转换为数组格式 + if (typeof format === 'string') { + format = thisModule.formatArr(format); + } + + format = (format || []).concat(); + + //转义为规定格式 + format.forEach(function (item, i) { + if (/yyyy|y/.test(item)) { + //年 + format[i] = lay.digit(dateTime.year, item.length); + } else if (/MM|M/.test(item)) { + //月 + format[i] = lay.digit(dateTime.month + (one || 0), item.length); + } else if (/dd|d/.test(item)) { + //日 + format[i] = lay.digit(dateTime.date, item.length); + } else if (/HH|H/.test(item)) { + //时 + format[i] = lay.digit(dateTime.hours, item.length); + } else if (/mm|m/.test(item)) { + //分 + format[i] = lay.digit(dateTime.minutes, item.length); + } else if (/ss|s/.test(item)) { + //秒 + format[i] = lay.digit(dateTime.seconds, item.length); + } + }); + + return format.join(''); +}; + +// 得到某月的最后一天 +laydate.getEndDate = function (month, year) { + var thisDate = new Date(); + //设置日期为下个月的第一天 + thisDate.setFullYear( + year || thisDate.getFullYear(), + month || thisDate.getMonth() + 1, + 1, + ); + //减去一天,得到当前月最后一天 + return new Date(thisDate.getTime() - 1000 * 60 * 60 * 24).getDate(); +}; + +export { laydate }; diff --git a/src/components/layer.js b/src/components/layer.js new file mode 100644 index 000000000..0805b362f --- /dev/null +++ b/src/components/layer.js @@ -0,0 +1,2200 @@ +/** + * layer + * 通用 Web 弹出层组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; + +var win; +var ready = { + config: { + removeFocus: true, + }, + end: {}, + beforeEnd: {}, + events: { resize: {} }, + minStackIndex: 0, + minStackArr: [], + // 五种原始层模式 + type: ['dialog', 'page', 'iframe', 'loading', 'tips'], +}; + +// 默认内置方法。 +var layer = { + config: function (options) { + options = options || {}; + layer.cache = ready.config = $.extend({}, ready.config, options); + typeof options.extend === 'string' && (options.extend = [options.extend]); + + return this; + }, + + // 主体 CSS 等待事件(已弃用) + ready: function (callback) { + typeof callback === 'function' && callback(); + return this; + }, + + // 各种快捷引用 + alert: function (content, options, yes) { + var type = typeof options === 'function'; + if (type) yes = options; + return layer.open( + $.extend( + { + content: content, + yes: yes, + }, + type ? {} : options, + ), + ); + }, + + confirm: function (content, options, yes, cancel) { + var type = typeof options === 'function'; + if (type) { + cancel = yes; + yes = options; + } + return layer.open( + $.extend( + { + content: content, + btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')], + yes: yes, + btn2: cancel, + }, + type ? {} : options, + ), + ); + }, + + msg: function (content, options, end) { + // 最常用提示层 + var type = typeof options === 'function', + rskin = ready.config.skin; + var skin = (rskin ? rskin + ' ' + rskin + '-msg' : '') || 'lay-layer-msg'; + var anim = doms.anim.length - 1; + if (type) end = options; + return layer.open( + $.extend( + { + content: content, + time: 3000, + shade: false, + skin: skin, + title: false, + closeBtn: false, + btn: false, + resize: false, + end: end, + removeFocus: false, + }, + type && !ready.config.skin + ? { + skin: skin + ' lay-layer-hui', + anim: anim, + } + : (function () { + options = options || {}; + if ( + options.icon === -1 || + (options.icon === undefined && !ready.config.skin) + ) { + options.skin = skin + ' ' + (options.skin || 'lay-layer-hui'); + } + return options; + })(), + ), + ); + }, + + load: function (icon, options) { + return layer.open( + $.extend( + { + type: 3, + icon: icon || 0, + resize: false, + shade: 0.01, + removeFocus: false, + }, + options, + ), + ); + }, + + tips: function (content, follow, options) { + return layer.open( + $.extend( + { + type: 4, + content: [content, follow], + closeBtn: false, + time: 3000, + shade: false, + resize: false, + fixed: false, + maxWidth: 260, + removeFocus: false, + }, + options, + ), + ); + }, +}; + +var Class = function (setings) { + var that = this, + creat = function () { + that.creat(); + }; + // TODO 临时的同步方案 + ready.config.title = i18n.$t('layer.defaultTitle'); + that.index = layer.index = lay.autoIncrementer('layer'); + that.config.maxWidth = $(win).width() - 15 * 2; // 初始最大宽度:当前屏幕宽,左右留 15px 边距 + that.config = $.extend({}, that.config, ready.config, setings); + document.body + ? creat() + : setTimeout(function () { + creat(); + }, 30); +}; + +Class.pt = Class.prototype; + +// 缓存常用字符 +var doms = [ + 'lay-layer', + '.lay-layer-title', + '.lay-layer-main', + '.lay-layer-dialog', + 'lay-layer-iframe', + 'lay-layer-content', + 'lay-layer-btn', + 'lay-layer-close', +]; + +// 内置动画类 +doms.anim = { + // 旧版动画 + 0: 'layer-anim-00', + 1: 'layer-anim-01', + 2: 'layer-anim-02', + 3: 'layer-anim-03', + 4: 'layer-anim-04', + 5: 'layer-anim-05', + 6: 'layer-anim-06', + + // 滑出方向 + slideDown: 'layer-anim-slide-down', + slideLeft: 'layer-anim-slide-left', + slideUp: 'layer-anim-slide-up', + slideRight: 'layer-anim-slide-right', +}; + +doms.SHADE = 'lay-layer-shade'; +doms.MOVE = 'lay-layer-move'; + +var SHADE_KEY = 'lay-LAYER-SHADE-KEY'; +var RECORD_HEIGHT_KEY = 'LAYUI_LAYER_CONTENT_RECORD_HEIGHT'; + +// 默认配置 +Class.pt.config = { + type: 0, + shade: 0.3, + fixed: true, + move: doms[1], + title: i18n.$t('layer.defaultTitle'), + offset: 'auto', + area: 'auto', + closeBtn: 1, + icon: -1, + time: 0, // 0 表示不自动关闭 + zIndex: 19891014, + maxWidth: 360, + anim: 0, + isOutAnim: true, // 退出动画 + minStack: true, // 最小化堆叠 + moveType: 1, + resize: true, + scrollbar: true, // 是否允许浏览器滚动条 + tips: 2, +}; + +// 容器 +Class.pt.vessel = function (conType, callback) { + var that = this, + times = that.index, + config = that.config; + var zIndex = config.zIndex + times, + titype = typeof config.title === 'object'; + var ismax = config.maxmin && (config.type === 1 || config.type === 2); + var titleHTML = config.title + ? '
                              ' + + (titype ? config.title[0] : config.title) + + '
                              ' + : ''; + + config.zIndex = zIndex; + callback( + [ + // 遮罩 + config.shade + ? '
                              ' + : '', + + // 主体 + '
                              ' + + (conType && config.type != 2 ? '' : titleHTML) + + // 内容区 + '' + + // 表情或图标 + (function () { + var face = [ + 'lay-icon-tips', + 'lay-icon-success', + 'lay-icon-error', + 'lay-icon-question', + 'lay-icon-lock', + 'lay-icon-face-cry', + 'lay-icon-face-smile', + ]; + + var additFaceClass; + + // 动画类 + var animClass = 'lay-anim lay-anim-rotate lay-anim-loop'; + + // 信息框表情 + if (config.type == 0 && config.icon !== -1) { + // 加载(加载图标) + if (config.icon == 16) { + additFaceClass = 'lay-icon lay-icon-loading ' + animClass; + } + return ( + '' + ); + } + + // 加载层图标 + if (config.type == 3) { + var type = ['lay-icon-loading', 'lay-icon-loading-1']; + // 风格 2 + if (config.icon == 2) { + return ( + '
                              ' + ); + } + return ( + '' + ); + } + + return ''; + })() + + (config.type == 1 && conType ? '' : config.content || '') + + '
                              ' + + // 右上角按钮 + '
                              ' + + (function () { + var arr = []; + + // 最小化、最大化 + if (ismax) { + arr.push(''); + arr.push(''); + } + + // 关闭按钮 + if (config.closeBtn) { + arr.push( + '', + ); + } + + return arr.join(''); + })() + + '
                              ' + + // 底部按钮 + (config.btn + ? (function () { + var button = ''; + typeof config.btn === 'string' && (config.btn = [config.btn]); + for (var i = 0, len = config.btn.length; i < len; i++) { + button += + '' + + config.btn[i] + + ''; + } + return ( + '
                              ' + + button + + '
                              ' + ); + })() + : '') + + (config.resize ? '' : '') + + '
                              ', + ], + titleHTML, + $('
                              '), + ); + return that; +}; + +// 创建骨架 +Class.pt.creat = function () { + var that = this; + var config = that.config; + var times = that.index; + var content = config.content; + var conType = typeof content === 'object'; + var body = $('body'); + + var setAnim = function (layero) { + // anim 兼容旧版 shift + if (config.shift) { + config.anim = config.shift; + } + + // 为兼容 jQuery3.0 的 css 动画影响元素尺寸计算 + if (doms.anim[config.anim]) { + var animClass = 'layer-anim ' + doms.anim[config.anim]; + layero + .addClass(animClass) + .one( + 'webkitAnimationEnd mozAnimationEnd MSAnimationEnd oanimationend animationend', + function () { + $(this).removeClass(animClass); + }, + ); + } + }; + + // 若 id 对应的弹层已经存在,则不重新创建 + if (config.id && $('.' + doms[0]).find('#' + config.id)[0]) { + return (function () { + var layero = $('#' + config.id).closest('.' + doms[0]); + var index = layero.attr('times'); + var options = layero.data('config'); + var elemShade = $('#' + doms.SHADE + index); + + var maxminStatus = layero.data('maxminStatus') || {}; + // 若弹层为最小化状态,则点击目标元素时,自动还原 + if (maxminStatus === 'min') { + layer.restore(index); + } else if (options.hideOnClose) { + elemShade.show(); + layero.show(); + setAnim(layero); + setTimeout(function () { + elemShade.css({ opacity: elemShade.data(SHADE_KEY) }); + }, 10); + } + })(); + } + + // 是否移除活动元素的焦点 + if (config.removeFocus && document.activeElement) { + document.activeElement.blur(); // 将原始的聚焦节点失焦 + } + + // 初始化 area 属性 + if (typeof config.area === 'string') { + config.area = config.area === 'auto' ? ['', ''] : [config.area, '']; + } + + switch (config.type) { + case 0: + config.btn = 'btn' in config ? config.btn : i18n.$t('layer.confirm'); + layer.closeAll('dialog'); + break; + case 2: + content = config.content = conType + ? config.content + : [config.content || '', 'auto']; + config.content = + ''; + break; + case 3: + delete config.title; + delete config.closeBtn; + config.icon === -1 && config.icon === 0; + layer.closeAll('loading'); + break; + case 4: + conType || (config.content = [config.content, 'body']); + config.follow = config.content[1]; + config.content = config.content[0] + ''; + delete config.title; + config.tips = + typeof config.tips === 'object' ? config.tips : [config.tips, true]; + config.tipsMore || layer.closeAll('tips'); + break; + } + + // 建立容器 + that + .vessel(conType, function (html, titleHTML, moveElem) { + body.append(html[0]); + conType + ? (function () { + config.type == 2 || config.type == 4 + ? (function () { + $('body').append(html[1]); + })() + : (function () { + if (!content.parents('.' + doms[0])[0]) { + content + .data('display', content.css('display')) + .show() + .addClass('lay-layer-wrap') + .wrap(html[1]); + $('#' + doms[0] + times) + .find('.' + doms[5]) + .before(titleHTML); + } + })(); + })() + : body.append(html[1]); + $('#' + doms.MOVE)[0] || body.append((ready.moveElem = moveElem)); + + that.layero = $('#' + doms[0] + times); + that.shadeo = $('#' + doms.SHADE + times); + + config.scrollbar || ready.setScrollbar(times); + }) + .auto(times); + + // 遮罩 + that.shadeo.css({ + 'background-color': config.shade[1] || '#000', + opacity: config.shade[0] || config.shade, + transition: config.shade[2] || '', + }); + that.shadeo.data(SHADE_KEY, config.shade[0] || config.shade); + + // 坐标自适应浏览器窗口尺寸 + config.type == 4 + ? that.tips() + : (function () { + that.offset(); + // 首次弹出时,若 css 尚未加载,则等待 css 加载完毕后,重新设定尺寸 + parseInt(lay.getStyle(document.getElementById(doms.MOVE), 'z-index')) || + (function () { + that.layero.css('visibility', 'hidden'); + layer.ready(function () { + that.offset(); + that.layero.css('visibility', 'visible'); + }); + })(); + })(); + + // 若是固定定位,则跟随 resize 事件来自适应坐标 + if (config.fixed) { + if (!ready.events.resize[that.index]) { + ready.events.resize[that.index] = function () { + that.resize(); + }; + // 此处 resize 事件不会一直叠加,当关闭弹层时会移除该事件 + win.on('resize', ready.events.resize[that.index]); + } + } + + // 记录配置信息 + that.layero.data('config', config); + + // 自动关闭 + config.time <= 0 || + setTimeout(function () { + layer.close(that.index); + }, config.time); + + that.move().callback(); + setAnim(that.layero); +}; + +// 当前实例的 resize 事件 +Class.pt.resize = function () { + var that = this; + var config = that.config; + + that.offset(); + (/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) && + that.auto(that.index); + config.type == 4 && that.tips(); +}; + +// 自适应 +Class.pt.auto = function (index) { + var that = this, + config = that.config, + layero = $('#' + doms[0] + index); + + if ( + (config.area[0] === '' || config.area[0] === 'auto') && + config.maxWidth > 0 + ) { + layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth); + } + + var area = [layero.innerWidth(), layero.innerHeight()]; + var titHeight = layero.find(doms[1]).outerHeight() || 0; + var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + var setHeight = function (elem) { + elem = layero.find(elem); + elem.height( + area[1] - + titHeight - + btnHeight - + 2 * (parseFloat(elem.css('padding-top')) | 0), + ); + }; + + switch (config.type) { + case 2: + setHeight('iframe'); + break; + default: + if (config.area[1] === '' || config.area[1] === 'auto') { + if (config.maxHeight > 0 && layero.outerHeight() > config.maxHeight) { + area[1] = config.maxHeight; + setHeight('.' + doms[5]); + } else if (config.fixed && area[1] >= win.height()) { + area[1] = win.height(); + setHeight('.' + doms[5]); + } + } else { + setHeight('.' + doms[5]); + } + break; + } + + return that; +}; + +// 计算坐标 +Class.pt.offset = function () { + var that = this, + config = that.config, + layero = that.layero; + var coords = ready.updatePosition(layero, config); + + that.offsetTop = coords.offsetTop; + that.offsetLeft = coords.offsetLeft; +}; + +// Tips +Class.pt.tips = function () { + var that = this, + config = that.config, + layero = that.layero; + var layArea = [layero.outerWidth(), layero.outerHeight()], + follow = $(config.follow); + if (!follow[0]) follow = $('body'); + var goal = { + width: follow.outerWidth(), + height: follow.outerHeight(), + top: follow.offset().top, + left: follow.offset().left, + }, + tipsG = layero.find('.lay-layer-TipsG'); + + var guide = config.tips[0]; + config.tips[1] || tipsG.remove(); + + goal.autoLeft = function () { + if (goal.left + layArea[0] - win.width() > 0) { + goal.tipLeft = goal.left + goal.width - layArea[0]; + tipsG.css({ right: 12, left: 'auto' }); + } else { + goal.tipLeft = + goal.left - (goal.width * 0.75 < 21 ? 21 - goal.width * 0.5 : 0); + goal.tipLeft = Math.max(goal.tipLeft, 0); + } + }; + + // 辨别 tips 的方位 + // 21 为箭头大小 8*2 + 箭头相对父元素的top偏移 5 + goal.where = [ + function () { + // 上 + goal.autoLeft(); + goal.tipTop = goal.top - layArea[1] - 10; + tipsG + .removeClass('lay-layer-TipsB') + .addClass('lay-layer-TipsT') + .css('border-right-color', config.tips[1]); + }, + function () { + // 右 + goal.tipLeft = goal.left + goal.width + 10; + goal.tipTop = + goal.top - (goal.height * 0.75 < 21 ? 21 - goal.height * 0.5 : 0); + goal.tipTop = Math.max(goal.tipTop, 0); + tipsG + .removeClass('lay-layer-TipsL') + .addClass('lay-layer-TipsR') + .css('border-bottom-color', config.tips[1]); + }, + function () { + // 下 + goal.autoLeft(); + goal.tipTop = goal.top + goal.height + 10; + tipsG + .removeClass('lay-layer-TipsT') + .addClass('lay-layer-TipsB') + .css('border-right-color', config.tips[1]); + }, + function () { + // 左 + goal.tipLeft = goal.left - layArea[0] - 10; + goal.tipTop = + goal.top - (goal.height * 0.75 < 21 ? 21 - goal.height * 0.5 : 0); + goal.tipTop = Math.max(goal.tipTop, 0); + tipsG + .removeClass('lay-layer-TipsR') + .addClass('lay-layer-TipsL') + .css('border-bottom-color', config.tips[1]); + }, + ]; + goal.where[guide - 1](); + + /* 8*2为小三角形占据的空间 */ + if (guide === 1) { + goal.top - (win.scrollTop() + layArea[1] + 8 * 2) < 0 && goal.where[2](); + } else if (guide === 2) { + win.width() - (goal.left + goal.width + layArea[0] + 8 * 2) > 0 || + goal.where[3](); + } else if (guide === 3) { + goal.top - + win.scrollTop() + + goal.height + + layArea[1] + + 8 * 2 - + win.height() > + 0 && goal.where[0](); + } else if (guide === 4) { + layArea[0] + 8 * 2 - goal.left > 0 && goal.where[1](); + } + + layero.find('.' + doms[5]).css({ + 'background-color': config.tips[1], + 'padding-right': config.closeBtn ? '30px' : '', + }); + layero.css({ + left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0), + top: goal.tipTop - (config.fixed ? win.scrollTop() : 0), + }); +}; + +// 拖拽层 +Class.pt.move = function () { + var that = this; + var config = that.config; + var _DOC = $(document); + var layero = that.layero; + var DATA_NAME = ['LAY_MOVE_DICT', 'LAY_RESIZE_DICT']; + var moveElem = layero.find(config.move); + var resizeElem = layero.find('.lay-layer-resize'); + + // 给指定元素添加拖动光标 + if (config.move) moveElem.css('cursor', 'move'); + + // 按下拖动元素 + moveElem.on('mousedown', function (e) { + if (e.button) { + return; + } // 不是左键不处理 + var othis = $(this); + var dict = {}; + + if (config.move) { + dict.layero = layero; + dict.config = config; + dict.offset = [ + e.clientX - parseFloat(layero.css('left')), + e.clientY - parseFloat(layero.css('top')), + ]; + + othis.data(DATA_NAME[0], dict); + ready.eventMoveElem = othis; + ready.moveElem.css('cursor', 'move').show(); + } + + e.preventDefault(); + }); + + // 按下右下角拉伸 + resizeElem.on('mousedown', function (e) { + var othis = $(this); + var dict = {}; + + if (config.resize) { + dict.layero = layero; + dict.config = config; + dict.offset = [e.clientX, e.clientY]; + dict.index = that.index; + dict.area = [layero.outerWidth(), layero.outerHeight()]; + + othis.data(DATA_NAME[1], dict); + ready.eventResizeElem = othis; + ready.moveElem.css('cursor', 'se-resize').show(); + } + + e.preventDefault(); + }); + + // 拖动元素,避免多次调用实例造成事件叠加 + if (ready.docEvent) return that; + _DOC + .on('mousemove', function (e) { + var dict, config, X, Y; + + // 拖拽移动 + if (ready.eventMoveElem) { + dict = ready.eventMoveElem.data(DATA_NAME[0]) || {}; + config = dict.config; + X = e.clientX - dict.offset[0]; + Y = e.clientY - dict.offset[1]; + + var layero = dict.layero; + var fixed = layero.css('position') === 'fixed'; + + e.preventDefault(); + + dict.stX = fixed ? 0 : win.scrollLeft(); + dict.stY = fixed ? 0 : win.scrollTop(); + + // 控制元素不被拖出窗口外 + if (!config.moveOut) { + var setRig = win.width() - layero.outerWidth() + dict.stX; + var setBot = win.height() - layero.outerHeight() + dict.stY; + X < dict.stX && (X = dict.stX); + X > setRig && (X = setRig); + Y < dict.stY && (Y = dict.stY); + Y > setBot && (Y = setBot); + } + + // 拖动时跟随鼠标位置 + layero.css({ + left: X, + top: Y, + }); + } + + // Resize + if (ready.eventResizeElem) { + dict = ready.eventResizeElem.data(DATA_NAME[1]) || {}; + config = dict.config; + X = e.clientX - dict.offset[0]; + Y = e.clientY - dict.offset[1]; + + e.preventDefault(); + + // 拉伸宽高 + layer.style(dict.index, { + width: dict.area[0] + X, + height: dict.area[1] + Y, + }); + + config.resizing && config.resizing(dict.layero); + } + }) + .on('mouseup', function () { + if (ready.eventMoveElem) { + var dict = ready.eventMoveElem.data(DATA_NAME[0]) || {}; + var config = dict.config; + + ready.eventMoveElem.removeData(DATA_NAME[0]); + delete ready.eventMoveElem; + ready.moveElem.hide(); + config.moveEnd && config.moveEnd(dict.layero); + } + if (ready.eventResizeElem) { + ready.eventResizeElem.removeData(DATA_NAME[1]); + delete ready.eventResizeElem; + ready.moveElem.hide(); + } + }); + + ready.docEvent = true; // 已给 document 执行全局事件 + return that; +}; + +Class.pt.btnLoading = function (btnElem, isLoading) { + if (isLoading) { + var loadingTpl = + ''; + if (btnElem.find('.lay-layer-btn-loading-icon')[0]) return; + btnElem + .addClass('lay-layer-btn-is-loading') + .attr({ disabled: '' }) + .prepend(loadingTpl); + } else { + btnElem + .removeClass('lay-layer-btn-is-loading') + .removeAttr('disabled') + .find('.lay-layer-btn-loading-icon') + .remove(); + } +}; + +Class.pt.callback = function () { + var that = this, + layero = that.layero, + config = that.config; + that.openLayer(); + if (config.success) { + if (config.type == 2) { + layero.find('iframe').on('load', function () { + config.success(layero, that.index, that); + }); + } else { + config.success(layero, that.index, that); + } + } + + // 按钮 + layero + .find('.' + doms[6]) + .children('a') + .on('click', function () { + var btnElem = $(this); + var index = btnElem.index(); + if (btnElem.attr('disabled')) return; + + // 若为异步按钮 + if (config.btnAsync) { + var btnCallback = + index === 0 + ? config.yes || config['btn1'] + : config['btn' + (index + 1)]; + that.loading = function (isLoading) { + that.btnLoading(btnElem, isLoading); + }; + + if (btnCallback) { + ready + .promiseLikeResolve( + btnCallback.call(config, that.index, layero, that), + ) + .then( + function (result) { + if (result !== false) { + layer.close(that.index); + } + }, + function (reason) { + reason !== undefined && + window.console && + window.console.error('layer error hint: ' + reason); + }, + ); + } else { + layer.close(that.index); + } + } else { + // 普通按钮 + if (index === 0) { + if (config.yes) { + config.yes(that.index, layero, that); + } else if (config['btn1']) { + config['btn1'](that.index, layero, that); + } else { + layer.close(that.index); + } + } else { + var close = + config['btn' + (index + 1)] && + config['btn' + (index + 1)](that.index, layero, that); + close === false || layer.close(that.index); + } + } + }); + + // 取消 + function cancel() { + var close = config.cancel && config.cancel(that.index, layero, that); + close === false || layer.close(that.index); + } + + // 右上角关闭回调 + layero.find('.' + doms[7]).on('click', cancel); + + // 点遮罩关闭 + if (config.shadeClose) { + that.shadeo.on('click', function () { + layer.close(that.index); + }); + } + + // 最小化 + layero.find('.lay-layer-min').on('click', function () { + var min = config.min && config.min(layero, that.index, that); + min === false || layer.min(that.index, config); + }); + + // 全屏/还原 + layero.find('.lay-layer-max').on('click', function () { + if ($(this).hasClass('lay-layer-maxmin')) { + layer.restore(that.index); + config.restore && config.restore(layero, that.index, that); + } else { + layer.full(that.index, config); + setTimeout(function () { + config.full && config.full(layero, that.index, that); + }, 100); + } + }); + + config.end && (ready.end[that.index] = config.end); + config.beforeEnd && + (ready.beforeEnd[that.index] = $.proxy( + config.beforeEnd, + config, + layero, + that.index, + that, + )); +}; + +// 需依赖原型的对外方法 +Class.pt.openLayer = function () { + var that = this; + + // 置顶当前窗口 + layer.zIndex = that.config.zIndex; + layer.setTop = function (layero) { + var setZindex = function () { + layer.zIndex++; + layero.css('z-index', layer.zIndex + 1); + }; + layer.zIndex = parseInt(layero[0].style.zIndex); + layero.on('mousedown', setZindex); + return layer.zIndex; + }; +}; + +// 记录宽高坐标,用于还原 +ready.record = function (layero) { + if (!layero[0]) return window.console && console.error('index error'); + var type = layero.attr('type'); + var contentElem = layero.find('.lay-layer-content'); + var contentRecordHeightElem = + type === ready.type[2] ? contentElem.children('iframe') : contentElem; + var area = [ + layero[0].style.width || lay.getStyle(layero[0], 'width'), + layero[0].style.height || lay.getStyle(layero[0], 'height'), + layero.position().top, + layero.position().left + parseFloat(layero.css('margin-left')), + ]; + layero.find('.lay-layer-max').addClass('lay-layer-maxmin'); + layero.attr({ area: area }); + contentElem.data( + RECORD_HEIGHT_KEY, + lay.getStyle(contentRecordHeightElem[0], 'height'), + ); +}; + +// 设置页面滚动条 +ready.setScrollbar = function () { + doms.html.css('overflow', 'hidden'); +}; + +// 恢复页面滚动条 +ready.restScrollbar = function (index) { + if (!doms.html.css('overflow')) return; + + // 关闭和大小化, layer-full 处理 + var targetEl = $('.' + doms[0]).filter(function () { + var layero = $(this); + var options = layero.data('config') || {}; + return ( + options.scrollbar === false && + layero.data('maxminStatus') !== 'min' && + layero.attr('times') !== String(index) + ); + }); + if (targetEl.length === 0) { + doms.html.css('overflow', ''); + } +}; + +// 类似 Promise.resolve +ready.promiseLikeResolve = function (value) { + var deferred = $.Deferred(); + + if (value && typeof value.then === 'function') { + value.then(deferred.resolve, deferred.reject); + } else { + deferred.resolve(value); + } + return deferred.promise(); +}; + +ready.updatePosition = function (layero, config) { + var area = [layero.outerWidth(), layero.outerHeight()]; + var coords = { + offsetTop: (win.height() - area[1]) / 2, + offsetLeft: (win.width() - area[0]) / 2, + }; + + if (typeof config.offset === 'object') { + coords.offsetTop = config.offset[0]; + coords.offsetLeft = config.offset[1] || coords.offsetLeft; + } else if (config.offset !== 'auto') { + if (config.offset === 't') { + // 上 + coords.offsetTop = 0; + } else if (config.offset === 'r') { + // 右 + coords.offsetLeft = win.width() - area[0]; + } else if (config.offset === 'b') { + // 下 + coords.offsetTop = win.height() - area[1]; + } else if (config.offset === 'l') { + // 左 + coords.offsetLeft = 0; + } else if (config.offset === 'lt') { + // 左上 + coords.offsetTop = 0; + coords.offsetLeft = 0; + } else if (config.offset === 'lb') { + // 左下 + coords.offsetTop = win.height() - area[1]; + coords.offsetLeft = 0; + } else if (config.offset === 'rt') { + // 右上 + coords.offsetTop = 0; + coords.offsetLeft = win.width() - area[0]; + } else if (config.offset === 'rb') { + // 右下 + coords.offsetTop = win.height() - area[1]; + coords.offsetLeft = win.width() - area[0]; + } else { + coords.offsetTop = config.offset; + } + } + + if (!config.fixed) { + coords.offsetTop = /%$/.test(coords.offsetTop) + ? (win.height() * parseFloat(coords.offsetTop)) / 100 + : parseFloat(coords.offsetTop); + coords.offsetLeft = /%$/.test(coords.offsetLeft) + ? (win.width() * parseFloat(coords.offsetLeft)) / 100 + : parseFloat(coords.offsetLeft); + coords.offsetTop += win.scrollTop(); + coords.offsetLeft += win.scrollLeft(); + } + + // 最小化窗口时的自适应 + if (layero.data('maxminStatus') === 'min') { + coords.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0); + coords.offsetLeft = layero.css('left'); + } + + // 设置坐标 + layero.css({ + top: coords.offsetTop, + left: coords.offsetLeft, + }); + + return coords; +}; + +/** + * 外部方法 + */ + +// 获取子 iframe 的 DOM +layer.getChildFrame = function (selector, index) { + index = index || $('.' + doms[4]).attr('times'); + return $('#' + doms[0] + index) + .find('iframe') + .contents() + .find(selector); +}; + +// 得到当前 iframe 层的索引,子 iframe 时使用 +layer.getFrameIndex = function (name) { + if (!name) return; + return $('#' + name) + .parents('.' + doms[4]) + .attr('times'); +}; + +// iframe 层自适应宽高 +layer.iframeAuto = function (index) { + if (!index) return; + var layero = $('#' + doms[0] + index); + var options = layero.data('config'); + var iframeHeight = layer.getChildFrame('html', index).outerHeight(); + var titleHeight = layero.find(doms[1]).outerHeight() || 0; + var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + var maxHeight = 'maxHeight' in options ? options.maxHeight : win.height(); + if (maxHeight) { + iframeHeight = Math.min(iframeHeight, maxHeight - titleHeight - btnHeight); + } + layero.css({ height: iframeHeight + titleHeight + btnHeight }); + layero.find('iframe').css({ height: iframeHeight }); + + ready.updatePosition(layero, options); +}; + +// 重置 iframe url +layer.iframeSrc = function (index, url) { + $('#' + doms[0] + index) + .find('iframe') + .attr('src', url); +}; + +// 设定层的样式 +layer.style = function (index, options, limit) { + var layero = $('#' + doms[0] + index); + var contentElem = layero.find('.lay-layer-content'); + var type = layero.attr('type'); + var titHeight = layero.find(doms[1]).outerHeight() || 0; + var btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + // var minLeft = layero.attr('minLeft'); + + // loading 和 tips 层不允许更改 + if (type === ready.type[3] || type === ready.type[4]) { + return; + } + + if (!limit) { + if (parseFloat(options.width) <= 260) { + options.width = 260; + } + + if (parseFloat(options.height) - titHeight - btnHeight <= 64) { + options.height = 64 + titHeight + btnHeight; + } + } + layero.css(options); + btnHeight = layero.find('.' + doms[6]).outerHeight() || 0; + + if (type === ready.type[2]) { + layero.find('iframe').css({ + height: + (typeof options.height === 'number' + ? options.height + : layero.height()) - + titHeight - + btnHeight, + }); + } else { + contentElem.css({ + height: + (typeof options.height === 'number' + ? options.height + : layero.height()) - + titHeight - + btnHeight - + parseFloat(contentElem.css('padding-top')) - + parseFloat(contentElem.css('padding-bottom')), + }); + } +}; + +// 最小化 +layer.min = function (index, options) { + var layero = $('#' + doms[0] + index); + var maxminStatus = layero.data('maxminStatus'); + + if (maxminStatus === 'min') return; // 当前的状态是否已经是最小化 + if (maxminStatus === 'max') layer.restore(index); // 若当前为最大化,则先还原后再最小化 + + layero.data('maxminStatus', 'min'); + options = options || layero.data('config') || {}; + + var shadeo = $('#' + doms.SHADE + index); + var elemMin = layero.find('.lay-layer-min'); + var titHeight = layero.find(doms[1]).outerHeight() || 0; + var minLeft = layero.attr('minLeft'); // 最小化时的横坐标 + var hasMinLeft = typeof minLeft === 'string'; // 是否已经赋值过最小化坐标 + var left = hasMinLeft ? minLeft : 181 * ready.minStackIndex + 'px'; + var position = layero.css('position'); + var minWidth = 180; // 最小化时的宽度 + var settings = { + width: minWidth, + height: titHeight, + position: 'fixed', + overflow: 'hidden', + }; + + ready.record(layero); // 记录当前尺寸、坐标,用于还原 + + // 简易最小化补位 + if (ready.minStackArr.length > 0) { + left = ready.minStackArr[0]; + ready.minStackArr.shift(); + } + + // left 是否超出边界 + if (parseFloat(left) + minWidth > win.width()) { + left = + win.width() - + minWidth - + (function () { + ready.minStackArr.edgeIndex = ready.minStackArr.edgeIndex || 0; + return (ready.minStackArr.edgeIndex += 3); + })(); + if (left < 0) left = 0; + } + + // 是否堆叠在左下角 + if (options.minStack) { + settings.left = left; + settings.top = win.height() - titHeight; + hasMinLeft || ready.minStackIndex++; // 若未赋值过最小化坐标,则最小化操作索引自增 + layero.attr('minLeft', left); + } + + layero.attr('position', position); + layer.style(index, settings, true); + + elemMin.hide(); + layero.attr('type') === 'page' && layero.find(doms[4]).hide(); + ready.restScrollbar(index); + + // 隐藏遮罩 + shadeo.hide(); +}; + +// 还原 +layer.restore = function (index) { + var layero = $('#' + doms[0] + index); + var shadeo = $('#' + doms.SHADE + index); + var contentElem = layero.find('.lay-layer-content'); + var area = layero.attr('area').split(','); + var type = layero.attr('type'); + var options = layero.data('config') || {}; + var contentRecordHeight = contentElem.data(RECORD_HEIGHT_KEY); + + layero.removeData('maxminStatus'); // 移除最大最小状态 + + // 恢复原来尺寸 + layer.style( + index, + { + width: area[0], // 数值或百分比 + height: area[1], + top: parseFloat(area[2]), + left: parseFloat(area[3]), + position: layero.attr('position'), + overflow: 'visible', + }, + true, + ); + + layero.find('.lay-layer-max').removeClass('lay-layer-maxmin'); + layero.find('.lay-layer-min').show(); + type === 'page' && layero.find(doms[4]).show(); + + // 恢复页面滚动条弹层打开时的状态 + options.scrollbar ? ready.restScrollbar(index) : ready.setScrollbar(index); + + // #1604 + if (contentRecordHeight !== undefined) { + contentElem.removeData(RECORD_HEIGHT_KEY); + var contentRecordHeightElem = + type === ready.type[2] ? contentElem.children('iframe') : contentElem; + contentRecordHeightElem.css({ height: contentRecordHeight }); + } + + // 恢复遮罩 + shadeo.show(); + // ready.events.resize[index](); // ? +}; + +// 全屏(最大化) +layer.full = function (index) { + var layero = $('#' + doms[0] + index); + var maxminStatus = layero.data('maxminStatus'); + + if (maxminStatus === 'max') return; // 检查当前的状态是否已经是最大化 + if (maxminStatus === 'min') layer.restore(index); // 若当前为最小化,则先还原后再最大化 + + layero.data('maxminStatus', 'max'); + ready.record(layero); // 记录当前尺寸、坐标 + + ready.setScrollbar(index); + + setTimeout(function () { + var isfix = layero.css('position') === 'fixed'; + layer.style( + index, + { + top: isfix ? 0 : win.scrollTop(), + left: isfix ? 0 : win.scrollLeft(), + width: '100%', + height: '100%', + }, + true, + ); + layero.find('.lay-layer-min').hide(); + }, 100); +}; + +// 改变 title +layer.title = function (name, index) { + var title = $('#' + doms[0] + (index || layer.index)).find(doms[1]); + title.html(name); +}; + +// 关闭 layer 总方法 +layer.close = function (index, callback) { + var layero = (function () { + var closest = $('.' + doms[0]) + .children('#' + index) + .closest('.' + doms[0]); + return closest[0] + ? ((index = closest.attr('times')), closest) + : $('#' + doms[0] + index); + })(); + var type = layero.attr('type'); + var options = layero.data('config') || {}; + var hideOnClose = options.id && options.hideOnClose; // 是否关闭时移除弹层容器 + + if (!layero[0]) return; + + var executor = function () { + // 关闭动画 + var closeAnim = + { + slideDown: 'layer-anim-slide-down-out', + slideLeft: 'layer-anim-slide-left-out', + slideUp: 'layer-anim-slide-up-out', + slideRight: 'layer-anim-slide-right-out', + }[options.anim] || 'layer-anim-close'; + + // 移除主容器 + var remove = function () { + var WRAP = 'lay-layer-wrap'; + + // 是否关闭时隐藏弹层容器 + if (hideOnClose) { + layero.removeClass('layer-anim ' + closeAnim); + return layero.hide(); + } + + // 是否为页面捕获层 + if (type === ready.type[1] && layero.attr('conType') === 'object') { + layero.children(':not(.' + doms[5] + ')').remove(); + var wrap = layero.find('.' + WRAP); + for (var i = 0; i < 2; i++) { + wrap.unwrap(); + } + wrap.css('display', wrap.data('display')).removeClass(WRAP); + } else { + layero[0].innerHTML = ''; + layero.remove(); + } + + typeof ready.end[index] === 'function' && ready.end[index](); + delete ready.end[index]; + typeof callback === 'function' && callback(); + + // 移除 reisze 事件 + if (ready.events.resize[index]) { + win.off('resize', ready.events.resize[index]); + delete ready.events.resize[index]; + } + }; + // 移除遮罩 + var shadeo = $('#' + doms.SHADE + index); + if (!options.isOutAnim) { + shadeo[hideOnClose ? 'hide' : 'remove'](); + } else { + shadeo.css({ opacity: 0 }); + setTimeout(function () { + shadeo[hideOnClose ? 'hide' : 'remove'](); + }, 350); + } + + // 是否允许关闭动画 + if (options.isOutAnim) { + layero.addClass('layer-anim ' + closeAnim); + } + + ready.restScrollbar(index); + + // 记住被关闭层的最小化堆叠坐标 + if (typeof layero.attr('minLeft') === 'string') { + ready.minStackIndex--; + ready.minStackArr.push(layero.attr('minLeft')); + } + + if (!options.isOutAnim) { + remove(); + } else { + setTimeout(function () { + remove(); + }, 200); + } + }; + + if (!hideOnClose && typeof ready.beforeEnd[index] === 'function') { + ready.promiseLikeResolve(ready.beforeEnd[index]()).then( + function (result) { + if (result !== false) { + delete ready.beforeEnd[index]; + executor(); + } + }, + function (reason) { + reason !== undefined && + window.console && + window.console.error('layer error hint: ' + reason); + }, + ); + } else { + delete ready.beforeEnd[index]; + executor(); + } +}; + +// 关闭所有层 +layer.closeAll = function (type, callback) { + if (typeof type === 'function') { + callback = type; + type = null; + } + var domsElem = $('.' + doms[0]); + $.each(domsElem, function (_index) { + var othis = $(this); + var is = type ? othis.attr('type') === type : 1; + is && + layer.close( + othis.attr('times'), + _index === domsElem.length - 1 ? callback : null, + ); + is = null; + }); + if (domsElem.length === 0) typeof callback === 'function' && callback(); +}; + +// 根据弹层类型关闭最近打开的层 +layer.closeLast = function (type, callback) { + var layerIndexList = []; + var isArrayType = Array.isArray(type); + $(typeof type === 'string' ? '.lay-layer-' + type : '.lay-layer').each( + function (i, el) { + var layero = $(el); + var shouldSkip = + (isArrayType && type.indexOf(layero.attr('type')) === -1) || + layero.css('display') === 'none'; + if (shouldSkip) return true; + layerIndexList.push(Number(layero.attr('times'))); + }, + ); + if (layerIndexList.length > 0) { + var layerIndexMax = Math.max.apply(null, layerIndexList); + layer.close(layerIndexMax, callback); + } +}; + +/* + * 拓展模块,layui 开始合并在一起 + */ + +var cache = layer.cache || {}; +var skin = function (type) { + return cache.skin ? ' ' + cache.skin + ' ' + cache.skin + '-' + type : ''; +}; + +// 仿系统 prompt +layer.prompt = function (options, yes) { + var style = ''; + var placeholder = ''; + options = options || {}; + + // 兼容旧版参数 + var legacyTypeMap = { + 0: 'text', + 1: 'password', + 2: 'textarea', + }; + if (options.formType in legacyTypeMap) { + options.formType = legacyTypeMap[options.formType]; + } + + if (typeof options === 'function') yes = options; + + if (options.area) { + var area = options.area; + style = 'style="width: ' + area[0] + '; height: ' + area[1] + ';"'; + delete options.area; + } + if (options.placeholder) { + placeholder = ' placeholder="' + options.placeholder + '"'; + } + var prompt; + var content = + options.formType == 'textarea' + ? '' + : (function () { + return ( + '' + ); + })(); + + var success = options.success; + delete options.success; + + return layer.open( + $.extend( + { + type: 1, + btn: [i18n.$t('layer.confirm'), i18n.$t('layer.cancel')], + content: content, + skin: 'lay-layer-prompt' + skin('prompt'), + maxWidth: win.width(), + success: function (layero) { + prompt = layero.find('.lay-layer-input'); + prompt.val(options.value || '').focus(); + typeof success === 'function' && success(layero); + }, + resize: false, + yes: function (index) { + var value = prompt.val(); + if (value.length > (options.maxlength || 500)) { + layer.tips( + i18n.$t('layer.prompt.inputLengthPrompt', { + length: options.maxlength || 500, + }), + prompt, + { tips: 1 }, + ); + } else { + yes && yes(value, index, prompt); + } + }, + }, + options, + ), + ); +}; + +// tab 层 +layer.tab = function (options) { + options = options || {}; + + var tab = options.tab || {}; + var THIS = 'lay-this'; + var success = options.success; + + delete options.success; + + return layer.open( + $.extend( + { + type: 1, + skin: 'lay-layer-tab' + skin('tab'), + resize: false, + title: (function () { + var len = tab.length, + ii = 1, + str = ''; + if (len > 0) { + str = '' + tab[0].title + ''; + for (; ii < len; ii++) { + str += '' + tab[ii].title + ''; + } + } + return str; + })(), + content: + '
                                ' + + (function () { + var len = tab.length, + ii = 1, + str = ''; + if (len > 0) { + str = + '
                              • ' + + (tab[0].content || 'no content') + + '
                              • '; + for (; ii < len; ii++) { + str += + '
                              • ' + + (tab[ii].content || 'no content') + + '
                              • '; + } + } + return str; + })() + + '
                              ', + success: function (layero) { + var btn = layero.find('.lay-layer-title').children(); + var main = layero.find('.lay-layer-tabmain').children(); + btn.on('mousedown', function (e) { + e.stopPropagation ? e.stopPropagation() : (e.cancelBubble = true); + var othis = $(this), + index = othis.index(); + othis.addClass(THIS).siblings().removeClass(THIS); + main.eq(index).show().siblings().hide(); + typeof options.change === 'function' && options.change(index); + }); + typeof success === 'function' && success(layero); + }, + }, + options, + ), + ); +}; + +// 图片层 +layer.photos = function (options, loop, key) { + var dict = {}; + + // 默认属性 + options = $.extend( + true, + { + toolbar: true, + footer: true, + }, + options, + ); + + if (!options.photos) return; + + // 若 photos 并非选择器或 jQuery 对象,则为普通 object + var isObject = !( + typeof options.photos === 'string' || options.photos instanceof $ + ); + var photos = isObject ? options.photos : {}; + var data = photos.data || []; + var start = photos.start || 0; + var success = options.success; + + dict.imgIndex = (start | 0) + 1; + options.img = options.img || 'img'; + delete options.success; + + // 若 options.photos 不是一个对象 + if (!isObject) { + // 页面直接获取 + var parent = $(options.photos), + pushData = function () { + data = []; + parent.find(options.img).each(function (index) { + var othis = $(this); + othis.attr('layer-index', index); + data.push({ + alt: othis.attr('alt'), + pid: othis.attr('layer-pid'), + src: + othis.attr('lay-src') || + othis.attr('layer-src') || + othis.attr('src'), + thumb: othis.attr('src'), + }); + }); + }; + + pushData(); + + loop || + parent.on('click', options.img, function () { + pushData(); + var othis = $(this), + index = othis.attr('layer-index'); + layer.photos( + $.extend(options, { + photos: { + start: index, + data: data, + tab: options.tab, + }, + full: options.full, + }), + true, + ); + }); + + // 不直接弹出 + if (!loop) return; + } else if (data.length === 0) { + return layer.msg(i18n.$t('layer.photos.noData')); + } + + // 上一张 + dict.imgprev = function (key) { + dict.imgIndex--; + if (dict.imgIndex < 1) { + dict.imgIndex = data.length; + } + dict.tabimg(key); + }; + + // 下一张 + dict.imgnext = function (key, errorMsg) { + dict.imgIndex++; + if (dict.imgIndex > data.length) { + dict.imgIndex = 1; + if (errorMsg) { + return; + } + } + dict.tabimg(key); + }; + + // 方向键 + dict.keyup = function (event) { + if (!dict.end) { + var code = event.keyCode; + event.preventDefault(); + if (code === 37) { + dict.imgprev(true); + } else if (code === 39) { + dict.imgnext(true); + } else if (code === 27) { + layer.close(dict.index); + } + } + }; + + // 切换 + dict.tabimg = function (key) { + if (data.length <= 1) return; + photos.start = dict.imgIndex - 1; + layer.close(dict.index); + return layer.photos(options, true, key); + }; + + dict.isNumber = function (n) { + return typeof n === 'number' && !isNaN(n); + }; + + dict.image = {}; + + dict.getTransform = function (opts) { + var transforms = []; + var rotate = opts.rotate; + var scaleX = opts.scaleX; + var scale = opts.scale; + + if (dict.isNumber(rotate) && rotate !== 0) { + transforms.push('rotate(' + rotate + 'deg)'); + } + + if (dict.isNumber(scaleX) && scaleX !== 1) { + transforms.push('scaleX(' + scaleX + ')'); + } + + if (dict.isNumber(scale)) { + transforms.push('scale(' + scale + ')'); + } + + return transforms.length ? transforms.join(' ') : 'none'; + }; + + // 一些动作 + dict.event = function (layero, index, that) { + // 上一张 + dict.main.find('.lay-layer-photos-prev').on('click', function (event) { + event.preventDefault(); + dict.imgprev(true); + }); + + // 下一张 + dict.main.find('.lay-layer-photos-next').on('click', function (event) { + event.preventDefault(); + dict.imgnext(true); + }); + + $(document).on('keyup', dict.keyup); + + // 头部工具栏事件 + layero.off('click').on('click', '*[toolbar-event]', function () { + var othis = $(this); + var event = othis.attr('toolbar-event'); + switch (event) { + case 'rotate': + dict.image.rotate = + ((dict.image.rotate || 0) + Number(othis.attr('data-option'))) % + 360; + dict.imgElem.css({ + transform: dict.getTransform(dict.image), + }); + break; + case 'scalex': + dict.image.scaleX = dict.image.scaleX === -1 ? 1 : -1; + dict.imgElem.css({ + transform: dict.getTransform(dict.image), + }); + break; + case 'zoom': + var ratio = Number(othis.attr('data-option')); + dict.image.scale = (dict.image.scale || 1) + ratio; + // 缩小状态最小值 + if (ratio < 0 && dict.image.scale < 0 - ratio) { + dict.image.scale = 0 - ratio; + } + dict.imgElem.css({ + transform: dict.getTransform(dict.image), + }); + break; + case 'reset': + dict.image.scaleX = 1; + dict.image.scale = 1; + dict.image.rotate = 0; + dict.imgElem.css({ + transform: 'none', + }); + break; + case 'close': + layer.close(index); + break; + } + that.offset(); + that.auto(index); + }); + + // 鼠标滚轮缩放图片事件 + dict.main.on('mousewheel DOMMouseScroll', function (e) { + var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail; + var zoomElem = dict.main.find('[toolbar-event="zoom"]'); + if (delta > 0) { + zoomElem.eq(0).trigger('click'); + } else { + zoomElem.eq(1).trigger('click'); + } + e.preventDefault(); + }); + + // 滑动切换图片事件 + var touchEndCallback = function (e, state) { + var duration = Date.now() - state.timeStart; + var speed = state.distanceX / duration; + var threshold = win.width() / 3; + var shouldSwipe = + Math.abs(speed) > 0.25 || Math.abs(state.distanceX) > threshold; + if (!shouldSwipe) return; + if (state.direction === 'left') { + dict.imgnext(true); + } else if (state.direction === 'right') { + dict.imgprev(true); + } + }; + + $.each([that.shadeo, dict.main], function (i, elem) { + lay.touchSwipe(elem, { + onTouchEnd: touchEndCallback, + }); + }); + }; + + // 图片预加载 + function loadImage(url, callback, error) { + var img = new Image(); + img.src = url; + if (img.complete) { + return callback(img); + } + img.onload = function () { + img.onload = null; + callback(img); + }; + img.onerror = function (e) { + img.onerror = null; + error(e); + }; + } + + dict.loadi = layer.load(1, { + shade: 'shade' in options ? false : [0.9, undefined, 'unset'], + scrollbar: false, + }); + + loadImage( + data[start].src, + function (img) { + layer.close(dict.loadi); + + var alt = data[start].alt || ''; + + // 切换图片时不出现动画 + if (key) options.anim = -1; + + // 弹出图片层 + dict.index = layer.open( + $.extend( + { + type: 1, + id: 'lay-layer-photos', + area: (function () { + var imgarea = [img.width, img.height]; + var winarea = [$(window).width() - 100, $(window).height() - 100]; + + // 若实际图片的宽或者高比 屏幕大(那么进行缩放) + if ( + !options.full && + (imgarea[0] > winarea[0] || imgarea[1] > winarea[1]) + ) { + var wh = [imgarea[0] / winarea[0], imgarea[1] / winarea[1]]; // 取宽度缩放比例、高度缩放比例 + if (wh[0] > wh[1]) { + // 取缩放比例最大的进行缩放 + imgarea[0] = imgarea[0] / wh[0]; + imgarea[1] = imgarea[1] / wh[0]; + } else if (wh[0] < wh[1]) { + imgarea[0] = imgarea[0] / wh[1]; + imgarea[1] = imgarea[1] / wh[1]; + } + } + + return [imgarea[0] + 'px', imgarea[1] + 'px']; + })(), + title: false, + shade: [0.9, undefined, 'unset'], + shadeClose: true, + closeBtn: false, + move: '.layer-layer-photos-main img', + moveType: 1, + scrollbar: false, + moveOut: true, + anim: 5, + isOutAnim: false, + skin: 'lay-layer-photos' + skin('photos'), + content: + '
                              ' + + '' +
+              alt +
+              '' + + (function () { + var arr = ['
                              ']; + + // 左右箭头翻页 + if (data.length > 1) { + arr.push( + [ + '
                              ', + '', + '', + '
                              ', + ].join(''), + ); + } + + // 头部工具栏 + if (options.toolbar) { + arr.push( + [ + '
                              ', + '', + '', + '', + '', + '', + '', + '
                              ', + ].join(''), + ); + } + + // 底部栏 + if (options.footer) { + arr.push( + [ + '', + ].join(''), + ); + } + + arr.push('
                              '); + return arr.join(''); + })() + + '
                              ', + success: function (layero, index, that) { + dict.main = layero.find('.layer-layer-photos-main'); + dict.footer = layero.find('.lay-layer-photos-footer'); + dict.imgElem = dict.main.children('img'); + dict.event(layero, index, that); + options.tab && options.tab(data[start], layero); + typeof success === 'function' && success(layero); + }, + end: function () { + dict.end = true; + $(document).off('keyup', dict.keyup); + }, + }, + options, + ), + ); + }, + function () { + layer.close(dict.loadi); + layer.msg( + '' + + i18n.$t('layer.photos.urlError.prompt') + + '', + { + time: 30000, + btn: [ + i18n.$t('layer.photos.urlError.confirm'), + i18n.$t('layer.photos.urlError.cancel'), + ], + yes: function () { + data.length > 1 && dict.imgnext(true, true); + }, + }, + ); + }, + ); +}; + +// 主入口 +ready.run = function (_$) { + var $ = _$; + win = $(window); + + // 移动端兼容性处理 + // https://gitee.com/layui/layui/issues/I81WGC + // https://github.com/jquery/jquery/issues/1729 + var agent = navigator.userAgent.toLowerCase(); + var isMobile = /android|iphone|ipod|ipad|ios/.test(agent); + var _win = $(window); + if (isMobile) { + $.each( + { Height: 'height', Width: 'width' }, + function (propSuffix, funcName) { + var propName = 'inner' + propSuffix; + win[funcName] = function () { + return propName in window ? window[propName] : _win[funcName](); + }; + }, + ); + } + doms.html = $('html'); + layer.open = function (deliver) { + var o = new Class(deliver); + return o.index; + }; +}; + +layer.ready(); +ready.run($); + +export { layer }; diff --git a/src/components/laypage.js b/src/components/laypage.js new file mode 100644 index 000000000..938dd81f9 --- /dev/null +++ b/src/components/laypage.js @@ -0,0 +1,407 @@ +/** + * laypage 分页组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; + +var doc = document; +var id = 'getElementById'; +var tag = 'getElementsByTagName'; + +// 字符常量 +// var MOD_NAME = 'laypage'; +var DISABLED = 'lay-disabled'; + +// 构造器 +var Class = function (options) { + var that = this; + that.config = options || {}; + that.index = laypage.index = lay.autoIncrementer('laypage'); + that.render(true); +}; + +// 判断传入的容器类型 +Class.prototype.type = function () { + var config = this.config; + if (typeof config.elem === 'object') { + return config.elem.length === undefined ? 2 : 3; + } +}; + +// 分页视图 +Class.prototype.view = function () { + var that = this; + var config = that.config; + + // 连续页码个数 + var groups = (config.groups = + 'groups' in config ? Number(config.groups) || 0 : 5); + + // 排版 + config.layout = + typeof config.layout === 'object' + ? config.layout + : ['prev', 'page', 'next']; + + config.count = Number(config.count) || 0; // 数据总数 + config.curr = Number(config.curr) || 1; // 当前页 + + // 每页条数的选择项 + config.limits = + typeof config.limits === 'object' ? config.limits : [10, 20, 30, 40, 50]; + + // 默认条数 + config.limit = Number(config.limit) || 10; + + // 总页数 + config.pages = Math.ceil(config.count / config.limit) || 1; + + // 当前页不能超过总页数 + if (config.curr > config.pages) { + config.curr = config.pages; + } else if (config.curr < 1) { + // 当前分页不能小于 1 + config.curr = 1; + } + + // 连续分页个数不能低于 0 且不能大于总页数 + if (groups < 0) { + groups = 1; + } else if (groups > config.pages) { + groups = config.pages; + } + + config.prev = 'prev' in config ? config.prev : i18n.$t('laypage.prev'); // 上一页文本 + config.next = 'next' in config ? config.next : i18n.$t('laypage.next'); // 下一页文本 + + // 计算当前组 + var index = + config.pages > groups + ? Math.ceil( + (config.curr + (groups > 1 ? 1 : 0)) / (groups > 0 ? groups : 1), + ) + : 1; + + // 视图片段 + var views = { + // 上一页 + prev: (function () { + return config.prev + ? '' + + config.prev + + '' + : ''; + })(), + + // 页码 + page: (function () { + var pager = []; + + // 数据量为0时,不输出页码 + if (config.count < 1) { + return ''; + } + + // 首页 + if (index > 1 && config.first !== false && groups !== 0) { + pager.push( + '' + + (config.first || 1) + + '', + ); + } + + // 计算当前页码组的起始页 + var halve = Math.floor((groups - 1) / 2); // 页码数等分 + var start = index > 1 ? config.curr - halve : 1; + var end = + index > 1 + ? (function () { + var max = config.curr + (groups - halve - 1); + return max > config.pages ? config.pages : max; + })() + : groups; + + // 防止最后一组出现“不规定”的连续页码数 + if (end - start < groups - 1) { + start = end - groups + 1; + } + + // 输出左分割符 + if (config.first !== false && start > 2) { + pager.push('...'); + } + + // 输出连续页码 + for (; start <= end; start++) { + if (start === config.curr) { + // 当前页 + pager.push( + '' + + start + + '', + ); + } else { + pager.push('' + start + ''); + } + } + + // 输出输出右分隔符 & 末页 + if ( + config.pages > groups && + config.pages > end && + config.last !== false + ) { + if (end + 1 < config.pages) { + pager.push('...'); + } + if (groups !== 0) { + pager.push( + '' + + (config.last || config.pages) + + '', + ); + } + } + + return pager.join(''); + })(), + + // 下一页 + next: (function () { + return config.next + ? '' + + config.next + + '' + : ''; + })(), + + // 数据总数 + count: (function () { + var countText = + typeof config.countText === 'object' + ? config.countText[0] + config.count + config.countText[1] + : i18n.$t('laypage.total', { total: config.count }); + + return '' + countText + ''; + })(), + + // 每页条数 + limit: (function () { + var elemArr = [''; + })(), + + // 刷新当前页 + refresh: [ + '', + '', + '', + ].join(''), + + // 跳页区域 + skip: (function () { + var skipText = + typeof config.skipText === 'object' + ? config.skipText + : [ + i18n.$t('laypage.goto'), + i18n.$t('laypage.page'), + i18n.$t('laypage.confirm'), + ]; + return [ + '' + skipText[0], + '', + skipText[1] + + '', + '', + ].join(''); + })(), + }; + + return [ + '
                              ', + (function () { + var plate = []; + config.layout.forEach(function (item) { + if (views[item]) { + plate.push(views[item]); + } + }); + return plate.join(''); + })(), + '
                              ', + ].join(''); +}; + +// 跳页的回调 +Class.prototype.jump = function (elem, isskip) { + if (!elem) return; + + var that = this; + var config = that.config; + var childs = elem.children; + var btn = elem[tag]('button')[0]; + var input = elem[tag]('input')[0]; + var select = elem[tag]('select')[0]; + var skip = function () { + var curr = Number(input.value.replace(/\s|\D/g, '')); + if (curr) { + config.curr = curr; + that.render(); + } + }; + + if (isskip) return skip(); + + // 页码 + for (var i = 0, len = childs.length; i < len; i++) { + if (childs[i].nodeName.toLowerCase() === 'a') { + laypage.on(childs[i], 'click', function () { + var curr = Number(this.getAttribute('data-page')); + if (curr < 1 || curr > config.pages) return; + config.curr = curr; + that.render(); + }); + } + } + + // 条数 + if (select) { + laypage.on(select, 'change', function () { + var value = this.value; + if (config.curr * value > config.count) { + config.curr = Math.ceil(config.count / value); + } + config.limit = value; + that.render(); + }); + } + + // 确定 + if (btn) { + laypage.on(btn, 'click', function () { + skip(); + }); + } +}; + +// 输入页数字控制 +Class.prototype.skip = function (elem) { + if (!elem) return; + + var that = this; + var input = elem[tag]('input')[0]; + + if (!input) return; + + // 键盘事件 + laypage.on(input, 'keyup', function (e) { + var value = this.value; + var keyCode = e.keyCode; + + if (/^(37|38|39|40)$/.test(keyCode)) return; + + if (/\D/.test(value)) { + this.value = value.replace(/\D/, ''); + } + if (keyCode === 13) { + that.jump(elem, true); + } + }); +}; + +// 渲染分页 +Class.prototype.render = function (load) { + var that = this; + var config = that.config; + var type = that.type(); + var view = that.view(); + + if (type === 2) { + config.elem && (config.elem.innerHTML = view); + } else if (type === 3) { + config.elem.html(view); + } else { + if (doc[id](config.elem)) { + doc[id](config.elem).innerHTML = view; + } + } + + config.jump && config.jump(config, load); + + var elem = doc[id]('lay-laypage-' + that.index); + that.jump(elem); + + if (config.hash && !load) { + location.hash = '!' + config.hash + '=' + config.curr; + } + + that.skip(elem); +}; + +// 外部接口 +var laypage = { + // 分页渲染 + render: function (options) { + var o = new Class(options); + return o.index; + }, + on: function (elem, even, fn) { + elem.addEventListener(even, fn, false); + return this; + }, +}; + +export { laypage }; diff --git a/src/components/nav.js b/src/components/nav.js new file mode 100644 index 000000000..4a52a9805 --- /dev/null +++ b/src/components/nav.js @@ -0,0 +1,267 @@ +/** + * nav + * 导航菜单组件 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +var SUPER_MOD_NAME = 'element'; // 所属的超级模块名,确保向下兼容 + +// 创建组件 +var component = componentBuilder({ + name: 'nav', // 组件名 + + // 默认配置 + config: { + elem: '.lay-nav', + }, + + CONST: { + NAV_ELEM: '.lay-nav', + NAV_ITEM: 'lay-nav-item', + NAV_BAR: 'lay-nav-bar', + NAV_TREE: 'lay-nav-tree', + NAV_CHILD: 'lay-nav-child', + NAV_CHILD_C: 'lay-nav-child-c', + NAV_MORE: 'lay-nav-more', + NAV_DOWN: 'lay-icon-down', + NAV_ANIM: 'lay-anim lay-anim-upbit', + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + var TIME = 200; + var timer = {}; + var timerMore = {}; + var timeEnd = {}; + var NAV_TITLE = 'lay-nav-title'; + + // 滑块跟随 + var follow = function (bar, nav, index) { + var othis = $(this); + var child = othis.find('.' + CONST.NAV_CHILD); + + // 是否垂直导航菜单 + if (nav.hasClass(CONST.NAV_TREE)) { + // 无子菜单时跟随 + if (!child[0]) { + var thisA = othis.children('.' + NAV_TITLE); + bar.css({ + top: othis.offset().top - nav.offset().top + nav.scrollTop(), + height: (thisA[0] ? thisA : othis).outerHeight(), + opacity: 1, + }); + } + } else { + child.addClass(CONST.NAV_ANIM); + + // 若居中对齐 + if (child.hasClass(CONST.NAV_CHILD_C)) { + child.css({ + left: -(child.outerWidth() - othis.width()) / 2, + }); + } + + // 滑块定位 + if (child[0]) { + // 若有子菜单,则滑块消失 + bar.css({ + left: bar.position().left + bar.width() / 2, + width: 0, + opacity: 0, + }); + } else { + // bar 跟随 + bar.css({ + left: othis.position().left + parseFloat(othis.css('marginLeft')), + top: othis.position().top + othis.height() - bar.height(), + }); + } + + // 渐显滑块并适配宽度 + timer[index] = setTimeout(function () { + bar.css({ + width: child[0] ? 0 : othis.width(), + opacity: child[0] ? 0 : 1, + }); + }, TIME); + + // 显示子菜单 + clearTimeout(timeEnd[index]); + if (child.css('display') === 'block') { + clearTimeout(timerMore[index]); + } + timerMore[index] = setTimeout(function () { + child.addClass(CONST.CLASS_SHOW); + othis.find('.' + CONST.NAV_MORE).addClass(CONST.NAV_MORE + 'd'); + }, 300); + } + }; + + // 遍历导航 + options.elem.each(function (index) { + var othis = $(this); + var bar = $(''); + var itemElem = othis.find('.' + CONST.NAV_ITEM); + + // hover 滑动效果 + var hasBarElem = othis.find('.' + CONST.NAV_BAR); + if (hasBarElem[0]) hasBarElem.remove(); + othis.append(bar); + (othis.hasClass(CONST.NAV_TREE) + ? itemElem.find('dd,>.' + CONST.NAV_TITLE) + : itemElem + ) + .off('mouseenter.lay_nav') + .on('mouseenter.lay_nav', function () { + follow.call(this, bar, othis, index); + }) + .off('mouseleave.lay_nav') + .on('mouseleave.lay_nav', function () { + // 鼠标移出 + // 是否为垂直导航 + if (othis.hasClass(CONST.NAV_TREE)) { + bar.css({ + height: 0, + opacity: 0, + }); + } else { + // 隐藏子菜单 + clearTimeout(timerMore[index]); + timerMore[index] = setTimeout(function () { + othis.find('.' + CONST.NAV_CHILD).removeClass(CONST.CLASS_SHOW); + othis + .find('.' + CONST.NAV_MORE) + .removeClass(CONST.NAV_MORE + 'd'); + }, 300); + } + }); + + // 鼠标离开当前菜单时 + othis.off('mouseleave.lay_nav').on('mouseleave.lay_nav', function () { + clearTimeout(timer[index]); + timeEnd[index] = setTimeout(function () { + if (!othis.hasClass(CONST.NAV_TREE)) { + bar.css({ + width: 0, + left: bar.position().left + bar.width() / 2, + opacity: 0, + }); + } + }, TIME); + }); + + // 展开子菜单 + itemElem.find('a').each(function () { + var thisA = $(this); + var child = thisA.siblings('.' + CONST.NAV_CHILD); + var clickEventName = 'click.lay_nav_click'; + + // 输出小箭头 + if (child[0] && !thisA.children('.' + CONST.NAV_MORE)[0]) { + thisA.append( + '', + ); + } + + // 点击菜单 + thisA + .off(clickEventName, events.clickThis) + .on(clickEventName, events.clickThis); + }); + }); + }, +}); + +var events = { + // 点击当前菜单 - a 标签触发 + clickThis: function () { + var othis = $(this); + var parents = othis.closest(CONST.NAV_ELEM); + var filter = parents.attr('lay-filter'); + var parent = othis.parent(); + var child = othis.siblings('.' + CONST.NAV_CHILD); + var unselect = typeof parent.attr('lay-unselect') === 'string'; // 是否禁用选中 + + // 满足点击选中的条件 + if ( + !( + othis.attr('href') !== 'javascript:;' && + othis.attr('target') === '_blank' + ) && + !unselect + ) { + if (!child[0]) { + parents.find('.' + CONST.CLASS_THIS).removeClass(CONST.CLASS_THIS); + parent.addClass(CONST.CLASS_THIS); + } + } + + // 若为垂直菜单 + if (parents.hasClass(CONST.NAV_TREE)) { + var NAV_ITEMED = CONST.NAV_ITEM + 'ed'; // 用于标注展开状态 + var needExpand = !parent.hasClass(NAV_ITEMED); // 是否执行展开 + var ANIM_MS = 200; // 动画过渡毫秒数 + + // 动画执行完成后的操作 + var complete = function () { + $(this).css({ + display: '', // 剔除动画生成的 style display,以适配外部样式的状态重置 + }); + // 避免导航滑块错位 + parents.children('.' + CONST.NAV_BAR).css({ + opacity: 0, + }); + }; + + // 是否正处于动画中的状态 + if (child.is(':animated')) return; + + // 剔除可能存在的 CSS3 动画类 + child.removeClass(CONST.NAV_ANIM); + + // 若有子菜单,则对其执行展开或收缩 + if (child[0]) { + if (needExpand) { + // 先执行 slideDown 动画,再标注展开状态样式,避免元素 `block` 状态导致动画无效 + child.slideDown(ANIM_MS, complete); + parent.addClass(NAV_ITEMED); + } else { + // 先取消展开状态样式,再将元素临时显示,避免 `none` 状态导致 slideUp 动画无效 + parent.removeClass(NAV_ITEMED); + child.show().slideUp(ANIM_MS, complete); + } + + // 手风琴 --- 收缩兄弟展开项 + if ( + typeof parents.attr('lay-accordion') === 'string' || + parents.attr('lay-shrink') === 'all' + ) { + var parentSibs = parent.siblings('.' + NAV_ITEMED); + parentSibs.removeClass(NAV_ITEMED); + parentSibs + .children('.' + CONST.NAV_CHILD) + .show() + .stop() + .slideUp(ANIM_MS, complete); + } + } + } + + lay.event.call(this, SUPER_MOD_NAME, 'nav(' + filter + ')', othis); + }, +}; + +var CONST = component.CONST; + +// export +export { component as nav }; diff --git a/src/components/progress.js b/src/components/progress.js new file mode 100644 index 000000000..8f9b98c63 --- /dev/null +++ b/src/components/progress.js @@ -0,0 +1,72 @@ +/** + * progress + * 进度条组件 + */ + +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +// 创建组件 +var component = componentBuilder({ + name: 'progress', // 组件名 + + // 默认配置 + config: { + elem: '.lay-progress', + }, + + CONST: { + ELEM: 'lay-progress', + }, + + render: function () { + var that = this; + var options = that.config; + + options.elem.each(function () { + var othis = $(this); + var elemBar = othis.find('.lay-progress-bar'); + var percent = elemBar.attr('lay-percent'); + + elemBar.css('width', function () { + return /^.+\/.+$/.test(percent) + ? new Function('return ' + percent)() * 100 + '%' + : percent; + }); + + if (othis.attr('lay-showpercent')) { + setTimeout(function () { + elemBar.html( + '' + percent + '', + ); + }, 350); + } + }); + }, +}); + +var CONST = component.CONST; + +// 扩展组件接口 +$.extend(component, { + // 动态改变进度条 + setValue: function (filter, percent) { + var ELEM = 'lay-progress'; + var elem = $('.' + ELEM + '[lay-filter=' + filter + ']'); + var elemBar = elem.find('.' + ELEM + '-bar'); + var text = elemBar.find('.' + ELEM + '-text'); + + elemBar + .css('width', function () { + return /^.+\/.+$/.test(percent) + ? new Function('return ' + percent)() * 100 + '%' + : percent; + }) + .attr('lay-percent', percent); + text.text(percent); + return this; + }, +}); + +// export +export { component as progress }; diff --git a/src/components/rate.js b/src/components/rate.js new file mode 100644 index 000000000..1c4893faf --- /dev/null +++ b/src/components/rate.js @@ -0,0 +1,263 @@ +/** + * rate + * 评分组件 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +// 创建组件 +var component = componentBuilder({ + name: 'rate', + + // 默认配置 + config: { + length: 5, // 评分的最大长度值 + value: 0, // 评分的初始值 + half: false, // 是否可以选择半星 + text: false, // 是否显示评分对应的文本 + readonly: false, // 是否只读 + theme: '', // 主题颜色 + }, + + CONST: { + ELEM: 'lay-rate', + ICON_RATE: 'lay-icon-rate', + ICON_RATE_SOLID: 'lay-icon-rate-solid', + ICON_RATE_HALF: 'lay-icon-rate-half', + ICON_SOLID_HALF: 'lay-icon-rate-solid lay-icon-rate-half', + ICON_SOLID_RATE: 'lay-icon-rate-solid lay-icon-rate', + ICON_HALF_RATE: 'lay-icon-rate lay-icon-rate-half', + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 自定义主题 + var style = options.theme ? 'style="color: ' + options.theme + ';"' : ''; + + // 最大值不能大于总长度 + if (options.value > options.length) { + options.value = options.length; + } + + // 如果没有选择半星的属性,却给了小数的数值,统一向上或向下取整 + if (parseInt(options.value) !== options.value) { + if (!options.half) { + options.value = + Math.ceil(options.value) - options.value < 0.5 + ? Math.ceil(options.value) + : Math.floor(options.value); + } + } + + // 组件模板 + var template = + '
                                '; + for (var i = 1; i <= options.length; i++) { + var item = + '
                              • '; + if ( + options.half && + parseInt(options.value) !== options.value && + i == Math.ceil(options.value) + ) { + template = + template + + '
                              • '; + } else { + template = template + item; + } + } + template += '
                              '; + + if (options.text) { + template += '' + options.value + ''; + } + + // 开始插入替代元素 + var othis = options.elem; + var hasRender = othis.next('.' + CONST.ELEM); + + // 生成替代元素 + hasRender[0] && hasRender.remove(); // 如果已经渲染,则 Rerender + that.elemTemplate = $(template); + + options.span = that.elemTemplate.next('span'); + options.setText && options.setText(options.value); + + othis.html(that.elemTemplate); + othis.addClass('lay-inline'); + + // 若非只读,则添加触控事件 + if (!options.readonly) { + that.action(); + } + }, + + // 扩展实例方法 + extendsInstance: function () { + var that = this; + var options = that.config; + return { + setvalue: function (value) { + options.value = value; + that.render(); + }, + }; + }, +}); + +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// li 相关事件 +Class.prototype.action = function () { + var that = this; + var options = that.config; + var _ul = that.elemTemplate; + var wide = _ul.find('i').width(); + var liElems = _ul.children('li'); + + liElems.each(function (index) { + var ind = index + 1; + var othis = $(this); + + // 点击 + othis.on('click', function (e) { + // 将当前点击li的索引值赋给 value + options.value = ind; + if (options.half) { + // 获取鼠标在 li 上的位置 + var x = e.pageX - $(this).offset().left; + if (x <= wide / 2) { + options.value = options.value - 0.5; + } + } + + if (options.text) { + _ul.next('span').text(options.value); + } + + options.choose && options.choose(options.value); + options.setText && options.setText(options.value); + }); + + // 移入 + othis.on('mousemove', function (e) { + _ul.find('i').each(function () { + $(this).addClass(CONST.ICON_RATE).removeClass(CONST.ICON_SOLID_HALF); + }); + _ul.find('i:lt(' + ind + ')').each(function () { + $(this) + .addClass(CONST.ICON_RATE_SOLID) + .removeClass(CONST.ICON_HALF_RATE); + }); + // 如果设置可选半星,那么判断鼠标相对 li 的位置 + if (options.half) { + var x = e.pageX - $(this).offset().left; + if (x <= wide / 2) { + othis + .children('i') + .addClass(CONST.ICON_RATE_HALF) + .removeClass(CONST.ICON_RATE_SOLID); + } + } + }); + + // 移出 + othis.on('mouseleave', function () { + _ul.find('i').each(function () { + $(this).addClass(CONST.ICON_RATE).removeClass(CONST.ICON_SOLID_HALF); + }); + _ul.find('i:lt(' + Math.floor(options.value) + ')').each(function () { + $(this) + .addClass(CONST.ICON_RATE_SOLID) + .removeClass(CONST.ICON_HALF_RATE); + }); + // 如果设置可选半星,根据分数判断是否有半星 + if (options.half) { + if (parseInt(options.value) !== options.value) { + _ul + .children('li:eq(' + Math.floor(options.value) + ')') + .children('i') + .addClass(CONST.ICON_RATE_HALF) + .removeClass(CONST.ICON_SOLID_RATE); + } + } + }); + }); + + lay.touchSwipe(_ul, { + onTouchMove: function (e, state) { + if (Date.now() - state.timeStart <= 200) return; + var pageX = e.touches[0].pageX; + var rateElemWidth = _ul.width(); + var itemElemWidth = rateElemWidth / options.length; // 单颗星的宽度 + var offsetX = pageX - _ul.offset().left; + var num = offsetX / itemElemWidth; // 原始值 + var remainder = num % 1; + var integer = num - remainder; + + // 最终值 + var score = + remainder <= 0.5 && options.half ? integer + 0.5 : Math.ceil(num); + if (score > options.length) score = options.length; + if (score < 0) score = 0; + + liElems.each(function (index) { + var iconElem = $(this).children('i'); + var isActiveIcon = Math.ceil(score) - index === 1; + var needSelect = Math.ceil(score) > index; + var shouldHalfIcon = score - index === 0.5; + + if (needSelect) { + // 设置选中样式 + iconElem + .addClass(CONST.ICON_RATE_SOLID) + .removeClass(CONST.ICON_HALF_RATE); + if (options.half && shouldHalfIcon) { + iconElem + .addClass(CONST.ICON_RATE_HALF) + .removeClass(CONST.ICON_RATE_SOLID); + } + } else { + // 恢复初始样式 + iconElem.addClass(CONST.ICON_RATE).removeClass(CONST.ICON_SOLID_HALF); + } + + // 设置缩放样式 + iconElem.toggleClass('lay-rate-hover', isActiveIcon); + }); + + // 更新最终值 + options.value = score; + if (options.text) _ul.next('span').text(options.value); + options.setText && options.setText(options.value); + }, + onTouchEnd: function (e, state) { + if (Date.now() - state.timeStart <= 200) return; + _ul.find('i').removeClass('lay-rate-hover'); + options.choose && options.choose(options.value); + options.setText && options.setText(options.value); + }, + }); +}; + +export { component as rate }; diff --git a/src/components/slider.js b/src/components/slider.js new file mode 100644 index 000000000..6b8d058fb --- /dev/null +++ b/src/components/slider.js @@ -0,0 +1,598 @@ +/** + * slider 滑块组件 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +var component = componentBuilder({ + name: 'slider', + config: { + type: 'default', // 滑块类型,垂直:vertical + min: 0, // 最小值 + max: 100, // 最大值,默认100 + value: 0, // 初始值,默认为0 + step: 1, // 间隔值 + showstep: false, // 间隔点开启 + tips: true, // 文字提示,开启 + tipsAlways: false, // 文字提示,始终开启 + input: false, // 输入框,关闭 + range: false, // 范围选择,与输入框不能同时开启,默认关闭 + height: 200, // 配合 type:"vertical" 使用,默认200px + disabled: false, // 滑块禁用,默认关闭 + theme: '#16baaa', // 主题颜色 + }, + CONST: { + ELEM_VIEW: 'lay-slider', + SLIDER_BAR: 'lay-slider-bar', + SLIDER_WRAP: 'lay-slider-wrap', + SLIDER_WRAP_BTN: 'lay-slider-wrap-btn', + SLIDER_TIPS: 'lay-slider-tips', + SLIDER_INPUT: 'lay-slider-input', + SLIDER_INPUT_TXT: 'lay-slider-input-txt', + SLIDER_INPUT_BTN: 'lay-slider-input-btn', + ELEM_HOVER: 'lay-slider-hover', + }, + render: function () { + var that = this; + var options = that.config; + var scale; + + //间隔值不能小于等于 0 + if (options.step <= 0) options.step = 1; + + //最大值不能小于最小值 + if (options.max < options.min) options.max = options.min + options.step; + + //判断是否开启双滑块 + if (options.range) { + options.value = + typeof options.value == 'object' + ? options.value + : [options.min, options.value]; + var minValue = Math.min(options.value[0], options.value[1]), + maxValue = Math.max(options.value[0], options.value[1]); + options.value[0] = Math.max(minValue, options.min); + options.value[1] = Math.max(maxValue, options.min); + options.value[0] = Math.min(options.value[0], options.max); + options.value[1] = Math.min(options.value[1], options.max); + + var scaleFir = + ((options.value[0] - options.min) / (options.max - options.min)) * 100; + var scaleSec = + ((options.value[1] - options.min) / (options.max - options.min)) * 100; + scale = scaleSec - scaleFir + '%'; + scaleFir = scaleFir + '%'; + scaleSec = scaleSec + '%'; + } else { + //如果初始值是一个数组,则获取数组的最小值 + if (typeof options.value == 'object') { + options.value = Math.min.apply(null, options.value); + } + + //初始值不能小于最小值且不能大于最大值 + if (options.value < options.min) options.value = options.min; + if (options.value > options.max) options.value = options.max; + + scale = + ((options.value - options.min) / (options.max - options.min)) * 100 + + '%'; + } + + //如果禁用,颜色为统一的灰色 + var theme = options.disabled ? '#c2c2c2' : options.theme; + + //滑块 + var temp = + '
                              ' + + (options.tips + ? '
                              ' + : '') + + '
                              ' + + '
                              ' + + (options.range + ? '
                              ' + : '') + + '
                              '; + + var othis = $(options.elem); + var hasRender = othis.next('.' + CONST.ELEM_VIEW); + //生成替代元素 + hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender + that.elemTemp = $(temp); + + //把数据缓存到滑块上 + if (options.range) { + that.elemTemp + .find('.' + CONST.SLIDER_WRAP) + .eq(0) + .data('value', options.value[0]); + that.elemTemp + .find('.' + CONST.SLIDER_WRAP) + .eq(1) + .data('value', options.value[1]); + } else { + that.elemTemp.find('.' + CONST.SLIDER_WRAP).data('value', options.value); + } + + //插入替代元素 + othis.html(that.elemTemp); + + //垂直滑块 + if (options.type === 'vertical') { + that.elemTemp.height(options.height + 'px'); + } + + //显示间断点 + if (options.showstep) { + var number = (options.max - options.min) / options.step, + item = ''; + for (var i = 1; i < number + 1; i++) { + var step = (i * 100) / number; + if (step < 100) { + item += + '
                              '; + } + } + that.elemTemp.append(item); + } + + //插入输入框 + if (options.input && !options.range) { + var elemInput = $( + '
                              ', + ); + othis.css('position', 'relative'); + othis.append(elemInput); + othis + .find('.' + CONST.SLIDER_INPUT_TXT) + .children('input') + .val(options.value); + if (options.type === 'vertical') { + elemInput.css({ + left: 0, + top: -48, + }); + } else { + that.elemTemp.css('margin-right', elemInput.outerWidth() + 15); + } + } + + //给未禁止的滑块滑动事件 + if (!options.disabled) { + that.slide(); + } else { + that.elemTemp.addClass(CONST.CLASS_DISABLED); + that.elemTemp + .find('.' + CONST.SLIDER_WRAP_BTN) + .addClass(CONST.CLASS_DISABLED); + } + + /** + * @description 设置提示文本内容 + * @param {Element} sliderWrapBtnElem 提示文本节点元素 + */ + function setSliderTipsTxt(sliderWrapBtnElem) { + var value = sliderWrapBtnElem.parent().data('value'); + var tipsTxt = options.setTips ? options.setTips(value) : value; + that.elemTemp.find('.' + CONST.SLIDER_TIPS).html(tipsTxt); + } + + /** + * @description 计算提示文本元素的 position left + * @param {Element} sliderWrapBtnElem 提示文本节点元素 + */ + function calcSliderTipsLeft(sliderWrapBtnElem) { + var sliderWidth = + options.type === 'vertical' + ? options.height + : that.elemTemp[0].offsetWidth; + var sliderWrap = that.elemTemp.find('.' + CONST.SLIDER_WRAP); + var tipsLeft = + options.type === 'vertical' + ? sliderWidth - + sliderWrapBtnElem.parent()[0].offsetTop - + sliderWrap.height() + : sliderWrapBtnElem.parent()[0].offsetLeft; + var left = (tipsLeft / sliderWidth) * 100; + return left; + } + + /** + * @description 设置提示文本元素的 position left + * @param {number} left 要设置的 left 的大小 + */ + function setSliderTipsLeft(left) { + if (options.type === 'vertical') { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({ + bottom: left + '%', + 'margin-bottom': '20px', + display: 'inline-block', + }); + } else { + that.elemTemp.find('.' + CONST.SLIDER_TIPS).css({ + left: left + '%', + display: 'inline-block', + }); + } + } + + //判断是否要始终显示提示文本 + if (options.tips) { + if (options.tipsAlways) { + var sliderWrapBtnElem = that.elemTemp.find('.' + CONST.SLIDER_WRAP_BTN); + setSliderTipsTxt(sliderWrapBtnElem); + var left = calcSliderTipsLeft(sliderWrapBtnElem); + setSliderTipsLeft(left); + } else { + //划过滑块显示数值 + var timer; + that.elemTemp + .find('.' + CONST.SLIDER_WRAP_BTN) + .on('mouseover', function () { + setSliderTipsTxt($(this)); + var left = calcSliderTipsLeft($(this)); + clearTimeout(timer); + timer = setTimeout(function () { + setSliderTipsLeft(left); + }, 300); + }) + .on('mouseout', function () { + clearTimeout(timer); + if (!options.tipsAlways) { + that.elemTemp + .find('.' + CONST.SLIDER_TIPS) + .css('display', 'none'); + } + }); + } + } + }, + extendsInstance: function () { + var that = this; + var options = that.config; + return { + setValue: function (value, index) { + value = value > options.max ? options.max : value; + value = value < options.min ? options.min : value; + options.value = value; + return that.slide('set', value, index || 0); + }, + }; + }, +}); + +var CONST = component.CONST; +var Class = component.Class; + +// 数值精度 +Class.prototype.precision = function () { + var that = this; + var options = that.config; + var precisions = $.map( + [options.min, options.max, options.step], + function (v) { + var decimalArr = String(v).split('.'); + return decimalArr[1] ? decimalArr[1].length : 0; + }, + ); + return Math.max.apply(null, precisions); +}; + +//滑块滑动 +Class.prototype.slide = function (setValue, value, i) { + var that = this; + var options = that.config; + var sliderAct = that.elemTemp; + var sliderWidth = function () { + return options.type === 'vertical' + ? options.height + : sliderAct[0].offsetWidth; + }; + var sliderWrap = sliderAct.find('.' + CONST.SLIDER_WRAP); + var sliderTxt = sliderAct.next('.' + CONST.SLIDER_INPUT); + var inputValue = sliderTxt + .children('.' + CONST.SLIDER_INPUT_TXT) + .children('input') + .val(); + var step = 100 / ((options.max - options.min) / options.step); + var precision = that.precision(); + var change = function (offsetValue, index, from) { + if (Math.ceil(offsetValue) * step > 100) { + offsetValue = Math.ceil(offsetValue) * step; + } else { + offsetValue = Math.round(offsetValue) * step; + } + offsetValue = offsetValue > 100 ? 100 : offsetValue; + offsetValue = offsetValue < 0 ? 0 : offsetValue; + sliderWrap + .eq(index) + .css(options.type === 'vertical' ? 'bottom' : 'left', offsetValue + '%'); + var firLeft = valueTo(sliderWrap[0].offsetLeft); + var secLeft = options.range ? valueTo(sliderWrap[1].offsetLeft) : 0; + if (options.type === 'vertical') { + sliderAct + .find('.' + CONST.SLIDER_TIPS) + .css({ bottom: offsetValue + '%', 'margin-bottom': '20px' }); + firLeft = valueTo( + sliderWidth() - sliderWrap[0].offsetTop - sliderWrap.height(), + ); + secLeft = options.range + ? valueTo(sliderWidth() - sliderWrap[1].offsetTop - sliderWrap.height()) + : 0; + } else { + sliderAct.find('.' + CONST.SLIDER_TIPS).css('left', offsetValue + '%'); + } + firLeft = firLeft > 100 ? 100 : firLeft; + secLeft = secLeft > 100 ? 100 : secLeft; + var minLeft = Math.min(firLeft, secLeft), + wrapWidth = Math.abs(firLeft - secLeft); + if (options.type === 'vertical') { + sliderAct + .find('.' + CONST.SLIDER_BAR) + .css({ height: wrapWidth + '%', bottom: minLeft + '%' }); + } else { + sliderAct + .find('.' + CONST.SLIDER_BAR) + .css({ width: wrapWidth + '%', left: minLeft + '%' }); + } + var selfValue = + options.min + ((options.max - options.min) * offsetValue) / 100; + selfValue = Number(parseFloat(selfValue).toFixed(precision)); + inputValue = selfValue; + sliderTxt + .children('.' + CONST.SLIDER_INPUT_TXT) + .children('input') + .val(inputValue); + sliderWrap.eq(index).data('value', selfValue); + sliderAct + .find('.' + CONST.SLIDER_TIPS) + .html(options.setTips ? options.setTips(selfValue) : selfValue); + + //如果开启范围选择,则返回数组值 + if (options.range) { + var arrValue = [ + sliderWrap.eq(0).data('value'), + sliderWrap.eq(1).data('value'), + ]; + if (arrValue[0] > arrValue[1]) arrValue.reverse(); //如果前面的圆点超过了后面的圆点值,则调换顺序 + } + + that.value = options.range ? arrValue : selfValue; // 最新值 + options.change && options.change(that.value); // change 回调 + + // 值完成选中的事件 + if (from === 'done') options.done && options.done(that.value); + }; + var valueTo = function (value) { + var oldLeft = ((value / sliderWidth()) * 100) / step; + var left = Math.round(oldLeft) * step; + if (value == sliderWidth()) { + left = Math.ceil(oldLeft) * step; + } + return left; + }; + + //拖拽元素 + var elemMove = $( + ['
                              sliderWidth()) left = sliderWidth(); + var reaLeft = ((left / sliderWidth()) * 100) / step; + change(reaLeft, index); + othis.addClass(CONST.ELEM_HOVER); + sliderAct.find('.' + CONST.SLIDER_TIPS).show(); + e.preventDefault(); + }; + + var up = function (delay) { + othis.removeClass(CONST.ELEM_HOVER); + if (!options.tipsAlways) { + setTimeout(function () { + sliderAct.find('.' + CONST.SLIDER_TIPS).hide(); + }, delay); + } + }; + + createMoveElem(othis, move, up); + }); + }); + + // 点击滑块 + sliderAct.on('click', function (e) { + var main = $('.' + CONST.SLIDER_WRAP_BTN); + var othis = $(this); + if ( + !main.is(event.target) && + main.has(event.target).length === 0 && + main.length + ) { + var index; + var offset = + options.type === 'vertical' + ? sliderWidth() - + e.clientY + + othis.offset().top - + $(window).scrollTop() + : e.clientX - othis.offset().left - $(window).scrollLeft(); + + if (offset < 0) offset = 0; + if (offset > sliderWidth()) offset = sliderWidth(); + var reaLeft = ((offset / sliderWidth()) * 100) / step; + if (options.range) { + if (options.type === 'vertical') { + index = + Math.abs(offset - parseInt($(sliderWrap[0]).css('bottom'))) > + Math.abs(offset - parseInt($(sliderWrap[1]).css('bottom'))) + ? 1 + : 0; + } else { + index = + Math.abs(offset - sliderWrap[0].offsetLeft) > + Math.abs(offset - sliderWrap[1].offsetLeft) + ? 1 + : 0; + } + } else { + index = 0; + } + change(reaLeft, index, 'done'); + e.preventDefault(); + } + }); + + //点击加减输入框 + sliderTxt + .children('.' + CONST.SLIDER_INPUT_BTN) + .children('i') + .each(function (index) { + $(this).on('click', function () { + inputValue = sliderTxt + .children('.' + CONST.SLIDER_INPUT_TXT) + .children('input') + .val(); + if (index == 1) { + //减 + inputValue = + inputValue - options.step < options.min + ? options.min + : Number(inputValue) - options.step; + } else { + inputValue = + Number(inputValue) + options.step > options.max + ? options.max + : Number(inputValue) + options.step; + } + var inputScale = + (((inputValue - options.min) / (options.max - options.min)) * 100) / + step; + change(inputScale, 0, 'done'); + }); + }); + + //获取输入框值 + var getInputValue = function () { + var realValue = this.value; + realValue = isNaN(realValue) ? 0 : realValue; + realValue = realValue < options.min ? options.min : realValue; + realValue = realValue > options.max ? options.max : realValue; + this.value = realValue; + var inputScale = + (((realValue - options.min) / (options.max - options.min)) * 100) / step; + change(inputScale, 0, 'done'); + }; + sliderTxt + .children('.' + CONST.SLIDER_INPUT_TXT) + .children('input') + .on('keydown', function (e) { + if (e.keyCode === 13) { + e.preventDefault(); + getInputValue.call(this); + } + }) + .on('change', getInputValue); +}; + +export { component as slider }; diff --git a/src/components/table.js b/src/components/table.js new file mode 100644 index 000000000..329050c66 --- /dev/null +++ b/src/components/table.js @@ -0,0 +1,3995 @@ +/** + * table + * 表格组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { log } from '../core/logger.js'; +import { $ } from 'jquery'; +import { laytpl } from '../core/laytpl.js'; +import { laypage } from './laypage.js'; +import { layer } from './layer.js'; +import { form } from './form.js'; + +var device = lay.device(); + +// api +var table = { + config: { + // 全局配置项 + checkName: 'LAY_CHECKED', // 是否选中状态的特定字段名 + indexName: 'LAY_INDEX', // 下标索引 + initIndexName: 'LAY_INDEX_INIT', // 初始下标索引名,仅用于内部恢复当前页表格排序 + numbersName: 'LAY_NUM', // 序号 + disabledName: 'LAY_DISABLED', // 禁用状态的特定字段名 + }, + cache: {}, // 数据缓存 + + // 设置全局项 + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + + // 事件 + on: function (events, callback) { + return lay.onevent.call(this, MOD_NAME, events, callback); + }, +}; + +// 操作当前实例 +var thisTable = function () { + var that = this; + var options = that.config; + var id = options.id || options.index; + + return { + config: options, + reload: function (options, deep) { + that.reload.call(that, options, deep); + }, + reloadData: function (options, deep) { + table.reloadData(id, options, deep); + }, + setColsWidth: function () { + that.setColsWidth.call(that); + }, + resize: function () { + // 重置表格尺寸/结构 + that.resize.call(that); + }, + }; +}; + +// 获取当前实例 +var getThisTable = function (id) { + var that = thisTable.that[id]; + if (!that) + log( + id + ? "The table instance with ID '" + id + "' not found" + : 'ID argument required', + ); + return that || null; +}; + +// 获取当前实例配置项 +var getThisTableConfig = function (id) { + var config = thisTable.config[id]; + if (!config) + log( + id + ? "The table instance with ID '" + id + "' not found" + : 'ID argument required', + ); + return config || null; +}; + +/** + * 该实现最早可追溯:https://github.com/layui/layui/pull/1438 + * 由于已取消 `lay()` 查找元素功能,此处按当年「兼容模板选择器与模板字符串」的契约重构: + * 1. 传入 HTMLElement 或 jQuery 对象时,读取首个元素的 innerHTML + * 2. 传入字符串时,沿用原生 querySelector 的行为,不再支持 jQuery 特有的选择器 + * 3. 无效的 CSS 选择器字符串,会抛出 SyntaxError 异常,此时直接返回 laytpl 模板字符串 + */ +var resolveTplStr = function (templet) { + try { + if (templet?.jquery) { + return templet[0] ? templet.html() : undefined; + } + + if (templet?.nodeType === 1) { + return templet.innerHTML; + } + + if (typeof templet === 'string') { + var elem = document.querySelector(templet); + return elem ? elem.innerHTML : undefined; + } + + return undefined; + } catch { + return templet; + } +}; + +// 解析自定义模板数据 +var parseTempData = function (obj) { + obj = obj || {}; + + var options = this.config || {}; + var item3 = obj.item3; // 表头数据 + var content = obj.content; // 原始内容 + if (item3.type === 'numbers') content = obj.tplData[table.config.numbersName]; + + // 是否编码 HTML + var escaped = 'escape' in item3 ? item3.escape : options.escape; + if (escaped) content = lay.escape(content); + + // 获取模板 + var templet = + (obj.text && item3.exportTemplet) || item3.templet || item3.toolbar; + + // 获取模板内容 + if (templet) { + content = + typeof templet === 'function' + ? templet.call(item3, obj.tplData, obj.obj) + : laytpl(resolveTplStr(templet) || String(content)).render( + $.extend( + { + LAY_COL: item3, + }, + obj.tplData, + ), + ); + } + + // 是否只返回文本 + return obj.text ? $('
                              ' + content + '
                              ').text() : content; +}; + +// 字符 +var MOD_NAME = 'table'; +var MOD_ID = 'lay-' + MOD_NAME + '-id'; +var ELEM = '.lay-table'; +// var THIS = 'lay-this'; +// var SHOW = 'lay-show'; +var HIDE = 'lay-hide'; +var HIDE_V = 'lay-hide-v'; +// var DISABLED = 'lay-disabled'; +var NONE = 'lay-none'; + +var ELEM_VIEW = 'lay-table-view'; +var ELEM_TOOL = '.lay-table-tool'; +var ELEM_BOX = '.lay-table-box'; +var ELEM_INIT = '.lay-table-init'; +var ELEM_HEADER = '.lay-table-header'; +var ELEM_BODY = '.lay-table-body'; +var ELEM_MAIN = '.lay-table-main'; +var ELEM_FIXED = '.lay-table-fixed'; +var ELEM_FIXL = '.lay-table-fixed-l'; +var ELEM_FIXR = '.lay-table-fixed-r'; +var ELEM_TOTAL = '.lay-table-total'; +var ELEM_PAGE = '.lay-table-page'; +var ELEM_PAGE_VIEW = '.lay-table-pageview'; +var ELEM_SORT = '.lay-table-sort'; +var ELEM_CHECKED = 'lay-table-checked'; +var ELEM_EDIT = 'lay-table-edit'; +var ELEM_HOVER = 'lay-table-hover'; +var ELEM_GROUP = 'laytable-cell-group'; +var ELEM_COL_SPECIAL = 'lay-table-col-special'; +var ELEM_TOOL_PANEL = 'lay-table-tool-panel'; +var ELEM_EXPAND = 'lay-table-expanded'; +var DISABLED_TRANSITION = 'lay-table-disabled-transition'; +var FIXED_HEIGHT_PATCH = 'lay-table-fixed-height-patch'; + +var DATA_MOVE_NAME = 'LAY_TABLE_MOVE_DICT'; + +var resizeObserver = lay.createSharedResizeObserver(MOD_NAME); + +// thead 区域模板 +var TPL_HEADER = function (options) { + var rowCols = + '{{ var colspan = lay.type(item2.colspan2) === \'number\' ? item2.colspan2 : item2.colspan; if(colspan){ }} colspan="{{=colspan}}"{{ } if(item2.rowspan){ }} rowspan="{{=item2.rowspan}}"{{ } }}'; + + options = options || {}; + return ` + + + {{ for(var i1 = 0; i1 < d.data.cols.length; i1++){ var item1 = d.data.cols[i1]; }} + + {{ for(var i2 = 0; i2 < item1.length; i2++){ var item2 = item1[i2]; }} + {{ if(item2.fixed && item2.fixed !== "right"){ left = true; } }} + {{ if(item2.fixed === "right"){ right = true; } }} + ${(function () { + if (options.fixed && options.fixed !== 'right') { + return '{{ if(item2.fixed && item2.fixed !== "right"){ }}'; + } + if (options.fixed === 'right') { + return '{{ if(item2.fixed === "right"){ }}'; + } + return ''; + })()} + {{ var isSort = !(item2.colGroup) && item2.sort; }} + + ${options.fixed ? '{{ }; }}' : ''} + {{ } }} + + {{ } }} + +
                              +
                              + {{ if(item2.type === "checkbox"){ }} + + {{ } else { }} + {{-item2.title||""}} + {{ if(isSort){ }} + + {{ } }} + {{ } }} +
                              +
                              + `; +}; + +// tbody 区域模板 +var TPL_BODY = ` + + +
                              +`; + +// 主模板 +var TPL_MAIN = ` + {{ var left, right, vars = d.vars, lay = vars.lay; }} + {{ if(d.data.toolbar){ }} +
                              +
                              +
                              +
                              + {{ } }} +
                              + {{ if(d.data.loading){ }} +
                              +
                              + {{ if(typeof d.data.loading === "string"){ }} + {{- d.data.loading}} + {{ } else{ }} + + {{ } }} +
                              +
                              + {{ } }} +
                              + ${TPL_HEADER()} +
                              +
                              + ${TPL_BODY} +
                              + {{ if(left){ }} +
                              +
                              + ${TPL_HEADER({ fixed: true })} +
                              +
                              + ${TPL_BODY} +
                              +
                              + {{ }; }} + {{ if(right){ }} +
                              +
                              + ${TPL_HEADER({ fixed: 'right' })} +
                              +
                              +
                              + ${TPL_BODY} +
                              +
                              + {{ }; }} +
                              + {{ if(d.data.totalRow){ }} +
                              + + +
                              +
                              + {{ } }} +
                              +
                              +
                              +`; + +var _WIN = $(window); +var _DOC = $(document); + +// constructor +var Class = function (options) { + var that = this; + that.index = table.index = lay.autoIncrementer('table'); + that.config = $.extend({}, that.config, table.config, options); + that.unobserveResize = $.noop; + that.render(); +}; + +// 初始默认配置 +Class.prototype.config = { + limit: 10, // 每页显示的数量 + loading: true, // 请求数据时,是否显示 loading + escape: true, // 是否开启 HTML 编码功能,即转义 html 原文 + cellMinWidth: 60, // 所有单元格默认最小宽度 + cellMaxWidth: Number.MAX_VALUE, // 所有单元格默认最大宽度 + editTrigger: 'click', // 单元格编辑的事件触发方式 + defaultToolbar: ['filter', 'exports', 'print'], // 工具栏右侧图标 + defaultContextmenu: true, // 显示默认上下文菜单 + autoSort: true, // 是否前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) + cols: [], +}; + +// 表格渲染 +Class.prototype.render = function (type) { + var that = this; + var options = that.config; + + options.elem = $(options.elem); + options.where = options.where || {}; + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + var id = (options.id = + 'id' in options ? options.id : options.elem.attr('id') || that.index); + + // 重复 render 时清理旧实例 + if (thisTable.that[id] && thisTable.that[id] !== that) { + thisTable.that[id].dispose(); + } + + thisTable.that[id] = that; // 记录当前实例对象 + thisTable.config[id] = options; // 记录当前实例配置项 + + // 请求参数的自定义格式 + options.request = $.extend( + { + pageName: 'page', + limitName: 'limit', + }, + options.request, + ); + + // 响应数据的自定义格式 + options.response = $.extend( + { + statusName: 'code', //规定数据状态的字段名称 + statusCode: 0, //规定成功的状态码 + msgName: 'msg', //规定状态信息的字段名称 + dataName: 'data', //规定数据总数的字段名称 + totalRowName: 'totalRow', //规定数据统计的字段名称 + countName: 'count', + }, + options.response, + ); + + // 如果 page 传入 laypage 对象 + if (options.page !== null && typeof options.page === 'object') { + options.limit = options.page.limit || options.limit; + options.limits = options.page.limits || options.limits; + that.page = options.page.curr = options.page.curr || 1; + delete options.page.elem; + delete options.page.jump; + } + + // 加载 i18n 自定义文本 + options.text = $.extend( + true, + { + none: i18n.$t('table.noData'), + }, + options.text, + ); + + if (!options.elem[0]) return that; + + // 若元素未设 lay-filter 属性,则取实例 id 值 + if (!options.elem.attr('lay-filter')) { + options.elem.attr('lay-filter', options.id); + } + + // 仅重载数据 + if (type === 'reloadData') { + // 请求数据 + return that.pullData(that.page, { + type: 'reloadData', + }); + } + + // 初始化索引 + options.index = that.index; + that.key = options.id || options.index; + + // 初始化一些其他参数 + that.setInit(); + + // 高度铺满:full-差距值 + if (options.height && /^full-.+$/.test(options.height)) { + that.fullHeightGap = options.height.split('-')[1]; + options.height = _WIN.height() - (parseFloat(that.fullHeightGap) || 0); + } else if (options.height && /^#\w+\S*-.+$/.test(options.height)) { + var parentDiv = options.height.split('-'); + that.parentHeightGap = parentDiv.pop(); + that.parentDiv = parentDiv.join('-'); + options.height = + $(that.parentDiv).height() - (parseFloat(that.parentHeightGap) || 0); + } else if (typeof options.height === 'function') { + that.customHeightFunc = options.height; + options.height = that.customHeightFunc(); + } + + // 开始插入替代元素 + var othis = options.elem; + var hasRender = othis.next('.' + ELEM_VIEW); + + // 主容器 + var reElem = (that.elem = $('
                              ')); + + // 添加 className + reElem + .addClass( + (function () { + var arr = [ + ELEM_VIEW, + ELEM_VIEW + '-' + that.index, + 'lay-form', + 'lay-border-box', + ]; + if (options.className) arr.push(options.className); + return arr.join(' '); + })(), + ) + .attr( + (function () { + var obj = { + 'lay-filter': 'LAY-TABLE-FORM-DF-' + that.index, + style: (function () { + var arr = []; + if (options.width) arr.push('width:' + options.width + 'px;'); + // if(options.height) arr.push('height:'+ options.height + 'px;'); + return arr.join(''); + })(), + }; + obj[MOD_ID] = options.id; + return obj; + })(), + ) + .html( + laytpl(TPL_MAIN, { + open: '{{', // 标签符前缀 + close: '}}', // 标签符后缀 + }).render({ + data: options, + index: that.index, //索引 + i18nMessages: { + table_sort_asc: i18n.$t('table.sort.asc'), + table_sort_desc: i18n.$t('table.sort.desc'), + }, + vars: { lay, i18n, $ }, + }), + ); + + // 初始化样式 + that.renderStyle(); + + // 生成替代元素 + hasRender[0] && hasRender.remove(); // 如果已经渲染,则 Rerender + othis.after(reElem); + + // 各级容器 + that.layTool = reElem.find(ELEM_TOOL); + that.layBox = reElem.find(ELEM_BOX); + that.layHeader = reElem.find(ELEM_HEADER); + that.layMain = reElem.find(ELEM_MAIN); + that.layBody = reElem.find(ELEM_BODY); + that.layFixed = reElem.find(ELEM_FIXED); + that.layFixLeft = reElem.find(ELEM_FIXL); + that.layFixRight = reElem.find(ELEM_FIXR); + that.layTotal = reElem.find(ELEM_TOTAL); + that.layPage = reElem.find(ELEM_PAGE); + + // 初始化头部工具栏 + that.renderToolbar(); + + // 初始化底部分页栏 + that.renderPagebar(); + + // 让表格平铺 + that.fullSize(); + that.setColsWidth({ isInit: true }); + + // 请求数据 + that.pullData(that.page, { + done: function () { + that.observeResize(); // 观察尺寸变化 + }, + }); + + that.events(); // 事件 +}; + +// 根据列类型,定制化参数 +Class.prototype.initOpts = function (item) { + // var that = this; + // var options = that.config; + var initWidth = { + checkbox: 50, + radio: 50, + space: 30, + numbers: 60, + }; + + // 让 type 参数兼容旧版本 + if (item.checkbox) item.type = 'checkbox'; + if (item.space) item.type = 'space'; + if (!item.type) item.type = 'normal'; + + if (item.type !== 'normal') { + item.unresize = true; + item.width = item.width || initWidth[item.type]; + } +}; + +//初始化一些参数 +Class.prototype.setInit = function (type) { + var that = this; + var options = that.config; + + options.clientWidth = + options.width || + (function () { + //获取容器宽度 + //如果父元素宽度为0(一般为隐藏元素),则继续查找上层元素,直到找到真实宽度为止 + var getWidth = function (parent) { + var width; + var isNone; + parent = parent || options.elem.parent(); + + width = that.getContentWidth(parent); + + try { + isNone = parent.css('display') === 'none'; + } catch { + // ignore + } + var parentElem = parent.parent(); + if (parent[0] && parentElem && parentElem[0] && (!width || isNone)) + return getWidth(parentElem); + return width; + }; + return getWidth(); + })(); + + if (type === 'width') return options.clientWidth; + // 初始化高度配置,如果设置了最高高度,以最高高度形式为准 + options.height = options.maxHeight || options.height; + + // 初始化 css 参数 + if (options.css && options.css.indexOf(ELEM_VIEW) === -1) { + var css = options.css.split('}'); + css.forEach(function (value, index) { + if (value) { + css[index] = '.' + ELEM_VIEW + '-' + that.index + ' ' + value; + } + }); + options.css = css.join('}'); + } + + // 封装对 col 的配置处理 + var initChildCols = function (i1, item1, i2, item2) { + //如果列参数为空,则移除 + if (!item2) { + item1.splice(i2, 1); + return; + } + + item2.key = [options.index, i1, i2].join('-'); + item2.colspan = item2.colspan || 0; + item2.rowspan = item2.rowspan || 0; + + //根据列类型,定制化参数 + that.initOpts(item2); + + //设置列的父列索引 + //如果是组合列,则捕获对应的子列 + var indexChild = i1 + (parseInt(item2.rowspan) || 1); + if (indexChild < options.cols.length) { + // 只要不是最后一层都会有子列 + item2.colGroup = true; + var childIndex = 0; + for (var i22 = 0; i22 < options.cols[indexChild].length; i22++) { + var item22 = options.cols[indexChild][i22]; + // 如果子列已经被标注为{HAS_PARENT},或者子列累计 colspan 数等于父列定义的 colspan,则跳过当前子列 + if ( + item22.HAS_PARENT || + (childIndex >= 1 && childIndex == (item2.colspan || 1)) + ) + continue; + + item22.HAS_PARENT = true; + item22.parentKey = [options.index, i1, i2].join('-'); // i1 + '-' + i2; + childIndex = + childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); + initChildCols(indexChild, options.cols[indexChild], i22, item22); + } + } else { + item2.colGroup = false; + } + item2.hide = (item2.hide && !item2.colGroup) || false; // 初始化中中间节点的hide信息不做处理,否则会出错,如果需要必须将其子节点也都同步成hide + }; + + // 初始化列参数 + options.cols.forEach(function (item1, i1) { + item1.forEach(function (item2, i2) { + if (i1) { + delete item2.HAS_PARENT; // 去掉临时的计数排除标识,避免有新字段插入的时候重新计算被跳过导致下标出错的问题 + } else { + initChildCols(i1, item1, i2, item2); // 只解析顶层节点由递归完成解析 + } + }); + }); +}; + +// 初始化样式 +Class.prototype.renderStyle = function () { + var that = this; + var options = that.config; + var index = that.index; + var text = []; + + // 单元格宽度 + options.cols.forEach(function (item1, i1) { + item1.forEach(function (item2, i2) { + var key = [index, i1, i2].join('-'); + var val = ['width: ', item2.width || options.cellMinWidth, 'px'].join(''); + text.push('.laytable-cell-' + key + '{' + val + '}'); + }); + }); + + // 自定义行样式 + (function (lineStyle) { + if (!lineStyle) return; + var trClassName = + '.lay-table-view-' + index + ' .lay-table-body .lay-table tr'; + var rules = lineStyle.split(';'); + var cellMaxHeight = 'none'; + + // 计算单元格最大高度 + for (let rule of rules) { + rule = rule.split(':'); + if (rule[0] === 'height') { + var val = parseFloat(rule[1]); + if (!isNaN(val)) cellMaxHeight = val - 1 + 'px'; + break; + } + } + + // 多行相关样式 + [ + '{' + lineStyle + '}', + '.lay-table-cell{height: auto; max-height: ' + + cellMaxHeight + + '; white-space: normal; text-overflow: clip;}', + '> td:hover > .lay-table-cell{overflow: auto;}', + ].forEach(function (val) { + val && text.push(trClassName + ' ' + val); + }); + })(options.lineStyle); + + // 自定义 css 属性 + if (options.css) text.push(options.css); + text.push('.' + FIXED_HEIGHT_PATCH + '{height:auto;}'); + + // 生成 style + lay.style({ + target: that.elem[0], + text: text.join(''), + id: 'DF-table-' + index, + }); +}; + +// 初始头部工具栏 +Class.prototype.renderToolbar = function () { + var that = this; + var options = that.config; + var filter = options.elem.attr('lay-filter'); + + // 添加工具栏左侧模板 + var leftDefaultTemp = [ + '
                              ', + '
                              ', + '
                              ', + ].join(''); + var elemToolTemp = that.layTool.find('.lay-table-tool-temp'); + + if (options.toolbar === 'default') { + elemToolTemp.html(leftDefaultTemp); + } else if (typeof options.toolbar === 'string') { + var toolbarHtml = $(options.toolbar).html() || ''; + toolbarHtml && elemToolTemp.html(laytpl(toolbarHtml).render(options)); + } + + // 头部工具栏右上角默认工具 + var defaultConfig = { + filter: { + title: i18n.$t('table.tools.filter.title'), + layEvent: 'LAYTABLE_COLS', + icon: 'lay-icon-cols', + onClick: function (obj) { + var options = obj.config; + var openPanel = obj.openPanel; + + openPanel({ + list: (function () { + var lis = []; + that.eachCols(function (i, item) { + if (item.field && item.type == 'normal') { + lis.push( + '
                            • ', + ); + } + }); + return lis.join(''); + })(), + done: function () { + form.on('checkbox(LAY_TABLE_TOOL_COLS)', function (obj) { + var othis = $(obj.elem); + var checked = this.checked; + var key = othis.data('key'); + var col = that.col(key); + var hide = col.hide; + var parentKey = othis.data('parentkey'); + + if (!col.key) return; + + // 同步勾选列的 hide 值和隐藏样式 + col.hide = !checked; + that.elem + .find('*[data-key="' + key + '"]') + [checked ? 'removeClass' : 'addClass'](HIDE); + + // 根据列的显示隐藏,同步多级表头的父级相关属性值 + if (hide != col.hide) { + that.setParentCol(!checked, parentKey); + } + + // 重新适配尺寸 + that.resize(); + + // 列筛选(显示或隐藏)后的事件 + lay.event.call(this, MOD_NAME, 'colToggled(' + filter + ')', { + col: col, + config: options, + }); + }); + }, + }); + }, + }, + exports: { + title: i18n.$t('table.tools.export.title'), + layEvent: 'LAYTABLE_EXPORT', + icon: 'lay-icon-export', + onClick: function (obj) { + // 自带导出 + var data = obj.data; + var options = obj.config; + var openPanel = obj.openPanel; + var elem = obj.elem; + + if (!data.length) + return layer.tips(i18n.$t('table.tools.export.noDataPrompt'), elem, { + tips: 3, + }); + openPanel({ + list: (function () { + return [ + '
                            • ' + + i18n.$t('table.tools.export.csvText') + + '
                            • ', + ].join(''); + })(), + done: function (panel, list) { + list.on('click', function () { + var type = $(this).data('type'); + table.exportFile.call(that, options.id, null, type); + }); + }, + }); + }, + }, + print: { + title: i18n.$t('table.tools.print.title'), + layEvent: 'LAYTABLE_PRINT', + icon: 'lay-icon-print', + onClick: function (obj) { + var data = obj.data; + // var options = obj.config; + var elem = obj.elem; + + if (!data.length) + return layer.tips(i18n.$t('table.tools.print.noDataPrompt'), elem, { + tips: 3, + }); + var printWin = window.open('about:blank', '_blank'); + var style = [ + '', + ].join(''); + var html = $(that.layHeader.html()); // 输出表头 + + html.append(that.layMain.find('table').html()); // 输出表体 + html.append(that.layTotal.find('table').html()); // 输出合计行 + + html.find('th.lay-table-patch').remove(); // 移除补丁 + // 移除表头特殊列 + html + .find('thead>tr>th.' + ELEM_COL_SPECIAL) + .filter(function (i, thElem) { + return !$(thElem).children('.' + ELEM_GROUP).length; // 父级表头除外 + }) + .remove(); + html.find('tbody>tr>td.' + ELEM_COL_SPECIAL).remove(); // 移除表体特殊列 + + printWin.document.write(style + html.prop('outerHTML')); + printWin.document.close(); + + if (lay.device('edg').edg) { + printWin.onafterprint = printWin.close; + printWin.print(); + } else { + printWin.print(); + printWin.close(); + } + }, + }, + }; + + // 若开启 defaultToolbar + if (typeof options.defaultToolbar === 'object') { + var iconElem = []; + options.defaultToolbar = $.map(options.defaultToolbar, function (item) { + var itemIsName = typeof item === 'string'; + var thisItem = itemIsName ? defaultConfig[item] : item; + if (thisItem) { + // 根据 name 匹配默认工具并合并 + if (thisItem.name && defaultConfig[thisItem.name]) { + thisItem = $.extend({}, defaultConfig[thisItem.name], thisItem); + } + // 初始化默认工具 name + if (!thisItem.name && itemIsName) { + thisItem.name = item; + } + // 图标列表 + iconElem.push( + '
                              ' + + '' + + '
                              ', + ); + } + return thisItem; + }); + that.layTool.find('.lay-table-tool-self').html(iconElem.join('')); + } +}; + +// 分页栏 +Class.prototype.renderPagebar = function () { + var that = this; + var options = that.config; + + var layPagebar = (that.layPagebar = $( + '
                              ', + )); + + // 开启分页栏自定义模板 + if (options.pagebar) { + var pagebarHtml = $(options.pagebar).html() || ''; + pagebarHtml && layPagebar.append(laytpl(pagebarHtml).render(options)); + that.layPage.append(layPagebar); + } +}; + +// 同步表头父列的相关值 +Class.prototype.setParentCol = function (hide, parentKey) { + var that = this; + var options = that.config; + + var parentTh = that.layHeader.find('th[data-key="' + parentKey + '"]'); // 获取父列元素 + var parentColspan = parseInt(parentTh.attr('colspan')) || 0; + + if (parentTh[0]) { + var arrParentKey = parentKey.split('-'); + var getThisCol = options.cols[arrParentKey[1]][arrParentKey[2]]; + + hide ? parentColspan-- : parentColspan++; + + parentTh.attr('colspan', parentColspan); + parentTh[parentColspan ? 'removeClass' : 'addClass'](HIDE); // 如果子列显示,父列必然需要显示 + + getThisCol.colspan2 = parentColspan; // 更新实际的 colspan 数 + getThisCol.hide = parentColspan < 1; // 同步 hide 参数 + + // 递归,继续往上查询是否有父列 + var nextParentKey = parentTh.data('parentkey'); + nextParentKey && that.setParentCol(hide, nextParentKey); + } +}; + +// 多级表头补丁 +Class.prototype.setColsPatch = function () { + var that = this; + var options = that.config; + + // 同步表头父列的相关值 + options.cols.forEach(function (item1) { + item1.forEach(function (item2) { + if (item2.hide) { + that.setParentCol(item2.hide, item2.parentKey); + } + }); + }); +}; + +// 设置组合表头的最大宽度 +Class.prototype.setGroupWidth = function (th) { + var that = this; + var options = that.config; + + if (options.cols.length <= 1) return; + + // 获取表头组合 + var groups = that.layHeader.find( + // 根据当前活动的表头 parentkey 属性查找其组合表头 + (th ? 'th[data-key=' + th.data('parentkey') + ']>' : '') + '.' + ELEM_GROUP, + ); // 若无指向当前活动表头,则自下而上获取所有组合表头 + + groups.css('width', 0); + groups + .get() + .reverse() + .forEach(function (group) { + var othis = $(group); + var key = othis.parent().data('key'); + var maxWidth = 0; + + that.layHeader + .eq(0) + .find('th[data-parentkey=' + key + ']') + .width(function (i, width) { + var oTh = $(this); + if (oTh.hasClass(HIDE)) return; + width > 0 && (maxWidth += width); + }); + + // 给组合表头赋值最大宽度 + if (maxWidth) othis.css('max-width', maxWidth - 1); + + // 若当前活动的组合表头仍存在上级,则继续向上设置 + if (th && othis.parent().data('parentkey')) { + that.setGroupWidth(othis.parent()); + } + }); + groups.css('width', 'auto'); +}; + +// 动态分配列宽 +Class.prototype.setColsWidth = function (opt) { + var that = this; + var options = that.config; + var colNums = 0; // 列个数 + var autoColNums = 0; // 自动列宽的列个数 + var autoWidth = 0; // 自动列分配的宽度 + var countWidth = 0; // 所有列总宽度和 + var cntrWidth = that.setInit('width'); + var borderWidth = parseFloat(lay.getStyle(that.elem[0], 'border-left-width')); + var lastSpreadCol; + var headerTableElem = that.layHeader.first().children('table'); + var mainTableElem = that.layMain.find('table'); + var isEmptyTable = that.layMain.find('tbody').is(':empty'); + var isInit = opt && opt.isInit; + + // 统计列个数和最后一个分配宽度的列 + that.eachCols(function (i, item) { + if (!item.hide) { + colNums++; + if (!(item.width || item.type !== 'normal')) { + lastSpreadCol = item; + } + } + }); + + // 减去边框差和滚动条宽 + cntrWidth = + cntrWidth - + (function () { + return options.skin === 'line' || options.skin === 'nob' + ? 2 + : colNums + 1; + })() * + borderWidth - + that.getScrollWidth(that.layMain[0]); + + // 计算自动分配的宽度 + var getAutoWidth = function (back) { + // 遍历所有列 + options.cols.forEach(function (item1) { + item1.forEach(function (item2, i2) { + var width = 0; + var minWidth = item2.minWidth || options.cellMinWidth; // 最小宽度 + var maxWidth = item2.maxWidth || options.cellMaxWidth; // 最大宽度 + + if (!item2) { + item1.splice(i2, 1); + return; + } + + if (item2.colGroup || item2.hide) return; + + if (!back) { + width = item2.width || 0; + if (/\d+%$/.test(width)) { + // 列宽为百分比 + width = (parseFloat(width) / 100) * cntrWidth; + width < minWidth && (width = minWidth); + width > maxWidth && (width = maxWidth); + } else if (!width) { + // 列宽未填写 + item2.width = width = 0; + autoColNums++; + } else if (item2.type === 'normal') { + // 若 width 小于 minWidth, 则将 width 值自动设为 minWidth 的值 + width < minWidth && (item2.width = width = minWidth); + // 若 width 大于 maxWidth, 则将 width 值自动设为 maxWidth 的值 + width > maxWidth && (item2.width = width = maxWidth); + } + } else if (autoWidth && autoWidth < minWidth) { + autoColNums--; + width = minWidth; + } else if (autoWidth && autoWidth > maxWidth) { + autoColNums--; + width = maxWidth; + } + + if (item2.hide) width = 0; + countWidth = countWidth + width; + }); + }); + + // 如果未填充满,则将剩余宽度平分 + cntrWidth > countWidth && + autoColNums > 0 && + (autoWidth = (cntrWidth - countWidth) / autoColNums); + }; + + getAutoWidth(); + getAutoWidth(true); // 重新检测分配的宽度是否低于最小列宽 + + // 记录自动列数 + that.autoColNums = autoColNums = autoColNums > 0 ? autoColNums : 0; + + var pixelsForLastCol = cntrWidth; + that.eachCols(function (i3, item3) { + var minWidth = item3.minWidth || options.cellMinWidth; + var maxWidth = item3.maxWidth || options.cellMaxWidth; + + if ( + item3.colGroup || + item3.hide || + (lastSpreadCol && lastSpreadCol.key === item3.key) + ) + return; + + // 给未分配宽的列平均分配宽 + if (item3.width === 0) { + that.cssRules(item3.key, function (item) { + var newWidth = Math.round( + (function () { + if (autoWidth < minWidth) return minWidth; + if (autoWidth > maxWidth) return maxWidth; + return autoWidth; + })(), + ); + item.style.width = newWidth + 'px'; + pixelsForLastCol = pixelsForLastCol - newWidth; + }); + } + + // 给设定百分比的列分配列宽 + else if (/\d+%$/.test(item3.width)) { + that.cssRules(item3.key, function (item) { + var width = Math.round((parseFloat(item3.width) / 100) * cntrWidth); + width < minWidth && (width = minWidth); + width > maxWidth && (width = maxWidth); + item.style.width = width + 'px'; + pixelsForLastCol = pixelsForLastCol - width; + }); + } + + // 给拥有普通 width 值的列分配最新列宽 + else { + that.cssRules(item3.key, function (item) { + item.style.width = item3.width + 'px'; + pixelsForLastCol = pixelsForLastCol - item3.width; + }); + } + }); + // 最后一列获取剩余的空间,避免舍入导致的布局问题 + if (lastSpreadCol) { + that.cssRules(lastSpreadCol.key, function (item) { + var minWidth = lastSpreadCol.minWidth || options.cellMinWidth; + var maxWidth = lastSpreadCol.maxWidth || options.cellMaxWidth; + var newWidth = Math.max(Math.min(pixelsForLastCol, maxWidth), minWidth); + item.style.width = newWidth + 'px'; + + if (!isInit && isEmptyTable) { + // 将表格宽度设置为跟表头一样的宽度,使之可以出现底部滚动条,以便滚动查看所有字段 + mainTableElem.width(that.getContentWidth(headerTableElem)); + } + // 二次校验,如果仍然出现横向滚动条(通常是 1px 的误差导致) + // 不同屏幕分辨率、缩放水平以及浏览器渲染差异,可能会触发这个问题 + if ( + that.layMain.prop('offsetHeight') > that.layMain.prop('clientHeight') + ) { + item.style.width = parseFloat(item.style.width) - borderWidth + 'px'; + } + }); + } + + if (!isInit && isEmptyTable) { + // 将表格宽度设置为跟表头一样的宽度,使之可以出现底部滚动条,以便滚动查看所有字段 + mainTableElem.width(that.getContentWidth(headerTableElem)); + } else { + mainTableElem.width('auto'); + } + + that.setGroupWidth(); +}; + +// 重置表格尺寸/结构 +var RESIZE_THRESHOLD = 2; +Class.prototype.resize = function (entry) { + var that = this; + + // 仅由 resizeObserver 触发时生效 + if (entry) { + // 当表格被隐藏时,不触发 resize + if (entry.contentRect.height === 0 && entry.contentRect.width === 0) { + return; + } + + // 忽略微小的尺寸变化 + var shouldIgnore = + entry.target._lay_lastSize && + Math.abs(entry.target._lay_lastSize.height - entry.contentRect.height) < + RESIZE_THRESHOLD && + Math.abs(entry.target._lay_lastSize.width - entry.contentRect.width) < + RESIZE_THRESHOLD; + + if (shouldIgnore) return; + + entry.target._lay_lastSize = { + height: entry.contentRect.height, + width: entry.contentRect.width, + }; + } + + var tableElemIsConnected = + that.layMain && + ('isConnected' in that.layMain[0] + ? that.layMain[0].isConnected + : $.contains(document.body, that.layMain[0])); + + if (!tableElemIsConnected) return; + + that.fullSize(); // 让表格铺满 + that.setColsWidth(); // 自适应列宽 + that.scrollPatch(); // 滚动条补丁 +}; + +// 表格重载 +Class.prototype.reload = function (options, deep, type) { + var that = this; + + options = options || {}; + delete that.haveInit; + + // 防止数组深度合并 + Object.entries(options).forEach(function ([key, item]) { + if (lay.type(item) === 'array') delete that.config[key]; + }); + + // 对参数进行深度或浅扩展 + that.config = $.extend(deep, {}, that.config, options); + if (type !== 'reloadData') { + that.config.cols.forEach(function (item1) { + item1.forEach(function (item2) { + delete item2.colspan2; + }); + }); + delete that.config.HAS_SET_COLS_PATCH; + } + // 执行渲染 + that.render(type); +}; + +// 异常提示 +Class.prototype.errorView = function (html) { + var that = this, + elemNone = that.layMain.find('.' + NONE), + layNone = $('
                              ' + (html || 'Error') + '
                              '); + + if (elemNone[0]) { + that.layNone.remove(); + elemNone.remove(); + } + + that.layFixed.addClass(HIDE); + that.layMain.find('tbody').html(''); + + that.layMain.append((that.layNone = layNone)); + + // 异常情况下对 page 和 total 的内容处理 + that.layTotal.addClass(HIDE_V); + that.layPage.find(ELEM_PAGE_VIEW).addClass(HIDE_V); + + table.cache[that.key] = []; //格式化缓存数据 + + that.syncCheckAll(); + that.renderForm(); + that.setColsWidth(); + that.loading(false); +}; + +// 初始页码 +Class.prototype.page = 1; + +// 获得数据 +Class.prototype.pullData = function (curr, opts) { + var that = this; + var options = that.config; + // 同步表头父列的相关值 + options.HAS_SET_COLS_PATCH || that.setColsPatch(); + options.HAS_SET_COLS_PATCH = true; + var request = options.request; + var response = options.response; + var res; + var sort = function () { + if (typeof options.initSort === 'object') { + that.sort({ + field: options.initSort.field, + type: options.initSort.type, + reloadType: opts.type, + }); + } + }; + var done = function (res, origin) { + that.setColsWidth(); + that.loading(false); + typeof options.done === 'function' && + options.done(res, curr, res[response.countName], origin); + typeof opts.done === 'function' && opts.done(); + }; + + opts = opts || {}; + + // 数据拉取前的回调 + typeof options.before === 'function' && options.before(options); + that.startTime = new Date().getTime(); // 渲染开始时间 + + if (opts.renderData) { + // 将 cache 信息重新渲染 + res = {}; + res[response.dataName] = table.cache[that.key]; + res[response.countName] = options.url + ? lay.type(options.page) === 'object' + ? options.page.count + : res[response.dataName].length + : options.data.length; + + // 记录合计行数据 + if (typeof options.totalRow === 'object') { + res[response.totalRowName] = $.extend({}, that.totalRow); + } + + (that.renderData({ + res: res, + curr: curr, + count: res[response.countName], + type: opts.type, + sort: true, + }), + done(res, 'renderData')); + } else if (options.url) { + // Ajax请求 + var params = {}; + // 当 page 开启,默认自动传递 page、limit 参数 + if (options.page) { + params[request.pageName] = curr; + params[request.limitName] = options.limit; + } + + // 参数 + var data = $.extend(params, options.where); + if ( + options.contentType && + options.contentType.indexOf('application/json') == 0 + ) { + // 提交 json 格式 + data = JSON.stringify(data); + } + + that.loading(true); + + var ajaxOptions = { + type: options.method || 'get', + url: options.url, + contentType: options.contentType, + data: data, + dataType: options.dataType || 'json', + jsonpCallback: options.jsonpCallback, + headers: options.headers || {}, + complete: + typeof options.complete === 'function' ? options.complete : undefined, + success: function (res) { + // 若有数据解析的回调,则获得其返回的数据 + if (typeof options.parseData === 'function') { + res = options.parseData(res) || res; + } + // 检查数据格式是否符合规范 + if (res[response.statusName] != response.statusCode) { + that.errorView( + res[response.msgName] || + i18n.$t('table.dataFormatError', { + statusName: response.statusName, + statusCode: response.statusCode, + }), + ); + } else { + // 当前页不能超过总页数 + var count = res[response.countName]; + var pages = Math.ceil(count / options.limit) || 1; + if (curr > pages) { + curr = pages; + } + that.totalRow = res[response.totalRowName]; + (that.renderData({ + res: res, + curr: curr, + count: count, + type: opts.type, + }), + sort()); + + // 耗时(接口请求+视图渲染) + options.time = new Date().getTime() - that.startTime + ' ms'; + } + done(res, opts.type); + }, + error: function (e, msg) { + if (e && e.status === 0 && that._xhrAbort) { + that._xhrAbort = false; + return; + } + that.errorView(i18n.$t('table.xhrError', { msg: msg })); + typeof options.error === 'function' && options.error(e, msg); + }, + }; + + if (options.ajax) { + options.ajax(ajaxOptions, 'table'); + } else { + // 4:代表响应已完成 + if (that._xhr && that._xhr.readyState !== 4) { + that._xhrAbort = true; + that._xhr.abort(); + } + that._xhr = $.ajax(ajaxOptions); + } + } else if (lay.type(options.data) === 'array') { + //已知数据 + res = {}; + var startLimit = curr * options.limit - options.limit; + var newData = options.data.concat(); + + res[response.dataName] = options.page + ? newData.splice(startLimit, options.limit) + : newData; + res[response.countName] = options.data.length; + + // 记录合计行数据 + if (typeof options.totalRow === 'object') { + res[response.totalRowName] = $.extend({}, options.totalRow); + } + that.totalRow = res[response.totalRowName]; + + (that.renderData({ + res: res, + curr: curr, + count: res[response.countName], + type: opts.type, + }), + sort()); + + done(res, opts.type); + } +}; + +// 遍历表头 +Class.prototype.eachCols = function (callback) { + var that = this; + table.eachCols(null, callback, that.config.cols); + return that; +}; + +// 获取表头参数项 +Class.prototype.col = function (key) { + try { + key = key.split('-'); + return this.config.cols[key[1]][key[2]] || {}; + } catch (e) { + log(e); + return {}; + } +}; + +Class.prototype.getTrHtml = function (data, sort, curr, trsObj) { + var that = this; + var options = that.config; + var trs = (trsObj && trsObj.trs) || []; + var trs_fixed = (trsObj && trsObj.trs_fixed) || []; + var trs_fixed_r = (trsObj && trsObj.trs_fixed_r) || []; + curr = curr || 1; + + data.forEach(function (item1, i1) { + var tds = []; + var tds_fixed = []; + var tds_fixed_r = []; + var numbers = i1 + options.limit * (curr - 1) + 1; // 序号 + + // 数组值是否为 object,如果不是,则自动转为 object + if (typeof item1 !== 'object') { + data[i1] = item1 = { LAY_KEY: item1 }; + try { + table.cache[that.key][i1] = item1; + } catch { + // ignore + } + } + + //若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) + if (lay.type(item1) === 'array' && item1.length === 0) return; + + // 加入序号保留字段 + item1[table.config.numbersName] = numbers; + + // 记录下标, + item1[table.config.indexName] = i1; + if (!sort) item1[table.config.initIndexName] = i1; // 记录初始状态下标,仅用于内部恢复当前页表格排序 + + // 遍历表头 + that.eachCols(function (i3, item3) { + var field = item3.field || i3; + var key = item3.key; + var content = item1[field]; + + if (content === undefined || content === null) content = ''; + if (item3.colGroup) return; + + // td 内容 + var td = [ + '', + '
                              ' + + (function () { + var tplData = $.extend( + true, + { + LAY_COL: item3, + }, + item1, + ); + var checkName = table.config.checkName; + var disabledName = table.config.disabledName; + + // 渲染不同风格的列 + switch (item3.type) { + case 'checkbox': // 复选 + return ( + '' + ); + //break; + case 'radio': // 单选 + return ( + '' + ); + //break; + case 'numbers': + return numbers; + //break; + } + + //解析工具列模板 + if (item3.toolbar) { + return laytpl($(item3.toolbar).html() || '').render(tplData); + } + return parseTempData.call(that, { + item3: item3, + content: content, + tplData: tplData, + }); + })(), + '
                              ', + ].join(''); + + tds.push(td); + if (item3.fixed && item3.fixed !== 'right') tds_fixed.push(td); + if (item3.fixed === 'right') tds_fixed_r.push(td); + }); + + // 添加 tr 属性 + var trAttr = (function () { + var arr = ['data-index="' + i1 + '"']; + if (item1[table.config.checkName]) + arr.push('class="' + ELEM_CHECKED + '"'); + return arr.join(' '); + })(); + + trs.push('' + tds.join('') + ''); + trs_fixed.push('' + tds_fixed.join('') + ''); + trs_fixed_r.push('' + tds_fixed_r.join('') + ''); + }); + + return { + trs: trs, + trs_fixed: trs_fixed, + trs_fixed_r: trs_fixed_r, + }; +}; + +// 返回行节点代码 +table.getTrHtml = function (id, data) { + var that = getThisTable(id); + return that.getTrHtml(data, null, that.page); +}; + +// 数据渲染 +Class.prototype.renderData = function (opts) { + var that = this; + var options = that.config; + + var res = opts.res; + var curr = opts.curr; + var count = (that.count = opts.count); + var sort = opts.sort; + + var data = res[options.response.dataName] || []; //列表数据 + var totalRowData = res[options.response.totalRowName]; //合计行数据 + var trs = []; + var trs_fixed = []; + var trs_fixed_r = []; + + // 渲染视图 + var render = function () { + // 后续性能提升的重点 + if (!sort && that.sortKey) { + return that.sort({ + field: that.sortKey.field, + type: that.sortKey.sort, + pull: true, + reloadType: opts.type, + }); + } + + that.getTrHtml(data, sort, curr, { + trs: trs, + trs_fixed: trs_fixed, + trs_fixed_r: trs_fixed_r, + }); + + // 容器的滚动条位置 + if (!(options.scrollPos === 'fixed' && opts.type === 'reloadData')) { + that.layBody.scrollTop(0); + } + if (options.scrollPos === 'reset') { + that.layBody.scrollLeft(0); + } + + that.layMain.find('.' + NONE).remove(); + that.layMain.find('tbody').html(trs.join('')); + that.layFixLeft.find('tbody').html(trs_fixed.join('')); + that.layFixRight.find('tbody').html(trs_fixed_r.join('')); + + // 渲染表单 + that.syncCheckAll(); + that.renderForm(); + + // 因为 page 参数有可能发生变化 先重新铺满 + that.fullSize(); + + // 滚动条补丁 + that.haveInit + ? that.scrollPatch() + : setTimeout(function () { + that.scrollPatch(); + }, 50); + that.haveInit = true; + + // reloadData 或 renderData 时,tbody 高度可能不变,需要主动同步 + if (that.needSyncFixedRowHeight) { + that.calcFixedRowHeight(); + } + + layer.close(that.tipsIndex); + }; + + table.cache[that.key] = data; //记录数据 + + //显示隐藏合计栏 + that.layTotal[data.length == 0 ? 'addClass' : 'removeClass'](HIDE_V); + + //显示隐藏分页栏 + that.layPage[options.page || options.pagebar ? 'removeClass' : 'addClass']( + HIDE, + ); + that.layPage + .find(ELEM_PAGE_VIEW) + [ + !options.page || count == 0 || (data.length === 0 && curr == 1) + ? 'addClass' + : 'removeClass' + ](HIDE_V); + + //如果无数据 + if (data.length === 0) { + return that.errorView(options.text.none); + } else { + that.layFixLeft.removeClass(HIDE); + } + + //如果执行初始排序 + if (sort) { + return render(); + } + + //正常初始化数据渲染 + render(); //渲染数据 + that.renderTotal(data, totalRowData); //数据合计 + that.layTotal && that.layTotal.removeClass(HIDE); + + //同步分页状态 + if (options.page) { + options.page = $.extend( + { + elem: 'lay-table-page' + options.index, + count: count, + limit: options.limit, + limits: options.limits || [10, 20, 30, 40, 50, 60, 70, 80, 90], + groups: 3, + layout: ['prev', 'page', 'next', 'skip', 'count', 'limit'], + prev: '', + next: '', + jump: function (obj, first) { + if (!first) { + //分页本身并非需要做以下更新,下面参数的同步,主要是因为其它处理统一用到了它们 + //而并非用的是 options.page 中的参数(以确保分页未开启的情况仍能正常使用) + that.page = obj.curr; //更新页码 + options.limit = obj.limit; //更新每页条数 + + that.pullData(obj.curr); + } + }, + }, + options.page, + ); + options.page.count = count; //更新总条数 + laypage.render(options.page); + } +}; + +// 重新渲染数据 +table.renderData = function (id) { + var that = getThisTable(id); + if (!that) { + return; + } + + that.pullData(that.page, { + renderData: true, + type: 'reloadData', + }); +}; + +// 数据合计行 +Class.prototype.renderTotal = function (data, totalRowData) { + var that = this; + var options = that.config; + var totalNums = {}; + + if (!options.totalRow) return; + + data.forEach(function (item1) { + // 若数据项为空数组,则不往下执行(因为删除数据时,会将原有数据设置为 []) + if (lay.type(item1) === 'array' && item1.length === 0) return; + + that.eachCols(function (i3, item3) { + var field = item3.field || i3, + content = item1[field]; + + if (item3.totalRow) { + totalNums[field] = (totalNums[field] || 0) + (parseFloat(content) || 0); + } + }); + }); + + that.dataTotal = []; // 记录合计行结果 + + var tds = []; + that.eachCols(function (i3, item3) { + var field = item3.field || i3; + + // 合计数据的特定字段 + var TOTAL_NUMS = totalRowData && totalRowData[item3.field]; + + // 合计数据的小数点位数处理 + var decimals = 'totalRowDecimals' in item3 ? item3.totalRowDecimals : 2; + var thisTotalNum = totalNums[field] + ? parseFloat(totalNums[field] || 0).toFixed(decimals) + : ''; + + // 合计内容 + var content = (function () { + var text = item3.totalRowText || ''; + var tplData = { + LAY_COL: item3, + }; + + tplData[field] = thisTotalNum; + + // 获取自动计算的合并内容 + var getContent = item3.totalRow + ? parseTempData.call(that, { + item3: item3, + content: thisTotalNum, + tplData: tplData, + }) || text + : text; + + // 如果直接传入了合计行数据,则不输出自动计算的结果 + return TOTAL_NUMS || getContent; + })(); + + // td 显示内容 + var tdContent = (function () { + var totalRow = item3.totalRow || options.totalRow; + + // 如果 totalRow 参数为字符类型,则解析为自定义模版 + if (typeof totalRow === 'string') { + return laytpl(totalRow).render( + $.extend( + { + TOTAL_NUMS: TOTAL_NUMS || totalNums[field], + TOTAL_ROW: totalRowData || {}, + LAY_COL: item3, + }, + item3, + ), + ); + } + + return content; + })(); + + // 合计原始结果 + item3.field && + that.dataTotal.push({ + field: item3.field, + total: $('
                              ' + tdContent + '
                              ').text(), + }); + + // td 容器 + var td = [ + '', + '
                              ' + + tdContent, + '
                              ', + ].join(''); + + tds.push(td); + }); + + var patchElem = that.layTotal.find('.lay-table-patch'); // 可能存在滚动条补丁 + that.layTotal + .find('tbody') + .html( + '' + + tds.join('') + + (patchElem.length ? patchElem.get(0).outerHTML : '') + + '', + ); +}; + +//找到对应的列元素 +Class.prototype.getColElem = function (parent, key) { + // var that = this; + //var options = that.config; + return parent.eq(0).find('.laytable-cell-' + key + ':eq(0)'); +}; + +// 渲染表单 +Class.prototype.renderForm = function (type) { + var that = this; + // var options = that.config; + var filter = that.elem.attr('lay-filter'); + form.render(type, filter); +}; + +// 定向渲染表单 +Class.prototype.renderFormByElem = function (elem) { + ['input', 'select'].forEach(function (formType) { + form.render(elem.find(formType)); + }); +}; + +// 同步全选按钮状态 +Class.prototype.syncCheckAll = function () { + var that = this; + var options = that.config; + var checkAllElem = that.layHeader.find('input[name="layTableCheckbox"]'); + var syncColsCheck = function (checked) { + that.eachCols(function (i, item) { + if (item.type === 'checkbox') { + item[options.checkName] = checked; + } + }); + return checked; + }; + var checkStatus = table.checkStatus(that.key); + + if (!checkAllElem[0]) return; + + // 选中状态 + syncColsCheck(checkStatus.isAll); + checkAllElem.prop({ + checked: checkStatus.isAll, + indeterminate: !checkStatus.isAll && checkStatus.data.length, // 半选 + }); +}; + +// 标记当前活动行背景色 +Class.prototype.setRowActive = function (index, className, removeClass) { + var that = this; + // var options = that.config; + var tr = that.layBody.find('tr[data-index="' + index + '"]'); + className = className || 'lay-table-click'; + + if (removeClass) return tr.removeClass(className); + + tr.addClass(className); + tr.siblings('tr').removeClass(className); +}; + +// 设置行选中状态 +Class.prototype.setRowChecked = function (opts) { + var that = this; + var options = that.config; + var isCheckAll = opts.index === 'all'; // 是否操作全部 + var isCheckMult = lay.type(opts.index) === 'array'; // 是否操作多个 + var isCheckAllOrMult = isCheckAll || isCheckMult; // 是否全选或多选 + + // treeTable 内部已处理选中,此处不再处理 + if (options.tree && options.tree.view) return; + + // 全选或多选时 + if (isCheckAllOrMult) { + that.layBox.addClass(DISABLED_TRANSITION); // 减少回流 + if (opts.type === 'radio') return; // radio 不允许全选或多选 + } + + if (isCheckMult) { + var makeMap = {}; + opts.index.forEach(function (v) { + makeMap[v] = true; + }); + opts.index = makeMap; + } + + // 匹配行元素 + var tbody = that.layBody.children('.lay-table').children('tbody'); + var selector = isCheckAllOrMult + ? 'tr' + : 'tr[data-index="' + opts.index + '"]'; + var tr = (function (tr) { + return isCheckAll + ? tr + : tr.filter( + isCheckMult + ? function () { + var dataIndex = $(this).data('index'); + return opts.index[dataIndex]; + } + : '[data-index="' + opts.index + '"]', + ); + })(tbody.children(selector)); + + // 默认属性 + opts = $.extend( + { + type: 'checkbox', // 选中方式 + }, + opts, + ); + + // 同步数据选中属性值 + var thisData = table.cache[that.key]; + var existChecked = 'checked' in opts; + + // 若为单选框,则单向选中;若为复选框,则切换选中。 + var getChecked = function (value) { + return opts.type === 'radio' ? true : existChecked ? opts.checked : !value; + }; + + var radioCheckedIndex; + + // 给匹配行设置选中状态 + tr.each(function () { + var el = $(this); + var i = el.attr('data-index'); + var item = thisData[i]; + + if (!i) return; // 此时 el 通常为静态表格嵌套时的原始模板 + + // 绕过空项和禁用项 + if (lay.type(item) === 'array' || item[options.disabledName]) { + return; + } + + // 标记数据选中状态 + var checked = (item[options.checkName] = getChecked( + el.hasClass(ELEM_CHECKED), + )); + + // 标记当前行背景色 + el.toggleClass(ELEM_CHECKED, !!checked); + + // 若为 radio 类型,则取消其他行选中背景色 + if (opts.type === 'radio') { + radioCheckedIndex = i; + el.siblings().removeClass(ELEM_CHECKED); + } + }); + + // 若为 radio 类型,移除其他行数据选中状态 + if (radioCheckedIndex) { + thisData.forEach(function (item, i) { + if (Number(radioCheckedIndex) !== Number(i)) { + delete item[options.checkName]; + } + }); + } + + // 若存在复选框或单选框,则标注选中状态样式 + var td = tr.children('td').children('.lay-table-cell'); + var checkedElem = td.children( + 'input[lay-type="' + + ({ + radio: 'layTableRadio', + checkbox: 'layTableCheckbox', + }[opts.type] || 'checkbox') + + '"]:not(:disabled)', + ); + var checkedSameElem = checkedElem.last(); + var fixRElem = checkedSameElem.closest(ELEM_FIXR); + + (opts.type === 'radio' && fixRElem.hasClass(HIDE) + ? checkedElem.first() + : checkedElem + ).prop('checked', getChecked(checkedSameElem.prop('checked'))); + + that.syncCheckAll(); + + if (isCheckAllOrMult) { + setTimeout(function () { + that.layBox.removeClass(DISABLED_TRANSITION); + }, 100); + } +}; + +// 数据排序 +Class.prototype.sort = function (opts) { + // field, type, pull, fromEvent + var that = this; + var field; + var res = {}; + var options = that.config; + var filter = options.elem.attr('lay-filter'); + var data = table.cache[that.key], + thisData; + + opts = opts || {}; + + // 字段匹配 + if (typeof opts.field === 'string') { + field = opts.field; + that.layHeader.find('th').each(function () { + var othis = $(this); + var _field = othis.data('field'); + if (_field === opts.field) { + opts.field = othis; + field = _field; + return false; + } + }); + } + + try { + field = field || opts.field.data('field'); + var key = opts.field.data('key'); + + // 如果欲执行的排序已在状态中,则不执行渲染 + if (that.sortKey && !opts.pull) { + if (field === that.sortKey.field && opts.type === that.sortKey.sort) { + return; + } + } + + var elemSort = that.layHeader + .find('th .laytable-cell-' + key) + .find(ELEM_SORT); + that.layHeader.find('th').find(ELEM_SORT).removeAttr('lay-sort'); // 清除其它标题排序状态 + elemSort.attr('lay-sort', opts.type || null); + that.layFixed.find('th'); + } catch { + log("Table modules: sort field '" + field + "' not matched"); + } + + // 记录排序索引和类型 + that.sortKey = { + field: field, + sort: opts.type, + }; + + // 默认为前端自动排序。如果否,则需自主排序(通常为服务端处理好排序) + if (options.autoSort) { + if (opts.type === 'asc') { + //升序 + thisData = lay.sort(data, field, null, true); + } else if (opts.type === 'desc') { + //降序 + thisData = lay.sort(data, field, true, true); + } else { + // 清除排序 + thisData = lay.sort(data, table.config.initIndexName, null, true); + delete that.sortKey; + delete options.initSort; + } + } + + res[options.response.dataName] = thisData || data; + + // 重载数据 + that.renderData({ + res: res, + curr: that.page, + count: that.count, + sort: true, + type: opts.reloadType, + }); + + // 排序是否来自于点击表头事件触发 + if (opts.fromEvent) { + options.initSort = { + field: field, + type: opts.type, + }; + lay.event.call( + opts.field, + MOD_NAME, + 'sort(' + filter + ')', + $.extend( + { + config: options, + }, + options.initSort, + ), + ); + } +}; + +// 请求 loading +Class.prototype.loading = function (show) { + var that = this; + var options = that.config; + + if (options.loading) { + that.layBox.find(ELEM_INIT).toggleClass(HIDE, !show); + } +}; + +// 获取对应单元格的 cssRules +Class.prototype.cssRules = function (key, callback) { + var that = this; + var style = that.elem.children('style')[0]; + + lay.getStyleRules(style, function (item) { + if (item.selectorText === '.laytable-cell-' + key) { + callback(item); + return true; + } + }); +}; + +// 让表格铺满 +Class.prototype.fullSize = function () { + var that = this; + var options = that.config; + var height = options.height; + var bodyHeight; + var MIN_HEIGHT = 135; + + if (that.fullHeightGap) { + height = _WIN.height() - that.fullHeightGap; + if (height < MIN_HEIGHT) height = MIN_HEIGHT; + // that.elem.css('height', height); + } else if (that.parentDiv && that.parentHeightGap) { + height = $(that.parentDiv).height() - that.parentHeightGap; + if (height < MIN_HEIGHT) height = MIN_HEIGHT; + // that.elem.css("height", height); + } else if (that.customHeightFunc) { + height = that.customHeightFunc(); + if (height < MIN_HEIGHT) height = MIN_HEIGHT; + } + + // 如果多级表头,则填补表头高度 + if (options.cols.length > 1) { + // 补全高度 + var th = that.layFixed.find(ELEM_HEADER).find('th'); + // 固定列表头同步跟本体 th 一致高度 + var headerMain = that.layHeader.first(); + th.each(function (thIndex, thElem) { + thElem = $(thElem); + thElem.height( + headerMain + .find('th[data-key="' + thElem.attr('data-key') + '"]') + .height() + 'px', + ); + }); + } + + if (!height) return; + + // 减去列头区域的高度 --- 此处的数字常量是为了防止容器处在隐藏区域无法获得高度的问题,只对默认尺寸表格做支持 + bodyHeight = parseFloat(height) - (that.layHeader.outerHeight() || 39); + + // 减去工具栏的高度 + if (options.toolbar) { + bodyHeight -= that.layTool.outerHeight() || 51; + } + + // 减去统计栏的高度 + if (options.totalRow) { + bodyHeight -= that.layTotal.outerHeight() || 40; + } + + // 减去分页栏的高度 + if (options.page || options.pagebar) { + bodyHeight -= that.layPage.outerHeight() || 43; + } + + if (options.maxHeight) { + Object.entries({ elem: height, layMain: bodyHeight }).forEach(function ([ + elemName, + elemHeight, + ]) { + that[elemName].css({ + height: 'auto', + maxHeight: elemHeight + 'px', + }); + }); + } else { + that.layMain.outerHeight(bodyHeight); + } +}; + +//获取滚动条宽度 +Class.prototype.getScrollWidth = function (elem) { + var width; + if (elem) { + width = elem.offsetWidth - elem.clientWidth; + } else { + elem = document.createElement('div'); + elem.style.width = '100px'; + elem.style.height = '100px'; + elem.style.overflowY = 'scroll'; + + document.body.appendChild(elem); + width = elem.offsetWidth - elem.clientWidth; + document.body.removeChild(elem); + } + return width; +}; + +// 滚动条补丁 +Class.prototype.scrollPatch = function () { + var that = this; + var layMainTable = that.layMain.children('table'); + var scrollWidth = that.layMain.width() - that.layMain.prop('clientWidth'); // 纵向滚动条宽度 + var scrollHeight = that.layMain.height() - that.layMain.prop('clientHeight'); // 横向滚动条高度 + // var getScrollWidth = that.getScrollWidth(that.layMain[0]); // 获取主容器滚动条宽度,如果有的话 + var outWidth = layMainTable.outerWidth() - that.layMain.width(); // 表格内容器的超出宽度 + + // 添加补丁 + var addPatch = function (elem) { + if (scrollWidth && scrollHeight) { + elem = elem.eq(0); + if (!elem.find('.lay-table-patch')[0]) { + var patchElem = $( + '
                              ', + ); // 补丁元素 + patchElem.find('div').css({ + width: scrollWidth, + }); + elem.find('tr').append(patchElem); + } + } else { + elem.find('.lay-table-patch').remove(); + } + }; + + addPatch(that.layHeader); + addPatch(that.layTotal); + + // 固定列区域高度 + var mainHeight = that.layMain.height(); + var fixHeight = mainHeight - scrollHeight; + + that.layFixed + .find(ELEM_BODY) + .css('height', layMainTable.height() >= fixHeight ? fixHeight : 'auto') + .scrollTop(that.layMain.scrollTop()); // 固定列滚动条高度 + + // 表格宽度小于容器宽度时,隐藏固定列 + that.layFixRight[ + table.cache[that.key] && table.cache[that.key].length && outWidth > 0 + ? 'removeClass' + : 'addClass' + ](HIDE); + + // 操作栏 + that.layFixRight.css('right', scrollWidth); +}; + +/** + * @typedef updateRowOptions + * @prop {number} index - 行索引 + * @prop {Object.} data - 行数据 + * @prop {boolean | ((field, index) => boolean)} [related] - 更新其他包含自定义模板且可能有所关联的列视图 + */ +/** + * 更新指定行 + * @param {updateRowOptions | updateRowOptions[]} opts + * @param {(field: string, value: any) => void} [callback] - 更新每个字段时的回调函数 + */ +Class.prototype.updateRow = function (opts, callback) { + opts = lay.type(opts) === 'array' ? opts : [opts]; + + var that = this; + var ELEM_CELL = '.lay-table-cell'; + var dataCache = table.cache[that.key] || []; + + var update = function (opt) { + var index = opt.index; + var row = opt.data; + var related = opt.related; + + var data = dataCache[index] || {}; + var tr = that.layBody.find('tr[data-index="' + index + '"]'); + + // 更新缓存中的数据 + Object.entries(row).forEach(function ([key, value]) { + data[key] = value; + callback && callback(key, value); + }); + + // 更新单元格 + that.eachCols(function (i, item3) { + var field = String(item3.field || i); + var shouldUpdate = + field in row || + ((typeof related === 'function' ? related(field, i) : related) && + (item3.templet || item3.toolbar)); + if (shouldUpdate) { + var td = tr.children('td[data-field="' + field + '"]'); + var cell = td.children(ELEM_CELL); + var content = data[item3.field]; + cell.html( + parseTempData.call(that, { + item3: item3, + content: content, + tplData: $.extend( + { + LAY_COL: item3, + }, + data, + ), + }), + ); + td.data('content', content); + that.renderFormByElem(cell); + } + }); + }; + + opts.forEach(function (opt) { + update(opt); + }); +}; + +/** + * 更新指定行 + * @param {string} id - table ID + * @param {updateRowOptions | updateRowOptions[]} options + */ +table.updateRow = function (id, options) { + var that = getThisTable(id); + return that.updateRow(options); +}; + +// 事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + var filter = options.elem.attr('lay-filter'); + var th = that.layHeader.find('th'); + var ELEM_CELL = '.lay-table-cell'; + + var _BODY = $('body'); + var dict = {}; + + // 头部工具栏操作事件 + that.layTool.on('click', '*[lay-event]', function (e) { + var othis = $(this); + var events = othis.attr('lay-event'); + var data = table.cache[options.id]; + + // 弹出工具下拉面板 + var openPanel = function (sets) { + var list = $(sets.list); + var panel = $('
                                '); + + panel.html(list); + + // 限制最大高度 + if (options.height) { + panel.css( + 'max-height', + options.height - (that.layTool.outerHeight() || 50), + ); + } + + // 插入元素 + othis.find('.' + ELEM_TOOL_PANEL)[0] || othis.append(panel); + that.renderForm(); + + panel.on('click', function (e) { + e.stopPropagation(); + }); + + sets.done && sets.done(panel, list); + }; + + e.stopPropagation(); + _DOC.trigger('table.tool.panel.remove'); + layer.close(that.tipsIndex); + + // 头部工具栏右侧图标 + for (const item of options.defaultToolbar) { + if (item.layEvent === events) { + typeof item.onClick === 'function' && + item.onClick({ + data: data, + config: options, + openPanel: openPanel, + elem: othis, + }); + break; + } + } + + // table toolbar 事件 + lay.event.call( + this, + MOD_NAME, + 'toolbar(' + filter + ')', + $.extend( + { + event: events, + config: options, + }, + {}, + ), + ); + }); + + // 表头自定义元素事件 + that.layHeader.on('click', '*[lay-event]', function () { + var othis = $(this); + var events = othis.attr('lay-event'); + var th = othis.closest('th'); + var key = th.data('key'); + var col = that.col(key); + + lay.event.call( + this, + MOD_NAME, + 'colTool(' + filter + ')', + $.extend( + { + event: events, + config: options, + col: col, + }, + {}, + ), + ); + }); + + // 分页栏操作事件 + that.layPagebar.on('click', '*[lay-event]', function () { + var othis = $(this); + var events = othis.attr('lay-event'); + + lay.event.call( + this, + MOD_NAME, + 'pagebar(' + filter + ')', + $.extend( + { + event: events, + config: options, + }, + {}, + ), + ); + }); + + // 拖拽调整宽度 + th.on('mousemove', function (e) { + var othis = $(this); + var oLeft = othis.offset().left; + var pLeft = e.clientX - oLeft; + if (othis.data('unresize') || thisTable.eventMoveElem) { + return; + } + dict.allowResize = othis.width() - pLeft <= 10; //是否处于拖拽允许区域 + _BODY.css('cursor', dict.allowResize ? 'col-resize' : ''); + }) + .on('mouseleave', function () { + // var othis = $(this); + if (thisTable.eventMoveElem) return; + dict.allowResize = false; + _BODY.css('cursor', ''); + }) + .on('mousedown', function (e) { + var othis = $(this); + if (dict.allowResize) { + var key = othis.data('key'); + e.preventDefault(); + dict.offset = [e.clientX, e.clientY]; //记录初始坐标 + + that.cssRules(key, function (item) { + var width = item.style.width || othis.outerWidth(); + dict.rule = item; + dict.ruleWidth = parseFloat(width); + dict.minWidth = othis.data('minwidth') || options.cellMinWidth; + dict.maxWidth = othis.data('maxwidth') || options.cellMaxWidth; + }); + + // 临时记录当前拖拽信息 + othis.data(DATA_MOVE_NAME, dict); + thisTable.eventMoveElem = othis; + } + }); + + // 拖拽中 + if (!thisTable.docEvent) { + _DOC + .on('mousemove', function (e) { + if (thisTable.eventMoveElem) { + var dict = thisTable.eventMoveElem.data(DATA_MOVE_NAME) || {}; + + thisTable.eventMoveElem.data('resizing', 1); + e.preventDefault(); + + if (dict.rule) { + var setWidth = dict.ruleWidth + e.clientX - dict.offset[0]; + var id = thisTable.eventMoveElem + .closest('.' + ELEM_VIEW) + .attr(MOD_ID); + var thatTable = getThisTable(id); + + if (!thatTable) return; + + if (setWidth < dict.minWidth) setWidth = dict.minWidth; + if (setWidth > dict.maxWidth) setWidth = dict.maxWidth; + + dict.rule.style.width = setWidth + 'px'; + thatTable.setGroupWidth(thisTable.eventMoveElem); + layer.close(that.tipsIndex); + } + } + }) + .on('mouseup', function () { + if (thisTable.eventMoveElem) { + var th = thisTable.eventMoveElem; // 当前触发拖拽的 th 元素 + var id = th.closest('.' + ELEM_VIEW).attr(MOD_ID); + var thatTable = getThisTable(id); + + if (!thatTable) return; + + var key = th.data('key'); + var col = thatTable.col(key); + var filter = thatTable.config.elem.attr('lay-filter'); + + // 重置过度信息 + dict = {}; + _BODY.css('cursor', ''); + thatTable.scrollPatch(); + + // 清除当前拖拽信息 + th.removeData(DATA_MOVE_NAME); + delete thisTable.eventMoveElem; + + // 列拖拽宽度后的事件 + thatTable.cssRules(key, function (item) { + col.width = parseFloat(item.style.width); + lay.event.call(th[0], MOD_NAME, 'colResized(' + filter + ')', { + col: col, + config: thatTable.config, + }); + }); + } + }); + } + + // 已给 document 执行全局事件,避免重复绑定 + thisTable.docEvent = true; + + // 排序 + th.on('click', function (e) { + var othis = $(this); + var elemSort = othis.find(ELEM_SORT); + var nowType = elemSort.attr('lay-sort'); + var type; + + // 表头工具元素不触发排序 + if ($(e.target).closest('[lay-event]')[0]) { + return; + } + + // 其他条件不触发排序 + if (!elemSort[0] || othis.data('resizing') === 1) { + return othis.removeData('resizing'); + } + + if (nowType === 'asc') { + type = 'desc'; + } else if (nowType === 'desc') { + type = null; + } else { + type = 'asc'; + } + that.sort({ + field: othis, + type: type, + fromEvent: true, + }); + }) + .find(ELEM_SORT + ' .lay-edge ') + .on('click', function (e) { + var othis = $(this); + var index = othis.index(); + var field = othis.parents('th').eq(0).data('field'); + e.stopPropagation(); + if (index === 0) { + that.sort({ + field: field, + type: 'asc', + fromEvent: true, + }); + } else { + that.sort({ + field: field, + type: 'desc', + fromEvent: true, + }); + } + }); + + //数据行中的事件返回的公共对象成员 + var commonMember = (that.commonMember = function (sets) { + var othis = $(this); + var index = othis.parents('tr').eq(0).data('index'); + var tr = that.layBody.find('tr[data-index="' + index + '"]'); + var data = table.cache[that.key] || []; + + data = data[index] || {}; + + // 事件返回的公共成员 + var obj = { + tr: tr, // 行元素 + config: options, + data: table.clearCacheKey(data), // 当前行数据 + dataCache: data, // 当前行缓存中的数据 + index: index, + del: function () { + // 删除行数据 + table.cache[that.key][index] = []; + tr.remove(); + that.scrollPatch(); + }, + update: function (fields, related) { + // 修改行数据 + fields = fields || {}; + that.updateRow( + { + index: index, + data: fields, + related: related, + }, + function (key, value) { + obj.data[key] = value; + }, + ); + }, + // 设置行选中状态 + setRowChecked: function (opts) { + that.setRowChecked( + $.extend( + { + index: index, + }, + opts, + ), + ); + }, + // 获取当前列 + }; + + return $.extend(obj, sets); + }); + + // 复选框选择(替代元素的 click 事件) + that.elem.on('click', 'input[name="layTableCheckbox"]+', function (e) { + var othis = $(this); + var td = othis.closest('td'); + var checkbox = othis.prev(); + // var children = that.layBody.find('input[name="layTableCheckbox"]'); + var index = checkbox.parents('tr').eq(0).data('index'); + var checked = checkbox[0].checked; + var isAll = checkbox.attr('lay-filter') === 'layTableAllChoose'; + + if (checkbox[0].disabled) return; + + // 全选 + if (isAll) { + that.setRowChecked({ + index: 'all', + checked: checked, + }); + } else { + that.setRowChecked({ + index: index, + checked: checked, + }); + } + + e.stopPropagation(); + + // 事件 + lay.event.call( + checkbox[0], + MOD_NAME, + 'checkbox(' + filter + ')', + commonMember.call(checkbox[0], { + checked: checked, + type: isAll ? 'all' : 'one', + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + }, + }), + ); + }); + + // 单选框选择 + that.elem.on('click', 'input[lay-type="layTableRadio"]+', function (e) { + var othis = $(this); + var td = othis.closest('td'); + var radio = othis.prev(); + var checked = radio[0].checked; + var index = radio.parents('tr').eq(0).data('index'); + + e.stopPropagation(); + if (radio[0].disabled) return false; + + // 标注选中样式 + that.setRowChecked({ + type: 'radio', + index: index, + }); + + // 事件 + lay.event.call( + radio[0], + MOD_NAME, + 'radio(' + filter + ')', + commonMember.call(radio[0], { + checked: checked, + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + }, + }), + ); + }); + + // 行事件 + that.layBody + .on('mouseenter', 'tr', function () { + // 鼠标移入行 + var othis = $(this); + var index = othis.index(); + if (othis.data('off')) return; // 不触发事件 + var trsElem = that.layBody.find('tr:eq(' + index + ')'); + trsElem.addClass(ELEM_HOVER); + if (that.needSyncFixedRowHeight) { + that.fixedRowHeightPatchOnHover(this, trsElem, true); + } + }) + .on('mouseleave', 'tr', function () { + // 鼠标移出行 + var othis = $(this); + var index = othis.index(); + if (othis.data('off')) return; // 不触发事件 + var trsElem = that.layBody.find('tr:eq(' + index + ')'); + trsElem.removeClass(ELEM_HOVER); + if (that.needSyncFixedRowHeight) { + that.fixedRowHeightPatchOnHover(this, trsElem, false); + } + }) + .on('click', 'tr', function (e) { + // 单击行 + setRowEvent.call(this, 'row', e); + }) + .on('dblclick', 'tr', function (e) { + // 双击行 + setRowEvent.call(this, 'rowDouble', e); + }) + .on('contextmenu', 'tr', function (e) { + // 菜单 + if (!options.defaultContextmenu) e.preventDefault(); + setRowEvent.call(this, 'rowContextmenu', e); + }); + + // 创建行单击、双击、菜单事件 + var setRowEvent = function (eventType, e) { + var othis = $(this); + if (othis.data('off')) return; // 不触发事件 + + // 不触发「行单/双击事件」的子元素 + if (eventType !== 'rowContextmenu') { + var UNROW = [ + '.lay-form-checkbox', + '.lay-form-switch', + '.lay-form-radio', + '[lay-unrow]', + '[lay-type="layTableCheckbox"]', + '[lay-type="layTableRadio"]', + ].join(','); + + if ($(e.target).is(UNROW) || $(e.target).closest(UNROW)[0]) { + return; + } + } + + lay.event.call( + this, + MOD_NAME, + eventType + '(' + filter + ')', + commonMember.call(othis.children('td')[0], { + e: e, + }), + ); + }; + + // 渲染单元格编辑状态 + var renderGridEdit = function (othis, e) { + othis = $(othis); + + if (othis.data('off')) return; // 不触发事件 + + var field = othis.data('field'); + var key = othis.data('key'); + var col = that.col(key); + var index = othis.closest('tr').data('index'); + var data = table.cache[that.key][index]; + // var elemCell = othis.children(ELEM_CELL); + + // 是否开启编辑 + // 若 edit 传入函数,则根据函数的返回结果判断是否开启编辑 + var editType = typeof col.edit === 'function' ? col.edit(data) : col.edit; + + // 显示编辑表单 + if (editType) { + var input = $( + (function () { + var inputElem = + ''; + if (editType === 'textarea') { + inputElem = + ''; + } + return inputElem; + })(), + ); + input[0].value = (function (val) { + return val === undefined || val === null ? '' : val; + })(othis.data('content') || data[field]); + othis.find('.' + ELEM_EDIT)[0] || othis.append(input); + input.focus(); + e?.stopPropagation(); + } + }; + + // 单元格编辑 - 输入框内容被改变的事件 + that.layBody + .on('change', '.' + ELEM_EDIT, function () { + var othis = $(this); + var td = othis.parent(); + var value = this.value; + var field = othis.parent().data('field'); + var index = othis.closest('tr').data('index'); + var data = table.cache[that.key][index]; + + //事件回调的参数对象 + var params = commonMember.call(td[0], { + value: value, + field: field, + oldValue: data[field], // 编辑前的值 + td: td, + reedit: function () { + // 重新编辑 + setTimeout(function () { + // 重新渲染为编辑状态 + renderGridEdit(params.td); + + // 将字段缓存的值恢复到编辑之前的值 + var obj = {}; + obj[field] = params.oldValue; + params.update(obj); + }); + }, + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + }, + }); + + // 更新缓存中的值 + var obj = {}; //变更的键值 + obj[field] = value; + params.update(obj); + + // 执行 API 编辑事件 + lay.event.call(td[0], MOD_NAME, 'edit(' + filter + ')', params); + }) + .on('blur', '.' + ELEM_EDIT, function () { + // 单元格编辑 - 恢复非编辑状态事件 + $(this).remove(); // 移除编辑状态 + }); + + // 表格主体单元格触发编辑的事件 + that.layBody + .on(options.editTrigger, 'td', function (e) { + renderGridEdit(this, e); + }) + .on('mouseenter', 'td', function () { + showGridExpandIcon.call(this); + }) + .on('mouseleave', 'td', function () { + showGridExpandIcon.call(this, 'hide'); + }); + + // 表格合计栏单元格 hover 显示展开图标 + that.layTotal + .on('mouseenter', 'td', function () { + showGridExpandIcon.call(this); + }) + .on('mouseleave', 'td', function () { + showGridExpandIcon.call(this, 'hide'); + }); + + // 显示单元格展开图标 + // var ELEM_GRID = 'lay-table-grid'; + var ELEM_GRID_DOWN = 'lay-table-grid-down'; + // var ELEM_GRID_PANEL = 'lay-table-grid-panel'; + var showGridExpandIcon = function (hide) { + var othis = $(this); + var elemCell = othis.children(ELEM_CELL); + + if (othis.data('off')) return; // 不触发事件 + if (othis.parent().hasClass(ELEM_EXPAND)) return; // 是否已为展开状态 + + if (hide) { + othis.find('.lay-table-grid-down').remove(); + } else if ( + (elemCell.prop('scrollWidth') > elemCell.prop('clientWidth') || + elemCell.find('br').length > 0) && + !options.lineStyle + ) { + if (elemCell.find('.' + ELEM_GRID_DOWN)[0]) return; + othis.append( + '
                                ', + ); + } + }; + // 展开单元格内容 + var gridExpand = function (e, expandedMode) { + var othis = $(this); + var td = othis.parent(); + var key = td.data('key'); + var col = that.col(key); + var index = td.parent().data('index'); + var elemCell = td.children(ELEM_CELL); + var ELEM_CELL_C = 'lay-table-cell-c'; + var elemCellClose = $( + '', + ); + + expandedMode = expandedMode || col.expandedMode || options.cellExpandedMode; + + // 展开风格 + if (expandedMode === 'tips') { + // TIPS 展开风格 + that.tipsIndex = layer.tips( + [ + '
                                ', + elemCell.html(), + '
                                ', + '', + ].join(''), + elemCell[0], + { + tips: [3, ''], + time: -1, + anim: -1, + maxWidth: device.ios || device.android ? 300 : that.elem.width() / 2, + isOutAnim: false, + skin: 'lay-table-tips', + success: function (layero, index) { + layero.find('.lay-table-tips-c').on('click', function () { + layer.close(index); + }); + }, + }, + ); + } else { + // 多行展开风格 + // 恢复其他已经展开的单元格 + that.elem.find('.' + ELEM_CELL_C).trigger('click'); + + // 设置当前单元格展开宽度 + that.cssRules(key, function (item) { + var width = item.style.width; + var expandedWidth = col.expandedWidth || options.cellExpandedWidth; + + // 展开后的宽度不能小于当前宽度 + if (expandedWidth < parseFloat(width)) + expandedWidth = parseFloat(width); + + elemCellClose.data('cell-width', width); + item.style.width = expandedWidth + 'px'; + + setTimeout(function () { + that.scrollPatch(); // 滚动条补丁 + }); + }); + + // 设置当前单元格展开样式 + that.setRowActive(index, ELEM_EXPAND); + + // 插入关闭按钮 + if (!elemCell.next('.' + ELEM_CELL_C)[0]) { + elemCell.after(elemCellClose); + } + + // 关闭展开状态 + elemCellClose.on('click', function () { + var $this = $(this); + that.setRowActive(index, [ELEM_EXPAND, ELEM_HOVER].join(' '), true); // 移除单元格展开样式 + that.cssRules(key, function (item) { + item.style.width = $this.data('cell-width'); // 恢复单元格展开前的宽度 + setTimeout(function () { + that.resize(); // 滚动条补丁 + }); + }); + $this.remove(); + // 重置单元格滚动条位置 + elemCell.scrollTop(0); + elemCell.scrollLeft(0); + }); + } + + othis.remove(); + e.stopPropagation(); + }; + + // 表格主体单元格展开事件 + that.layBody.on('click', '.' + ELEM_GRID_DOWN, function (e) { + gridExpand.call(this, e); + }); + // 表格合计栏单元格展开事件 + that.layTotal.on('click', '.' + ELEM_GRID_DOWN, function (e) { + gridExpand.call(this, e, 'tips'); // 强制采用 tips 风格 + }); + + // 行工具条操作事件 + var toolFn = function (type) { + var othis = $(this); + var td = othis.closest('td'); + var index = othis.parents('tr').eq(0).data('index'); + // 标记当前活动行 + that.setRowActive(index); + + // 执行事件 + lay.event.call( + this, + MOD_NAME, + (type || 'tool') + '(' + filter + ')', + commonMember.call(this, { + event: othis.attr('lay-event'), + getCol: function () { + // 获取当前列的表头配置信息 + return that.col(td.data('key')); + }, + }), + ); + }; + + // 行工具条单击事件 + that.layBody + .on('click', '*[lay-event]', function (e) { + toolFn.call(this); + e.stopPropagation(); + }) + .on('dblclick', '*[lay-event]', function (e) { + //行工具条双击事件 + toolFn.call(this, 'toolDouble'); + e.stopPropagation(); + }); + + // 同步滚动条 + that.layMain.on('scroll', function () { + var othis = $(this); + var scrollLeft = othis.scrollLeft(); + var scrollTop = othis.scrollTop(); + + that.layHeader.scrollLeft(scrollLeft); + that.layTotal.scrollLeft(scrollLeft); + that.layFixed.find(ELEM_BODY).scrollTop(scrollTop); + + layer.close(that.tipsIndex); + }); + + var rAF = + window.requestAnimationFrame || + function (fn) { + return setTimeout(fn, 1000 / 60); + }; + + // 固定列滚轮事件 - 临时兼容方案 + that.layFixed.find(ELEM_BODY).on('mousewheel DOMMouseScroll', function (e) { + var delta = e.originalEvent.wheelDelta || -e.originalEvent.detail; + var scrollTop = that.layMain.scrollTop(); + var step = 100; + var rAFStep = 10; + + e.preventDefault(); + var cb = function () { + if (step > 0) { + step -= rAFStep; + scrollTop += delta > 0 ? -rAFStep : rAFStep; + that.layMain.scrollTop(scrollTop); + rAF(cb); + } + }; + rAF(cb); + }); +}; + +/** + * 获取元素的大小 + * @param {HTMLElement} elem - HTML 元素 + */ +Class.prototype.getElementSize = function (elem) { + if (!window.getComputedStyle) return; + + var style = window.getComputedStyle(elem, null); + return { + height: parseFloat(style.height || '0'), + width: parseFloat(style.width || '0'), + borderTopWidth: parseFloat(style.borderTopWidth || '0'), + borderRightWidth: parseFloat(style.borderRightWidth || '0'), + borderBottomWidth: parseFloat(style.borderBottomWidth || '0'), + borderLeftWidth: parseFloat(style.borderLeftWidth || '0'), + paddingTop: parseFloat(style.paddingTop || '0'), + paddingRight: parseFloat(style.paddingRight || '0'), + paddingBottom: parseFloat(style.paddingBottom || '0'), + paddingLeft: parseFloat(style.paddingLeft || '0'), + marginTop: parseFloat(style.marginTop || '0'), + marginRight: parseFloat(style.marginRight || '0'), + marginBottom: parseFloat(style.marginBottom || '0'), + marginLeft: parseFloat(style.marginLeft || '0'), + boxSizing: style.boxSizing, + }; +}; + +/** + * 获取元素 content 区域宽度值 + * + * layui 内置 jQuery v1.12.4 中的 jQuery.fn.width 始终对值四舍五入(3.x 已修复), + * 在支持 subpixel Rendering 的浏览器中渲染表格,由于列宽分配时计算值精度不足, + * 可能会导致一些小问题(#1726) + * + * 这个方法使用 getComputedStyle 获取精确的宽度值进行计算,为了尽可能和以前的行为 + * 保持一致(主要是隐藏元素内渲染 table 递归获取父元素宽度 https://github.com/layui/layui/discussions/2398), + * 任何非预期的值,都回退到 jQuery.fn.width。未来的版本使用 ResizeObserver 时,可以直接获取表格视图元素的宽度, + * 并移除兼容性代码 + * + * @param {JQuery} elem - 元素的 jQuery 对象 + * + * @see {@link https://learn.microsoft.com/zh-cn/archive/blogs/ie_cn/css-3} + */ +Class.prototype.getContentWidth = function (elem) { + var that = this; + + if ( + // document + elem[0].nodeType === 9 || + elem.css('display') === 'none' + ) { + return elem.width(); + } + + var size = that.getElementSize(elem[0]); + + // display: none|inline 元素,getComputedStyle 无法得到准确的 width/height + if (typeof size === 'undefined' || !size.width) { + return elem.width(); + } else { + return size.boxSizing === 'border-box' + ? size.width - + size.paddingLeft - + size.paddingRight - + size.borderLeftWidth - + size.borderRightWidth + : size.width; + } +}; + +Class.prototype.dispose = function () { + var that = this; + + that.unobserveResize(); + for (var propName in that) { + if (lay.hasOwn(that, propName) && propName !== 'config') { + that[propName] = null; + } + } +}; + +Class.prototype.calcFixedRowHeight = function () { + var that = this; + + var tableElem = that.layMain.children('table'); + var leftTrs = that.layFixLeft.find('>.lay-table-body>table>tbody>tr'); + var rightTrs = that.layFixRight.find('>.lay-table-body>table>tbody>tr'); + var mainTrs = tableElem.find('>tbody>tr'); + + // 批量获取主表格行高,设置高度以优化性能 + var heights = []; + mainTrs.each(function () { + heights.push(that.getElementSize(this).height); + }); + + if (leftTrs.length) { + leftTrs.each(function (i) { + if (heights[i]) { + this.style.height = heights[i] + 'px'; + } + }); + } + + if (rightTrs.length) { + rightTrs.each(function (i) { + if (heights[i]) { + this.style.height = heights[i] + 'px'; + } + }); + } +}; + +// 鼠标悬停于某一列纵向移动时,若单元格会出现横向滚动条,此时 tbody 高度不变,需要修复行高 +Class.prototype.fixedRowHeightPatchOnHover = function ( + targetEl, + trsElem, + isEnter, +) { + var that = this; + var style = that.elem.children('style')[0]; + var selector = '.' + FIXED_HEIGHT_PATCH; + + trsElem.toggleClass(FIXED_HEIGHT_PATCH, isEnter); + // 将当前鼠标悬停行的高度同步到 FIXED_HEIGHT_PATCH (所有区域)类名的样式中 + if (isEnter) { + lay.getStyleRules(style, function (item) { + if (item.selectorText === selector) { + item.style.setProperty( + 'height', + that.getElementSize(targetEl).height + 'px', + 'important', + ); + } + }); + } else { + // 将当前鼠标悬停行主区域的行高同步到固定列行 + var height; + lay.getStyleRules(style, function (item) { + if (item.selectorText === selector) { + item.style.setProperty('height', 'auto'); + } + }); + trsElem = trsElem.filter(function () { + var tr = $(this); + var isFixed = tr.closest(ELEM_FIXED, that.layBox).length > 0; + if (!isFixed) { + height = that.getElementSize(tr[0]).height; + } + return isFixed; + }); + + trsElem.css('height', height); + } +}; + +Class.prototype.observeResize = function () { + var that = this; + + if (!resizeObserver) return; + + that.unobserveResize(); + + var el = that.elem[0]; + var tableEl = that.layMain.children('table')[0]; + + // 显示或隐藏时重置列宽 + resizeObserver.observe(el, that.resize.bind(that)); + + // 同步固定列表格和主表格高度 + var lineStyle = that.config.lineStyle; + var isAutoHeight = lineStyle && /\bheight\s*:\s*auto\b/g.test(lineStyle); + + // 只重载数据时需要主动同步高度,因为 tbody 大小可能不变 + var needSyncFixedRowHeight = (that.needSyncFixedRowHeight = + that.layBody.length > 1 && + (that.config.syncFixedRowHeight || + (that.config.syncFixedRowHeight !== false && isAutoHeight))); + + if (needSyncFixedRowHeight) { + resizeObserver.observe(tableEl, that.calcFixedRowHeight.bind(that)); + } + + that.unobserveResize = function () { + resizeObserver.unobserve(el); + if (needSyncFixedRowHeight) { + resizeObserver.unobserve(tableEl); + } + + that.unobserveResize = $.noop; + }; +}; + +// 全局事件 +(function () { + // 自适应尺寸 + _WIN.on('resize', function () { + Object.values(thisTable.that).forEach(function (tableInst) { + tableInst.resize(); + }); + }); + + // 全局点击 + _DOC.on('click', function () { + _DOC.trigger('table.remove.tool.panel'); + }); + + // 工具面板移除事件 + _DOC.on('table.remove.tool.panel', function () { + $('.' + ELEM_TOOL_PANEL).remove(); + }); +})(); + +// 初始化 +table.init = function (filter, settings) { + settings = settings || {}; + var that = this; + // var inst = null; + var elemTable = + typeof filter === 'object' + ? filter + : typeof filter === 'string' + ? $('table[lay-filter="' + filter + '"]') + : $(ELEM + '[lay-data], ' + ELEM + '[lay-options]'); + var errorTips = + 'Table element property lay-data configuration item has a syntax error: '; + + //遍历数据表格 + elemTable.each(function () { + var othis = $(this); + var attrData = othis.attr('lay-data'); + var tableData = lay.options(this, { + attr: attrData ? 'lay-data' : null, + errorText: errorTips + (attrData || othis.attr('lay-options')), + }); + + var options = $.extend( + { + elem: this, + cols: [], + data: [], + skin: othis.attr('lay-skin'), //风格 + size: othis.attr('lay-size'), //尺寸 + even: typeof othis.attr('lay-even') === 'string', //偶数行背景 + }, + table.config, + settings, + tableData, + ); + + filter && othis.hide(); + + //获取表头数据 + othis.find('thead>tr').each(function (i) { + options.cols[i] = []; + $(this) + .children() + .each(function () { + var th = $(this); + var attrData = th.attr('lay-data'); + var itemData = lay.options(this, { + attr: attrData ? 'lay-data' : null, + errorText: errorTips + (attrData || th.attr('lay-options')), + }); + + var row = $.extend( + { + title: th.text(), + colspan: parseInt(th.attr('colspan')) || 1, //列单元格 + rowspan: parseInt(th.attr('rowspan')) || 1, //行单元格 + }, + itemData, + ); + + options.cols[i].push(row); + }); + }); + + //缓存静态表体数据 + var trElem = othis.find('tbody>tr'); + + //执行渲染 + var tableIns = table.render(options); + + //获取表体数据 + if (trElem.length && !settings.data && !tableIns.config.url) { + var tdIndex = 0; + table.eachCols(tableIns.config.id, function (i3, item3) { + trElem.each(function (i1) { + options.data[i1] = options.data[i1] || {}; + var tr = $(this); + var field = item3.field; + options.data[i1][field] = tr.children('td').eq(tdIndex).html(); + }); + tdIndex++; + }); + + tableIns.reloadData({ + data: options.data, + }); + } + }); + + return that; +}; + +//记录所有实例 +thisTable.that = {}; //记录所有实例对象 +thisTable.config = {}; //记录所有实例配置项 + +var eachChildCols = function (index, cols, i1, item2) { + //如果是组合列,则捕获对应的子列 + if (item2.colGroup) { + var childIndex = 0; + index++; + item2.CHILD_COLS = []; + // 找到它的子列所在cols的下标 + var i2 = i1 + (parseInt(item2.rowspan) || 1); + for (var i22 = 0; i22 < cols[i2].length; i22++) { + var item22 = cols[i2][i22]; + if (item22.parentKey) { + // 如果字段信息中包含了parentKey和key信息 + if (item22.parentKey === item2.key) { + item22.PARENT_COL_INDEX = index; + item2.CHILD_COLS.push(item22); + eachChildCols(index, cols, i2, item22); + } + } else { + // 没有key信息以colspan数量所谓判断标准 + // 如果子列已经被标注为{PARENT_COL_INDEX},或者子列累计 colspan 数等于父列定义的 colspan,则跳过当前子列 + if ( + item22.PARENT_COL_INDEX || + (childIndex >= 1 && childIndex == (item2.colspan || 1)) + ) + continue; + item22.PARENT_COL_INDEX = index; + item2.CHILD_COLS.push(item22); + childIndex = + childIndex + parseInt(item22.colspan > 1 ? item22.colspan : 1); + eachChildCols(index, cols, i2, item22); + } + } + } +}; + +// 遍历表头 +table.eachCols = function (id, callback, cols) { + var config = thisTable.config[id] || {}; + var arrs = [], + index = 0; + + cols = $.extend(true, [], cols || config.cols); + + //重新整理表头结构 + if (cols[0]) { + cols[0].forEach(function (item2) { + eachChildCols(index, cols, 0, item2); + if (item2.PARENT_COL_INDEX) return; //如果是子列,则不进行追加,因为已经存储在父列中 + arrs.push(item2); + }); + } + + //重新遍历列,如果有子列,则进入递归 + var eachArrs = function (obj) { + (obj || arrs).forEach(function (item, i) { + if (item.CHILD_COLS) return eachArrs(item.CHILD_COLS); + typeof callback === 'function' && callback(i, item); + }); + }; + + eachArrs(); +}; + +// 获取表格选中状态 +table.checkStatus = function (id) { + var invalidNum = 0; + var arr = []; + var dataCache = []; + var data = table.cache[id] || []; + + // 过滤禁用或已删除的数据 + data.forEach(function (item) { + if (lay.type(item) === 'array' || item[table.config.disabledName]) { + invalidNum++; // 无效数据数量 + return; + } + if (item[table.config.checkName]) { + arr.push(table.clearCacheKey(item)); + dataCache.push(item); + } + }); + + return { + data: arr, // 选中的数据 + dataCache: dataCache, // 选中的原始缓存数据,包含内部特定字段 + isAll: + data.length && arr.length + ? arr.length === data.length - invalidNum + : false, // 是否全选 + }; +}; + +// 设置行选中状态 +table.setRowChecked = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + that.setRowChecked(opts); +}; + +// 获取表格当前页的所有行数据 +table.getData = function (id) { + var arr = []; + var data = table.cache[id] || []; + data.forEach(function (item) { + if (lay.type(item) === 'array') { + return; + } + arr.push(table.clearCacheKey(item)); + }); + return arr; +}; + +// 重置表格尺寸结构 +table.resize = function (id) { + // 若指定表格唯一 id,则只执行该 id 对应的表格实例 + if (id) { + var config = getThisTableConfig(id); // 获取当前实例配置项 + if (!config) return; + + getThisTable(id).resize(); + } else { + // 否则重置所有表格实例尺寸 + Object.values(thisTable.that).forEach(function (tableInst) { + tableInst.resize(); + }); + } +}; + +// 表格导出 +table.exportFile = function (id, data, opts) { + data = data || table.clearCacheKey(table.cache[id]); + opts = + typeof opts === 'object' + ? opts + : (function () { + var obj = {}; + opts && (obj.type = opts); + return obj; + })(); + + var type = opts.type || 'csv'; + var thatTable = thisTable.that[id]; + var config = thisTable.config[id] || {}; + var textType = { + csv: 'text/csv', + xls: 'application/vnd.ms-excel', + }[type]; + var alink = document.createElement('a'); + + // 处理 treeTable 数据 + var isTreeTable = config.tree && config.tree.view; + if (isTreeTable) { + try { + data = $.extend(true, [], table.cache[id]); + data = (function fn(data) { + return data.reduce(function (acc, obj) { + var children = obj.children || []; + delete obj.children; + return acc.concat(obj, fn(children)); + }, []); + })(Array.from(data)); + } catch { + // ignore + } + } + + alink.href = + 'data:' + + textType + + ';charset=utf-8,\ufeff' + + encodeURIComponent( + (function () { + var dataTitle = []; + var dataMain = []; + var dataTotal = []; + var fieldsIsHide = {}; + + // 表头和表体 + data.forEach(function (item1, i1) { + var vals = []; + if (typeof id === 'object') { + // 若 id 参数直接为表头数据 + id.forEach(function (item) { + i1 == 0 && dataTitle.push(item || ''); + }); + (lay.isArray(item1) + ? $.extend([], item1) + : table.clearCacheKey(item1) + ).forEach(function (item2) { + vals.push('"' + (item2 || '') + '"'); + }); + } else { + table.eachCols(id, function (i3, item3) { + if ( + item3.ignoreExport === false || + (item3.field && item3.type == 'normal') + ) { + // 不导出隐藏列,除非设置 ignoreExport 强制导出 + if ( + (item3.hide && item3.ignoreExport !== false) || + item3.ignoreExport === true // 忽略导出 + ) { + if (i1 == 0) fieldsIsHide[item3.field] = true; // 记录隐藏列 + return; + } + + var content = item1[item3.field]; + if (content === undefined || content === null) content = ''; + + i1 == 0 && + dataTitle.push( + item3.fieldTitle || item3.title || item3.field || '', + ); + + // 解析内容 + content = parseTempData.call(thatTable, { + item3: item3, + content: content, + tplData: item1, + text: 'text', + obj: { + td: function (field) { + if (isTreeTable) i1 = item1['LAY_DATA_INDEX']; // 兼容 treeTable 索引 + var td = thatTable.layBody.find( + 'tr[data-index="' + i1 + '"]>td', + ); + return td.filter('[data-field="' + field + '"]'); + }, + }, + }); + + // 异常处理 + content = content.replace(/"/g, '""'); // 避免内容存在「双引号」导致异常分隔 + // content += '\t'; // 加「水平制表符」 避免内容被转换格式 + content = '"' + content + '"'; // 避免内容存在「逗号」导致异常分隔 + + // 插入内容 + vals.push(content); + } else if (item3.field && item3.type !== 'normal') { + // https://gitee.com/layui/layui/issues/I8PHCR + if (i1 == 0) fieldsIsHide[item3.field] = true; + } + }); + } + dataMain.push(vals.join(',')); + }); + + // 表合计 + thatTable && + thatTable.dataTotal.forEach(function (o) { + fieldsIsHide[o.field] || + dataTotal.push('"' + (o.total || '') + '"'); + }); + + return ( + dataTitle.join(',') + + '\r\n' + + dataMain.join('\r\n') + + '\r\n' + + dataTotal.join(',') + ); + })(), + ); + + alink.download = + (opts.title || config.title || 'table_' + (config.index || '')) + + '.' + + type; + document.body.appendChild(alink); + alink.click(); + document.body.removeChild(alink); +}; + +// 获取表格配置信息 +table.getOptions = function (id) { + return getThisTableConfig(id); +}; + +// 显示或隐藏列 +table.hideCol = function (id, cols) { + var that = getThisTable(id); + if (!that) { + return; + } + + if (lay.type(cols) === 'boolean') { + // 显示全部或者隐藏全部 + that.eachCols(function (i2, item2) { + var key = item2.key; + var col = that.col(key); + var parentKey = item2.parentKey; + // 同步勾选列的 hide 值和隐藏样式 + if (col.hide != cols) { + var hide = (col.hide = cols); + that.elem + .find('*[data-key="' + key + '"]') + [hide ? 'addClass' : 'removeClass'](HIDE); + // 根据列的显示隐藏,同步多级表头的父级相关属性值 + that.setParentCol(hide, parentKey); + } + }); + } else { + cols = lay.isArray(cols) ? cols : [cols]; + cols.forEach(function (item1) { + that.eachCols(function (i2, item2) { + if (item1.field === item2.field) { + var key = item2.key; + var col = that.col(key); + var parentKey = item2.parentKey; + // 同步勾选列的 hide 值和隐藏样式 + if ('hide' in item1 && col.hide != item1.hide) { + var hide = (col.hide = !!item1.hide); + that.elem + .find('*[data-key="' + key + '"]') + [hide ? 'addClass' : 'removeClass'](HIDE); + // 根据列的显示隐藏,同步多级表头的父级相关属性值 + that.setParentCol(hide, parentKey); + } + } + }); + }); + } + $('.' + ELEM_TOOL_PANEL).remove(); // 关闭字段筛选面板如果打开的话 + // 重新适配尺寸 + that.resize(); +}; + +// 重载 +table.reload = function (id, options, deep, type) { + var config = getThisTableConfig(id); //获取当前实例配置项 + if (!config) return; + + var that = getThisTable(id); + that.reload(options, deep, type); + + return thisTable.call(that); +}; + +// 仅重载数据 +table.reloadData = function () { + var args = $.extend([], arguments); + args[3] = 'reloadData'; + + // 重载时,影响整个结构的参数,不适合更新的参数 + var dataParams = new RegExp( + '^(' + + [ + 'elem', + 'id', + 'cols', + 'width', + 'height', + 'maxHeight', + 'toolbar', + 'defaultToolbar', + 'className', + 'css', + 'pagebar', + ].join('|') + + ')$', + ); + + // 过滤与数据无关的参数 + Object.keys(args[1] || {}).forEach(function (key) { + if (dataParams.test(key)) { + delete args[1][key]; + } + }); + + return table.reload.apply(null, args); +}; + +// 核心入口 +table.render = function (options) { + var inst = new Class(options); + return thisTable.call(inst); +}; + +// 清除临时 Key +table.clearCacheKey = function (data) { + data = $.extend({}, data); + delete data[table.config.checkName]; + delete data[table.config.indexName]; + delete data[table.config.initIndexName]; + delete data[table.config.numbersName]; + delete data[table.config.disabledName]; + return data; +}; + +// 自动完成渲染 +lay.use(function () { + table.init(); +}); + +export { table }; diff --git a/src/components/tabs.js b/src/components/tabs.js new file mode 100644 index 000000000..3d67c6f07 --- /dev/null +++ b/src/components/tabs.js @@ -0,0 +1,880 @@ +/** + * tabs + * 标签页组件 + */ + +import { lay } from '../core/lay.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; + +// 创建组件 +var component = componentBuilder({ + name: 'tabs', // 组件名 + + // 默认配置 + config: { + elem: '.lay-tabs', + trigger: 'click', // 标签切换的触发事件 + headerMode: 'auto', // 标签头部的显示模式 auto | scroll | normal + }, + + CONST: { + ELEM: 'lay-tabs', + HEADER: 'lay-tabs-header', + CLOSE: 'lay-tabs-close', + BODY: 'lay-tabs-body', + ITEM: 'lay-tabs-item', + CARD: 'lay-tabs-card', + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 标签页元素项 + that.headerElem = ['.' + component.CONST.HEADER + ':eq(0)', '>li']; + that.bodyElem = [ + '.' + component.CONST.BODY + ':eq(0)', + '>.' + component.CONST.ITEM, + ]; + + // 获取标签容器中的 header body 相关元素 + that.getContainer = function () { + var elem = that.documentElem || options.elem; + return { + header: { + elem: elem.find(that.headerElem[0]), + items: elem.find(that.headerElem.join('')), + }, + body: { + elem: elem.find(that.bodyElem[0]), + items: elem.find(that.bodyElem.join('')), + }, + }; + }; + + // 若 header 选项类型为数组 + if (lay.type(options.header) === 'array') { + // if (options.header.length === 0) return; + + // 给任意元素绑定 tabs 切换功能 + if (typeof options.header[0] === 'string') { + that.headerElem = options.header.concat(); + that.documentElem = $(document); + } else { + // 方法传值渲染 + that.elemView = $('
                                '); + if (options.className) that.elemView.addClass(options.className); + + var headerElem = $('
                                  '); + var bodyElem = $('
                                  '); + + // 生成标签项 + options.header.forEach(function (item) { + var elemHeaderItem = that.renderHeaderItem(item); + headerElem.append(elemHeaderItem); + }); + options.body.forEach(function (item) { + var elemBodyItem = that.renderBodyItem(item); + bodyElem.append(elemBodyItem); + }); + + that.elemView.append(headerElem).append(bodyElem); + options.elem.html(that.elemView); + } + } else { + that.renderClose(); // 初始化标签关闭结构 + } + + // 若 body 选项类型为数组 + if (lay.type(options.body) === 'array') { + if (typeof options.body[0] === 'string') { + that.documentElem = $(document); + that.bodyElem = options.body.concat(); + } + } + + // 初始选中项 + var data = that.data(); + if ('index' in options && data.index != options.index) { + that.change(that.findHeaderItem(options.index), true); + } else if (data.index === -1) { + // 初始选中项为空时,默认选中第一个 + that.change(that.findHeaderItem(0), true); + } + + // 初始化滚动结构 + that.roll('auto'); + + // 清除隐藏占位 + if (options.elem.hasClass(component.CONST.CLASS_HIDEV)) { + options.elem.removeClass(component.CONST.CLASS_HIDEV); + } + + // 回调 + typeof options.afterRender === 'function' && options.afterRender(data); + + // 渲染成功后的事件 + lay.event.call( + options.elem[0], + component.CONST.MOD_NAME, + 'afterRender(' + options.id + ')', + data, + ); + }, + + // 事件 + events: function () { + var that = this; + var options = that.config; + var container = that.getContainer(); + var MOD_NAME = component.CONST.MOD_NAME; + var TRIGGER_NAMESPACE = '.lay_' + MOD_NAME + '_trigger'; + var delegatedElement = that.documentElem + ? container.header.elem + : options.elem; + + // 标签头部事件 + var trigger = options.trigger + TRIGGER_NAMESPACE; + var elemHeaderItem = that.documentElem + ? that.headerElem[1] + : that.headerElem.join(''); + delegatedElement.off(trigger).on(trigger, elemHeaderItem, function () { + that.change($(this)); + }); + + // 窗口 resize 事件 + if (!inner.onresize) { + var timer; + $(window).on('resize', function () { + clearTimeout(timer); + timer = setTimeout(function () { + Object.keys(component.cache.id).forEach(function (key) { + var that = component.getInst(key); + if (!that) return; + that.roll('init'); + }); + }, 50); + }); + inner.onresize = true; + } + }, +}); + +// 内部变量集 +var inner = {}; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +/** + * 增加标签 + * @param {Object} opts + * @param {string} opts.title - 标签标题 + * @param {string} opts.content - 标签内容 + * @param {string} opts.id - 标签的 lay-id 属性值 + * @param {string} [opts.index] - 活动标签索引,默认取当前选中标签的索引 + * @param {('append'|'prepend'|'after'|'before')} [opts.mode='append'] - 标签插入方式 + * @param {boolean} [opts.active] - 是否将新增项设置为活动标签 + * @param {boolean} [opts.closable] - 标签是否可关闭。初始值取决于 options.closable + * @param {string} [opts.headerItem] - 自定义标签头部元素 + * @param {string} [opts.bodyItem] - 自定义标签内容元素 + * @param {Function} [opts.done] - 标签添加成功后执行的回调函数 + */ +Class.prototype.add = function (opts) { + var that = this; + // var options = that.config; + var container = that.getContainer(); + var newHeaderItem = that.renderHeaderItem(opts); + var newBodyItem = that.renderBodyItem(opts); + var data = that.data(); + + // 选项默认值 + opts = $.extend( + { + active: true, + }, + opts, + ); + + // 插入方式 + if (/(before|after)/.test(opts.mode)) { + // 在活动标签前后插入 + var hasOwnIndex = Object.prototype.hasOwnProperty.call(opts, 'index'); + var headerItem = hasOwnIndex + ? that.findHeaderItem(opts.index) + : data.thisHeaderItem; + var bodyItem = hasOwnIndex + ? that.findBodyItem(opts.index) + : data.thisHeaderItem; + headerItem[opts.mode](newHeaderItem); + bodyItem[opts.mode](newBodyItem); + } else { + // 在标签最前后插入 + var mode = + { + prepend: 'prepend', // 插入标签到最前 + append: 'append', // 插入标签到最后 + }[opts.mode || 'append'] || 'append'; + container.header.elem[mode](newHeaderItem); + container.body.elem[mode](newBodyItem); + } + + // 是否将新增项设置为活动标签 + if (opts.active) { + that.change(newHeaderItem, true); + } else { + that.roll('auto'); + } + + // 回调 + typeof opts.done === 'function' && + opts.done( + $.extend(data, { + headerItem: newHeaderItem, + bodyItem: newBodyItem, + }), + ); +}; + +/** + * 关闭指定标签 + * @param {Object} thisHeaderItem - 当前标签头部项元素 + * @param {boolean} force - 是否强制删除 + */ +Class.prototype.close = function (thisHeaderItem, force) { + if (!thisHeaderItem || !thisHeaderItem[0]) return; + + var that = this; + var options = that.config; + var layid = thisHeaderItem.attr('lay-id'); + var index = thisHeaderItem.index(); + + // 标签是否不可关闭 + if (thisHeaderItem.attr('lay-closable') === 'false') { + return; + } + + // 当前标签相关数据 + var data = that.data(); + + // 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭 + if (!force) { + var closable = lay.event.call( + thisHeaderItem[0], + component.CONST.MOD_NAME, + 'beforeClose(' + options.id + ')', + $.extend(data, { + index: index, + }), + ); + + // 是否阻止关闭 + if (closable === false) { + return; + } + } + + // 如果关闭的是当前标签,则更换当前标签索引 + if (thisHeaderItem.hasClass(component.CONST.CLASS_THIS)) { + if (thisHeaderItem.next()[0]) { + that.change(thisHeaderItem.next(), true); + } else if (thisHeaderItem.prev()[0]) { + that.change(thisHeaderItem.prev(), true); + } + } + + // 移除元素 + that.findBodyItem(layid || index).remove(); + thisHeaderItem.remove(); + + that.roll('auto', index); + + // 获取当前标签相关数据 + data = that.data(); + + // 标签关闭后的事件 + lay.event.call( + data.thisHeaderItem[0], + component.CONST.MOD_NAME, + 'afterClose(' + options.id + ')', + data, + ); +}; + +/** + * 批量关闭标签 + * @see tabs.close + */ +Class.prototype.closeMult = function (mode, index) { + var that = this; + var options = that.config; + var container = that.getContainer(); + var data = that.data(); + var headers = container.header.items; + // var bodys = container.body.items; + var DISABLED_CLOSE_SELECTOR = '[lay-closable="false"]'; // 不可关闭标签选择器 + // var FILTER = ':not(' + DISABLED_CLOSE_SELECTOR + ')'; // 不可关闭标签过滤器 + + index = index === undefined ? data.index : index; + + var headerItem = that.findHeaderItem(index); + // var bodyItem = that.findBodyItem(index); + var itemIndex = headerItem.index(); + + // 若当前选中标签也允许关闭,则尝试寻找不可关闭的标签并将其选中 + if (data.thisHeaderItem.attr('lay-closable') !== 'false') { + if (mode === 'all' || !mode) { + var nextHeader = headers + .filter(':gt(' + data.index + ')' + DISABLED_CLOSE_SELECTOR) + .eq(0); + var prevHeader = $( + headers + .filter(':lt(' + data.index + ')' + DISABLED_CLOSE_SELECTOR) + .get() + .reverse(), + ).eq(0); + if (nextHeader[0]) { + that.change(nextHeader, true); + } else if (prevHeader[0]) { + that.change(prevHeader, true); + } + } else if (index !== data.index) { + // 自动切换到活动标签 + that.change(headerItem, true); + } + } + + // 执行批量关闭标签 + headers.each(function (i) { + var $this = $(this); + var layid = $this.attr('lay-id'); + var bodyItem = that.findBodyItem(layid || i); + + // 标签是否不可关闭 + if ($this.attr('lay-closable') === 'false') { + return; + } + + // 批量关闭方式 + var isCloseOther = mode === 'other' && i !== itemIndex; // 关闭其他标签 + var isCloseRight = mode === 'right' && i > itemIndex; // 关闭右侧标签 + var isCloseLeft = mode === 'left' && i < itemIndex; // 关闭左侧标签(不推荐) + var isCloseAll = mode === 'all'; // 关闭所有标签 + + if (isCloseOther || isCloseRight || isCloseLeft || isCloseAll) { + $this.remove(); + bodyItem.remove(); + } + }); + + that.roll('auto'); + + // 回调 + data = that.data(); + + // 标签关闭后的事件 + lay.event.call( + data.thisHeaderItem[0], + component.CONST.MOD_NAME, + 'afterClose(' + options.id + ')', + data, + ); +}; + +/** + * 切换标签 + * @param {Object} thisHeaderItem - 当前标签头部项元素 + * @param {boolean} [force=false] - 是否强制切换 + * @returns + */ +Class.prototype.change = function (thisHeaderItem, force) { + if (!thisHeaderItem || !thisHeaderItem[0]) return; + + var that = this; + var options = that.config; + var layid = thisHeaderItem.attr('lay-id'); + var index = thisHeaderItem.index(); + var thatA = thisHeaderItem.find('a'); + // 是否存在跳转链接 + var isLink = + typeof thatA.attr('href') === 'string' && thatA.attr('target') === '_blank'; + // 是否不允许选中 + var unselect = typeof thisHeaderItem.attr('lay-unselect') === 'string'; + + // 不满足切换的条件 + if (isLink || unselect) { + return; + } + + // 当前标签相关数据 + var data = that.data(); + + // 标签关闭前的事件。若非强制关闭,可则根据事件的返回结果决定是否关闭 + if (!force) { + var enable = lay.event.call( + thisHeaderItem[0], + component.CONST.MOD_NAME, + 'beforeChange(' + options.id + ')', + $.extend(data, { + from: { + index: data.index, + headerItem: data.thisHeaderItem, + }, + to: { + index: index, + headerItem: thisHeaderItem, + }, + }), + ); + + // 是否阻止切换 + if (enable === false) { + return; + } + } + + // 执行标签头部切换 + thisHeaderItem + .addClass(component.CONST.CLASS_THIS) + .siblings() + .removeClass(component.CONST.CLASS_THIS); + + // 执行标签内容切换 + that + .findBodyItem(layid || index) + .addClass(component.CONST.CLASS_SHOW) + .siblings() + .removeClass(component.CONST.CLASS_SHOW); + + that.roll('auto', index); + + // 重新获取标签相关数据 + data = that.data(); + + // 标签切换后的事件 + lay.event.call( + data.thisHeaderItem[0], + component.CONST.MOD_NAME, + 'afterChange(' + options.id + ')', + data, + ); +}; + +/** + * 渲染标签头部项 + * @param {Object} opts - 标签项配置信息 + */ +Class.prototype.renderHeaderItem = function (opts) { + var that = this; + var options = that.config; + var headerItem = $(opts.headerItem || options.headerItem || '
                                • '); + + headerItem.html(opts.title || 'New Tab').attr('lay-id', opts.id); + that.appendClose(headerItem, opts); // 追加标签关闭元素 + return headerItem; +}; + +/** + * 渲染标签内容项 + * @param {Object} opts - 标签项配置信息 + */ +Class.prototype.renderBodyItem = function (opts) { + var that = this; + var options = that.config; + var bodyItem = $( + opts.bodyItem || + options.bodyItem || + '
                                  ', + ); + + bodyItem.html(opts.content || '').attr('lay-id', opts.id); + return bodyItem; +}; + +/** + * 给某一个标签项追加可关闭元素 + * @param {Object} headerItem - 标签项元素 + * @param {Object} opts - 标签项配置信息 + */ +Class.prototype.appendClose = function (headerItem, opts) { + var that = this; + var options = that.config; + + if (!options.closable) return; + + opts = opts || {}; + + // 不可关闭项 + if (opts.closable == false) { + headerItem.attr('lay-closable', 'false'); + } + + if (headerItem.attr('lay-closable') === 'false') { + return; + } + + // 可关闭项追加关闭按钮 + if (!headerItem.find('.' + component.CONST.CLOSE)[0]) { + var close = $( + '', + ); + close.on('click', function () { + that.close($(this).parent()); + return false; + }); + headerItem.append(close); + } +}; + +// 渲染标签可关闭元素 +Class.prototype.renderClose = function () { + var that = this; + var options = that.config; + var container = that.getContainer(); + + container.header.items.each(function () { + var $this = $(this); + // 是否开启关闭 + if (options.closable) { + that.appendClose($this); + } else { + $this.find('.' + component.CONST.CLOSE).remove(); + } + }); +}; + +/** + * 标签头滚动 + * @param {('auto'|'prev'|'next'|'init')} [mode='next'] - 滚动方式 + * @param {number} index - 标签索引。默认取当前选中标签的索引值 + * @returns + */ +Class.prototype.roll = function (mode, index) { + var that = this; + var options = that.config; + var container = that.getContainer(); + var headerElem = container.header.elem; + var headerItems = container.header.items; + var scrollWidth = headerElem.prop('scrollWidth'); // 实际总长度 + var outerWidth = Math.ceil(headerElem.outerWidth()); // 可视区域的长度 + var tabsLeft = headerElem.data('left') || 0; + var scrollMode = options.headerMode === 'scroll'; // 标签头部是否始终保持滚动模式 + + // 让选中标签始终保持在可视区域 + var rollToVisibleArea = function () { + index = isNaN(index) ? that.data().index : index; + + var thisItemElem = headerItems.eq(index); + if (!thisItemElem[0]) return; + + // 当前标签的相对水平坐标值 + var thisLeft = Math.ceil(thisItemElem.position().left); + var padding = 1; // 让边界额外保持一定间距 + + // 当选中标签溢出在可视区域「左侧」时 + var countWidth = thisLeft - (thisItemElem.prev().outerWidth() || 0); // 始终空出上一个标签 + if (countWidth > 0) countWidth = countWidth - padding; + + // 左侧临界值 + if (tabsLeft + countWidth < 0) { + tabsLeft = countWidth >= 0 ? countWidth : 0; // 标签的复原位移不能超出 0 + return headerElem.css('left', -tabsLeft).data('left', -tabsLeft); + } + + // 当选中标签溢出在可视区域「右侧」时, + countWidth = + thisLeft + + thisItemElem.outerWidth() + + (thisItemElem.next().outerWidth() || 0) + + padding; // 始终空出下一个标签 + + // 右侧临界值 + if (tabsLeft + countWidth - outerWidth > 0) { + tabsLeft = countWidth - outerWidth; + headerElem.css('left', -tabsLeft).data('left', -tabsLeft); + } + }; + + // css 类名 + var CLASS_SCROLL = 'lay-tabs-scroll'; + var CLASS_BAR = 'lay-tabs-bar'; + var CLASS_BAR_ICON = ['lay-icon-prev', 'lay-icon-next']; + + // 滚动结构 + var rollElem = { + elem: $( + '
                                  ', + ), + bar: $( + [ + '
                                  ', + '', + '', + '
                                  ', + ].join(''), + ), + }; + + // 不渲染头部滚动结构 + if (options.headerMode === 'normal') return; + + // 是否渲染滚动结构 + var elemScroll = headerElem.parent('.' + CLASS_SCROLL); + if (scrollMode || (!scrollMode && scrollWidth > outerWidth)) { + if (!elemScroll[0]) { + if (options.elem.hasClass(component.CONST.CARD)) { + rollElem.elem.addClass(component.CONST.CARD); + } + headerElem.wrap(rollElem.elem); + headerElem.after(rollElem.bar); + + // 点击左右箭头 + rollElem.bar.children().on('click', function () { + var othis = $(this); + var mode = othis.attr('lay-mode'); + if ($(this).hasClass(component.CONST.CLASS_DISABLED)) return; + mode && that.roll(mode); + }); + } + } else if (!scrollMode) { + if (elemScroll[0]) { + elemScroll.find('.' + CLASS_BAR).remove(); + headerElem.unwrap().css('left', 0).data('left', 0); + } else { + return; + } + } + + // 初始化滚动模式 + if (mode === 'init') return; + + // 重新获取 + scrollWidth = headerElem.prop('scrollWidth'); // 实际总长度 + outerWidth = headerElem.outerWidth(); // 可视区域的长度 + elemScroll = headerElem.parent('.' + CLASS_SCROLL); + + // 左箭头(往右滚动) + if (mode === 'prev') { + // 当前的 left 减去可视宽度,用于与上一轮的页签比较 + var prevLeft = -tabsLeft - outerWidth; + if (prevLeft < 0) prevLeft = 0; + headerItems.each(function (i, item) { + var li = $(item); + var left = Math.ceil(li.position().left); + + if (left >= prevLeft) { + headerElem.css('left', -left).data('left', -left); + return false; + } + }); + } else if (mode === 'auto') { + // 自动识别滚动 + rollToVisibleArea(); + } else { + // 右箭头(往左滚动) 默认 next + headerItems.each(function (i, item) { + var li = $(item); + var left = Math.ceil(li.position().left); + + if (left + li.outerWidth() >= outerWidth - tabsLeft) { + headerElem.css('left', -left).data('left', -left); + return false; + } + }); + } + + // 同步箭头状态 + tabsLeft = headerElem.data('left') || 0; + + // 左 + elemScroll + .find('.' + CLASS_BAR_ICON[0]) + [tabsLeft < 0 ? 'removeClass' : 'addClass'](component.CONST.CLASS_DISABLED); + // 右 + elemScroll + .find('.' + CLASS_BAR_ICON[1]) + [ + parseFloat(tabsLeft + scrollWidth) - outerWidth > 0 + ? 'removeClass' + : 'addClass' + ](component.CONST.CLASS_DISABLED); +}; + +/** + * 获取标签头部项 + * @param {number|string} index - 标签索引或 lay-id + */ +Class.prototype.findHeaderItem = function (index) { + var container = this.getContainer(); + var headerItems = container.header.items; + + // 根据 lay-id 匹配 + if (typeof index === 'string') { + return headerItems.filter('[lay-id="' + index + '"]'); + } + + return headerItems.eq(index); +}; + +/** + * 获取标签内容项 + * @param {number|string} index - 标签索引或 lay-id + */ +Class.prototype.findBodyItem = function (index) { + var container = this.getContainer(); + var bodyItems = container.body.items; + + // 根据 lay-id 匹配 + if (typeof index === 'string') { + var bodyItem = bodyItems.filter('[lay-id="' + index + '"]'); + return bodyItem[0] + ? bodyItem + : (function () { + // 若未匹配到 lay-id 对应内容项,则通过对应头部项的索引匹配内容项 + var headerItems = container.header.items; + var headerItemIndex = headerItems + .filter('[lay-id="' + index + '"]') + .index(); + + return headerItemIndex !== -1 + ? bodyItems.eq(headerItemIndex) + : bodyItem; + })(); + } + + return bodyItems.eq(index); +}; + +/** + * 返回给回调的公共信息 + * @returns + */ +Class.prototype.data = function () { + var that = this; + var options = that.config; + var container = that.getContainer(); + var thisHeaderItem = container.header.items.filter( + '.' + component.CONST.CLASS_THIS, + ); + var index = thisHeaderItem.index(); + var layid = thisHeaderItem.attr('lay-id'); + + return { + options: options, // 标签配置信息 + container: container, // 标签容器的相关元素 + thisHeaderItem: thisHeaderItem, // 当前活动标签头部项 + thisBodyItem: that.findBodyItem(layid || index), // 当前活动标签内容项 + index: index, // 当前活动标签索引 + length: container.header.items.length, // 标签数量 + }; +}; + +// 扩展组件接口 +$.extend(component, { + /** + * 添加标签 + * @param {string} id - 渲染时的实例 ID + * @param {Object} opts - 添加标签的配置项,详见 Class.prototype.add + */ + add: function (id, opts) { + var that = component.getInst(id); + if (!that) return; + that.add(opts); + }, + + /** + * 关闭标签 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引 + * @param {boolean} [force=false] - 是否强制关闭 + */ + close: function (id, index, force) { + var that = component.getInst(id); + if (!that) return; + // index 若不传,则表示关闭当前标签 + if (index === undefined) { + index = that.data().index; + } + that.close(that.findHeaderItem(index), force); + }, + + /** + * 关闭多个标签 + * @param {string} id - 渲染时的实例 ID + * @param {('other'|'right'|'all')} [mode="all"] - 关闭方式 + * @param {number} index - 活动标签的索引,默认取当前选中标签的索引。一般用于标签右键事件 + */ + closeMult: function (id, mode, index) { + var that = component.getInst(id); + if (!that) return; + that.closeMult(mode, index); + }, + + /** + * 切换标签 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引 + */ + change: function (id, index, force) { + var that = component.getInst(id); + if (!that) return; + that.change(that.findHeaderItem(index), force); + }, + + /** + * 获取标签信息 + * @param {string} id - 渲染时的实例 ID + */ + data: function (id) { + var that = component.getInst(id); + return that ? that.data() : {}; + }, + + /** + * 获取标签指定头部项 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引或 lay-id 值 + * @returns + */ + getHeaderItem: function (id, index) { + var that = component.getInst(id); + if (!that) return; + return that.findHeaderItem(index); + }, + + /** + * 获取标签指定内容项 + * @param {string} id - 渲染时的实例 ID + * @param {number} index - 标签索引或 lay-id 值 + * @returns + */ + getBodyItem: function (id, index) { + var that = component.getInst(id); + if (!that) return; + return that.findBodyItem(index); + }, + + /** + * 刷新标签视图结构 + * @param {string} id - 渲染时的实例 ID + */ + refresh: function (id) { + var that = component.getInst(id); + if (!that) return; + that.roll('auto'); + }, +}); + +// 初始化渲染 +lay.use(function () { + component.render(); +}); + +export { component as tabs }; diff --git a/src/components/transfer.js b/src/components/transfer.js new file mode 100644 index 000000000..65accc5bc --- /dev/null +++ b/src/components/transfer.js @@ -0,0 +1,518 @@ +/** + * transfer + * 穿梭框组件 + */ + +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; +import { laytpl } from '../core/laytpl.js'; +import { form } from './form.js'; + +var component = componentBuilder({ + name: 'transfer', + + // 默认配置 + config: { + width: 200, + height: 360, + data: [], // 数据源 + value: [], // 选中的数据 + showSearch: false, // 是否开启搜索 + id: '', // 唯一索引,默认自增 index + }, + + CONST: { + ELEM: 'lay-transfer', + ELEM_BOX: 'lay-transfer-box', + ELEM_HEADER: 'lay-transfer-header', + ELEM_SEARCH: 'lay-transfer-search', + ELEM_ACTIVE: 'lay-transfer-active', + ELEM_DATA: 'lay-transfer-data', + BTN_DISABLED: 'lay-btn-disabled', + }, + + beforeRender: function (options) { + var that = this; + that.config = $.extend( + { + title: i18n.$t('transfer.title'), + text: { + none: i18n.$t('transfer.noData'), + searchNone: i18n.$t('transfer.noMatch'), + }, + }, + that.config, + options, + ); + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + // 穿梭框模板 + var TPL_BOX = function (obj) { + obj = obj || {}; + return ` +
                                  +
                                  + +
                                  + {{ if(d.data.showSearch){ }} + + {{ } }} +
                                    +
                                    + `; + }; + + // 主模板 + var TPL_MAIN = ` +
                                    + ${TPL_BOX({ + index: 0, + checkAllName: 'layTransferLeftCheckAll', + })} +
                                    + + +
                                    + ${TPL_BOX({ + index: 1, + checkAllName: 'layTransferRightCheckAll', + })} +
                                    + `; + + // 解析模板 + var thisElem = (that.elem = $( + laytpl(TPL_MAIN, { + open: '{{', // 标签符前缀 + close: '}}', // 标签符后缀 + }).render({ + data: options, + index: that.index, // 索引 + }), + )); + + var othis = options.elem; + if (!othis[0]) return; + + // 初始化属性 + options.data = options.data || []; + options.value = options.value || []; + + // 插入组件结构 + othis.html(that.elem); + + // 各级容器 + that.layBox = that.elem.find('.' + CONST.ELEM_BOX); + that.layHeader = that.elem.find('.' + CONST.ELEM_HEADER); + that.laySearch = that.elem.find('.' + CONST.ELEM_SEARCH); + that.layData = thisElem.find('.' + CONST.ELEM_DATA); + that.layBtn = thisElem.find('.' + CONST.ELEM_ACTIVE + ' .lay-btn'); + + // 初始化尺寸 + that.layBox.css({ + width: options.width, + height: options.height, + }); + that.layData.css({ + height: (function () { + var height = options.height - that.layHeader.outerHeight(); + if (options.showSearch) { + height -= that.laySearch.outerHeight(); + } + return height - 2; + })(), + }); + + that.renderData(); // 渲染数据 + that.events(); // 事件 + }, + + // 扩展实例方法 + extendsInstance: function () { + var that = this; + // var options = that.config; + return { + // 获取右侧数据 + getData: function () { + return that.getData.call(that); + }, + }; + }, +}); + +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 渲染数据 +Class.prototype.renderData = function () { + var that = this; + var options = that.config; + + // 左右穿梭框差异数据 + var arr = [ + { + checkName: 'layTransferLeftCheck', + views: [], + }, + { + checkName: 'layTransferRightCheck', + views: [], + }, + ]; + + // 解析格式 + that.parseData(function (item) { + // 标注为 selected 的为右边的数据 + var _index = item.selected ? 1 : 0; + var listElem = ` +
                                  • + +
                                  • + `; + // 按照 options.value 顺序排列右侧数据 + if (_index) { + options.value.forEach(function (v, i) { + if (v == item.value && item.selected) { + arr[_index].views[i] = listElem; + } + }); + } else { + arr[_index].views.push(listElem); + } + delete item.selected; + }); + + that.layData.eq(0).html(arr[0].views.join('')); + that.layData.eq(1).html(arr[1].views.join('')); + + that.renderCheckBtn(); +}; + +// 渲染表单 +Class.prototype.renderForm = function (type) { + form.render(type, 'LAY-transfer-' + this.index); +}; + +// 同步复选框和按钮状态 +Class.prototype.renderCheckBtn = function (obj) { + var that = this; + var options = that.config; + + obj = obj || {}; + + that.layBox.each(function (_index) { + var othis = $(this); + var thisDataElem = othis.find('.' + CONST.ELEM_DATA); + var allElemCheckbox = othis + .find('.' + CONST.ELEM_HEADER) + .find('input[type="checkbox"]'); + var listElemCheckbox = thisDataElem.find('input[type="checkbox"]'); + + // 同步复选框和按钮状态 + var nums = 0; + var haveChecked = false; + + listElemCheckbox.each(function () { + var isHide = $(this).data('hide'); + if (this.checked || this.disabled || isHide) { + nums++; + } + if (this.checked && !isHide) { + haveChecked = true; + } + }); + + allElemCheckbox.prop( + 'checked', + haveChecked && nums === listElemCheckbox.length, + ); // 全选复选框状态 + that.layBtn + .eq(_index) + [haveChecked ? 'removeClass' : 'addClass'](CONST.BTN_DISABLED); // 对应的按钮状态 + + // 无数据视图 + if (!obj.stopNone) { + var isNone = thisDataElem.children( + 'li:not(.' + CONST.CLASS_HIDE + ')', + ).length; + that.noneView(thisDataElem, isNone ? '' : options.text.none); + } + }); + + that.renderForm('checkbox'); +}; + +// 无数据视图 +Class.prototype.noneView = function (thisDataElem, text) { + var createNoneElem = $('

                                    ' + (text || '') + '

                                    '); + if (thisDataElem.find('.' + CONST.CLASS_NONE)[0]) { + thisDataElem.find('.' + CONST.CLASS_NONE).remove(); + } + text.replace(/\s/g, '') && thisDataElem.append(createNoneElem); +}; + +// 同步 value 属性值 +Class.prototype.setValue = function () { + var that = this; + var options = that.config; + var arr = []; + + that.layBox + .eq(1) + .find('.' + CONST.ELEM_DATA + ' input[type="checkbox"]') + .each(function () { + var isHide = $(this).data('hide'); + isHide || arr.push(this.value); + }); + options.value = arr; + + return that; +}; + +// 解析数据 +Class.prototype.parseData = function (callback) { + var that = this; + var options = that.config; + var newData = []; + + options.data.forEach(function (item) { + // 解析格式 + item = + (typeof options.parseData === 'function' + ? options.parseData(item) + : item) || item; + + newData.push((item = $.extend({}, item))); + + options.value.forEach(function (item2) { + if (item2 == item.value) { + item.selected = true; + } + }); + callback && callback(item); + }); + + options.data = newData; + return that; +}; + +// 获得右侧面板数据 +Class.prototype.getData = function (value) { + var that = this; + var options = that.config; + var selectedData = []; + + that.setValue(); + + (value || options.value).forEach(function (item) { + options.data.forEach(function (item2) { + delete item2.selected; + if (item == item2.value) { + selectedData.push(item2); + } + }); + }); + return selectedData; +}; + +// 执行穿梭 +Class.prototype.transfer = function (_index, elem) { + var that = this; + var options = that.config; + var thisBoxElem = that.layBox.eq(_index); + var arr = []; + + if (!elem) { + // 通过按钮触发找到选中的进行移动 + thisBoxElem.each(function () { + var othis = $(this); + var thisDataElem = othis.find('.' + CONST.ELEM_DATA); + + thisDataElem.children('li').each(function () { + var thisList = $(this); + var thisElemCheckbox = thisList.find('input[type="checkbox"]'); + var isHide = thisElemCheckbox.data('hide'); + + if (thisElemCheckbox[0].checked && !isHide) { + thisElemCheckbox[0].checked = false; + thisBoxElem + .siblings('.' + CONST.ELEM_BOX) + .find('.' + CONST.ELEM_DATA) + .append(thisList.clone()); + thisList.remove(); + + // 记录当前穿梭的数据 + arr.push(thisElemCheckbox[0].value); + } + + that.setValue(); + }); + }); + } else { + // 双击单条记录移动 + var thisList = elem; + var thisElemCheckbox = thisList.find('input[type="checkbox"]'); + + thisElemCheckbox[0].checked = false; + thisBoxElem + .siblings('.' + CONST.ELEM_BOX) + .find('.' + CONST.ELEM_DATA) + .append(thisList.clone()); + thisList.remove(); + + // 记录当前穿梭的数据 + arr.push(thisElemCheckbox[0].value); + + that.setValue(); + } + + that.renderCheckBtn(); + + // 穿梭时,如果另外一个框正在搜索,则触发匹配 + var siblingInput = thisBoxElem + .siblings('.' + CONST.ELEM_BOX) + .find('.' + CONST.ELEM_SEARCH + ' input'); + siblingInput.val() === '' || siblingInput.trigger('keyup'); + + // 穿梭时的回调 + options.onchange && options.onchange(that.getData(arr), _index); +}; + +// 事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 左右复选框 + that.elem.on( + 'click', + 'input[lay-filter="layTransferCheckbox"]+', + function () { + var thisElemCheckbox = $(this).prev(); + var checked = thisElemCheckbox[0].checked; + var thisDataElem = thisElemCheckbox + .parents('.' + CONST.ELEM_BOX) + .eq(0) + .find('.' + CONST.ELEM_DATA); + + if (thisElemCheckbox[0].disabled) return; + + // 判断是否全选 + if (thisElemCheckbox.attr('lay-type') === 'all') { + thisDataElem.find('input[type="checkbox"]').each(function () { + if (this.disabled) return; + this.checked = checked; + }); + } + + setTimeout(function () { + that.renderCheckBtn({ stopNone: true }); + }, 0); + }, + ); + + // 双击穿梭 + that.elem.on('dblclick', '.' + CONST.ELEM_DATA + '>li', function () { + var elemThis = $(this); + var thisElemCheckbox = elemThis.children('input[type="checkbox"]'); + var thisDataElem = elemThis.parent(); + var thisBoxElem = thisDataElem.parent(); + var index = thisBoxElem.data('index'); + + if (thisElemCheckbox[0].disabled) return; + + // 根据 dblclick 回调函数返回值决定是否执行穿梭 --- 2.9.3+ + var ret = + typeof options.dblclick === 'function' + ? options.dblclick({ + elem: elemThis, + data: that.getData([thisElemCheckbox[0].value])[0], + index: index, + }) + : null; + + if (ret === false) return; + + that.transfer(index, elemThis); + }); + + // 穿梭按钮事件 + that.layBtn.on('click', function () { + var othis = $(this); + var _index = othis.data('index'); + + if (othis.hasClass(CONST.BTN_DISABLED)) return; + that.transfer(_index); + }); + + // 搜索 + that.laySearch.find('input').on('keyup', function () { + var value = this.value; + var thisDataElem = $(this) + .parents('.' + CONST.ELEM_SEARCH) + .eq(0) + .siblings('.' + CONST.ELEM_DATA); + var thisListElem = thisDataElem.children('li'); + + thisListElem.each(function () { + var thisList = $(this); + var thisElemCheckbox = thisList.find('input[type="checkbox"]'); + var title = thisElemCheckbox[0].title; + + // 是否区分大小写 + if (options.showSearch !== 'cs') { + title = title.toLowerCase(); + value = value.toLowerCase(); + } + + var isMatch = title.indexOf(value) !== -1; + + thisList[isMatch ? 'removeClass' : 'addClass'](CONST.CLASS_HIDE); + thisElemCheckbox.data('hide', isMatch ? false : true); + }); + + that.renderCheckBtn(); + + // 无匹配数据视图 + var isNone = + thisListElem.length === + thisDataElem.children('li.' + CONST.CLASS_HIDE).length; + that.noneView(thisDataElem, isNone ? options.text.searchNone : ''); + }); +}; + +// 扩展组件接口 +$.extend(component, { + // 获得选中的数据(右侧面板) + getData: function (id) { + var that = component.getInst(id); + if (!that) return; + return that.getData(); + }, +}); + +export { component as transfer }; diff --git a/src/components/tree.js b/src/components/tree.js new file mode 100644 index 000000000..5134af998 --- /dev/null +++ b/src/components/tree.js @@ -0,0 +1,1025 @@ +/** + * tree 树组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { $ } from 'jquery'; +import { componentBuilder } from '../core/component.js'; +import { layer } from './layer.js'; +import { form } from './form.js'; + +// 创建组件 +var component = componentBuilder({ + name: 'tree', + + // 默认配置 + config: { + data: [], // 数据 + showCheckbox: false, // 是否显示复选框 + showLine: true, // 是否开启连接线 + accordion: false, // 是否开启手风琴模式 + onlyIconControl: false, // 是否仅允许节点左侧图标控制展开收缩 + isJump: false, // 是否允许点击节点时弹出新窗口跳转 + edit: false, // 是否开启节点的操作图标 + customName: { + // 自定义 data 字段名 + id: 'id', + title: 'title', + children: 'children', + }, + }, + + CONST: { + ELEM: 'lay-tree', + ELEM_SET: 'lay-tree-set', + ICON_CLICK: 'lay-tree-iconClick', + ICON_ADD: 'lay-icon-addition', + ICON_SUB: 'lay-icon-subtraction', + ELEM_ENTRY: 'lay-tree-entry', + ELEM_MAIN: 'lay-tree-main', + ELEM_TEXT: 'lay-tree-txt', + ELEM_PACK: 'lay-tree-pack', + ELEM_SPREAD: 'lay-tree-spread', + ELEM_LINE_SHORT: 'lay-tree-setLineShort', + ELEM_SHOW: 'lay-tree-showLine', + ELEM_EXTEND: 'lay-tree-lineExtend', + }, + + // 渲染之前 + beforeRender: function (options) { + var that = this; + that.config = $.extend( + { + text: { + defaultNodeName: i18n.$t('tree.defaultNodeName'), // 节点默认名称 + none: i18n.$t('tree.noData'), // 数据为空时的文本提示 + }, + }, + that.config, + options, + ); + + // 扁平化数据 + var customName = options.customName || {}; + that.config.flatData = lay.treeToFlat(that.config.data, { + idKey: customName.id, + childrenKey: customName.children, + keepChildren: true, + }); + }, + + // 渲染 + render: function () { + var that = this; + var options = that.config; + + that.checkids = []; + + var wrapper = $( + '
                                    ', + ); + that.tree(wrapper); + + var othis = options.elem; + if (!othis[0]) return; + + // 插入组件结构 + that.elem = wrapper; + that.elemNone = $( + '
                                    ' + options.text.none + '
                                    ', + ); + othis.html(that.elem); + + if (that.elem.find('.' + CONST.ELEM_SET).length == 0) { + return that.elem.append(that.elemNone); + } + + // 复选框渲染 + if (options.showCheckbox) { + that.renderForm('checkbox'); + } + + that.elem.find('.' + CONST.ELEM_SET).each(function () { + var othis = $(this); + + // 最外层 + if (!othis.parent('.lay-tree-pack')[0]) { + othis.addClass('lay-tree-setHide'); + } + + // 没有下一个节点 上一层父级有延伸线 + if ( + !othis.next()[0] && + othis.parents('.lay-tree-pack').eq(1).hasClass('lay-tree-lineExtend') + ) { + othis.addClass(CONST.ELEM_LINE_SHORT); + } + + // 没有下一个节点 外层最后一个 + if ( + !othis.next()[0] && + !othis + .parents('.' + CONST.ELEM_SET) + .eq(0) + .next()[0] + ) { + othis.addClass(CONST.ELEM_LINE_SHORT); + } + }); + }, + + // 扩展实例方法 + extendsInstance: function () { + var that = this; + // var options = that.config; + return { + getChecked: function () { + return that.getChecked.call(that); + }, + setChecked: function (id) { + // 设置值 + return that.setChecked.call(that, id); + }, + }; + }, +}); + +var CONST = component.CONST; + +/** + * 扩展组件原型方法 + */ + +var Class = component.Class; + +// 重载实例 +Class.prototype.reload = function (options, type) { + var that = this; + + // 数组直接覆盖 + Object.entries(options).forEach(function ([key, item]) { + if (lay.type(item) === 'array') { + delete that.config[key]; + } + }); + + that.config = $.extend(true, {}, that.config, options); + that.init(true, type); +}; + +// 渲染表单 +Class.prototype.renderForm = function (type) { + form.render(type, 'LAY-tree-' + this.index); +}; + +// 节点解析 +Class.prototype.tree = function (elem, children) { + var that = this; + var options = that.config; + var customName = options.customName; + var data = children || options.data; + + // 遍历数据 + data.forEach(function (item) { + var hasChild = + item[customName.children] && item[customName.children].length > 0; + var packDiv = $( + '
                                    ', + ); + var entryDiv = $( + [ + '
                                    ', + '
                                    ', + '
                                    ', + // 箭头 + (function () { + if (options.showLine) { + if (hasChild) { + return ( + '' + ); + } else { + return ''; + } + } else { + return ( + '' + ); + } + })(), + // 复选框 + (function () { + return options.showCheckbox + ? '' + : ''; + })(), + // 节点 + (function () { + if (options.isJump && item.href) { + return ( + '' + + (item[customName.title] || + item.label || + options.text.defaultNodeName) + + '' + ); + } else { + return ( + '' + + (item[customName.title] || + item.label || + options.text.defaultNodeName) + + '' + ); + } + })(), + '
                                    ', + // 节点操作图标 + (function () { + if (!options.edit) { + return ''; + } + + var editIcon = { + add: '', + update: '', + del: '', + }; + var arr = ['
                                    ']; + + if (options.edit === true) { + options.edit = ['update', 'del']; + } + + if (typeof options.edit === 'object') { + options.edit.forEach(function (val) { + arr.push(editIcon[val] || ''); + }); + return arr.join('') + '
                                    '; + } + })(), + '
                                    ', + '
                                    ', + ].join(''), + ); + + // 如果有子节点,则递归继续生成树 + if (hasChild) { + entryDiv.append(packDiv); + that.tree(packDiv, item[customName.children]); + } + + elem.append(entryDiv); + + // 若有前置节点,前置节点加连接线 + if (entryDiv.prev('.' + CONST.ELEM_SET)[0]) { + entryDiv.prev().children('.lay-tree-pack').addClass('lay-tree-showLine'); + } + + // 若无子节点,则父节点加延伸线 + if (!hasChild) { + entryDiv.parent('.lay-tree-pack').addClass('lay-tree-lineExtend'); + } + + // 展开节点操作 + that.spread(entryDiv, item); + + // 选择框 + if (options.showCheckbox) { + item.checked && that.checkids.push(item[customName.id]); + that.checkClick(entryDiv, item); + } + + // 操作节点 + options.edit && that.operate(entryDiv, item); + }); +}; + +// 展开节点 +Class.prototype.spread = function (elem, item) { + var that = this; + var options = that.config; + var entry = elem.children('.' + CONST.ELEM_ENTRY); + var elemMain = entry.children('.' + CONST.ELEM_MAIN); + var elemCheckbox = elemMain.find('input[same="layuiTreeCheck"]'); + var elemIcon = entry.find('.' + CONST.ICON_CLICK); + var elemText = entry.find('.' + CONST.ELEM_TEXT); + var touchOpen = options.onlyIconControl ? elemIcon : elemMain; // 判断展开通过节点还是箭头图标 + var state = ''; + + // 展开收缩 + touchOpen.on('click', function () { + var packCont = elem.children('.' + CONST.ELEM_PACK); + var iconClick = touchOpen.children('.lay-icon')[0] + ? touchOpen.children('.lay-icon') + : touchOpen.find('.lay-tree-icon').children('.lay-icon'); + + // 若没有子节点 + if (!packCont[0]) { + state = 'normal'; + } else { + if (elem.hasClass(CONST.ELEM_SPREAD)) { + elem.removeClass(CONST.ELEM_SPREAD); + packCont.slideUp(200); + iconClick.removeClass(CONST.ICON_SUB).addClass(CONST.ICON_ADD); + that.updateFieldValue(item, 'spread', false); + } else { + elem.addClass(CONST.ELEM_SPREAD); + packCont.slideDown(200); + iconClick.addClass(CONST.ICON_SUB).removeClass(CONST.ICON_ADD); + that.updateFieldValue(item, 'spread', true); + + // 是否手风琴 + if (options.accordion) { + var sibls = elem.siblings('.' + CONST.ELEM_SET); + sibls.removeClass(CONST.ELEM_SPREAD); + sibls.children('.' + CONST.ELEM_PACK).slideUp(200); + sibls + .find('.lay-tree-icon') + .children('.lay-icon') + .removeClass(CONST.ICON_SUB) + .addClass(CONST.ICON_ADD); + } + } + } + }); + + // 点击回调 + elemText.on('click', function () { + var othis = $(this); + + // 判断是否禁用状态 + if (othis.hasClass(CONST.CLASS_DISABLED)) return; + + // 判断展开收缩状态 + if (elem.hasClass(CONST.ELEM_SPREAD)) { + state = options.onlyIconControl ? 'open' : 'close'; + } else { + state = options.onlyIconControl ? 'close' : 'open'; + } + + // 获取选中状态 + if (elemCheckbox[0]) { + that.updateFieldValue(item, 'checked', elemCheckbox.prop('checked')); + } + + // 点击产生的回调 + options.click && + options.click({ + elem: elem, + state: state, + data: item, + }); + }); +}; + +// 更新数据源 checked,spread 字段值 +Class.prototype.updateFieldValue = function (obj, field, value) { + if (field in obj) { + obj[field] = value; + } +}; + +/** + * 同步节点选中状态 + * @param {JQuery} elemCheckbox - 复选框元素的 jQuery 对象 + * @param {Object} item - 当前节点数据 + * @param {boolean} isManual - 是否手动触发 + * @returns + */ +Class.prototype.syncCheckedState = function (elemCheckbox, item, isManual) { + var that = this; + var options = that.config; + var customName = options.customName; + var checked = elemCheckbox.prop('checked'); + var nodeWrapper = elemCheckbox.closest('.' + CONST.ELEM_SET); + + if (elemCheckbox.prop('disabled')) return; + + // 同步子节点选中状态 + var setChildrenChecked = function (thisNodeElem, item) { + var children = item[customName.children]; + if (!children || children.length === 0) return; + + var childrenPack = thisNodeElem.children('.' + CONST.ELEM_PACK); + var childrenWrapper = childrenPack.children('.' + CONST.ELEM_SET); + var elemCheckboxs = childrenWrapper + .children('.' + CONST.ELEM_ENTRY) + .find('input[same="layuiTreeCheck"]'); + + elemCheckboxs.each(function (i) { + if (this.disabled) return; // 不可点击则跳过 + var child = children[i]; + // 手动触发时,子节点跟随父节点选中状态;自动渲染时,子节点优先跟随 checked 字段值 + var childChecked = isManual + ? checked + : 'checked' in child + ? child.checked + : checked; + + this.checked = childChecked; + that.updateFieldValue(child, 'checked', childChecked); + + if (child[customName.children]) { + setChildrenChecked(childrenWrapper.eq(i), child); + } + }); + }; + + // 同步父节点选中状态 + var setParentsChecked = function (thisNodeElem) { + // 若无父节点,则终止递归 + if (!thisNodeElem.parents('.' + CONST.ELEM_SET)[0]) return; + + var descendantsChecked; // 后代节点选中状态 + var parentPack = thisNodeElem.parent('.' + CONST.ELEM_PACK); + var parentNodeElem = parentPack.parent(); + var parentCheckbox = parentPack.prev().find('input[same="layuiTreeCheck"]'); + + if (parentCheckbox.prop('disabled')) return; + + // 如果后代节点有任意一条选中,则父节点为选中状态(考虑到兼容性,暂时不支持半选状态) + if (checked) { + parentCheckbox.prop('checked', checked); + } else { + // 如果当前节点取消选中,则根据计算后代节点选中状态,来同步父节点选中状态 + parentPack.find('input[same="layuiTreeCheck"]').each(function () { + if (this.checked) { + descendantsChecked = true; + } + }); + + // 如果后代节点全部未选中,则父节点也应为非选中状态 + descendantsChecked || parentCheckbox.prop('checked', false); + } + + // 向父节点递归 + setParentsChecked(parentNodeElem); + }; + + setChildrenChecked(nodeWrapper, item); + setParentsChecked(nodeWrapper); + + that.renderForm('checkbox'); +}; + +// 复选框选择 +Class.prototype.checkClick = function (elem, item) { + var that = this; + var options = that.config; + var entry = elem.children('.' + CONST.ELEM_ENTRY); + var elemMain = entry.children('.' + CONST.ELEM_MAIN); + + // 点击复选框 + elemMain.on('click', 'input[same="layuiTreeCheck"]', function (e) { + e.stopPropagation(); + }); + elemMain.on('click', 'input[same="layuiTreeCheck"]+', function (e) { + e.stopPropagation(); // 阻止点击节点事件 + + var elemCheckbox = $(this).prev(); + var checked = elemCheckbox.prop('checked'); + + if (elemCheckbox.prop('disabled')) return; + + that.syncCheckedState(elemCheckbox, item, 'manual'); + that.updateFieldValue(item, 'checked', checked); + + // 复选框点击产生的回调 + options.oncheck && + options.oncheck({ + elem: elem, + checked: checked, + data: item, + }); + }); +}; + +// 节点操作 +Class.prototype.operate = function (elem, item) { + var that = this; + var options = that.config; + var customName = options.customName; + var entry = elem.children('.' + CONST.ELEM_ENTRY); + var elemMain = entry.children('.' + CONST.ELEM_MAIN); + + entry.children('.lay-tree-btnGroup').on('click', '.lay-icon', function (e) { + e.stopPropagation(); // 阻止节点操作 + + var type = $(this).data('type'); + var packCont = elem.children('.' + CONST.ELEM_PACK); + var returnObj = { + data: item, + type: type, + elem: elem, + }; + // 增加 + if (type == 'add') { + // 若节点本身无子节点 + if (!packCont[0]) { + // 若开启连接线,更改图标样式 + if (options.showLine) { + elemMain.find('.' + CONST.ICON_CLICK).addClass('lay-tree-icon'); + elemMain + .find('.' + CONST.ICON_CLICK) + .children('.lay-icon') + .addClass(CONST.ICON_ADD) + .removeClass('lay-icon-leaf'); + // 若未开启连接线,显示箭头 + } else { + elemMain.find('.lay-tree-iconArrow').removeClass(CONST.CLASS_HIDE); + } + // 节点添加子节点容器 + elem.append('
                                    '); + } + + // 新增节点 + var key = options.operate && options.operate(returnObj); + var obj = {}; + + obj[customName.title] = options.text.defaultNodeName; + obj[customName.id] = key; + that.tree(elem.children('.' + CONST.ELEM_PACK), [obj]); + + // 放在新增后面,因为要对元素进行操作 + if (options.showLine) { + // 节点本身无子节点 + if (!packCont[0]) { + // 遍历兄弟节点,判断兄弟节点是否有子节点 + var siblings = elem.siblings('.' + CONST.ELEM_SET); + var num = 1; + var parentPack = elem.parent('.' + CONST.ELEM_PACK); + + siblings.each(function (_index, i) { + if (!$(i).children('.' + CONST.ELEM_PACK)[0]) { + num = 0; + } + }); + + // 若兄弟节点都有子节点 + if (num == 1) { + // 兄弟节点添加连接线 + siblings.children('.' + CONST.ELEM_PACK).addClass(CONST.ELEM_SHOW); + siblings + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .removeClass(CONST.ELEM_LINE_SHORT); + elem.children('.' + CONST.ELEM_PACK).addClass(CONST.ELEM_SHOW); + // 父级移除延伸线 + parentPack.removeClass(CONST.ELEM_EXTEND); + // 同层节点最后一个更改线的状态 + parentPack + .children('.' + CONST.ELEM_SET) + .last() + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .last() + .addClass(CONST.ELEM_LINE_SHORT); + } else { + elem + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .addClass(CONST.ELEM_LINE_SHORT); + } + } else { + // 添加延伸线 + if (!packCont.hasClass(CONST.ELEM_EXTEND)) { + packCont.addClass(CONST.ELEM_EXTEND); + } + // 子节点添加延伸线 + elem.find('.' + CONST.ELEM_PACK).each(function () { + $(this) + .children('.' + CONST.ELEM_SET) + .last() + .addClass(CONST.ELEM_LINE_SHORT); + }); + // 如果前一个节点有延伸线 + if ( + packCont + .children('.' + CONST.ELEM_SET) + .last() + .prev() + .hasClass(CONST.ELEM_LINE_SHORT) + ) { + packCont + .children('.' + CONST.ELEM_SET) + .last() + .prev() + .removeClass(CONST.ELEM_LINE_SHORT); + } else { + // 若之前的没有,说明处于连接状态 + packCont + .children('.' + CONST.ELEM_SET) + .last() + .removeClass(CONST.ELEM_LINE_SHORT); + } + // 若是最外层,要始终保持相连的状态 + if (!elem.parent('.' + CONST.ELEM_PACK)[0] && elem.next()[0]) { + packCont + .children('.' + CONST.ELEM_SET) + .last() + .removeClass(CONST.ELEM_LINE_SHORT); + } + } + } + if (!options.showCheckbox) return; + // 若开启复选框,同步新增节点状态 + if (elemMain.find('input[same="layuiTreeCheck"]')[0].checked) { + var packLast = elem + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .last(); + packLast.find('input[same="layuiTreeCheck"]')[0].checked = true; + } + that.renderForm('checkbox'); + + // 修改 + } else if (type == 'update') { + var text = elemMain.children('.' + CONST.ELEM_TEXT).html(); + elemMain.children('.' + CONST.ELEM_TEXT).html(''); + // 添加输入框,覆盖在文字上方 + elemMain.append(''); + // 获取焦点 + elemMain.children('.lay-tree-editInput').val(lay.unescape(text)).focus(); + // 嵌入文字移除输入框 + var getVal = function (input) { + var textNew = lay.escape(input.val().trim()); + textNew = textNew ? textNew : options.text.defaultNodeName; + input.remove(); + elemMain.children('.' + CONST.ELEM_TEXT).html(textNew); + + // 同步数据 + returnObj.data[customName.title] = textNew; + + // 节点修改的回调 + options.operate && options.operate(returnObj); + }; + // 失去焦点 + elemMain.children('.lay-tree-editInput').blur(function () { + getVal($(this)); + }); + // 回车 + elemMain.children('.lay-tree-editInput').on('keydown', function (e) { + if (e.keyCode === 13) { + e.preventDefault(); + getVal($(this)); + } + }); + + // 删除 + } else { + var i18nText = i18n.$t('tree.deleteNodePrompt', { + name: item[customName.title] || '', + }); + layer.confirm(i18nText, function (index) { + options.operate && options.operate(returnObj); // 节点删除的回调 + returnObj.status = 'remove'; // 标注节点删除 + + layer.close(index); + + // 若删除最后一个,显示空数据提示 + if ( + !elem.prev('.' + CONST.ELEM_SET)[0] && + !elem.next('.' + CONST.ELEM_SET)[0] && + !elem.parent('.' + CONST.ELEM_PACK)[0] + ) { + elem.remove(); + that.elem.append(that.elemNone); + return; + } + // 若有兄弟节点 + if ( + elem + .siblings('.' + CONST.ELEM_SET) + .children('.' + CONST.ELEM_ENTRY)[0] + ) { + // 若开启复选框 + if (options.showCheckbox) { + // 若开启复选框,进行下步操作 + var elemDel = function (elem) { + // 若无父结点,则不执行 + if (!elem.parents('.' + CONST.ELEM_SET)[0]) return; + var siblingTree = elem + .siblings('.' + CONST.ELEM_SET) + .children('.' + CONST.ELEM_ENTRY); + var parentTree = elem.parent('.' + CONST.ELEM_PACK).prev(); + var checkState = parentTree.find( + 'input[same="layuiTreeCheck"]', + )[0]; + var state = 1; + var num = 0; + + // 若父节点未勾选 + if (checkState.checked == false) { + // 遍历兄弟节点 + siblingTree.each(function (i, item1) { + var input = $(item1).find('input[same="layuiTreeCheck"]')[0]; + if (input.checked == false && !input.disabled) { + state = 0; + } + // 判断是否全为不可勾选框 + if (!input.disabled) { + num = 1; + } + }); + // 若有可勾选选择框并且已勾选 + if (state == 1 && num == 1) { + // 勾选父节点 + checkState.checked = true; + that.renderForm('checkbox'); + // 向上遍历祖先节点 + elemDel(parentTree.parent('.' + CONST.ELEM_SET)); + } + } + }; + elemDel(elem); + } + // 若开启连接线 + if (options.showLine) { + // 遍历兄弟节点,判断兄弟节点是否有子节点 + var siblings = elem.siblings('.' + CONST.ELEM_SET); + var num = 1; + var parentPack = elem.parent('.' + CONST.ELEM_PACK); + + siblings.each(function (_index, i) { + if (!$(i).children('.' + CONST.ELEM_PACK)[0]) { + num = 0; + } + }); + // 若兄弟节点都有子节点 + if (num == 1) { + // 若节点本身无子节点 + if (!packCont[0]) { + // 父级去除延伸线,因为此时子节点里没有空节点 + parentPack.removeClass(CONST.ELEM_EXTEND); + siblings + .children('.' + CONST.ELEM_PACK) + .addClass(CONST.ELEM_SHOW); + siblings + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .removeClass(CONST.ELEM_LINE_SHORT); + } + // 若为最后一个节点 + if (!elem.next()[0]) { + elem + .prev() + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .last() + .addClass(CONST.ELEM_LINE_SHORT); + } else { + parentPack + .children('.' + CONST.ELEM_SET) + .last() + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .last() + .addClass(CONST.ELEM_LINE_SHORT); + } + // 若为最外层最后一个节点,去除前一个结点的连接线 + if ( + !elem.next()[0] && + !elem.parents('.' + CONST.ELEM_SET)[1] && + !elem + .parents('.' + CONST.ELEM_SET) + .eq(0) + .next()[0] + ) { + elem.prev('.' + CONST.ELEM_SET).addClass(CONST.ELEM_LINE_SHORT); + } + } else { + // 若为最后一个节点且有延伸线 + if (!elem.next()[0] && elem.hasClass(CONST.ELEM_LINE_SHORT)) { + elem.prev().addClass(CONST.ELEM_LINE_SHORT); + } + } + } + } else { + // 若无兄弟节点 + var prevDiv = elem.parent('.' + CONST.ELEM_PACK).prev(); + // 若开启了连接线 + if (options.showLine) { + prevDiv.find('.' + CONST.ICON_CLICK).removeClass('lay-tree-icon'); + prevDiv + .find('.' + CONST.ICON_CLICK) + .children('.lay-icon') + .removeClass(CONST.ICON_SUB) + .addClass('lay-icon-leaf'); + // 父节点所在层添加延伸线 + var pare = prevDiv.parents('.' + CONST.ELEM_PACK).eq(0); + pare.addClass(CONST.ELEM_EXTEND); + + // 兄弟节点最后子节点添加延伸线 + pare.children('.' + CONST.ELEM_SET).each(function () { + $(this) + .children('.' + CONST.ELEM_PACK) + .children('.' + CONST.ELEM_SET) + .last() + .addClass(CONST.ELEM_LINE_SHORT); + }); + } else { + // 父节点隐藏箭头 + prevDiv.find('.lay-tree-iconArrow').addClass(CONST.CLASS_HIDE); + } + // 移除展开属性 + elem + .parents('.' + CONST.ELEM_SET) + .eq(0) + .removeClass(CONST.ELEM_SPREAD); + // 移除节点容器 + elem.parent('.' + CONST.ELEM_PACK).remove(); + } + + elem.remove(); + }); + } + }); +}; + +// 部分事件 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 初始选中 + that.setChecked(that.checkids); + + // 搜索 + that.elem.find('.lay-tree-search').on('keyup', function () { + var input = $(this); + var val = input.val(); + var pack = input.nextAll(); + var arr = []; + + // 遍历所有的值 + pack.find('.' + CONST.ELEM_TEXT).each(function () { + var entry = $(this).parents('.' + CONST.ELEM_ENTRY); + // 若值匹配,加一个类以作标识 + if ($(this).html().indexOf(val) != -1) { + arr.push($(this).parent()); + + var select = function (div) { + div.addClass('lay-tree-searchShow'); + // 向上父节点渲染 + if (div.parent('.' + CONST.ELEM_PACK)[0]) { + select( + div.parent('.' + CONST.ELEM_PACK).parent('.' + CONST.ELEM_SET), + ); + } + }; + select(entry.parent('.' + CONST.ELEM_SET)); + } + }); + + // 根据标志剔除 + pack.find('.' + CONST.ELEM_ENTRY).each(function () { + var parent = $(this).parent('.' + CONST.ELEM_SET); + if (!parent.hasClass('lay-tree-searchShow')) { + parent.addClass(CONST.CLASS_HIDE); + } + }); + if (pack.find('.lay-tree-searchShow').length == 0) { + that.elem.append(that.elemNone); + } + + // 节点过滤的回调 + options.onsearch && + options.onsearch({ + elem: arr, + }); + }); + + // 还原搜索初始状态 + that.elem.find('.lay-tree-search').on('keydown', function () { + $(this) + .nextAll() + .find('.' + CONST.ELEM_ENTRY) + .each(function () { + var parent = $(this).parent('.' + CONST.ELEM_SET); + parent.removeClass('lay-tree-searchShow ' + CONST.CLASS_HIDE); + }); + if ($('.lay-tree-emptyText')[0]) $('.lay-tree-emptyText').remove(); + }); +}; + +// 得到选中节点 +Class.prototype.getChecked = function () { + var that = this; + var options = that.config; + var customName = options.customName; + var checkedId = []; + var checkedData = []; + + // 遍历节点找到选中索引 + that.elem.find('.lay-form-checked').each(function () { + checkedId.push($(this).prev()[0].value); + }); + + // 遍历节点 + var eachNodes = function (data, checkNode) { + for (const item of data) { + for (const item2 of checkedId) { + if (item[customName.id] == item2) { + that.updateFieldValue(item, 'checked', true); + + var cloneItem = $.extend({}, item); + delete cloneItem[customName.children]; + + checkNode.push(cloneItem); + + if (item[customName.children]) { + cloneItem[customName.children] = []; + eachNodes( + item[customName.children], + cloneItem[customName.children], + ); + } + break; + } + } + } + }; + + eachNodes($.extend({}, options.data), checkedData); + return checkedData; +}; + +// 设置选中节点 +Class.prototype.setChecked = function (checkedId) { + var that = this; + var options = that.config; + var flatData = options.flatData; + + if (typeof checkedId !== 'object') { + checkedId = [checkedId]; + } + + // 初始选中状态 + that.elem.find('.' + CONST.ELEM_SET).each(function (i) { + var thisId = $(this).data('id'); + var input = $(this) + .children('.' + CONST.ELEM_ENTRY) + .find('input[same="layuiTreeCheck"]'); + var checked = input.prop('checked'); + + for (const id of checkedId) { + if (thisId == id) { + if (input.prop('disabled')) continue; + if (!checked) { + input.prop('checked', true); + that.syncCheckedState(input, flatData[i]); + break; + } + } + } + }); +}; + +// 扩展组件接口 +$.extend(component, { + // 获得选中的节点数据 + getChecked: function (id) { + var that = component.getInst(id); + if (!that) return; + return that.getChecked(); + }, + + // 设置选中节点 + setChecked: function (id, checkedId) { + var that = component.getInst(id); + if (!that) return; + return that.setChecked(checkedId); + }, +}); + +export { component as tree }; diff --git a/src/components/treeTable.js b/src/components/treeTable.js new file mode 100644 index 000000000..d53adea41 --- /dev/null +++ b/src/components/treeTable.js @@ -0,0 +1,2608 @@ +/** + * treeTable + * 树表组件 + */ + +import { lay } from '../core/lay.js'; +import { log } from '../core/logger.js'; +import { $ } from 'jquery'; +import { form } from './form.js'; +import { table } from './table.js'; + +// api +var treeTable = { + config: {}, + // 事件 + on: table.on, + // 遍历字段 + eachCols: table.eachCols, + index: table.index, + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + resize: table.resize, + getOptions: table.getOptions, + hideCol: table.hideCol, + renderData: table.renderData, +}; + +// 操作当前实例 +var thisTreeTable = function () { + var that = this; + var options = that.config; + var id = options.id || options.index; + + return { + config: options, + reload: function (options, deep) { + that.reload.call(that, options, deep); + }, + reloadData: function (options, deep) { + treeTable.reloadData(id, options, deep); + }, + }; +}; + +/** + * 获取当前实例 + * @param {string} id 表格id + * @returns {Class} + */ +var getThisTable = function (id) { + var that = thisTreeTable.that[id]; + if (!that) + log( + id + ? "The treeTable instance with ID '" + id + "' not found" + : 'ID argument required', + ); + return that || null; +}; + +// 字符 +// var MOD_NAME = 'treeTable'; +var MOD_ID = 'lay-table-id'; +var HIDE = 'lay-hide'; + +var ELEM_VIEW = '.lay-table-view'; +// var ELEM_TREE = '.lay-table-tree'; +// var ELEM_TOOL = '.lay-table-tool'; +// var ELEM_BOX = '.lay-table-box'; +// var ELEM_HEADER = '.lay-table-header'; +var ELEM_BODY = '.lay-table-body'; +var ELEM_MAIN = '.lay-table-main'; +// var ELEM_FIXED = '.lay-table-fixed'; +var ELEM_FIXL = '.lay-table-fixed-l'; +var ELEM_FIXR = '.lay-table-fixed-r'; +var ELEM_CHECKED = 'lay-table-checked'; + +var TABLE_TREE = 'lay-table-tree'; +var LAY_DATA_INDEX = 'LAY_DATA_INDEX'; +var LAY_DATA_INDEX_HISTORY = 'LAY_DATA_INDEX_HISTORY'; +var LAY_PARENT_INDEX = 'LAY_PARENT_INDEX'; +var LAY_CHECKBOX_HALF = 'LAY_CHECKBOX_HALF'; +var LAY_EXPAND = 'LAY_EXPAND'; +var LAY_HAS_EXPANDED = 'LAY_HAS_EXPANDED'; +var LAY_ASYNC_STATUS = 'LAY_ASYNC_STATUS'; +var LAY_CASCADE = ['all', 'parent', 'children', 'none']; +var HTML_TAG_RE = /<[^>]+?>/; +var ICON_PROPS = [ + 'flexIconClose', + 'flexIconOpen', + 'iconClose', + 'iconOpen', + 'iconLeaf', + 'icon', +]; + +/** + * 构造器 + * @class + */ +var Class = function (options) { + var that = this; + that.index = ++treeTable.index; + that.config = $.extend(true, {}, that.config, treeTable.config, options); + // 处理一些属性 + that.init(); + that.render(); +}; + +var updateCache = function (id, childrenKey, data) { + var tableCache = table.cache[id]; + (data || tableCache).forEach(function (item) { + var itemDataIndex = item[LAY_DATA_INDEX] || ''; + if (itemDataIndex.indexOf('-') !== -1) { + tableCache[itemDataIndex] = item; + } + item[childrenKey] && updateCache(id, childrenKey, item[childrenKey]); + }); +}; + +var updateOptions = function (id, options, reload) { + var that = getThisTable(id); + reload === 'reloadData' || + (that.status = { + // 用于记录一些状态信息 + expand: {}, // 折叠状态 + }); + var thatOptionsTemp = $.extend(true, {}, that.getOptions(), options); + var treeOptions = thatOptionsTemp.tree; + var childrenKey = treeOptions.customName.children; + var idKey = treeOptions.customName.id; + // 处理属性 + delete options.hasNumberCol; + delete options.hasChecboxCol; + delete options.hasRadioCol; + table.eachCols( + null, + function (i1, item1) { + if (item1.type === 'numbers') { + options.hasNumberCol = true; + } else if (item1.type === 'checkbox') { + options.hasChecboxCol = true; + } else if (item1.type === 'radio') { + options.hasRadioCol = true; + } + }, + thatOptionsTemp.cols, + ); + + var parseData = options.parseData; + var done = options.done; + + // treeTable重载数据时,会先加载显示顶层节点,然后根据重载数据前的子节点展开状态,展开相应的子节点, + // 那么如果重载数据前有滚动条滚动在某个位子,重新加载时顶层节点如果比较少,只显示顶层节点时没有滚动条的情况下, + // 自动展开子节点后,滚动条就会显示在顶部,无法保持在重载数据之前的位置。 + // 处理保持滚动条的问题,重载数据前记录滚动条的位置 + if (reload === 'reloadData' && thatOptionsTemp.scrollPos === 'fixed') { + that.scrollTopCache = that.config.elem.next().find(ELEM_BODY).scrollTop(); + } + + if (thatOptionsTemp.url) { + // 异步加载的时候需要处理parseData进行转换 + if (!reload || (reload && parseData && !parseData.mod)) { + options.parseData = function () { + var parseDataThat = this; + var args = arguments; + var retData = args[0]; + if (lay.type(parseData) === 'function') { + retData = parseData.apply(parseDataThat, args) || args[0]; + } + var dataName = parseDataThat.response.dataName; + // 处理 isSimpleData + if (treeOptions.data.isSimpleData && !treeOptions.async.enable) { + // 异步加载和 isSimpleData 不应该一起使用 + retData[dataName] = that.flatToTree(retData[dataName]); + } + // 处理节点状态 + updateStatus( + retData[dataName], + function (item) { + item[LAY_EXPAND] = + LAY_EXPAND in item + ? item[LAY_EXPAND] + : item[idKey] !== undefined && that.status.expand[item[idKey]]; + }, + childrenKey, + ); + + if ( + parseDataThat.autoSort && + parseDataThat.initSort && + parseDataThat.initSort.type + ) { + lay.sort( + retData[dataName], + parseDataThat.initSort.field, + parseDataThat.initSort.type === 'desc', + true, + ); + } + + that.initData(retData[dataName]); + + return retData; + }; + options.parseData.mod = true; + } + } else { + if (options.data !== undefined) { + options.data = options.data || []; + // 处理 isSimpleData + if (treeOptions.data.isSimpleData) { + options.data = that.flatToTree(options.data); + } + that.initData(options.data); + } + } + + if (!reload || (reload && done && !done.mod)) { + options.done = function () { + var args = arguments; + var doneThat = this; + // undefined: 初始 render 或 reload,两者本质没有区别可以不做区分 + // 'reloadData': 重载数据 + // 'renderData': 重新渲染数据 + var renderType = args[3]; + var isRenderData = renderType === 'renderData'; + if (!isRenderData) { + delete that.isExpandAll; + } + + var tableView = this.elem.next(); + that.updateStatus(null, { + LAY_HAS_EXPANDED: false, // 去除已经打开过的状态 + }); + // 更新cache中的内容 将子节点也存到cache中 + updateCache(id, childrenKey); + // 更新全选框的状态 + var layTableAllChooseElem = tableView.find( + '[name="layTableCheckbox"][lay-filter="layTableAllChoose"]', + ); + if (layTableAllChooseElem.length) { + var checkStatus = treeTable.checkStatus(id); + layTableAllChooseElem.prop({ + checked: checkStatus.isAll && checkStatus.data.length, + indeterminate: !checkStatus.isAll && checkStatus.data.length, + }); + } + if ( + !isRenderData && + thatOptionsTemp.autoSort && + thatOptionsTemp.initSort && + thatOptionsTemp.initSort.type + ) { + treeTable.sort(id); + } + + that.renderTreeTable(tableView); + + // 恢复滚动条位置 + if (renderType === 'reloadData' && doneThat.scrollPos === 'fixed') { + tableView.find(ELEM_BODY).scrollTop(that.scrollTopCache); + } + + if (lay.type(done) === 'function') { + return done.apply(doneThat, args); + } + }; + options.done.mod = true; + } + + // 处理图标 + if (options && options.tree && options.tree.view) { + ICON_PROPS.forEach(function (iconProp) { + if (options.tree.view[iconProp] !== undefined) { + options.tree.view[iconProp] = that.normalizedIcon( + options.tree.view[iconProp], + ); + } + }); + } +}; + +Class.prototype.init = function () { + var that = this; + var options = that.config; + var cascade = options.tree.data.cascade; + if (LAY_CASCADE.indexOf(cascade) === -1) { + options.tree.data.cascade = 'all'; // 超出范围的都重置为全联动 + } + + // 先初始一个空的表格以便拿到对应的表格实例信息 + var tableIns = table.render( + $.extend({}, options, { + data: [], + url: '', + done: null, + }), + ); + var id = tableIns.config.id; + thisTreeTable.that[id] = that; // 记录当前实例对象 + that.tableIns = tableIns; + + updateOptions(id, options); +}; + +// 初始默认配置 +Class.prototype.config = { + tree: { + customName: { + children: 'children', // 节点数据中保存子节点数据的属性名称 + isParent: 'isParent', // 节点数据保存节点是否为父节点的属性名称 + name: 'name', // 节点数据保存节点名称的属性名称 + id: 'id', // 唯一标识的属性名称 + pid: 'parentId', // 父节点唯一标识的属性名称 + icon: 'icon', // 图标的属性名称 + }, + view: { + indent: 14, // 层级缩进量 + flexIconClose: '', // 关闭时候的折叠图标 + flexIconOpen: '', // 打开时候的折叠图标 + showIcon: true, // 是否显示图标(节点类型图标) + icon: '', // 节点图标,如果设置了这个属性或者数据中有这个字段信息,不管打开还是关闭都以这个图标的值为准 + iconClose: '', // 关闭时候的图标 + iconOpen: '', // 打开时候的图标 + iconLeaf: '', // 叶子节点的图标 + showFlexIconIfNotParent: false, // 当节点不是父节点的时候是否显示折叠图标 + dblClickExpand: true, // 双击节点时,是否自动展开父节点的标识 + expandAllDefault: false, // 默认展开所有节点 + }, + data: { + isSimpleData: false, // 是否简单数据模式 + rootPid: null, // 根节点的父 ID 值 + cascade: 'all', // 级联方式 默认全部级联:all 可选 级联父 parent 级联子 children + }, + async: { + enable: false, // 是否开启异步加载模式,只有开启的时候其他参数才起作用 + url: '', // 异步加载的接口,可以根据需要设置与顶层接口不同的接口,如果相同可以不设置该参数 + type: null, // 请求的接口类型,设置可缺省同上 + contentType: null, // 提交参数的数据类型,设置可缺省同上 + headers: null, // 设置可缺省同上 + where: null, // 设置可缺省同上 + autoParam: [], // 自动参数 + }, + callback: { + beforeExpand: null, // 展开前的回调 return false 可以阻止展开的动作 + onExpand: null, // 展开之后的回调 + }, + }, +}; + +Class.prototype.normalizedIcon = function (iconStr) { + return iconStr + ? HTML_TAG_RE.test(iconStr) + ? iconStr + : '' + : ''; +}; + +Class.prototype.getOptions = function () { + var that = this; + if (that.tableIns) { + return table.getOptions(that.tableIns.config.id); // 获取表格的实时配置信息 + } else { + return that.config; + } +}; + +function flatToTree(flatArr, idKey, pIdKey, childrenKey, rootPid) { + idKey = idKey || 'id'; + pIdKey = pIdKey || 'parentId'; + childrenKey = childrenKey || 'children'; + // 创建一个空的 map 对象,用于保存所有的节点 + var map = {}; + var rootNodes = []; + + var idTemp = ''; + var pidTemp = ''; + flatArr.forEach(function (item) { + idTemp = idKey + item[idKey]; + pidTemp = idKey + item[pIdKey]; + + // 将节点存入 map 对象 + if (!map[idTemp]) { + map[idTemp] = {}; + map[idTemp][childrenKey] = []; + } + + // 合并节点 + var tempObj = {}; + tempObj[childrenKey] = map[idTemp][childrenKey]; + map[idTemp] = $.extend({}, item, tempObj); + + var isRootNode = rootPid + ? map[idTemp][pIdKey] === rootPid + : !map[idTemp][pIdKey]; + if (isRootNode) { + rootNodes.push(map[idTemp]); + } else { + if (!map[pidTemp]) { + map[pidTemp] = {}; + map[pidTemp][childrenKey] = []; + } + map[pidTemp][childrenKey].push(map[idTemp]); + } + }); + + return rootNodes; +} + +Class.prototype.flatToTree = function (tableData) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var tableId = options.id; + + tableData = tableData || table.cache[tableId]; + + return flatToTree( + tableData, + customName.id, + customName.pid, + customName.children, + treeOptions.data.rootPid, + ); +}; + +Class.prototype.treeToFlat = function (tableData, parentId, parentIndex) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var childrenKey = customName.children; + var pIdKey = customName.pid; + + var flat = []; + (tableData || []).forEach(function (item1, i1) { + var dataIndex = (parentIndex ? parentIndex + '-' : '') + i1; + var dataNew = $.extend({}, item1); + + dataNew[pIdKey] = + typeof item1[pIdKey] !== 'undefined' ? item1[pIdKey] : parentId; + flat.push(dataNew); + flat = flat.concat( + that.treeToFlat(item1[childrenKey], item1[customName.id], dataIndex), + ); + }); + + return flat; +}; + +// 通过当前行数据返回 treeNode 信息 +Class.prototype.getTreeNode = function (data) { + var that = this; + if (!data) { + return log('Node data not found'); + } + // var options = that.getOptions(); + // var treeOptions = options.tree; + // var tableId = options.id; + // var customName = treeOptions.customName; + + // 带上一些常用的方法 + return { + data: data, + dataIndex: data[LAY_DATA_INDEX], + getParentNode: function () { + return that.getNodeByIndex(data[LAY_PARENT_INDEX]); + }, + }; +}; + +// 通过 index 返回节点信息 +Class.prototype.getNodeByIndex = function (index) { + var that = this; + var treeNodeData = that.getNodeDataByIndex(index); + if (!treeNodeData) { + return log('Node data not found by index: ' + index); + } + var options = that.getOptions(); + // var treeOptions = options.tree; + // var customName = treeOptions.customName; + // var parentKey = customName.parent; + var tableId = options.id; + + var treeNode = { + data: treeNodeData, + dataIndex: treeNodeData[LAY_DATA_INDEX], + getParentNode: function () { + return that.getNodeByIndex(treeNodeData[LAY_PARENT_INDEX]); + }, + update: function (data) { + return treeTable.updateNode(tableId, index, data); + }, + remove: function () { + return treeTable.removeNode(tableId, index); + }, + expand: function (opts) { + return treeTable.expandNode( + tableId, + $.extend({}, opts, { + index: index, + }), + ); + }, + setChecked: function (opts) { + return treeTable.setRowChecked( + tableId, + $.extend({}, opts, { + index: index, + }), + ); + }, + }; + + treeNode.dataIndex = index; + return treeNode; +}; + +// 通过 id 获取节点信息 +Class.prototype.getNodeById = function (id) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var customName = treeOptions.customName; + var idKey = customName.id; + + // 通过 id 拿到数据的 dataIndex + var dataIndex = ''; + var tableDataFlat = treeTable.getData(options.id, true); + for (const item1 of tableDataFlat) { + if (item1[idKey] === id) { + dataIndex = item1[LAY_DATA_INDEX]; + break; + } + } + if (!dataIndex) { + return; + } + + // 用 index + return that.getNodeByIndex(dataIndex); +}; + +// 通过 index 获取节点数据 +Class.prototype.getNodeDataByIndex = function (index, clone, newValue) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var tableCache = table.cache[tableId]; + + // 获取当前行中的数据 + var dataCache = tableCache[index]; + + // 若非删除操作,则返回合并后的数据 + if (newValue !== 'delete' && dataCache) { + $.extend(dataCache, newValue); + return clone ? $.extend({}, dataCache) : dataCache; + } + + // 删除操作 + var dataRet = tableCache; + var indexArr = String(index).split('-'); + + // if (options.url || indexArr.length > 1) tableCache = null // 只有在删除根节点的时候才需要处理 + + // 根据 index 进行数据处理 + for ( + var i = 0, childrenKey = treeOptions.customName.children; + i < indexArr.length; + i++ + ) { + if (newValue && i === indexArr.length - 1) { + if (newValue === 'delete') { + // 删除并返回当前数据 + // 同步 cache --- 此段代码注释缘由:data 属性模式造成数据重复执行 splice (@Gitee: #I7Z0A/I82E2S) + /*if (tableCache) { + for (const [item1, i1] of tableCache.entries()) { + if (item1[LAY_DATA_INDEX] === index) { + tableCache.splice(i1, 1); + break; + } + } + }*/ + return (i ? dataRet[childrenKey] : dataRet).splice(indexArr[i], 1)[0]; + } else { + // 更新值 + $.extend((i ? dataRet[childrenKey] : dataRet)[indexArr[i]], newValue); + } + } + dataRet = i ? dataRet[childrenKey][indexArr[i]] : dataRet[indexArr[i]]; + } + return clone ? $.extend({}, dataRet) : dataRet; +}; + +treeTable.getNodeDataByIndex = function (id, index) { + var that = getThisTable(id); + if (!that) return; + return that.getNodeDataByIndex(index, true); +}; + +// 判断是否是父节点 +/* var checkIsParent = function (data, isParentKey, childrenKey) { + isParentKey = isParentKey || 'isParent'; + childrenKey = childrenKey || 'children'; + (data || []).forEach(function (item1) { + if (!(isParentKey in item1)) { + item1[isParentKey] = !!(item1[childrenKey] && item1[childrenKey].length); + checkIsParent(item1[childrenKey]); + } + }); +}; */ + +Class.prototype.initData = function (data, parentIndex) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + + data = data || that.getTableData(); + + var customName = treeOptions.customName; + var isParentKey = customName.isParent; + var childrenKey = customName.children; + + var update = function (data, parentIndex) { + (data || []).forEach(function (item1, i1) { + if (!(isParentKey in item1)) { + item1[isParentKey] = !!( + item1[childrenKey] && item1[childrenKey].length + ); + } + item1[LAY_DATA_INDEX_HISTORY] = item1[LAY_DATA_INDEX]; + item1[LAY_PARENT_INDEX] = parentIndex = parentIndex || ''; + var dataIndex = (item1[LAY_DATA_INDEX] = + (parentIndex ? parentIndex + '-' : '') + i1); + update(item1[childrenKey] || [], dataIndex); + }); + }; + + update(data, parentIndex); + + updateCache(tableId, childrenKey, data); + + return data; +}; + +// 与 tableId 有关带防抖的方法 +var debounceFn = (function () { + var fn = {}; + return function (tableId, func, wait) { + if (!fn[tableId]) { + fn[tableId] = lay.debounce(func, wait); + } + return fn[tableId]; + }; +})(); + +// 优化参数,添加一个 getNodeByIndex 方法 只传 表格id 和行 dataIndex 分几步优化 todo +var expandNode = function ( + treeNode, + expandFlag, + sonSign, + focus, + callbackFlag, + done, +) { + // treeNode // 需要展开的节点 + var trElem = treeNode.trElem; + var tableViewElem = treeNode.tableViewElem || trElem.closest(ELEM_VIEW); + var tableId = treeNode.tableId || tableViewElem.attr(MOD_ID); + var options = treeNode.options || table.getOptions(tableId); + var dataIndex = treeNode.dataIndex || trElem.attr('lay-data-index'); // 可能出现多层 + var treeTableThat = getThisTable(tableId); + + var treeOptions = options.tree || {}; + var customName = treeOptions.customName || {}; + var isParentKey = customName.isParent; + + var trData = treeTableThat.getNodeDataByIndex(dataIndex); + + // 后续调优:对已经展开的节点进行展开和已经关闭的节点进行关闭应该做优化减少不必要的代码执行 todo + var isToggle = lay.type(expandFlag) !== 'boolean'; + var trExpand = isToggle ? !trData[LAY_EXPAND] : expandFlag; + var retValue = trData[isParentKey] ? trExpand : null; + + if ( + callbackFlag && + trExpand != trData[LAY_EXPAND] && + (!trData[LAY_ASYNC_STATUS] || trData[LAY_ASYNC_STATUS] === 'local') + ) { + var beforeExpand = treeOptions.callback.beforeExpand; + if (lay.type(beforeExpand) === 'function') { + if (beforeExpand(tableId, trData, expandFlag) === false) { + return retValue; + } + } + } + + var trExpanded = trData[LAY_HAS_EXPANDED]; // 展开过,包括异步加载 + + // 找到表格中的同类节点(需要找到lay-data-index一致的所有行) + var trsElem = tableViewElem.find('tr[lay-data-index="' + dataIndex + '"]'); + var flexIconElem = trsElem.find('.lay-table-tree-flexIcon'); + treeTableThat.updateNodeIcon({ + scopeEl: trsElem, + isExpand: trExpand, + isParent: trData[isParentKey], + }); + trData[LAY_EXPAND] = trExpand; + var trDataId = trData[customName.id]; + trDataId !== undefined && (treeTableThat.status.expand[trDataId] = trExpand); + if (retValue === null) { + return retValue; + } + + var childNodes = trData[customName.children] || []; + // 处理子节点展示与否 + if (trExpand) { + // 展开 + if (trExpanded) { + // 已经展开过 + if (!childNodes.length) return; //异步如果子节点没有数据情况下双点行展开所有已展开的节点问题解决 + trsElem + .nextAll( + childNodes + .map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }) + .join(','), + ) + .removeClass(HIDE); + childNodes.forEach(function (item1) { + if (!item1[isParentKey]) { + return; + } + + if (sonSign && !isToggle && !item1[LAY_EXPAND]) { + // 非状态切换的情况下 + // 级联展开子节点 + expandNode( + { + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem + .find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]') + .first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options, + }, + expandFlag, + sonSign, + focus, + callbackFlag, + done, + ); + } else if (item1[LAY_EXPAND]) { + // 初始化级联展开 + expandNode( + { + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem + .find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]') + .first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options, + }, + true, + undefined, + undefined, + undefined, + done, + ); + } + }); + } else { + var asyncSetting = treeOptions.async || {}; + var asyncUrl = asyncSetting.url || options.url; + if ( + asyncSetting.enable && + trData[isParentKey] && + (!trData[LAY_ASYNC_STATUS] || trData[LAY_ASYNC_STATUS] === 'error') + ) { + trData[LAY_ASYNC_STATUS] = 'loading'; + flexIconElem.html( + '', + ); + + // 异步获取子节点数据成功之后处理方法 + var asyncSuccessFn = function (data) { + trData[LAY_ASYNC_STATUS] = 'success'; + trData[customName.children] = data; + treeTableThat.initData( + trData[customName.children], + trData[LAY_DATA_INDEX], + ); + expandNode( + treeNode, + true, + isToggle ? false : sonSign, + focus, + callbackFlag, + done, + ); + }; + + var format = asyncSetting.format; // 自定义数据返回方法 + if (lay.type(format) === 'function') { + format(trData, options, asyncSuccessFn); + return retValue; + } + + var params = {}; + // 参数 + var data = $.extend(params, asyncSetting.where || options.where); + var asyncAutoParam = asyncSetting.autoParam; + asyncAutoParam.forEach(function (item) { + // var itemStr = item; + var itemArr = item.split('='); + data[itemArr[0].trim()] = trData[(itemArr[1] || itemArr[0]).trim()]; + }); + + var asyncContentType = asyncSetting.contentType || options.contentType; + if ( + asyncContentType && + asyncContentType.indexOf('application/json') == 0 + ) { + // 提交 json 格式 + data = JSON.stringify(data); + } + var asyncType = asyncSetting.method || options.method; + var asyncDataType = asyncSetting.dataType || options.dataType; + var asyncJsonpCallback = + asyncSetting.jsonpCallback || options.jsonpCallback; + var asyncHeaders = asyncSetting.headers || options.headers; + var asyncParseData = asyncSetting.parseData || options.parseData; + var asyncResponse = asyncSetting.response || options.response; + + var ajaxOptions = { + type: asyncType || 'get', + url: asyncUrl, + contentType: asyncContentType, + data: data, + dataType: asyncDataType || 'json', + jsonpCallback: asyncJsonpCallback, + headers: asyncHeaders || {}, + success: function (res) { + // 若有数据解析的回调,则获得其返回的数据 + if (typeof asyncParseData === 'function') { + res = asyncParseData.call(options, res) || res; + } + // 检查数据格式是否符合规范 + if (res[asyncResponse.statusName] != asyncResponse.statusCode) { + trData[LAY_ASYNC_STATUS] = 'error'; + trData[LAY_EXPAND] = false; + // 异常处理 todo + flexIconElem.html(''); + // 事件 + } else { + // 正常返回 + asyncSuccessFn(res[asyncResponse.dataName]); + } + }, + error: function (e, msg) { + trData[LAY_ASYNC_STATUS] = 'error'; + trData[LAY_EXPAND] = false; + // 异常处理 todo + typeof options.error === 'function' && options.error(e, msg); + }, + }; + + if (options.ajax) { + options.ajax(ajaxOptions, 'treeNodes'); + } else { + $.ajax(ajaxOptions); + } + + return retValue; + } + trExpanded = trData[LAY_HAS_EXPANDED] = true; + if (childNodes.length) { + // 判断是否需要排序 + if (options.initSort && (!options.url || options.autoSort)) { + var initSort = options.initSort; + if (initSort.type) { + lay.sort( + childNodes, + initSort.field, + initSort.type === 'desc', + true, + ); + } else { + // 恢复默认 + lay.sort(childNodes, table.config.indexName, null, true); + } + } + treeTableThat.initData( + trData[customName.children], + trData[LAY_DATA_INDEX], + ); + // 将数据通过模板得出节点的html代码 + var str2 = table.getTrHtml(tableId, childNodes, null, null, dataIndex); + + var str2Obj = { + trs: $(str2.trs.join('')), + trs_fixed: $(str2.trs_fixed.join('')), + trs_fixed_r: $(str2.trs_fixed_r.join('')), + }; + var dataLevel = dataIndex.split('-').length - 1; + var dataLevelNew = (dataLevel || 0) + 1; + childNodes.forEach(function (childItem, childIndex) { + str2Obj.trs + .eq(childIndex) + .attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew, + }) + .data('index', childItem[LAY_DATA_INDEX]); + + str2Obj.trs_fixed + .eq(childIndex) + .attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew, + }) + .data('index', childItem[LAY_DATA_INDEX]); + + str2Obj.trs_fixed_r + .eq(childIndex) + .attr({ + 'data-index': childItem[LAY_DATA_INDEX], + 'lay-data-index': childItem[LAY_DATA_INDEX], + 'data-level': dataLevelNew, + }) + .data('index', childItem[LAY_DATA_INDEX]); + }); + + tableViewElem + .find(ELEM_MAIN) + .find('tbody tr[lay-data-index="' + dataIndex + '"]') + .after(str2Obj.trs); + tableViewElem + .find(ELEM_FIXL) + .find('tbody tr[lay-data-index="' + dataIndex + '"]') + .after(str2Obj.trs_fixed); + tableViewElem + .find(ELEM_FIXR) + .find('tbody tr[lay-data-index="' + dataIndex + '"]') + .after(str2Obj.trs_fixed_r); + + // 初始化新增的节点中的内容 + treeTableThat.renderTreeTable(str2Obj.trs, dataLevelNew); + + if (sonSign && !isToggle) { + // 非状态切换的情况下 + // 级联展开/关闭子节点 + childNodes.forEach(function (item1) { + expandNode( + { + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem + .find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]') + .first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options, + }, + expandFlag, + sonSign, + focus, + callbackFlag, + done, + ); + }); + } + } + } + } else { + treeTableThat.isExpandAll = false; + // 关闭 + if (sonSign && !isToggle) { + // 非状态切换的情况下 + childNodes.forEach(function (item1) { + expandNode( + { + dataIndex: item1[LAY_DATA_INDEX], + trElem: tableViewElem + .find('tr[lay-data-index="' + item1[LAY_DATA_INDEX] + '"]') + .first(), + tableViewElem: tableViewElem, + tableId: tableId, + options: options, + }, + expandFlag, + sonSign, + focus, + callbackFlag, + done, + ); + }); + tableViewElem + .find( + childNodes + .map(function (value) { + // 只隐藏直接子节点,其他由递归的处理 + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }) + .join(','), + ) + .addClass(HIDE); + } else { + var childNodesFlat = treeTableThat.treeToFlat( + childNodes, + trData[customName.id], + dataIndex, + ); + tableViewElem + .find( + childNodesFlat + .map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }) + .join(','), + ) + .addClass(HIDE); + } + } + + debounceFn( + 'resize-' + tableId, + function () { + treeTable.resize(tableId); + }, + 0, + )(); + + if (callbackFlag && trData[LAY_ASYNC_STATUS] !== 'loading') { + var onExpand = treeOptions.callback.onExpand; + lay.type(onExpand) === 'function' && onExpand(tableId, trData, trExpand); + } + + if (lay.type(done) === 'function' && trData[LAY_ASYNC_STATUS] !== 'loading') { + done(tableId, trData, trExpand); + } + + return retValue; +}; + +/** + * 展开或关闭一个节点 + * @param {String} id 树表id + * @param {Object} opts + * @param {Number|String} opts.index 展开行的数据下标 + * @param {Boolean} [opts.expandFlag] 展开、关闭、切换 + * @param {Boolean} [opts.inherit] 是否级联子节点 + * @param {Boolean} [opts.callbackFlag] 是否触发 tree.callback 事件 + * @param {Boolean} [opts.done] 节点操作完成后的回调函数 + * @return [{Boolean}] 状态结果 + * */ +treeTable.expandNode = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + + opts = opts || {}; + + var index = opts.index; + var expandFlag = opts.expandFlag; + var sonSign = opts.inherit; + var callbackFlag = opts.callbackFlag; + + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + return expandNode( + { + trElem: tableViewElem.find('tr[lay-data-index="' + index + '"]').first(), + }, + expandFlag, + sonSign, + null, + callbackFlag, + opts.done, + ); +}; + +/** + * 展开或关闭全部节点 + * @param {String} id 树表id + * @param {Boolean} expandFlag 展开或关闭 + * */ +treeTable.expandAll = function (id, expandFlag) { + if (lay.type(expandFlag) !== 'boolean') { + return log( + 'treeTable.expandAll param "expandFlag" must be a boolean value.', + ); + } + + var that = getThisTable(id); + if (!that) return; + + that.isExpandAll = expandFlag; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableView = options.elem.next(); + var isParentKey = treeOptions.customName.isParent; + var idKey = treeOptions.customName.id; + var showFlexIconIfNotParent = treeOptions.view.showFlexIconIfNotParent; + + if (!expandFlag) { + // 关闭所有 + // 将所有已经打开的节点的状态设置为关闭, + that.updateStatus(null, function (d) { + if (d[isParentKey] || showFlexIconIfNotParent) { + d[LAY_EXPAND] = false; + d[idKey] !== undefined && (that.status.expand[d[idKey]] = false); + } + }); // 只处理当前页,如果需要处理全部表格,需要用treeTable.updateStatus + // 隐藏所有非顶层的节点 + tableView.find('.lay-table-box tbody tr[data-level!="0"]').addClass(HIDE); + + tableView + .find('.lay-table-tree-flexIcon') + .html(treeOptions.view.flexIconClose); + treeOptions.view.showIcon && + tableView + .find( + '.lay-table-tree-nodeIcon:not(.lay-table-tree-iconCustom,.lay-table-tree-iconLeaf)', + ) + .html(treeOptions.view.iconClose); + } else { + var tableDataFlat = treeTable.getData(id, true); + // 展开所有 + // 存在异步加载 + if (treeOptions.async.enable) { + // 判断是否有未加载过的节点 + var isAllAsyncDone = true; + for (const item1 of tableDataFlat) { + if (item1[isParentKey] && !item1[LAY_ASYNC_STATUS]) { + isAllAsyncDone = false; + break; + } + } + // 有未加载过的节点 + if (!isAllAsyncDone) { + // 逐个展开 + treeTable.getData(id).forEach(function (item1) { + treeTable.expandNode(id, { + index: item1[LAY_DATA_INDEX], + expandFlag: true, + inherit: true, + }); + }); + return; + } + } + + // 先判断是否全部打开过了 + var isAllExpanded = true; + for (const item1 of tableDataFlat) { + if (item1[isParentKey] && !item1[LAY_HAS_EXPANDED]) { + isAllExpanded = false; + break; + } + } + // 如果全部节点已经都打开过,就可以简单处理跟隐藏所有节点反操作 + if (isAllExpanded) { + that.updateStatus(null, function (d) { + if (d[isParentKey] || showFlexIconIfNotParent) { + d[LAY_EXPAND] = true; + d[idKey] !== undefined && (that.status.expand[d[idKey]] = true); + } + }); + // 显示所有子节点 + tableView.find('tbody tr[data-level!="0"]').removeClass(HIDE); + // 处理节点的图标 + tableView + .find('.lay-table-tree-flexIcon') + .html(treeOptions.view.flexIconOpen); + treeOptions.view.showIcon && + tableView + .find( + '.lay-table-tree-nodeIcon:not(.lay-table-tree-iconCustom,.lay-table-tree-iconLeaf)', + ) + .html(treeOptions.view.iconOpen); + } else { + // 如果有未打开过的父节点,将 tr 内容全部重新生成 + that.updateStatus(null, function (d) { + if (d[isParentKey] || showFlexIconIfNotParent) { + d[LAY_EXPAND] = true; + d[LAY_HAS_EXPANDED] = true; + d[idKey] !== undefined && (that.status.expand[d[idKey]] = true); + } + }); + if (options.initSort && options.initSort.type && options.autoSort) { + return treeTable.sort(id); + } + var trAll = table.getTrHtml(id, tableDataFlat); + + var trAllObj = { + trs: $(trAll.trs.join('')), + trs_fixed: $(trAll.trs_fixed.join('')), + trs_fixed_r: $(trAll.trs_fixed_r.join('')), + }; + var props; + tableDataFlat.forEach(function (dataItem, dataIndex) { + var dataLevel = dataItem[LAY_DATA_INDEX].split('-').length - 1; + props = { + 'data-index': dataItem[LAY_DATA_INDEX], + 'lay-data-index': dataItem[LAY_DATA_INDEX], + 'data-level': dataLevel, + }; + trAllObj.trs + .eq(dataIndex) + .attr(props) + .data('index', dataItem[LAY_DATA_INDEX]); + trAllObj.trs_fixed + .eq(dataIndex) + .attr(props) + .data('index', dataItem[LAY_DATA_INDEX]); + trAllObj.trs_fixed_r + .eq(dataIndex) + .attr(props) + .data('index', dataItem[LAY_DATA_INDEX]); + }); + ['main', 'fixed-l', 'fixed-r'].forEach(function (item, i) { + tableView + .find('.lay-table-' + item + ' tbody') + .html(trAllObj[['trs', 'trs_fixed', 'trs_fixed_r'][i]]); + }); + that.renderTreeTable(tableView, 0, false); + } + } + treeTable.resize(id); +}; + +/** + * @typedef updateNodeIconOptions + * @prop {JQuery} scopeEl - tr 元素 + * @prop {boolean} isExpand - 是否是展开图标 + * @prop {boolean} isParent - 是否是父节点图标 + */ +/** + * 更新节点图标 + * @param {updateNodeIconOptions} opts + */ +Class.prototype.updateNodeIcon = function (opts) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree || {}; + var scopeEl = opts.scopeEl; + var isExpand = opts.isExpand; + var isParent = opts.isParent; + + // 处理折叠按钮图标 + var flexIconElem = scopeEl.find('.lay-table-tree-flexIcon'); + + flexIconElem + .css( + 'visibility', + isParent || treeOptions.view.showFlexIconIfNotParent + ? 'visible' + : 'hidden', + ) + .html( + isExpand ? treeOptions.view.flexIconOpen : treeOptions.view.flexIconClose, + ); + // 处理节点图标 + if (treeOptions.view.showIcon) { + var nodeIconElem = scopeEl.find( + '.lay-table-tree-nodeIcon:not(.lay-table-tree-iconCustom)', + ); + var nodeIcon = isParent + ? isExpand + ? treeOptions.view.iconOpen + : treeOptions.view.iconClose + : treeOptions.view.iconLeaf; + + nodeIconElem + .toggleClass('lay-table-tree-iconLeaf', !isParent) + .html(nodeIcon); + } +}; + +Class.prototype.renderTreeTable = function (tableView, level, sonSign) { + var that = this; + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + !tableViewElem.hasClass(TABLE_TREE) && tableViewElem.addClass(TABLE_TREE); + var tableId = options.id; + var treeOptions = options.tree || {}; + // var treeOptionsData = treeOptions.data || {}; + var treeOptionsView = treeOptions.view || {}; + var customName = treeOptions.customName || {}; + var isParentKey = customName.isParent; + // var tableFilterId = tableViewElem.attr('lay-filter'); + var treeTableThat = that; + var existsData = options.data.length; // 是否直接赋值 data + // var tableData = treeTableThat.getTableData(); + + level = level || 0; + + if (!level) { + // 初始化的表格里面没有level信息,可以作为顶层节点的判断 + tableViewElem + .find('.lay-table-body tr:not([data-level])') + .attr('data-level', level); + table.cache[tableId].forEach(function (dataItem, dataIndex) { + // fix: 修正直接赋值 data 时顶层节点 LAY_DATA_INDEX 值的异常问题 + if (existsData) { + dataItem[LAY_DATA_INDEX] = String(dataIndex); + } + var layDataIndex = dataItem[LAY_DATA_INDEX]; + tableViewElem + .find('.lay-table-main tbody tr[data-level="0"]:eq(' + dataIndex + ')') + .attr('lay-data-index', layDataIndex); + tableViewElem + .find( + '.lay-table-fixed-l tbody tr[data-level="0"]:eq(' + dataIndex + ')', + ) + .attr('lay-data-index', layDataIndex); + tableViewElem + .find( + '.lay-table-fixed-r tbody tr[data-level="0"]:eq(' + dataIndex + ')', + ) + .attr('lay-data-index', layDataIndex); + }); + } + + var dataExpand = null; // 记录需要展开的数据 + var nameKey = customName.name; + var indent = treeOptionsView.indent || 14; + tableView.find('td[data-field="' + nameKey + '"]').each(function () { + var item = $(this); + var trElem = item.closest('tr'); + var itemCell = item.children('.lay-table-cell'); + if (itemCell.hasClass('lay-table-tree-item')) { + return; + } + var trIndex = trElem.attr('lay-data-index'); + if (!trIndex) { + // 排除在统计行中的节点 + return; + } + trElem = tableViewElem.find('tr[lay-data-index="' + trIndex + '"]'); + var trData = treeTableThat.getNodeDataByIndex(trIndex); + + if (trData[LAY_EXPAND] && trData[isParentKey]) { + // 需要展开 + dataExpand = dataExpand || {}; + dataExpand[trIndex] = true; + } + if (trData[LAY_CHECKBOX_HALF]) { + trElem + .find('input[type="checkbox"][name="layTableCheckbox"]') + .prop('indeterminate', true); + } + + var htmlTemp = itemCell.html(); + itemCell = trElem.find( + 'td[data-field="' + nameKey + '"]>div.lay-table-cell', + ); + itemCell.addClass('lay-table-tree-item'); + var flexIconElem = itemCell + .html( + [ + '
                                    ', + trData[LAY_EXPAND] + ? treeOptionsView.flexIconOpen + : treeOptionsView.flexIconClose, // 折叠图标 + '
                                    ', + treeOptionsView.showIcon + ? '
                                    ' + + (that.normalizedIcon(trData[customName.icon]) || + treeOptionsView.icon || + (trData[isParentKey] + ? trData[LAY_EXPAND] + ? treeOptionsView.iconOpen + : treeOptionsView.iconClose + : treeOptionsView.iconLeaf) || + '') + + '
                                    ' + : '', // 区分父子节点 + htmlTemp, + ].join(''), + ) // 图标要可定制 + .find('.lay-table-tree-flexIcon'); + + // 添加展开按钮的事件 + flexIconElem.on('click', function (e) { + e.stopPropagation(); + + // 处理数据 + // var trElem = item.closest('tr'); + expandNode({ trElem: trElem }, null, null, null, true); + }); + }); + + if ( + !level && + treeOptions.view.expandAllDefault && + that.isExpandAll === undefined + ) { + return treeTable.expandAll(tableId, true); // 默认展开全部 + } + + // 当前层的数据看看是否需要展开 + if (sonSign !== false && dataExpand) { + Object.keys(dataExpand).forEach(function (index) { + var trDefaultExpand = tableViewElem.find( + 'tr[lay-data-index="' + index + '"]', + ); + trDefaultExpand + .find('.lay-table-tree-flexIcon') + .html(treeOptionsView.flexIconOpen); + expandNode({ trElem: trDefaultExpand.first() }, true); + }); + // #1463 expandNode 中已经展开过的节点不会重新渲染 + debounceFn( + 'renderTreeTable2-' + tableId, + function () { + form.render($('.lay-table-tree[' + MOD_ID + '="' + tableId + '"]')); + }, + 0, + )(); + } else { + debounceFn( + 'renderTreeTable-' + tableId, + function () { + options.hasNumberCol && formatNumber(that); + form.render($('.lay-table-tree[' + MOD_ID + '="' + tableId + '"]')); + }, + 0, + )(); + } +}; + +var formatNumber = function (that) { + var options = that.getOptions(); + var tableViewElem = options.elem.next(); + + var num = 0; + var trMain = tableViewElem.find('.lay-table-main tbody tr'); + var trFixedL = tableViewElem.find('.lay-table-fixed-l tbody tr'); + var trFixedR = tableViewElem.find('.lay-table-fixed-r tbody tr'); + that.treeToFlat(table.cache[options.id]).forEach(function (item1, i1) { + if (item1['LAY_HIDE']) return; + var itemData = that.getNodeDataByIndex(item1[LAY_DATA_INDEX]); + itemData['LAY_NUM'] = ++num; + trMain.eq(i1).find('.laytable-cell-numbers').html(num); + trFixedL.eq(i1).find('.laytable-cell-numbers').html(num); + trFixedR.eq(i1).find('.laytable-cell-numbers').html(num); + }); +}; + +// 树表渲染 +Class.prototype.render = function (type) { + var that = this; + that.tableIns = table[type === 'reloadData' ? 'reloadData' : 'reload']( + that.tableIns.config.id, + $.extend(true, {}, that.config), + ); + that.config = that.tableIns.config; +}; + +// 表格重载 +Class.prototype.reload = function (options, deep, type) { + var that = this; + + options = options || {}; + delete that.haveInit; + + // 防止数组深度合并 + Object.entries(options).forEach(function ([key, item]) { + if (lay.type(item) === 'array') delete that.config[key]; + }); + + // 根据需要处理options中的一些参数 + updateOptions(that.getOptions().id, options, type || true); + + // 对参数进行深度或浅扩展 + that.config = $.extend(deep, {}, that.config, options); + + // 执行渲染 + that.render(type); +}; + +// 仅重载数据 +treeTable.reloadData = function () { + var args = $.extend(true, [], arguments); + args[3] = 'reloadData'; + + return treeTable.reload.apply(null, args); +}; + +var updateStatus = function (data, statusObj, childrenKey, notCascade) { + var dataUpdated = []; + (data || []).forEach(function (item1) { + if (lay.type(statusObj) === 'function') { + statusObj(item1); + } else { + $.extend(item1, statusObj); + } + dataUpdated.push($.extend({}, item1)); + notCascade || + (dataUpdated = dataUpdated.concat( + updateStatus(item1[childrenKey], statusObj, childrenKey, notCascade), + )); + }); + return dataUpdated; +}; + +Class.prototype.updateStatus = function (data, statusObj, notCascade) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + data = data || table.cache[options.id]; + + return updateStatus( + data, + statusObj, + treeOptions.customName.children, + notCascade, + ); +}; + +Class.prototype.getTableData = function () { + var that = this; + var options = that.getOptions(); + // return options.url ? table.cache[options.id] : options.data; + return table.cache[options.id]; +}; + +treeTable.updateStatus = function (id, statusObj, data) { + var that = getThisTable(id); + var options = that.getOptions(); + if (!data) { + if (options.url) { + data = table.cache[options.id]; + } else { + data = options.data; + } + } + return that.updateStatus(data, statusObj); +}; + +treeTable.sort = function (id) { + var that = getThisTable(id); + if (!that) return; + + var options = that.getOptions(); + var treeOptions = options.tree; + + var tableData = treeTable.getData(id); + var customName = treeOptions.customName; + var childrenKey = customName.children; + + // 只和同级节点排序 + var sort = function (data, field, type) { + lay.sort(data, field, type, true); + data.forEach(function (trData) { + sort(trData[childrenKey] || [], field, type); + }); + }; + + if (options.autoSort) { + var initSort = options.initSort; + if (initSort.type) { + sort(tableData, initSort.field, initSort.type === 'desc'); + } else { + // 恢复默认 + sort(tableData, table.config.indexName, null); + } + // 更新缓存中数据的顺序 + table.cache[id] = tableData; + // 重新初始化缓存数据 + that.initData(tableData); + treeTable.renderData(id); + } +}; + +// 处理事件 +var updateObjParams = function (obj) { + var tableId = obj.config.id; + var tableThat = getThisTable(tableId); + var trData = (obj.data = treeTable.getNodeDataByIndex(tableId, obj.index)); // 克隆的 + var trIndex = trData[LAY_DATA_INDEX]; + obj.dataIndex = trIndex; + + // 处理update方法 + var updateFn = obj.update; + obj.update = function () { + var updateThat = this; + var args = arguments; + $.extend(tableThat.getNodeDataByIndex(trIndex), args[0]); + var ret = updateFn.apply(updateThat, args); // 主要负责更新节点内容 + var nameKey = obj.config.tree.customName.name; + nameKey in args[0] && + obj.tr + .find('td[data-field="' + nameKey + '"]') + .children('div.lay-table-cell') + .removeClass('lay-table-tree-item'); + tableThat.renderTreeTable(obj.tr, obj.tr.attr('data-level'), false); + return ret; + }; + + // 处理del方法 + obj.del = function () { + treeTable.removeNode(tableId, trData); + }; + + // 处理setRowChecked + obj.setRowChecked = function (checked) { + treeTable.setRowChecked(tableId, { + index: trData, + checked: checked, + }); + }; +}; + +// 更新数据 +treeTable.updateNode = function (id, index, newNode) { + var that = getThisTable(id); + if (!that) return; + + var options = that.getOptions(); + // var treeOptions = options.tree; + var tableView = options.elem.next(); + var trElem = tableView.find('tr[lay-data-index="' + index + '"]'); + var trIndex = trElem.attr('data-index'); + var trLevel = trElem.attr('data-level'); + + if (!newNode) { + return; + } + // 更新值 + var newNodeTemp = that.getNodeDataByIndex(index, false, newNode); + // 获取新的tr替换 + var trNew = table.getTrHtml(id, [newNodeTemp]); + // 重新渲染tr + ['main', 'fixed-l', 'fixed-r'].forEach(function (item, i) { + tableView + .find('.lay-table-' + item + ' tbody tr[lay-data-index="' + index + '"]') + .replaceWith( + $(trNew[['trs', 'trs_fixed', 'trs_fixed_r'][i]].join('')) + .attr({ + 'data-index': trIndex, + 'lay-data-index': index, + 'data-level': trLevel, + }) + .data('index', trIndex), + ); + }); + that.renderTreeTable( + tableView.find('tr[lay-data-index="' + index + '"]'), + trLevel, + ); +}; + +// 删除数据 +// _keepParent 暂时为私有参数,仅供内部使用 +treeTable.removeNode = function (id, node, _keepParent) { + var that = getThisTable(id); + if (!that) return; + + var options = that.getOptions(); + var treeOptions = options.tree; + var isParentKey = treeOptions.customName.isParent; + var childrenKey = treeOptions.customName.children; + var tableView = options.elem.next(); + var delNode; + var indexArr = []; + var tableCache = table.cache[id]; + delNode = that.getNodeDataByIndex( + lay.type(node) === 'string' ? node : node[LAY_DATA_INDEX], + false, + 'delete', + ); + var nodeP = that.getNodeDataByIndex(delNode[LAY_PARENT_INDEX]); + that.updateCheckStatus(nodeP); + var delNodesFlat = that.treeToFlat( + [delNode], + delNode[treeOptions.customName.pid], + delNode[LAY_PARENT_INDEX], + ); + delNodesFlat.forEach(function (delNode) { + var delNodeDataIndex = delNode[LAY_DATA_INDEX]; + indexArr.push('tr[lay-data-index="' + delNodeDataIndex + '"]'); + // 删除临时 key + if (delNodeDataIndex.indexOf('-') !== -1) { + delete tableCache[delNodeDataIndex]; + } + }); + + tableView.find(indexArr.join(',')).remove(); // 删除行 + + var deleteCacheKey = function () { + for (var key in tableCache) { + // 根节点 getNodeDataByIndex 内部已处理 + if (key.indexOf('-') !== -1) { + // L93 updateCache() 中,cacheKey 取自 rowData 中的 LAY_DATA_INDEX, + // 两者不同说明当前 cacheKey 引用的 rowData 已被更新 + if (key !== tableCache[key][LAY_DATA_INDEX]) { + delete tableCache[key]; + } + } + } + }; + + // 重新整理数据 + var tableData = that.initData(); + deleteCacheKey(); + // index发生变化需要更新页面tr中对应的lay-data-index 新增和删除都要注意数据结构变动之后的index问题 + that.treeToFlat(tableData).forEach(function (item3) { + if ( + item3[LAY_DATA_INDEX_HISTORY] && + item3[LAY_DATA_INDEX_HISTORY] !== item3[LAY_DATA_INDEX] + ) { + tableView + .find('tr[lay-data-index="' + item3[LAY_DATA_INDEX_HISTORY] + '"]') + .attr({ + 'data-index': item3[LAY_DATA_INDEX], + 'lay-data-index': item3[LAY_DATA_INDEX], + }) + .data('index', item3[LAY_DATA_INDEX]); + // item3[LAY_DATA_INDEX_HISTORY] = item3[LAY_DATA_INDEX] + } + }); + // 重新更新顶层节点的data-index; + tableCache.forEach(function (item4, i4) { + tableView + .find( + 'tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]', + ) + .attr('data-index', i4) + .data('index', i4); + }); + options.hasNumberCol && formatNumber(that); + // 更新父节点状态 + if (nodeP) { + var trEl = tableView.find( + 'tr[lay-data-index="' + nodeP[LAY_DATA_INDEX] + '"]', + ); + + if (!_keepParent) { + nodeP[isParentKey] = !!(nodeP[childrenKey] && nodeP[childrenKey].length); + } + + that.updateNodeIcon({ + scopeEl: trEl, + isExpand: nodeP[LAY_EXPAND], + isParent: nodeP[isParentKey], + }); + } + + // 重新适配尺寸 + treeTable.resize(id); +}; + +/** + * 新增数据节点 + * @param {String} id 树表id + * @param {Object} opts + * @param {String|Number} opts.parentIndex 指定的父节点,如果增加根节点,请设置 parentIndex 为 null 即可 + * @param {Number} opts.index 新节点插入的位置(从 0 开始)index = -1(默认) 时,插入到最后 + * @param {Object|Array} opts.data 新增的节点,单个或者多个 + * @param {Boolean} opts.focus 新增的节点,单个或者多个 + * @return {Array} 新增的节点 + * */ +treeTable.addNodes = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + + var options = that.getOptions(); + var treeOptions = options.tree; + var tableViewElem = options.elem.next(); + var checkName = table.config.checkName; + + opts = opts || {}; + + var parentIndex = opts.parentIndex; + var index = opts.index; + var newNodes = opts.data; + var focus = opts.focus; + + parentIndex = + lay.type(parentIndex) === 'number' ? parentIndex.toString() : parentIndex; + var parentNode = parentIndex ? that.getNodeDataByIndex(parentIndex) : null; + index = lay.type(index) === 'number' ? index : -1; + + // 添加数据 + newNodes = $.extend(true, [], lay.isArray(newNodes) ? newNodes : [newNodes]); + + // 若未传入 LAY_CHECKED 属性,则继承父节点的 checked 状态 + newNodes.forEach(function (item) { + if (!(checkName in item) && parentNode) { + item[checkName] = parentNode[checkName]; + } + }); + + // var tableData = that.getTableData(); + var dataAfter; + + if (!parentNode) { + // 添加到根节点 + dataAfter = table.cache[id].splice( + index === -1 ? table.cache[id].length : index, + ); + table.cache[id] = table.cache[id].concat(newNodes, dataAfter); + if (!options.url) { + // 静态data模式 + if (!options.page) { + options.data = table.cache[id]; + } else { + var pageOptions = options.page; + options.data.splice.apply( + options.data, + [ + pageOptions.limit * (pageOptions.curr - 1), + pageOptions.limit, + ].concat(table.cache[id]), + ); + } + } + // 将新节点添加到页面 + // tableData = that.initData(); + + if (tableViewElem.find('.lay-none').length) { + table.renderData(id); + return newNodes; + } + + var newNodesHtml = table.getTrHtml(id, newNodes); + var newNodesHtmlObj = { + trs: $(newNodesHtml.trs.join('')), + trs_fixed: $(newNodesHtml.trs_fixed.join('')), + trs_fixed_r: $(newNodesHtml.trs_fixed_r.join('')), + }; + + var attrs = {}; + newNodes.forEach(function (newNodeItem, newNodeIndex) { + attrs = { + 'data-index': newNodeItem[LAY_DATA_INDEX], + 'lay-data-index': newNodeItem[LAY_DATA_INDEX], + 'data-level': '0', + }; + newNodesHtmlObj.trs + .eq(newNodeIndex) + .attr(attrs) + .data('index', newNodeItem[LAY_DATA_INDEX]); + newNodesHtmlObj.trs_fixed + .eq(newNodeIndex) + .attr(attrs) + .data('index', newNodeItem[LAY_DATA_INDEX]); + newNodesHtmlObj.trs_fixed_r + .eq(newNodeIndex) + .attr(attrs) + .data('index', newNodeItem[LAY_DATA_INDEX]); + }); + var trIndexPrev = parseInt(newNodes[0][LAY_DATA_INDEX]) - 1; + var tableViewElemMAIN = tableViewElem.find(ELEM_MAIN); + var tableViewElemFIXL = tableViewElem.find(ELEM_FIXL); + var tableViewElemFIXR = tableViewElem.find(ELEM_FIXR); + if (trIndexPrev === -1) { + // 插入到开头 + var hasTr = tableViewElemMAIN.find( + 'tr[data-level="0"][data-index="0"]', + )[0]; + if (hasTr) { + tableViewElemMAIN + .find('tr[data-level="0"][data-index="0"]') + .before(newNodesHtmlObj.trs); + tableViewElemFIXL + .find('tr[data-level="0"][data-index="0"]') + .before(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR + .find('tr[data-level="0"][data-index="0"]') + .before(newNodesHtmlObj.trs_fixed_r); + } else { + tableViewElemMAIN.find('tbody').prepend(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tbody').prepend(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tbody').prepend(newNodesHtmlObj.trs_fixed_r); + } + } else { + if (index === -1) { + // 追加到最后 + tableViewElemMAIN.find('tbody').append(newNodesHtmlObj.trs); + tableViewElemFIXL.find('tbody').append(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR.find('tbody').append(newNodesHtmlObj.trs_fixed_r); + } else { + var trIndexNext = dataAfter[0][LAY_DATA_INDEX_HISTORY]; + tableViewElemMAIN + .find('tr[data-level="0"][data-index="' + trIndexNext + '"]') + .before(newNodesHtmlObj.trs); + tableViewElemFIXL + .find('tr[data-level="0"][data-index="' + trIndexNext + '"]') + .before(newNodesHtmlObj.trs_fixed); + tableViewElemFIXR + .find('tr[data-level="0"][data-index="' + trIndexNext + '"]') + .before(newNodesHtmlObj.trs_fixed_r); + } + } + + // 重新更新顶层节点的data-index; + table.cache[id].forEach(function (item4, i4) { + tableViewElem + .find( + 'tr[data-level="0"][lay-data-index="' + item4[LAY_DATA_INDEX] + '"]', + ) + .attr('data-index', i4) + .data('index', i4); + }); + + that.renderTreeTable( + tableViewElem.find( + newNodes + .map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }) + .join(','), + ), + ); + } else { + var isParentKey = treeOptions.customName.isParent; + var childKey = treeOptions.customName.children; + + parentNode[isParentKey] = true; + var childrenNodes = parentNode[childKey]; + if (!childrenNodes) { + childrenNodes = parentNode[childKey] = newNodes; + } else { + dataAfter = childrenNodes.splice( + index === -1 ? childrenNodes.length : index, + ); + childrenNodes = parentNode[childKey] = childrenNodes.concat( + newNodes, + dataAfter, + ); + } + // 删除已经存在的同级节点以及他们的子节点,并且把中间节点的已展开过的状态设置为false + that.updateStatus(childrenNodes, function (d) { + if (d[isParentKey] || treeOptions.view.showFlexIconIfNotParent) { + d[LAY_HAS_EXPANDED] = false; + } + }); + var childrenNodesFlat = that.treeToFlat(childrenNodes); + tableViewElem + .find( + childrenNodesFlat + .map(function (value) { + return 'tr[lay-data-index="' + value[LAY_DATA_INDEX] + '"]'; + }) + .join(','), + ) + .remove(); + + // tableData = that.initData(); + // 去掉父节点的已经展开过的状态,重新执行一次展开的方法 + parentNode[LAY_HAS_EXPANDED] = false; + parentNode[LAY_ASYNC_STATUS] = 'local'; // 转为本地数据,应该规定异步加载子节点的时候addNodes的规则 + expandNode( + { + trElem: tableViewElem.find('tr[lay-data-index="' + parentIndex + '"]'), + }, + true, + ); + } + that.updateCheckStatus(parentNode); + // 更新父节点图标状态 + if (parentNode) { + var trEl = tableViewElem.find( + 'tr[lay-data-index="' + parentNode[LAY_DATA_INDEX] + '"]', + ); + that.updateNodeIcon({ + scopeEl: trEl, + isExpand: parentNode[LAY_EXPAND], + isParent: parentNode[isParentKey], + }); + } + treeTable.resize(id); + if (focus) { + // 滚动到第一个新增的节点 + tableViewElem + .find(ELEM_MAIN) + .find('tr[lay-data-index="' + newNodes[0][LAY_DATA_INDEX] + '"]') + .get(0) + .scrollIntoViewIfNeeded(); + } + + return newNodes; +}; + +// 获取表格选中状态 +treeTable.checkStatus = function (id, includeHalfCheck) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + var treeOptions = options.tree; + var checkName = table.config.checkName; + + // 需要区分单双选 + var tableData = treeTable.getData(id, true); + var checkedData = tableData.filter(function (value) { + return value[checkName] || (includeHalfCheck && value[LAY_CHECKBOX_HALF]); + }); + + var isAll = true; + for (const item1 of treeOptions.data.cascade === 'all' + ? table.cache[id] + : treeTable.getData(id, true)) { + if (!item1[checkName]) { + isAll = false; + break; + } + } + + return { + data: checkedData, + isAll: isAll, + }; +}; + +// 排序之后重新渲染成树表 +treeTable.on('sort', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + treeTable.sort(tableId); + } +}); + +// 行点击 +treeTable.on('row', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + } +}); + +// 行双击 +treeTable.on('rowDouble', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + + var treeOptions = options.tree || {}; + if (treeOptions.view.dblClickExpand) { + expandNode({ trElem: obj.tr.first() }, null, null, null, true); + } + } +}); + +// 菜单 +treeTable.on('rowContextmenu', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + } +}); + +// tr中带lay-event节点点击 +treeTable.on('tool', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + } +}); + +// 行内编辑 +treeTable.on('edit', function (obj) { + // 如果编辑涉及到关键的name字段需要重新更新一下tr节点 + var options = obj.config; + var tableView = options.elem.next(); + // var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + updateObjParams(obj); + if (obj.field === options.tree.customName.name) { + var updateData = {}; + updateData[obj.field] = obj.value; + obj.update(updateData); // 通过update调用执行tr节点的更新 + } + } +}); + +// 单选 +treeTable.on('radio', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + var that = getThisTable(tableId); + updateObjParams(obj); + checkNode.call(that, obj.tr, obj.checked); + } +}); + +// 设置或取消行选中样式 +Class.prototype.setRowCheckedClass = function (tr, checked) { + var that = this; + var options = that.getOptions(); + + // var index = tr.data('index'); + var tableViewElem = options.elem.next(); + + tr[checked ? 'addClass' : 'removeClass'](ELEM_CHECKED); // 主体行 + + // 右侧固定行 + tr.each(function () { + var index = $(this).data('index'); + var trFixedR = tableViewElem.find( + '.lay-table-fixed-r tbody tr[data-index="' + index + '"]', + ); + trFixedR[checked ? 'addClass' : 'removeClass'](ELEM_CHECKED); + }); +}; + +// 更新表格的复选框状态 +Class.prototype.updateCheckStatus = function (dataP, checked) { + var that = this; + var options = that.getOptions(); + if (!options.hasChecboxCol) { + return false; // 如果没有复选列则不需要更新状态 + } + var treeOptions = options.tree; + var tableId = options.id; + var tableView = options.elem.next(); + + var checkName = table.config.checkName; + + var cascade = treeOptions.data.cascade; + var isCascadeParent = cascade === 'all' || cascade === 'parent'; + + // 如有必要更新父节点们的状态 + if (isCascadeParent && dataP) { + var trsP = that.updateParentCheckStatus( + dataP, + lay.type(checked) === 'boolean' ? checked : null, + ); + trsP.forEach(function (itemP) { + var checkboxElem = tableView.find( + 'tr[lay-data-index="' + + itemP[LAY_DATA_INDEX] + + '"] input[name="layTableCheckbox"]:not(:disabled)', + ); + var checked = itemP[checkName]; + + // 标记父节点行背景色 + that.setRowCheckedClass(checkboxElem.closest('tr'), checked); + + // 设置原始复选框 checked 属性值并渲染 + checkboxElem.prop({ + checked: checked, + indeterminate: itemP[LAY_CHECKBOX_HALF], + }); + }); + } + + // 更新全选的状态 + var isAll = true; + var isIndeterminate = false; + var data = + treeOptions.data.cascade === 'all' + ? table.cache[tableId] + : treeTable.getData(tableId, true); + data = data.filter(function (item) { + return !item[options.disabledName]; + }); + + if (data.length > 0) { + for (const item1 of data) { + if (item1[checkName] || item1[LAY_CHECKBOX_HALF]) { + isIndeterminate = true; + } + if (!item1[checkName]) { + isAll = false; + } + if (isIndeterminate && !isAll) { + break; + } + } + } else { + isAll = false; + } + + isIndeterminate = isIndeterminate && !isAll; + tableView + .find('input[name="layTableCheckbox"][lay-filter="layTableAllChoose"]') + .prop({ + checked: isAll, + indeterminate: isIndeterminate, + }); + + return isAll; +}; + +// 更新父节点的选中状态 +Class.prototype.updateParentCheckStatus = function (dataP, checked) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var checkName = table.config.checkName; + var childrenKey = treeOptions.customName.children; + + var dataRet = []; + dataP[LAY_CHECKBOX_HALF] = false; // 先设置为非半选,是否为半选又下面逻辑判断 + if (checked === true) { + // 为真需要判断子节点的情况 + if (!dataP[childrenKey].length) { + checked = false; + } else { + for (const item of dataP[childrenKey]) { + if (!item[checkName]) { + // 只要有一个子节点为false + checked = false; + dataP[LAY_CHECKBOX_HALF] = true; + break; // 跳出循环 + } + } + } + } else if (checked === false) { + // 判断是否为半选 + for (const item of dataP[childrenKey]) { + if (item[checkName] || item[LAY_CHECKBOX_HALF]) { + // 只要有一个子节点为选中或者半选状态 + dataP[LAY_CHECKBOX_HALF] = true; + break; + } + } + } else { + // 状态不确定的情况下根据子节点的信息 + checked = false; + var checkedNum = 0; + dataP[childrenKey].forEach(function (item) { + if (item[checkName]) { + checkedNum++; + } + }); + checked = dataP[childrenKey].length + ? dataP[childrenKey].length === checkedNum + : dataP[checkName]; // 如果没有子节点保留原来的状态; + dataP[LAY_CHECKBOX_HALF] = checked ? false : checkedNum > 0; + } + dataP[checkName] = checked; + dataRet.push($.extend({}, dataP)); + if (dataP[LAY_PARENT_INDEX]) { + dataRet = dataRet.concat( + that.updateParentCheckStatus( + table.cache[tableId][dataP[LAY_PARENT_INDEX]], + checked, + ), + ); + } + return dataRet; +}; + +var checkNode = function (trElem, checked, callbackFlag) { + var that = this; + var options = that.getOptions(); + var treeOptions = options.tree; + var tableId = options.id; + var tableView = options.elem.next(); + var inputElem = (trElem.length ? trElem : tableView) + .find('.laytable-cell-radio, .laytable-cell-checkbox') + .children('input') + .last(); + // 判断是单选还是多选 不应该同时存在radio列和checkbox列 + var isRadio = inputElem.attr('type') === 'radio'; + + if (callbackFlag) { + var triggerEvent = function () { + var fn = function (e) { + e.stopPropagation(); + }; + inputElem.parent().on('click', fn); // 添加临时的阻止冒泡事件 + inputElem.next().click(); + inputElem.parent().off('click', fn); + }; + // 如果需要触发事件可以简单的触发对应节点的click事件 + if (isRadio) { + // 单选只能选中或者切换其他的不能取消选中 后续看是否有支持的必要 todo + if (checked && !inputElem.prop('checked')) { + triggerEvent(); + } + } else { + if (lay.type(checked) === 'boolean') { + if (inputElem.prop('checked') !== checked) { + // 如果当前已经是想要修改的状态则不做处理 + triggerEvent(); + } + } else { + // 切换 + triggerEvent(); + } + } + } else { + var trData = that.getNodeDataByIndex(trElem.attr('data-index')); + var checkName = table.config.checkName; + // 如果不触发事件应该有一个方法可以更新数据以及页面的节点 + if (isRadio) { + if (!trData) { + // 单选必须是一个存在的行 + return; + } + var statusChecked = {}; + statusChecked[checkName] = false; + // that.updateStatus(null, statusChecked); // 取消其他的选中状态 + that.updateStatus(null, function (d) { + if (d[checkName]) { + var radioElem = tableView.find( + 'tr[lay-data-index="' + + d[LAY_DATA_INDEX] + + '"] input[type="radio"][lay-type="layTableRadio"]', + ); + d[checkName] = false; + + // 取消当前选中行背景色 + that.setRowCheckedClass(radioElem.closest('tr'), false); + radioElem.prop('checked', false); + } + }); // 取消其他的选中状态 + trData[checkName] = checked; + + that.setRowCheckedClass(trElem, checked); // 标记当前选中行背景色 + that.setRowCheckedClass(trElem.siblings(), false); // 取消其他行背景色 + + trElem + .find('input[type="radio"][lay-type="layTableRadio"]') + .prop('checked', checked); + } else { + // 切换只能用到单条,全选到这一步的时候应该是一个确定的状态 + checked = lay.type(checked) === 'boolean' ? checked : !trData[checkName]; // 状态切换,如果遇到不可操作的节点待处理 todo + // 全选或者是一个父节点,将子节点的状态同步为当前节点的状态 + // 处理不可操作的信息 + var checkedStatusFn = function (d) { + if (!d[table.config.disabledName]) { + // 节点不可操作的不处理 + d[checkName] = checked; + d[LAY_CHECKBOX_HALF] = false; + } + }; + + var trs = that.updateStatus( + trData ? [trData] : table.cache[tableId], + checkedStatusFn, + trData && ['parent', 'none'].indexOf(treeOptions.data.cascade) !== -1, + ); + var checkboxElem = tableView.find( + trs + .map(function (value) { + return ( + 'tr[lay-data-index="' + + value[LAY_DATA_INDEX] + + '"] input[name="layTableCheckbox"]:not(:disabled)' + ); + }) + .join(','), + ); + + that.setRowCheckedClass(checkboxElem.closest('tr'), checked); // 标记当前选中行背景色 + checkboxElem.prop({ checked: checked, indeterminate: false }); + + var trDataP; + + // 更新父节点以及更上层节点的状态 + if (trData && trData[LAY_PARENT_INDEX]) { + // 找到父节点,然后判断父节点的子节点是否全部选中 + trDataP = that.getNodeDataByIndex(trData[LAY_PARENT_INDEX]); + } + + return that.updateCheckStatus(trDataP, checked); + } + } +}; + +// 多选 +treeTable.on('checkbox', function (obj) { + var options = obj.config; + var tableView = options.elem.next(); + var tableId = options.id; + + if (tableView.hasClass(TABLE_TREE)) { + var that = getThisTable(tableId); + var checked = obj.checked; + updateObjParams(obj); + obj.isAll = checkNode.call(that, obj.tr, checked); + } +}); + +/** + * 设置行选中状态 + * @param {String} id 树表id + * @param {Object} opts + * @param {Object|String} opts.index 节点下标 + * @param {Boolean} opts.checked 选中或取消 + * @param {Boolean} [opts.callbackFlag] 是否触发事件回调 + * */ +treeTable.setRowChecked = function (id, opts) { + var that = getThisTable(id); + if (!that) return; + + var options = that.getOptions(); + var tableView = options.elem.next(); + + opts = opts || {}; + + var node = opts.index; + var checked = opts.checked; + var callbackFlag = opts.callbackFlag; + + var dataIndex = lay.type(node) === 'string' ? node : node[LAY_DATA_INDEX]; + // 判断是否在当前页面中 + var nodeData = that.getNodeDataByIndex(dataIndex); + if (!nodeData) { + // 目前只能处理当前页的数据 + return; + } + + var collectNeedExpandNodeIndex = function (index) { + needExpandIndex.push(index); + var trElem = tableView.find('tr[lay-data-index="' + index + '"]'); + if (!trElem.length) { + var nodeData = that.getNodeDataByIndex(index); + var parentIndex = nodeData[LAY_PARENT_INDEX]; + parentIndex && collectNeedExpandNodeIndex(parentIndex); + } + }; + + // 判断是否展开过 + var trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]'); + if (!trElem.length) { + var parentIndex = nodeData[LAY_PARENT_INDEX]; + var needExpandIndex = []; + collectNeedExpandNodeIndex(parentIndex); + // 如果还没有展开没有渲染的要先渲染出来 + needExpandIndex.reverse().forEach(function (nodeIndex) { + treeTable.expandNode(id, { + index: nodeIndex, + expandFlag: true, + }); + }); + trElem = tableView.find('tr[lay-data-index="' + dataIndex + '"]'); + } + checkNode.call(that, trElem, checked, callbackFlag); +}; + +treeTable.checkAllNodes = function (id, checked) { + var that = getThisTable(id); + if (!that) return; + + var options = that.getOptions(); + var tableView = options.elem.next(); + + checkNode.call(that, tableView.find('tr[data-index="NONE"]'), !!checked); +}; + +/** + * 获得数据 + * @param {String} id 表格id + * @param {Boolean} [isSimpleData] 是否返回平铺结构的数据 + * @return {Array} 表格数据 + * */ +treeTable.getData = function (id, isSimpleData) { + var that = getThisTable(id); + if (!that) return; + + var tableData = []; + $.extend(true, [], table.cache[id] || []).forEach(function (item) { + // 遍历排除掉临时的数据 + tableData.push(item); + }); + return isSimpleData ? that.treeToFlat(tableData) : tableData; +}; + +/** + * 重新加载子节点 + * @param {String} id 表格id + * @param {String} dataIndex 父节点的dataIndex + * */ +treeTable.reloadAsyncNode = function (id, dataIndex) { + var that = getThisTable(id); + if (!that) { + return; + } + + var options = that.getOptions(); + var treeOptions = options.tree; + if (!treeOptions.async || !treeOptions.async.enable) { + return; + } + var dataP = that.getNodeDataByIndex(dataIndex); + if (!dataP) { + return; + } + dataP[LAY_HAS_EXPANDED] = false; + dataP[LAY_EXPAND] = false; + dataP[LAY_ASYNC_STATUS] = false; + that + .treeToFlat(dataP[treeOptions.customName.children]) + .reverse() + .forEach(function (item1) { + treeTable.removeNode(id, item1[LAY_DATA_INDEX], true); + }); + // 重新展开 + treeTable.expandNode(id, { + index: dataIndex, + expandFlag: true, + callbackFlag: true, + }); +}; + +/** + * 通过数据id获取节点对象 + * */ +treeTable.getNodeById = function (id, dataId) { + var that = getThisTable(id); + if (!that) return; + + return that.getNodeById(dataId); +}; + +/** + * 根据自定义规则搜索节点数据 + * @param {String} id 树表id + * @param {Function} filter 自定义过滤器函数 + * @param {Object} [opts] + * @param {Boolean} [opts.isSingle] 是否只找到第一个 + * @param {Object} [opts.parentNode] 在指定在某个父节点下的子节点中搜索 + * @return {Object} 节点对象 + * */ +treeTable.getNodesByFilter = function (id, filter, opts) { + var that = getThisTable(id); + if (!that) return; + var options = that.getOptions(); + + opts = opts || {}; + var isSingle = opts.isSingle; + var parentNode = opts.parentNode; + var dataP = parentNode && parentNode.data; + // dataP = dataP || table.cache[id]; + var nodes = that + .treeToFlat( + dataP ? dataP[options.tree.customName.children] || [] : table.cache[id], + ) + .filter(filter); + var nodesResult = []; + for (const item1 of nodes) { + nodesResult.push(that.getNodeByIndex(item1[LAY_DATA_INDEX])); + if (isSingle) { + break; + } + } + + return nodesResult; +}; + +// 记录所有实例 +thisTreeTable.that = {}; // 记录所有实例对象 +// thisTreeTable.config = {}; // 记录所有实例配置项 + +// 重载 +treeTable.reload = function (id, options, deep, type) { + // deep = deep !== false; // 默认采用深拷贝 + var that = getThisTable(id); + if (!that) return; + that.reload(options, deep, type); + return thisTreeTable.call(that); +}; + +// 核心入口 +treeTable.render = function (options) { + var inst = new Class(options); + return thisTreeTable.call(inst); +}; + +export { treeTable }; diff --git a/src/components/upload.js b/src/components/upload.js new file mode 100644 index 000000000..78a6f95fb --- /dev/null +++ b/src/components/upload.js @@ -0,0 +1,847 @@ +/** + * upload + * 上传组件 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { log } from '../core/logger.js'; +import { $ } from 'jquery'; +import { layer } from './layer.js'; + +// 模块名 +var MOD_NAME = 'upload'; +var MOD_INDEX = 'layui_' + MOD_NAME + '_index'; // 模块索引名 + +// 外部接口 +var upload = { + config: {}, // 全局配置项 + // 设置全局项 + set: function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + return that; + }, + // 事件 + on: function (events, callback) { + return lay.onevent.call(this, MOD_NAME, events, callback); + }, +}; + +// 操作当前实例 +var thisModule = function () { + var that = this; + var options = that.config; + var id = options.id; + + thisModule.that[id] = that; // 记录当前实例对象 + + return { + upload: function (files) { + that.upload.call(that, files); + }, + reload: function (options) { + that.reload.call(that, options); + }, + config: that.config, + }; +}; + +var ELEM_FILE = 'lay-upload-file'; +var ELEM_CHOOSE = 'lay-upload-choose'; +var UPLOADING = 'UPLOADING'; + +// 构造器 +var Class = function (options) { + var that = this; + that.index = upload.index = lay.autoIncrementer('upload'); + that.config = $.extend({}, that.config, upload.config, options); + that.render(); +}; + +// 默认配置 +Class.prototype.config = { + accept: 'images', // 允许上传的文件类型:images/file/video/audio + exts: '', // 允许上传的文件后缀名 + auto: true, // 是否选完文件后自动上传 + bindAction: '', // 手动上传触发的元素 + url: '', // 上传地址 + force: '', // 强制规定返回的数据格式,目前只支持是否强制 json + field: 'file', // 文件字段名 + acceptMime: '', // 筛选出的文件类型,默认为所有文件 + method: 'post', // 请求上传的 http 类型 + data: {}, // 请求上传的额外参数 + drag: true, // 是否允许拖拽上传 + size: 0, // 文件限制大小,默认不限制 + number: 0, // 允许同时上传的文件数,默认不限制 + multiple: false, // 是否允许多文件上传 + text: { + // 自定义提示文本 + 'cross-domain': 'Cross-domain requests are not supported', // 跨域 + 'data-format-error': 'Please return JSON data format', // 数据格式错误 + 'check-error': '', // 文件格式校验失败 + error: '', // 上传失败 + 'limit-number': null, // 限制 number 属性的提示 --- function + 'limit-size': null, // 限制 size 属性的提示 --- function + }, +}; + +// 重载实例 +Class.prototype.reload = function (options) { + var that = this; + that.config = $.extend({}, that.config, options); + that.render(true); +}; + +// 初始渲染 +Class.prototype.render = function (rerender) { + var that = this; + var options = that.config; + + // 若 elem 非唯一 + var elem = $(options.elem); + if (elem.length > 1) { + elem.each(function () { + upload.render( + $.extend({}, options, { + elem: this, + }), + ); + }); + return that; + } + + // 合并 lay-options 属性上的配置信息 + $.extend( + options, + lay.options(elem[0], { + attr: elem.attr('lay-data') ? 'lay-data' : null, // 兼容旧版的 lay-data 属性 + }), + ); + + // 若重复执行 render,则视为 reload 处理 + if (!rerender && elem[0] && elem.data(MOD_INDEX)) { + var newThat = thisModule.getThis(elem.data(MOD_INDEX)); + if (!newThat) return; + + return newThat.reload(options); + } + + options.elem = $(options.elem); + options.bindAction = $(options.bindAction); + + // 初始化 id 属性 - 优先取 options > 元素 id > 自增索引 + options.id = 'id' in options ? options.id : elem.attr('id') || that.index; + + that.file(); + that.events(); +}; + +//追加文件域 +Class.prototype.file = function () { + var that = this; + var options = that.config; + var elemFile = (that.elemFile = $( + [ + '', + ].join(''), + )); + var next = options.elem.next(); + + if (next.hasClass(ELEM_FILE)) { + next.remove(); + } + + that.isFile() + ? ((that.elemFile = options.elem), (options.field = options.elem[0].name)) + : options.elem.after(elemFile); +}; + +//异常提示 +Class.prototype.msg = function (content) { + return layer.msg(content, { + icon: 2, + shift: 6, + }); +}; + +//判断绑定元素是否为文件域本身 +Class.prototype.isFile = function () { + var elem = this.config.elem[0]; + if (!elem) return; + return elem.tagName.toLocaleLowerCase() === 'input' && elem.type === 'file'; +}; + +//预读图片信息 +Class.prototype.preview = function (callback) { + var that = this; + if (window.FileReader) { + Object.entries(that.chooseFiles || {}).forEach(function ([index, file]) { + var reader = new FileReader(); + reader.readAsDataURL(file); + reader.onload = function () { + callback && callback(index, file, this.result); + }; + }); + } +}; + +// 执行上传 +Class.prototype.upload = function (files, type) { + var that = this; + var options = that.config; + var text = options.text || {}; + var elemFile = that.elemFile[0]; + + // 获取文件队列 + var getFiles = function () { + return files || that.files || that.chooseFiles || elemFile.files; + }; + + // 高级浏览器处理方式,支持跨域 + var ajaxSend = function () { + var successful = 0; + var failed = 0; + var items = getFiles(); + + // 多文件全部上传完毕的回调 + var allDone = function () { + if (options.multiple && successful + failed === that.fileLength) { + typeof options.allDone === 'function' && + options.allDone({ + total: that.fileLength, + successful: successful, + failed: failed, + }); + } + }; + + // 发送请求 + var request = function (sets) { + var formData = new FormData(); + + // 恢复文件状态 + var resetFileState = function (file) { + if (sets.unified) { + Object.values(items || {}).forEach(function (file) { + delete file[UPLOADING]; + }); + } else { + delete file[UPLOADING]; + } + }; + + // 追加额外的参数 + Object.entries(options.data || {}).forEach(function ([key, value]) { + value = + typeof value === 'function' + ? sets.unified + ? value() + : value(sets.index, sets.file) + : value; + formData.append(key, value); + }); + + /* + * 添加 file 到表单域 + */ + + // 是否统一上传 + if (sets.unified) { + Object.values(items || {}).forEach(function (file) { + if (file[UPLOADING]) return; + file[UPLOADING] = true; // 上传中的标记 + formData.append(options.field, file); + }); + } else { + // 逐一上传 + if (sets.file[UPLOADING]) return; + formData.append(options.field, sets.file); + sets.file[UPLOADING] = true; // 上传中的标记 + } + + // ajax 参数 + var opts = { + url: options.url, + type: 'post', // 统一采用 post 上传 + data: formData, + dataType: options.dataType || 'json', + contentType: false, + processData: false, + headers: options.headers || {}, + success: function (res) { + // 成功回调 + options.unified ? (successful += that.fileLength) : successful++; + done(sets.index, res); + allDone(sets.index); + resetFileState(sets.file); + }, + error: function (e) { + // 异常回调 + options.unified ? (failed += that.fileLength) : failed++; + that.msg( + text['error'] || + [ + 'Upload failed, please try again.', + 'status: ' + + (e.status || '') + + ' - ' + + (e.statusText || 'error'), + ].join('
                                    '), + ); + error(sets.index, e.responseText, e); + allDone(sets.index); + resetFileState(sets.file); + }, + }; + + // 进度条 + if (typeof options.progress === 'function') { + opts.xhr = function () { + var xhr = $.ajaxSettings.xhr(); + // 上传进度 + xhr.upload.addEventListener('progress', function (obj) { + if (obj.lengthComputable) { + var percent = Math.floor((obj.loaded / obj.total) * 100); // 百分比 + options.progress( + percent, + options.item ? options.item[0] : options.elem[0], + obj, + sets.index, + ); + } + }); + return xhr; + }; + } + $.ajax(opts); + }; + + // 多文件是否一起上传 + if (options.unified) { + request({ + unified: true, + index: 0, + }); + } else { + Object.entries(items || {}).forEach(function ([index, file]) { + request({ + index: index, + file: file, + }); + }); + } + }; + + // 强制返回的数据格式 + var forceConvert = function (src) { + if (options.force === 'json') { + if (typeof src !== 'object') { + try { + return { + status: 'CONVERTED', + data: JSON.parse(src), + }; + } catch { + that.msg(text['data-format-error']); + return { + status: 'FORMAT_ERROR', + data: {}, + }; + } + } + } + return { status: 'DO_NOTHING', data: {} }; + }; + + // 统一回调 + var done = function (index, res) { + that.elemFile.next('.' + ELEM_CHOOSE).remove(); + elemFile.value = ''; + + var convert = forceConvert(res); + + switch (convert.status) { + case 'CONVERTED': + res = convert.data; + break; + case 'FORMAT_ERROR': + return; + } + + typeof options.done === 'function' && + options.done(res, index || 0, function (files) { + that.upload(files); + }); + }; + + // 统一网络异常回调 + var error = function (index, res, xhr) { + if (options.auto) { + elemFile.value = ''; + } + + var convert = forceConvert(res); + + switch (convert.status) { + case 'CONVERTED': + res = convert.data; + break; + case 'FORMAT_ERROR': + return; + } + + typeof options.error === 'function' && + options.error( + index || 0, + function (files) { + that.upload(files); + }, + res, + xhr, + ); + }; + + var check; + var exts = options.exts; + var value = (function () { + var arr = []; + Object.values(files || that.chooseFiles || {}).forEach(function (item) { + arr.push(item.name); + }); + return arr; + })(); + + // 回调函数返回的参数 + var args = { + // 预览 + preview: function (callback) { + that.preview(callback); + }, + // 上传 + upload: function (index, file) { + var thisFile = {}; + thisFile[index] = file; + that.upload(thisFile); + }, + // 追加文件到队列 + pushFile: function () { + that.files = that.files || {}; + Object.entries(that.chooseFiles || {}).forEach(function ([index, item]) { + that.files[index] = item; + }); + return that.files; + }, + // 重置文件 + resetFile: function (index, file, filename) { + var newFile = new File([file], filename); + that.files = that.files || {}; + that.files[index] = newFile; + }, + // 获取本次选取的文件 + getChooseFiles: function () { + return that.chooseFiles; + }, + }; + + // 提交上传 + var send = function () { + var ready = function () { + ajaxSend(); + }; + // 上传前的回调 - 如果回调函数明确返回 false 或 Promise.reject,则停止上传 + if (typeof options.before === 'function') { + upload.util.promiseLikeResolve(options.before(args)).then( + function (result) { + if (result !== false) { + ready(); + } else { + if (options.auto) { + elemFile.value = ''; + } + } + }, + function (error) { + if (options.auto) { + elemFile.value = ''; + } + error !== undefined && log(error); + }, + ); + } else { + ready(); + } + }; + + // 文件类型名称 + var typeName = + { + file: i18n.$t('upload.fileType.file'), + images: i18n.$t('upload.fileType.image'), + video: i18n.$t('upload.fileType.video'), + audio: i18n.$t('upload.fileType.audio'), + }[options.accept] || i18n.$t('upload.fileType.file'); + + // 校验文件格式 + value = + value.length === 0 + ? elemFile.value.match(/[^/\\]+\..+/g) || [] || '' + : value; + + // 若文件域值为空 + if (value.length === 0) return; + + // 根据文件类型校验 + switch (options.accept) { + case 'file': // 一般文件 + for (const item of value) { + if (exts && !RegExp('.\\.(' + exts + ')$', 'i').test(escape(item))) { + check = true; + break; + } + } + break; + case 'video': // 视频文件 + for (const item of value) { + if ( + !RegExp( + '.\\.(' + (exts || 'avi|mp4|wma|rmvb|rm|flash|3gp|flv') + ')$', + 'i', + ).test(escape(item)) + ) { + check = true; + break; + } + } + break; + case 'audio': // 音频文件 + for (const item of value) { + if ( + !RegExp('.\\.(' + (exts || 'mp3|wav|mid') + ')$', 'i').test( + escape(item), + ) + ) { + check = true; + break; + } + } + break; + default: // 图片文件 + for (const item of value) { + if ( + !RegExp( + '.\\.(' + (exts || 'jpg|png|gif|bmp|jpeg|svg|webp') + ')$', + 'i', + ).test(escape(item)) + ) { + check = true; + break; + } + } + break; + } + + // 校验失败提示 + if (check) { + that.msg( + text['check-error'] || + i18n.$t('upload.validateMessages.fileExtensionError', { + fileType: typeName, + }), + ); + return (elemFile.value = ''); + } + + // 选择文件的回调 + if (type === 'choose' || options.auto) { + options.choose && options.choose(args); + if (type === 'choose') { + return; + } + } + + // 检验文件数量 + that.fileLength = (function () { + return Object.keys(getFiles() || {}).length; + })(); + + if (options.number && that.fileLength > options.number) { + return that.msg( + typeof text['limit-number'] === 'function' + ? text['limit-number'](options, that.fileLength) + : i18n.$t('upload.validateMessages.filesOverLengthLimit', { + length: options.number, + }) + + '
                                    ' + + i18n.$t('upload.validateMessages.currentFilesLength', { + length: that.fileLength, + }), + ); + } + + // 检验文件大小 + if (options.size > 0) { + var limitSize; + + Object.values(getFiles() || {}).forEach(function (file) { + if (file.size > 1024 * options.size) { + var size = options.size / 1024; + size = size >= 1 ? size.toFixed(2) + 'MB' : options.size + 'KB'; + elemFile.value = ''; + limitSize = size; + } + }); + if (limitSize) + return that.msg( + typeof text['limit-size'] === 'function' + ? text['limit-size'](options, limitSize) + : i18n.$t('upload.validateMessages.fileOverSizeLimit', { + size: limitSize, + }), + ); + } + + send(); +}; + +//事件处理 +Class.prototype.events = function () { + var that = this; + var options = that.config; + + // 设置当前选择的文件队列 + var setChooseFile = function (files) { + that.chooseFiles = {}; + Array.from(files || []).forEach(function (item, i) { + var time = new Date().getTime(); + that.chooseFiles[time + '-' + i] = item; + }); + }; + + // 设置选择的文本 + var setChooseText = function (files) { + var elemFile = that.elemFile; + // var item = options.item ? options.item : options.elem; + var value = + files.length > 1 + ? i18n.$t('upload.chooseText', { length: files.length }) + : (files[0] || {}).name || + elemFile[0].value.match(/[^/\\]+\..+/g) || + [] || + ''; + + if (elemFile.next().hasClass(ELEM_CHOOSE)) { + elemFile.next().remove(); + } + that.upload(null, 'choose'); + if (that.isFile() || options.choose) return; + elemFile.after( + '' + value + '', + ); + }; + + /** + * 判断文件是否加入排队 + * @param {File} file + * @return {boolean} + */ + var checkFile = function (file) { + return !Object.values(that.files || {}).some(function (item) { + return item.name === file.name; + }); + }; + + /** + * 扩展文件信息 + * @template {File | FileList} T + * @param {T} obj + * @return {T} + */ + var extendInfo = function (obj) { + var extInfo = function (file) { + //文件扩展名 + file.ext = file.name.substr(file.name.lastIndexOf('.') + 1).toLowerCase(); + // 文件大小 + file.sizes = upload.util.parseSize(file.size); + // 可以继续扩展 + }; + + //FileList对象 + if (obj instanceof FileList) { + Array.from(obj).forEach(function (item) { + extInfo(item); + }); + } else { + extInfo(obj); + } + + return obj; + }; + + /** + * 检查获取文件 + * @param {FileList} files + * @return {Array|FileList} + */ + var getFiles = function (files) { + files = files || []; + if (!files.length) return []; + if (!that.files) return extendInfo(files); + var result = []; + Array.from(files).forEach(function (item) { + if (checkFile(item)) { + result.push(extendInfo(item)); + } + }); + return result; + }; + + // 点击上传容器 + options.elem.off('upload.start').on('upload.start', function () { + var othis = $(this); + + that.config.item = othis; + that.elemFile[0].click(); + }); + + // 拖拽上传 + options.elem + .off('upload.over') + .on('upload.over', function () { + var othis = $(this); + othis.attr('lay-over', ''); + }) + .off('upload.leave') + .on('upload.leave', function () { + var othis = $(this); + othis.removeAttr('lay-over'); + }) + .off('upload.drop') + .on('upload.drop', function (e, param) { + var othis = $(this); + var files = getFiles(param.originalEvent.dataTransfer.files); + + othis.removeAttr('lay-over'); + setChooseFile(files); + + options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传 + }); + + // 文件选择 + that.elemFile.on('change', function () { + var files = getFiles(this.files); + + if (files.length === 0) return; + + setChooseFile(files); + + options.auto ? that.upload() : setChooseText(files); // 是否自动触发上传 + }); + + // 手动触发上传 + options.bindAction.off('upload.action').on('upload.action', function () { + that.upload(); + }); + + // 防止事件重复绑定 + if (options.elem.data(MOD_INDEX)) return; + + // 目标元素 click 事件 + options.elem.on('click', function () { + if (that.isFile()) return; + $(this).trigger('upload.start'); + }); + + // 目标元素 drop 事件 + if (options.drag) { + options.elem + .on('dragover', function (e) { + e.preventDefault(); + $(this).trigger('upload.over'); + }) + .on('dragleave', function () { + $(this).trigger('upload.leave'); + }) + .on('drop', function (e) { + e.preventDefault(); + $(this).trigger('upload.drop', e); + }); + } + + // 手动上传时触发上传的元素 click 事件 + options.bindAction.on('click', function () { + $(this).trigger('upload.action'); + }); + + // 绑定元素索引 + options.elem.data(MOD_INDEX, options.id); +}; + +/** + * 上传组件辅助方法 + */ +upload.util = { + /** + * 文件大小处理 + * @param {number | string} size -文件大小 + * @param {number} [precision] - 数值精度 + * @return {string} + */ + parseSize: function (size, precision) { + precision = precision || 2; + if (null == size || !size) { + return '0'; + } + var unitArr = ['Bytes', 'Kb', 'Mb', 'Gb', 'Tb', 'Pb', 'Eb', 'Zb', 'Yb']; + var index; + var formatSize = typeof size === 'string' ? parseFloat(size) : size; + index = Math.floor(Math.log(formatSize) / Math.log(1024)); + size = formatSize / Math.pow(1024, index); + size = size % 1 === 0 ? size : parseFloat(size.toFixed(precision)); //保留的小数位数 + return size + unitArr[index]; + }, + /** + * 将给定的值转换为一个 JQueryDeferred 对象 + */ + promiseLikeResolve: function (value) { + var deferred = $.Deferred(); + + if (value && typeof value.then === 'function') { + value.then(deferred.resolve, deferred.reject); + } else { + deferred.resolve(value); + } + return deferred.promise(); + }, +}; + +// 记录所有实例 +thisModule.that = {}; // 记录所有实例对象 + +// 获取当前实例对象 +thisModule.getThis = function (id) { + var that = thisModule.that[id]; + if (!that) + log( + id + ? MOD_NAME + " instance with ID '" + id + "' not found" + : 'ID argument required', + ); + return that; +}; + +// 核心入口 +upload.render = function (options) { + var inst = new Class(options); + return thisModule.call(inst); +}; + +export { upload }; diff --git a/src/core/component.js b/src/core/component.js new file mode 100644 index 000000000..59c3efc3f --- /dev/null +++ b/src/core/component.js @@ -0,0 +1,268 @@ +/** + * component + * 组件构建器 + */ + +import { lay } from './lay.js'; +import { $ } from 'jquery'; + +// export +export function component(settings) { + // 默认设置 + settings = $.extend( + true, + { + isDeepReload: false, // 是否默认为深度重载 + }, + settings, + ); + + // 组件名 + var MOD_NAME = settings.name; + var MOD_ID = 'lay-' + MOD_NAME + '-id'; // 用于记录组件实例 id 的属性名 + + // 组件基础对外接口 + var component = { + config: {}, // 全局配置项,一般通过 component.set() 设置 + + // 通用常量集,一般存放固定字符,如类名等 + CONST: $.extend( + true, + { + MOD_NAME: MOD_NAME, + MOD_ID: MOD_ID, + + CLASS_THIS: 'lay-this', + CLASS_SHOW: 'lay-show', + CLASS_HIDE: 'lay-hide', + CLASS_HIDEV: 'lay-hide-v', + CLASS_DISABLED: 'lay-disabled', + CLASS_NONE: 'lay-none', + }, + settings.CONST, + ), + + // 设置全局项 + set: function (options) { + var that = this; + $.extend(true, that.config, options); + return that; + }, + + // 事件 + on: function (events, callback) { + return lay.onevent.call(this, MOD_NAME, events, callback); + }, + }; + + // 操作当前实例 + var instance = function () { + var that = this; + var options = that.config; + var id = options.id; + + // 实例对象 + var inst = { + config: options, + id: id, + index: that.index, + + // 重置实例 + reload: function (options) { + that.reload.call(that, options); + }, + }; + + // 扩展实例对象的回调 + if (typeof settings.extendsInstance === 'function') { + $.extend(true, inst, settings.extendsInstance.call(that)); + } + + // 返回实例对象 + return inst; + }; + + // 构造器 + var Class = function (options) { + var that = this; + that.index = component.index = lay.autoIncrementer(MOD_NAME); + + // 扩展配置项:传入选项 -> 全局选项 -> 默认选项 = 当前选项 + that.config = $.extend(true, {}, that.config, component.config, options); + + // 初始化之前的回调 + if (typeof settings.beforeInit === 'function') { + settings.beforeInit.call(that, that.config); + } + + // 初始化 + that.init(); + }; + + // 默认配置 + Class.prototype.config = settings.config; + + // 重载实例 + Class.prototype.reload = function (options, type) { + var that = this; + that.config = $.extend(settings.isDeepReload, {}, that.config, options); + that.init(true, type); + }; + + // 初始化准备(若由事件触发渲染,则必经此步) + Class.prototype.init = function (rerender, type) { + var that = this; + var options = that.config; + var elem = $(options.elem); + + // 若 elem 非唯一,则拆分为多个实例 + if (elem.length > 1) { + elem.each(function () { + component.render( + $.extend({}, options, { + elem: this, + }), + ); + }); + return that; + } + + // 合并 lay-options 属性上的配置信息 + var layOptions = lay.options(elem[0]); + if (rerender) { + // 若重载渲染,则重载传入的 options 配置优先 + options = that.config = $.extend(layOptions, options); + } else { + $.extend(options, layOptions); // 若首次渲染,则 lay-options 配置优先 + } + + // 若重复执行 render,则视为 reload 处理 + if (!rerender && elem.attr(MOD_ID)) { + var newThat = component.getInst(elem.attr(MOD_ID)); + if (!newThat) return; + return newThat.reload(options, type); + } + + options.elem = $(options.elem); + + // 初始化 id 属性 - 优先取 options.id > 元素 id > 自增索引 + options.id = lay.hasOwn(options, 'id') + ? options.id + : elem.attr('id') || that.index; + + // 记录当前实例对象 + instance.that[options.id] = that; + + // 渲染之前的回调 + if (typeof settings.beforeRender === 'function') { + settings.beforeRender.call(that, options); + } + + // 渲染 + if (typeof that.render === 'function') { + component.cache.id[options.id] = null; // 记录所有实例 id,用于批量操作(如 resize) + elem.attr(MOD_ID, options.id); // 目标元素已渲染过的标记 + that.render(rerender); // 渲染核心 + } + + // 事件 + typeof that.events === 'function' && that.events(); + }; + + // 组件必传项 + Class.prototype.render = settings.render; // 渲染 + Class.prototype.events = settings.events; // 事件 + + /** + * 元素缓存操作 + * @param {string} key - 缓存键 + * @param {*} value - 缓存值 + * @param {boolean} remove - 是否删除缓存 + * @returns {*} - 若 value 未传,则返回缓存值 + */ + Class.prototype.cache = function (key, value, remove) { + var that = this; + var options = that.config; + var elem = options.elem; + var MOD_CACHE_NAME = MOD_ID + '-cache'; + if (!elem) return; + + var cache = elem.data(MOD_CACHE_NAME) || {}; + + // value 未传则获取缓存值 + if (value === undefined) { + return cache[key]; + } + + if (remove) { + delete cache[key]; // 删除缓存 + } else { + cache[key] = value; // 设置缓存 + } + + elem.data(MOD_CACHE_NAME, cache); + }; + + // 清除缓存 + Class.prototype.removeCache = function (key) { + this.cache(key, null, true); + }; + + // 缓存所有实例对象 + instance.that = {}; + + // 获取指定的实例对象 + component.getInst = component.getThis = function (id) { + if (id === undefined) { + throw new Error('ID argument required'); + } + return instance.that[id]; + }; + + // 获取所有实例 + component.getAllInst = function () { + return instance.that; + }; + + // 移除指定的实例对象 + component.removeInst = function (id) { + delete instance.that[id]; + delete component.cache.id[id]; + }; + + // 组件缓存 + component.cache = { + id: {}, + }; + + // 用于扩展原型 + component.Class = Class; + + /** + * 组件完整重载 + * @param {string} id - 实例 id + * @param {Object} options - 配置项 + * @returns + */ + component.reload = function (id, options) { + var that = component.getInst(id); + if (!that) return; + + that.reload(options); + return instance.call(that); + }; + + /** + * 组件渲染 + * @param {Object} options - 配置项 + * @returns + */ + component.render = function (options) { + var inst = new Class(options); + return instance.call(inst); + }; + + return component; +} + +export { component as componentBuilder }; diff --git a/src/core/i18n.js b/src/core/i18n.js new file mode 100644 index 000000000..f8e4215b4 --- /dev/null +++ b/src/core/i18n.js @@ -0,0 +1,377 @@ +/** + * i18n + * 国际化 + */ + +import { lay } from './lay.js'; +import { logOnce } from './logger.js'; + +// 识别预先可能定义的指定全局对象 +var GLOBAL = window.LAYUI_GLOBAL || {}; + +// 简体中文 +var zhCN = { + code: { + copy: '复制代码', + copied: '已复制', + copyError: '复制失败', + maximize: '最大化显示', + restore: '还原显示', + preview: '在新窗口预览', + }, + colorpicker: { + clear: '清除', + confirm: '确定', + }, + dropdown: { + noData: '暂无数据', + }, + flow: { + loadMore: '加载更多', + noMore: '没有更多了', + }, + form: { + select: { + noData: '暂无数据', + noMatch: '无匹配数据', + placeholder: '请选择', + }, + validateMessages: { + required: '必填项不能为空', + phone: '手机号格式不正确', + email: '邮箱格式不正确', + url: '链接格式不正确', + number: '只能填写数字', + date: '日期格式不正确', + identity: '身份证号格式不正确', + }, + verifyErrorPromptTitle: '提示', + }, + laydate: { + months: [ + '1月', + '2月', + '3月', + '4月', + '5月', + '6月', + '7月', + '8月', + '9月', + '10月', + '11月', + '12月', + ], + weeks: ['日', '一', '二', '三', '四', '五', '六'], + time: ['时', '分', '秒'], + literal: { + year: '年', + }, + selectDate: '选择日期', + selectTime: '选择时间', + startTime: '开始时间', + endTime: '结束时间', + tools: { + confirm: '确定', + clear: '清空', + now: '现在', + reset: '重置', + }, + rangeOrderPrompt: '结束时间不能早于开始时间\n请重新选择', + invalidDatePrompt: '不在有效日期或时间范围内\n', + formatErrorPrompt: '日期格式不合法\n必须遵循:\n{format}\n', + autoResetPrompt: '已自动重置', + preview: '当前选中的结果', + }, + layer: { + confirm: '确定', + cancel: '取消', + defaultTitle: '信息', + prompt: { + inputLengthPrompt: '最多输入 {length} 个字符', + }, + photos: { + noData: '没有图片', + tools: { + rotate: '旋转', + scaleX: '水平变换', + zoomIn: '放大', + zoomOut: '缩小', + reset: '还原', + close: '关闭', + }, + viewPicture: '查看原图', + urlError: { + prompt: '当前图片地址异常,\n是否继续查看下一张?', + confirm: '下一张', + cancel: '不看了', + }, + }, + }, + laypage: { + prev: '上一页', + next: '下一页', + first: '首页', + last: '尾页', + total: '共 {total} 条', + pagesize: '条/页', + goto: '到第', + page: '页', + confirm: '确定', + }, + table: { + sort: { + asc: '升序', + desc: '降序', + }, + noData: '暂无数据', + tools: { + filter: { + title: '筛选列', + }, + export: { + title: '导出', + noDataPrompt: '当前表格无数据', + csvText: '导出 CSV 文件', + }, + print: { + title: '打印', + noDataPrompt: '当前表格无数据', + }, + }, + dataFormatError: + '返回的数据不符合规范,正确的成功状态码应为:"{statusName}": {statusCode}', + xhrError: '请求异常,错误提示:{msg}', + }, + transfer: { + noData: '暂无数据', + noMatch: '无匹配数据', + title: ['列表一', '列表二'], + searchPlaceholder: '关键词搜索', + }, + tree: { + defaultNodeName: '未命名', + noData: '暂无数据', + deleteNodePrompt: '确认删除"{name}"节点吗?', + }, + upload: { + fileType: { + file: '文件', + image: '图片', + video: '视频', + audio: '音频', + }, + validateMessages: { + fileExtensionError: '选择的{fileType}中包含不支持的格式', + filesOverLengthLimit: '同时最多只能上传: {length} 个文件', + currentFilesLength: '当前已经选择了: {length} 个文件', + fileOverSizeLimit: '文件大小不能超过 {size}', + }, + chooseText: '{length} 个文件', + }, + utils: { + timeAgo: { + days: '{days} 天前', + hours: '{hours} 小时前', + minutes: '{minutes} 分钟前', + future: '未来', + justNow: '刚刚', + }, + toDateString: { + // https://www.unicode.org/cldr/charts/47/supplemental/day_periods.html + meridiem: function (hours, minutes) { + var hm = hours * 100 + minutes; + if (hm < 500) { + return '凌晨'; + } else if (hm < 800) { + return '早上'; + } else if (hm < 1200) { + return '上午'; + } else if (hm < 1300) { + return '中午'; + } else if (hm < 1900) { + return '下午'; + } + return '晚上'; + }, + }, + }, +}; + +// 默认配置 +var config = lay.extend( + { + locale: 'zh-CN', // 全局内置语言 + messages: { + // 全局国际化消息对象 + 'zh-CN': zhCN, + }, + }, + GLOBAL.i18n, +); // 读取全局预设配置,确保打包后的版本初始调用时机 + +var OBJECT_REPLACE_REGEX = /\{(\w+)\}/g; + +/** + * 获取对象中指定路径的值,类似于 lodash 的 _.get 方法(简易版) + * @param {Record} obj - 要查找的对象 + * @param {string} path - 要查找的路径,支持类似 'a[0].b.c' 的格式 + * @param {any} defaultValue - 若未找到对应值时返回的默认值 + * @returns {any} - 找到的值或默认值 + */ +function get(obj, path, defaultValue) { + // 'a[0].b.c' ==> ['a', '0', 'b', 'c'] + var casePath = path.replace(/\[(\d+)\]/g, '.$1').split('.'); + var result = obj; + + for (var i = 0; i < casePath.length; i++) { + result = result && result[casePath[i]]; + if (result === null || result === undefined) { + return defaultValue; + } + } + + return result; +} + +/** + * 为纯函数创建具有缓存功能的版本,类似于 lodash 的 _.memoize 方法(简易版) + * @template T + * @param {(key: string, ...args) => T} fn - 需要缓存的函数,第一个参数为键 + * @returns {{(key: string, ...args): T, cleanup: () => void}} - 带有缓存的函数 + */ +function memoize(fn) { + /** @type Record */ + var cache = Object.create(null); + + function cachedFn(key) { + var hit = cache[key]; + return hit || (cache[key] = fn.apply(cache, arguments)); + } + + cachedFn.cleanup = function () { + cache = Object.create(null); + }; + return cachedFn; +} + +/** + * 对传入的值进行转义处理 + * 若值为字符串,直接进行转义;若为函数,对函数返回的字符串进行转义;若为数组,对数组中的字符串元素进行转义 + * @param {any} value - 需要进行转义处理的值 + * @returns {any} - 转义后的结果 + */ +function escape(value) { + if (typeof value === 'string') { + value = lay.escape(value); + } else if (typeof value === 'function') { + var origFn = value; + value = function () { + var val = origFn.apply(this, arguments); + return typeof val === 'string' ? lay.escape(val) : val; + }; + } else if (lay.type(value) === 'array') { + value = value.map(function (v) { + return typeof v === 'string' ? lay.escape(v) : v; + }); + } + + return value; +} + +function isDef(value) { + return value !== null && value !== undefined; +} + +var resolveValue = memoize(function (path, obj, defaultValue) { + var pathParts = path.split(':'); + var locale = pathParts[0]; + + path = pathParts[1]; + + var value = get(obj, path, defaultValue); + + if (config.debug) { + var isFallback = defaultValue === value || value === path; + var isNotFound = !isDef(value) || isFallback; + if (isNotFound) { + logOnce( + "Not found '" + path + "' key in '" + locale + "' locale messages.", + 'warn', + ); + } + if (isFallback) { + logOnce("Fallback to default message for key: '" + path + "'", 'warn'); + } + } + + return isDef(value) ? value : path; +}); + +var i18n = { + config: config, + set: function (options) { + lay.extend(config, options); + resolveValue.cleanup(); + }, +}; + +/** + * 根据给定的键从国际化消息中获取翻译后的内容 + * 未文档化的私有方法,仅限内部使用 + * + * @internal + * @param {string} keypath 要翻译的键路径 + * @param {Record | any[]} [parameters] 可选的占位符替换参数: + * - 对象形式:用于替换 `{key}` 形式的占位符; + * - 数组形式:用于替换 `{0}`, `{1}` 等占位符; + * @param {{locale: string, default: string}} [options] 翻译选项 + * @returns {string} 翻译后的文本 + * + * @example 使用对象替换命名占位符 + * message: { + * hello: '{msg} world' + * } + * i18n.$t('message.hello', { msg: 'Hello' }) + * + * @example 使用数组替换索引占位符 + * message: { + * hello: '{0} world' + * } + * i18n.$t('message.hello', ['Hello']) + */ +i18n.translate = function (keypath, parameters, options) { + var locale = (options && options.locale) || config.locale; + var i18nMessages = config.messages[locale]; + var namespace = locale + ':'; + var hasDefault = options && lay.hasOwn(options, 'default'); + var fallbackMessage = hasDefault ? options.default : undefined; + + if (!i18nMessages && !hasDefault) { + logOnce( + "Locale '" + + locale + + "' not found. Please add i18n messages for this locale first.", + 'warn', + ); + } + + var result = resolveValue(namespace + keypath, i18nMessages, fallbackMessage); + + // 替换占位符 + if (typeof result === 'string' && parameters) { + // 第二个参数为对象或数组,替换占位符 {key} 或 {0}, {1}... + result = result.replace(OBJECT_REPLACE_REGEX, function (match, key) { + return parameters[key] !== undefined ? parameters[key] : match; + }); + } + + return escape(result); +}; + +/** + * i18n.translate 的别名,用于简化代码书写,未文档化仅限内部使用 + */ +i18n.$t = i18n.translate; + +export { i18n }; diff --git a/src/core/lay.js b/src/core/lay.js new file mode 100644 index 000000000..02399b44c --- /dev/null +++ b/src/core/lay.js @@ -0,0 +1,1535 @@ +/** + * lay + * 基础模块 + */ + +import { log } from './logger.js'; + +const { document } = window; +const lay = Object.create(null); +const version = '__VERSION__'; + +const fnToString = Function.prototype.toString; +const ObjectFunctionString = fnToString.call(Object); +const hasOwnProperty = Object.prototype.hasOwnProperty; + +/** + * 使用入口 + * + * 保留 `layui.use` 作为「开始使用」的语义,用于确保组件实例化的执行时序。 + * 但当前不再承载模块加载或依赖解析的职责,模块体系已全面迁移至 ES Modules。 + * 我们希望它依然是一个具有高辨别度的门户、一个具有特殊意蕴的连接。 + * + * @param {Function} callback - DOM 就绪后执行的回调函数 + */ +const use = (lay.use = (callback) => { + if (document.readyState === 'loading') { + document.addEventListener( + 'DOMContentLoaded', + () => { + queueMicrotask(callback); + }, + { once: true }, + ); + } else { + queueMicrotask(callback); + } +}); + +/** + * 将一个或多个对象合并到目标对象中 + * 对象类型值始终进行「深拷贝」合并。若需浅拷贝合并,请使用 Object.assign() + * @param {*} target - 目标对象 + * @param {...*} objectN - 一个或多个包含要应用的属性的源对象 + * @param {Function} customizer - 可选的自定义合并函数 + * @returns {*} 返回合并后的对象 + * @example + *```js + * console.log(lay.extend({}, {a:1})); // expected: {a:1} + * console.log(lay.extend({a:1}, {a:3}, {a:5,b:5})); // expected: {a:5,b:5} + * // 多个相同源对象的不同合并方式 + * const objN = [ + * { + * a: [1, 3], + * b: {ba: 1} + * }, + * { + * a: [5], + * b: {bb: 2} + * }, + * { + * b: {ba: 3}, + * c: 3 + * } + * ]; + * console.log(lay.extend({}, ...objN)); // expected: {a:[5,3],b:{ba:3,bb:2},c:3} + * // 使用 customizer 实现数组覆盖而非合并 + * const obj1 = lay.extend({}, ...objN, function(objValue, srcValue) { + * if (Array.isArray(objValue) && Array.isArray(srcValue)) { + * return srcValue; + * } + * }); + * console.log(obj1); // expected: {a:[5],b:{ba:3,bb:2},c:3} + * // 使用 customizer 实现特定字段跳过合并 + * const obj2 = lay.extend({}, ...objN, function(objValue, srcValue, key, target, source) { + * if (key === 'b') { + * return objValue; + * } + * }); + * console.log(obj2); // expected: {a:[5,3],b:{ba:1},c:3} + * ``` + */ +lay.extend = function () { + var args = [].slice.call(arguments); + + // 最后一个参数是否为 customizer + var customizer = + typeof args[args.length - 1] === 'function' ? args.pop() : false; + + // 深拷贝合并 + return args.reduce(function (target, source) { + // 确保 target 始终是一个对象 + if (typeof target !== 'object' || target === null) { + target = {}; + } + + for (var key in source) { + if (!hasOwnProperty.call(source, key)) continue; // 仅处理自有属性 + + var targetValue = target[key]; + var sourceValue = source[key]; + + // 自定义合并逻辑(如数组覆盖、特定字段跳过等) + if (customizer) { + var customResult = customizer( + targetValue, + sourceValue, + key, + target, + source, + ); + if (customResult !== undefined) { + target[key] = customResult; + continue; + } + } + + // 默认深拷贝逻辑 + if (Array.isArray(sourceValue)) { + targetValue = Array.isArray(targetValue) ? targetValue : []; + } else if (lay.isPlainObject(sourceValue)) { + targetValue = lay.isPlainObject(targetValue) ? targetValue : {}; + } + target[key] = + lay.isPlainObject(sourceValue) || Array.isArray(sourceValue) + ? lay.extend(targetValue, sourceValue, customizer) + : sourceValue; + } + + return target; + }); +}; + +/** + * 判断是否为纯对象 + * @param {*} obj - 要检查的对象 + * @returns {boolean} + */ +lay.isPlainObject = function (obj) { + if ( + obj === null || + typeof obj !== 'object' || + Object.prototype.toString.call(obj) !== '[object Object]' + ) { + return false; + } + + var proto = Object.getPrototypeOf(obj); + + // Object.create(null) 创建的对象 + if (proto === null) { + return true; + } + + // 判定具有原型且由全局 Object 构造函数创建的对象为纯对象(来自 jQuery 方案) + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return ( + typeof Ctor === 'function' && fnToString.call(Ctor) === ObjectFunctionString + ); +}; + +/** + * typeof 类型细分 -> string/number/boolean/undefined/null、object/array/function/… + * @param {*} operand - 任意值 + * @returns {string} + */ +lay.type = function (operand) { + if (operand === null) return String(operand); + + // 细分引用类型 + return typeof operand === 'object' || typeof operand === 'function' + ? (function () { + var type = + Object.prototype.toString.call(operand).match(/\s(.+)\]$/) || []; // 匹配类型字符 + var classType = 'Function|Array|Date|RegExp|Object|Error|Symbol'; // 常见类型字符 + + type = type[1] || 'Object'; + + // 除匹配到的类型外,其他对象均返回 object + return new RegExp('\\b(' + classType + ')\\b').test(type) + ? type.toLowerCase() + : 'object'; + })() + : typeof operand; +}; + +/** + * 对象是否具备「类数组」结构(此处为兼容 jQuery 对象) + * @param {Object} obj - 任意对象 + * @returns {boolean} + */ +lay.isArray = function (obj) { + var len; + var type = lay.type(obj); + + if (!obj || typeof obj !== 'object' || obj === window) return false; + + len = 'length' in obj && obj.length; + return ( + type === 'array' || + len === 0 || + (typeof len === 'number' && len > 0 && len - 1 in obj) // 兼容 jQuery 对象 + ); +}; + +/** + * 本地存储 + * @param {string} table - 表名 + * @param {Object} settings - 设置项 + * @param {Storage} storage - 存储对象,localStorage | sessionStorage + * @returns {Object} + */ +lay.storage = function (table = 'LAY', settings, storage) { + storage = storage || localStorage; + + // 如果 settings 为 null,则删除表 + if (settings === null) { + return delete storage[table]; + } + + settings = typeof settings === 'object' ? settings : { key: settings }; + + var data; + + try { + data = JSON.parse(storage[table]); + } catch { + data = {}; + } + + if ('value' in settings) { + data[settings.key] = settings.value; + } + if (settings.remove) { + delete data[settings.key]; + } + + storage[table] = JSON.stringify(data); + + return settings.key ? data[settings.key] : data; +}; + +/** + * 本地会话存储 + * @param {string} table - 表名 + * @param {Object} settings - 设置项 + * @returns {Object} + */ +lay.sessionStorage = function (table, settings) { + return lay.storage(table, settings, sessionStorage); +}; + +/** + * 设备信息 + * @param {string} key - 任意 key + * @returns {Object} + */ +lay.device = function (key) { + var agent = navigator.userAgent.toLowerCase(); + + // 获取版本号 + var getVersion = function (label) { + var exp = new RegExp(label + '/([^\\s\\_\\-]+)'); + label = (agent.match(exp) || [])[1]; + return label || false; + }; + + // 返回结果集 + var result = { + os: (function () { + // 底层操作系统 + if (/windows/.test(agent)) { + return 'windows'; + } else if (/linux/.test(agent)) { + return 'linux'; + } else if (/iphone|ipod|ipad|ios/.test(agent)) { + return 'ios'; + } else if (/mac/.test(agent)) { + return 'mac'; + } + })(), + weixin: getVersion('micromessenger'), // 是否微信 + }; + + // 任意的 key + if (key && !result[key]) { + result[key] = getVersion(key); + } + + // 移动设备 + result.android = /android/.test(agent); + result.ios = result.os === 'ios'; + result.mobile = result.android || result.ios; + + return result; +}; + +/** + * IE 版本 + * @type {string | boolean} - 如果是 IE 返回版本字符串,否则返回 false + */ +lay.ie = (function () { + var agent = navigator.userAgent.toLowerCase(); + return !!window.ActiveXObject || 'ActiveXObject' in window + ? (agent.match(/msie\s(\d+)/) || [])[1] || '11' // 由于 ie11 并没有 msie 的标识 + : false; +})(); + +/** + * 将数组中的成员对象按照某个 key 的 value 值进行排序 + * @param {Object[]} arr - 任意数组 + * @param {string} key - 任意 key + * @param {boolean} desc - 是否降序 + * @param {boolean} notClone - 是否不对 arr 进行克隆 + * @returns {Object[]} + */ +lay.sort = function (arr, key, desc, notClone) { + var clone = notClone ? arr || [] : JSON.parse(JSON.stringify(arr || [])); + + // 若未传入 key,则直接返回原对象 + if (lay.type(arr) === 'object' && !key) { + return clone; + } else if (typeof arr !== 'object') { + // 若 arr 非对象 + return [clone]; + } + + // 开始排序 + clone.sort(function (o1, o2) { + var v1 = o1[key]; + var v2 = o2[key]; + + /* + * 特殊数据 + * 若比较的成员均非对象 + */ + + // 若比较的成员均为数字 + if (!isNaN(o1) && !isNaN(o2)) return o1 - o2; + + // 若比较的成员只存在某一个非对象 + if (!isNaN(o1) && isNaN(o2)) { + if (key && typeof o2 === 'object') { + v1 = o1; + } else { + return -1; + } + } else if (isNaN(o1) && !isNaN(o2)) { + if (key && typeof o1 === 'object') { + v2 = o2; + } else { + return 1; + } + } + + /* + * 正常数据 + * 即成员均为对象,也传入了对比依据: key + * 若 value 为数字,按「大小」排序;若 value 非数字,则按「字典序」排序 + */ + + // value 是否为数字 + var isNum = [!isNaN(v1), !isNaN(v2)]; + + // 若为数字比较 + if (isNum[0] && isNum[1]) { + if (v1 && !v2 && v2 !== 0) { + // 数字 vs 空 + return 1; + } else if (!v1 && v1 !== 0 && v2) { + // 空 vs 数字 + return -1; + } else { + // 数字 vs 数字 + return v1 - v2; + } + } + + /** + * 字典序排序 + */ + + // 若为非数字比较 + if (!isNum[0] && !isNum[1]) { + // 字典序比较 + if (v1 > v2) { + return 1; + } else if (v1 < v2) { + return -1; + } else { + return 0; + } + } + + // 若为混合比较 + if (isNum[0] || !isNum[1]) { + // 数字 vs 非数字 + return -1; + } else if (!isNum[0] || isNum[1]) { + // 非数字 vs 数字 + return 1; + } + }); + + desc && clone.reverse(); // 倒序 + return clone; +}; + +// 移除事件的特殊标识 +var EV_REMOVE = 'LAY-EVENT-REMOVE'; + +// 事件缓存集 +lay.events = {}; + +/** + * 自定义模块事件 + * @param {string} modName - 模块名 + * @param {string} events - 事件名 + * @param {Function} callback - 回调 + * @returns {Object} + */ +lay.onevent = function (modName, events, callback) { + if (typeof modName !== 'string' || typeof callback !== 'function') { + return this; + } + return lay.event(modName, events, null, callback); +}; + +/** + * 执行自定义模块事件 + * @param {string} modName - 模块名 + * @param {string} events - 事件名 + * @param {Object} params - 参数 + * @param {Function} fn - 回调 + */ +lay.event = function (modName, events, params, fn) { + var result = null; + var filter = (events || '').match(/\((.*)\)$/) || []; // 提取事件过滤器字符结构,如:select(xxx) + var eventName = (modName + '.' + events).replace(filter[0], ''); // 获取事件名称,如:form.select + var filterName = filter[1] || ''; // 获取过滤器名称, 如:xxx + var callback = (item) => { + var res = item && item.call(this, params); + res === false && result === null && (result = false); + }; + + // 如果参数传入特定字符,则执行移除事件 + if (params === EV_REMOVE) { + delete (lay.events[eventName] || {})[filterName]; + return lay; + } + + // 添加事件 + if (fn) { + lay.events[eventName] = lay.events[eventName] || {}; + + if (filterName) { + // 带 filter 不支持重复事件 + lay.events[eventName][filterName] = [fn]; + } else { + // 不带 filter 处理的是所有的同类事件,应该支持重复事件 + lay.events[eventName][filterName] = + lay.events[eventName][filterName] || []; + lay.events[eventName][filterName].push(fn); + } + return this; + } + + // 执行事件回调 + const eventHandlers = lay.events[eventName]; + for (const key in eventHandlers) { + const item = eventHandlers[key]; + + // 执行当前模块的全部事件 + if (filterName === '{*}') { + item.forEach(callback); + continue; + } + + // 执行指定事件 + key === '' && item.forEach(callback); + filterName && key === filterName && item.forEach(callback); + } + + return result; +}; + +/** + * 新增模块事件 + * @param {string} events - 事件名 + * @param {string} modName - 模块名 + * @param {Function} callback - 回调 + * @returns {Object} + */ +lay.on = function (events, modName, callback) { + return lay.onevent(modName, events, callback); +}; + +/** + * 移除模块事件 + * @param {string} events - 事件名 + * @param {string} modName - 模块名 + * @returns {Object} + */ +lay.off = function (events, modName) { + return lay.event(modName, events, EV_REMOVE); +}; + +/** + * 防抖 + * @param {Function} func - 回调 + * @param {number} wait - 延时执行的毫秒数 + * @returns {Function} + */ +lay.debounce = function (func, wait) { + var timeout; + return function () { + var context = this; + var args = arguments; + clearTimeout(timeout); + timeout = setTimeout(function () { + func.apply(context, args); + }, wait); + }; +}; + +/** + * 节流 + * @param {Function} func - 回调 + * @param {number} wait - 不重复执行的毫秒数 + */ +lay.throttle = function (func, wait) { + var cooldown = false; + return function () { + var context = this; + var args = arguments; + if (!cooldown) { + func.apply(context, args); + cooldown = true; + setTimeout(function () { + cooldown = false; + }, wait); + } + }; +}; + +/** + * 数字前置补零 + * @param {number | string} num - 原始数字 + * @param {number} [length=2] - 数字长度,如果原始数字长度小于 length,则前面补零 + * @returns {string} 返回补 0 后的数字 + * @example + * ```js + * lay.digit(6, 2); // "06" + * lay.digit('7', 3); // "007" + * ``` + */ +lay.digit = function (num, length) { + if (!(typeof num === 'string' || typeof num === 'number')) return ''; + + var str = ''; + num = String(num); + length = length || 2; + for (var i = num.length; i < length; i++) { + str += '0'; + } + return num < Math.pow(10, length) ? str + num : num; +}; + +/** + * 获取单个 DOM 元素 + * @param {string | HTMLElement | JQuery} elem - 目标元素或选择器 + * @returns {HTMLElement | null} + */ +var getElement = function (elem) { + if (!elem) return null; + if (typeof elem === 'string') { + return document.querySelector(elem); + } + if (elem.jquery || typeof elem.length === 'number') { + return elem[0] || null; + } + return elem; +}; + +/** + * 创建元素 + * @param {string} elemName - 元素的标签名 + * @param {Object.} [attr] - 添加到元素上的属性 + * @returns {HTMLElement} 返回创建的 HTML 元素 + * @example + * ```js + * lay.elem('div', {id: 'test'}) //
                                    + * ``` + */ +lay.elem = function (elemName, attr) { + var elem = document.createElement(elemName); + + for (const [key, value] of Object.entries(attr || {})) { + elem.setAttribute(key, value); + } + + return elem; +}; + +/** + * 当前页面是否存在滚动条 + * @returns {boolean} 是否存在滚动条 + * @example + * ``` + * lay.hasScrollbar() // true 或 false + * ``` + */ +lay.hasScrollbar = function () { + return ( + document.body.scrollHeight > + (window.innerHeight || document.documentElement.clientHeight) + ); +}; + +/** + * 自动递增器,一般用于组件自增索引 + */ +lay.autoIncrementer = function (key, opts = {}) { + const { target = document.body } = opts; + const name = '_LAY_AUTOINCREMENTER_ID_'; + const incrementer = (target[name] = target[name] || {}); + + incrementer[key] = incrementer[key] || 0; + return ++incrementer[key]; +}; + +/** + * 获取节点的 style 属性值 + * @param {HTMLElement} node - 节点 + * @param {string} name - 属性名 + * @returns 属性值 + */ +lay.getStyle = function (node, name) { + var style = window.getComputedStyle(node, null); + return style.getPropertyValue(name); +}; + +/** + * 获取 style rules + * @param {HTMLStyleElement} style - HTMLStyle 元素 + * @param {(ruleItem: CSSStyleRule, index: number) => boolean} [callback] - 用来返回 style 元素中的每个 `style rule` 的函数,返回 true 终止遍历 + * @returns {CSSRuleList} 返回 `style rules` + * @example + * ``` + * + * + * lay.getStyleRules($('#test')[0], function(rule, index){ + * if(rule.selectorText === '.lay-card'){ + * console.log(index, rule.cssText) // 0 '.lay-card{color: #000}' + * rule.style.color = '#EEE'; + * return true; // 终止遍历 + * } + * }) // RuleList + * ``` + */ +lay.getStyleRules = function (style, callback) { + if (!style) return; + + var sheet = style.sheet || {}; + var rules = sheet.cssRules || []; + + if (typeof callback === 'function') { + for (const [index, item] of Array.from(rules).entries()) { + if (callback(item, index)) { + break; + } + } + } + + return rules; +}; + +/** + * 创建 style 样式 + * @param {Object} options - 可配置的选项 + * @param {string | HTMLElement | JQuery} [options.target] - 目标容器,指定后会将样式追加到目标容器 + * @param {string} [options.id] - 样式元素的 id,默认自增 + * @param {string} options.text - 样式内容 + * @returns {HTMLStyleElement} 返回创建的样式元素 + * @example + * ```html + *
                                    + * + * + *
                                    + * + * lay.style({ + * target: '#targetEl', + * text: '.card{color: #000}' + * }) // + * ``` + */ +lay.style = function (options) { + options = options || {}; + + var style = lay.elem('style'); + var styleText = options.text || ''; + var target = options.target; + + if (!styleText) return; + + // 添加样式 + style.innerHTML = styleText; + + // ID + style.id = + 'LAY-STYLE-' + + (options.id || + (function (index) { + lay.style.index = ++index; + return 'DF-' + index; + })(lay.style.index || 0)); + + // 是否向目标容器中追加 style 元素 + if (target) { + var targetElem = getElement(target); + if (!targetElem) return style; + + var styleElem = targetElem.querySelector('#' + style.id); + styleElem?.remove(); + targetElem.appendChild(style); + } + + return style; +}; + +/** + * 将元素定位到指定目标元素附近 + * @param {HTMLElement} target - 目标元素 + * @param {HTMLElement} elem - 定位元素 + * @param {Object} [opts] - 可配置的选项 + * @param {'absolute' | 'fixed'} [opts.position] - 元素的定位类型 + * @param {'left' | 'right'} [opts.clickType="left"] - 点击类型,默认为 'left',如果 {@link target} 是 document 或 body 元素,则为 'right' + * @param {'left' | 'right' | 'center'} [opts.align="left"] - 对齐方式 + * @param {boolean} [opts.allowBottomOut=false] - 顶部没有足够区域显示时,是否允许底部溢出 + * @param {string | number} [opts.margin=5] - 边距 + * @param {Event} [opts.e] - 事件对象,仅右键生效 + * @param {boolean} [opts.SYSTEM_RELOAD] - 是否重载,用于出现滚动条时重新计算位置 + * @param {[offsetX:number, offsetY:number]} [opts.offset] - 相对于触发元素的额外偏移量[x,y] + * @example + * ```js + * + * + * + * // 下拉菜单将被定位到按钮附近 + * lay.position( + * $('#targetEl')[0], + * $('#contentEl')[0], + * { + * position: 'fixed', + * align: 'center' + * } + * ) + * ``` + */ +lay.position = function (target, elem, opts) { + if (!elem) return; + opts = opts || {}; + + // 如果绑定的是 document 或 body 元素,则直接获取鼠标坐标 + if (target === document || target === document.body) { + opts.clickType = 'right'; + } + + // 绑定绑定元素的坐标 + var rect = + opts.clickType === 'right' + ? (function () { + var e = opts.e || window.event || {}; + return { + left: e.clientX, + top: e.clientY, + right: e.clientX, + bottom: e.clientY, + }; + })() + : target.getBoundingClientRect(); + var elemWidth = elem.offsetWidth; // 控件的宽度 + var elemHeight = elem.offsetHeight; // 控件的高度 + + // 滚动条高度 + var scrollArea = function (type) { + type = type ? 'scrollLeft' : 'scrollTop'; + return document.body[type] | document.documentElement[type]; + }; + + // 窗口宽高 + var winArea = function (type) { + return document.documentElement[type ? 'clientWidth' : 'clientHeight']; + }; + var margin = 'margin' in opts ? opts.margin : 5; + var left = rect.left; + var top = rect.bottom; + + // 相对元素居中 + if (opts.align === 'center') { + left = left - (elemWidth - target.offsetWidth) / 2; + } else if (opts.align === 'right') { + left = left - elemWidth + target.offsetWidth; + } + + // 判断右侧是否超出边界 + if (left + elemWidth + margin > winArea('width')) { + left = winArea('width') - elemWidth - margin; // 如果超出右侧,则将面板向右靠齐 + } + // 左侧是否超出边界 + if (left < margin) left = margin; + + // 判断底部和顶部是否超出边界 + if (rect.bottom + elemHeight + margin > winArea()) { + // 底部超出边界 + // 优先判断顶部是否有足够区域显示完全,且底部不能超出边界 + if (rect.top > elemHeight + margin && rect.top <= winArea()) { + top = rect.top - elemHeight - margin * 2; // 顶部有足够的区域显示 + } else if (!opts.allowBottomOut) { + // 顶部没有足够区域显示时,是否允许底部溢出 + top = winArea() - elemHeight - margin * 2; // 面板向底部靠齐 + if (top < 0) top = 0; // 如果面板底部靠齐时,又溢出窗口顶部,则只能将顶部靠齐 + } + } + /* + if(top + elemHeight + margin > winArea()){ + // 优先顶部是否有足够区域显示完全 + if(rect.top > elemHeight + margin){ + top = rect.top - elemHeight - margin*2; // 顶部有足够的区域显示 + } else { + // 如果面板是鼠标右键弹出,且顶部没有足够区域显示,则将面板向底部靠齐 + if(obj.clickType === 'right'){ + top = winArea() - elemHeight - margin*2; + if(top < 0) top = 0; // 不能溢出窗口顶部 + } else { + top = margin; // 位置计算逻辑完备性处理 + } + } + } + */ + + // 定位类型 + var position = opts.position; + if (position) elem.style.position = position; + var offsetX = opts.offset ? opts.offset[0] : 0; + var offsetY = opts.offset ? opts.offset[1] : 0; + + // 设置坐标 + elem.style.left = + left + (position === 'fixed' ? 0 : scrollArea(1)) + offsetX + 'px'; + elem.style.top = + top + (position === 'fixed' ? 0 : scrollArea()) + offsetY + 'px'; + + // 防止页面无滚动条时,又因为弹出面板而出现滚动条导致的坐标计算偏差 + if (!lay.hasScrollbar()) { + var rect1 = elem.getBoundingClientRect(); + // 如果弹出面板的溢出窗口底部,则表示将出现滚动条,此时需要重新计算坐标 + if (!opts.SYSTEM_RELOAD && rect1.bottom + margin > winArea()) { + opts.SYSTEM_RELOAD = true; + setTimeout(function () { + lay.position(target, elem, opts); + }, 50); + } + } +}; + +/** + * 获取元素上的属性配置项 + * @param {string | HTMLElement | JQuery} elem - HTML 元素 + * @param {{attr: string} | string} [opts="lay-options"] - 可配置的选项,string 类型指定属性名 + * @returns {Object.} 返回元素上的属性配置项 + * @example + * ```js + *
                                    + * + * var elem = $('#testEl') + * lay.options(elem) // {color:red} + * lay.options(elem[0]) // {color:red} + * lay.options('#testEl') // {color:red} + * lay.options('#testEl', {attr: 'lay-toc'}) // {hot: true} + * lay.options('#testEl', 'lay-toc') // {hot: true} + * + * $('#testEl').attr('lay-toc') // '{hot: true}' + * ``` + */ +lay.options = function (elem, opts) { + opts = typeof opts === 'object' ? opts : { attr: opts }; + + if (elem === document) return {}; + + var attrName = opts.attr || 'lay-options'; + var targetElem = getElement(elem); + var attrValue = targetElem ? targetElem.getAttribute(attrName) : null; + + try { + /** + * 请注意: 开发者在使用 lay-options="{}" 配置组件选项时,需确保属性值不来自于网页用户, + * 即属性值必须在网页开发者自身的可控范围内,否则请勿在 HTML 标签属性中获取组件选项。 + */ + return new Function('return ' + (attrValue || '{}'))(); + } catch (ev) { + log( + opts.errorText || + [attrName + '="' + attrValue + '"', '\n parseerror: ' + ev].join('\n'), + 'error', + ); + return {}; + } +}; + +/** + * 元素是否属于顶级元素(document 或 body) + * @param {HTMLElement} elem - HTML 元素 + * @returns {boolean} 是否属于顶级元素 + * @example + * ```js + * lay.isTopElem(document) // true + * ``` + */ +lay.isTopElem = function (elem) { + const topElems = [document, document.body]; + let matched = false; + + for (const item of topElems) { + if (item === elem) { + matched = true; + break; + } + } + + return matched; +}; + +// 剪切板 +lay.clipboard = { + /** + * 写入文本 + * @param {Object} options - 可配置的选项 + * @param {string} options.text - 写入剪贴板的文本 + * @param {() => void} [options.done] - 写入成功/完成回调 + * @param {(err?: any) => void} [options.error] - 写入失败回调 + * @example + * ```js + * lay.clipboard.writeText({ + * text: '测试文本', + * done: function(){ layer.msg('copied')}, + * error: function(){ layer.msg('error')} + * }) + * ``` + */ + writeText: function (options) { + var text = String(options.text); + + if (navigator && 'clipboard' in navigator) { + navigator.clipboard.writeText(text).then(options.done, function () { + legacyCopy(); + }); + } else { + legacyCopy(); + } + + function legacyCopy() { + var elem = document.createElement('textarea'); + + elem.value = text; + elem.style.position = 'fixed'; + elem.style.opacity = '0'; + elem.style.top = '0px'; + elem.style.left = '0px'; + + document.body.appendChild(elem); + elem.select(); + + try { + document.execCommand('copy'); + typeof options.done === 'function' && options.done(); + } catch (err) { + typeof options.error === 'function' && options.error(err); + } finally { + elem.remove ? elem.remove() : document.body.removeChild(elem); + } + } + }, +}; + +/** + * 检测是否支持 Passive Event Listeners + * 引用自 https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md + * @type {boolean} + */ +lay.passiveSupported = (function () { + var passiveSupported = false; + try { + var opts = Object.defineProperty({}, 'passive', { + get: function () { + passiveSupported = true; + return passiveSupported; + }, + }); + window.addEventListener('test', null, opts); + window.removeEventListener('test', null, opts); + } catch { + // ignore + } + return passiveSupported; +})(); + +/** + * 是否支持 touch 事件 + */ +lay.touchEventsSupported = function () { + return 'ontouchstart' in window; +}; + +/** + * @typedef touchSwipeState + * @prop {{x: number,y: number}} pointerStart - 初始坐标 + * @prop {{x: number,y: number}} pointerEnd - 结束坐标 + * @prop {number} distanceX - X 轴移动距离 + * @prop {number} distanceY - Y 轴移动距离 + * @prop {'none'|'right'|'left'|'up'|'down'} direction - 滑动方向 + * @prop {Date} timeStart 开始时间 + */ +/** + * @callback touchSwipeCallback + * @param {TouchEvent} e 滑动事件 + * @param {touchSwipeState} state 滑动相关的状态 + */ +/** + * 基于 touch 事件的触摸滑动 + * @param {string | HTMLElement | JQuery} elem - HTML 元素 + * @param {{onTouchStart?: touchSwipeCallback; onTouchMove?: touchSwipeCallback; onTouchEnd?: touchSwipeCallback; preventDefault?: boolean}} opts - 配置项 + */ +lay.touchSwipe = function (elem, opts) { + var options = opts; + var targetElem = getElement(elem); + var preventDefault = + 'preventDefault' in options ? options.preventDefault : true; + + if (!targetElem || !lay.touchEventsSupported()) return; + + var state = { + pointerStart: { x: 0, y: 0 }, + pointerEnd: { x: 0, y: 0 }, + distanceX: 0, + distanceY: 0, + direction: 'none', // 'up','down','left','right','none + timeStart: null, + }; + + var onStart = function (e) { + if (e.touches.length !== 1) return; + bindEvents(); + // 重置状态 + state.timeStart = Date.now(); + state.pointerStart.x = state.pointerEnd.x = e.touches[0].clientX; + state.pointerStart.y = state.pointerEnd.y = e.touches[0].clientY; + state.distanceX = state.distanceY = 0; + state.direction = 'none'; + + options.onTouchStart && options.onTouchStart(e, state); + }; + + var onMove = function (e) { + if (preventDefault) { + e.preventDefault(); + } + state.pointerEnd.x = e.touches[0].clientX; + state.pointerEnd.y = e.touches[0].clientY; + state.distanceX = state.pointerStart.x - state.pointerEnd.x; + state.distanceY = state.pointerStart.y - state.pointerEnd.y; + if (Math.abs(state.distanceX) > Math.abs(state.distanceY)) { + state.direction = state.distanceX > 0 ? 'left' : 'right'; + } else { + state.direction = state.distanceY > 0 ? 'up' : 'down'; + } + options.onTouchMove && options.onTouchMove(e, state); + }; + + var onEnd = function (e) { + options.onTouchEnd && options.onTouchEnd(e, state); + unbindEvents(); + }; + + var bindEvents = function () { + targetElem.addEventListener( + 'touchmove', + onMove, + lay.passiveSupported ? { passive: false } : false, + ); + targetElem.addEventListener('touchend', onEnd); + targetElem.addEventListener('touchcancel', onEnd); + }; + + var unbindEvents = function () { + targetElem.removeEventListener('touchmove', onMove); + targetElem.removeEventListener( + 'touchend', + onEnd, + lay.passiveSupported ? { passive: false } : false, + ); + targetElem.removeEventListener('touchcancel', onEnd); + }; + + // 防止事件重复绑定 + if (targetElem.__lay_touchswipe_cb_) { + targetElem.removeEventListener( + 'touchstart', + targetElem.__lay_touchswipe_cb_, + ); + } + targetElem.__lay_touchswipe_cb_ = onStart; + targetElem.addEventListener('touchstart', onStart); +}; + +/** @type {(elem: Element|Document|Window,eventName: string,fn:EventListenerOrEventListenerObject,options: boolean | AddEventListenerOptions) => any}*/ +lay.addEvent = function (elem, eventName, fn, options) { + elem.addEventListener(eventName, fn, options); +}; + +/** @type {(elem: Element|Document|Window,eventName: string,fn:EventListenerOrEventListenerObject,options: boolean | EventListenerOptions) => any}*/ +lay.removeEvent = function (elem, eventName, fn, options) { + elem.removeEventListener(eventName, fn, options); +}; + +/** + * 绑定指定元素外部的点击事件 + * @param {HTMLElement} target - 响应事件的元素 + * @param {(e: Event) => void} handler - 事件触发时执行的函数 + * @param {object} [options] - 选项 + * @param {string} [options.event="pointerdown"] - 事件类型 + * @param {HTMLElement | Window} [options.scope=document] - 事件范围 + * @param {Array} [options.ignore] - 忽略触发事件的元素或选择器字符串 + * @param {boolean} [options.capture=true] - 对内部事件 listener 使用捕获阶段 + * @param {boolean} [options.detectIframe] - 是否检测 iframe + * @returns {() => void} - 返回一个停止事件响应的函数 + */ +lay.onClickOutside = function (target, handler, options) { + options = options || {}; + var eventType = + options.event || ('onpointerdown' in window ? 'pointerdown' : 'mousedown'); + var scopeTarget = options.scope || document; + var ignore = options.ignore || []; + var useCapture = 'capture' in options ? options.capture : true; + var detectIframe = options.detectIframe; + + var listener = function (event) { + var el = target; + var eventTarget = event.target; + var eventPath = getEventPath(event); + + if (!el || el === eventTarget || eventPath.indexOf(el) !== -1) { + return; + } + if (shouldIgnore(event, eventPath)) { + return; + } + + handler(event); + }; + + function shouldIgnore(event, eventPath) { + var eventTarget = event.target; + for (var i = 0; i < ignore.length; i++) { + var target = ignore[i]; + if (typeof target === 'string') { + var targetElements = document.querySelectorAll(target); + for (var j = 0; j < targetElements.length; j++) { + var targetEl = targetElements[j]; + if (targetEl === eventTarget || eventPath.indexOf(targetEl) !== -1) { + return true; + } + } + } else { + if ( + target && + (target === eventTarget || eventPath.indexOf(target) !== -1) + ) { + return true; + } + } + } + } + + function getEventPath(event) { + var path = (event.composedPath && event.composedPath()) || event.path; + var eventTarget = event.target; + + if (path !== null && path !== undefined) { + return path; + } + + function getParents(node, memo) { + memo = memo || []; + var parentNode = node.parentNode; + + return parentNode + ? getParents(parentNode, memo.concat([parentNode])) + : memo; + } + + return [eventTarget].concat(getParents(eventTarget)); + } + + function bindEventListener(elem, eventName, handler, opts) { + elem.addEventListener(eventName, handler, opts); + + return function () { + elem.removeEventListener(eventName, handler, opts); + }; + } + + var cleanup = [ + bindEventListener( + scopeTarget, + eventType, + listener, + lay.passiveSupported + ? { passive: true, capture: useCapture } + : useCapture, + ), + detectIframe && + bindEventListener(window, 'blur', function (event) { + setTimeout(function () { + if ( + document.activeElement && + document.activeElement.tagName === 'IFRAME' && + target.contains && + !target.contains(document.activeElement) + ) { + handler(event); + } + }, 0); + }), + ]; + + return function () { + for (var i = 0; i < cleanup.length; i++) { + cleanup[i] && cleanup[i](); + } + cleanup = null; + }; +}; + +/** + * 检查对象是否具有指定的属性 + * @param {Record} obj 要检查的对象 + * @param {string} prop 要检查的属性名 + * @returns {boolean} 如果对象具有指定的属性,则为 true;否则为 false + */ +lay.hasOwn = function (obj, prop) { + return hasOwnProperty.call(obj, prop); +}; + +/** + * 转义 HTML 字符串中的特殊字符 + * @param {string} html 要转义的 HTML 字符串 + * @returns {string} 转义后的 HTML 字符串 + */ +lay.escape = function (html) { + var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g; + if (html === undefined || html === null) return ''; + + html += ''; + if (!exp.test(html)) return html; + + return html + .replace(/&(?=#?[a-zA-Z0-9]+;?)/g, '&') + .replace(//g, '>') + .replace(/'/g, ''') + .replace(/"/g, '"'); +}; + +/** + * 还原转义的 HTML 字符串中的特殊字符 + * @param {string} html 要还原转义的 HTML 字符串 + * @returns {string} 还原转义后的 HTML 字符串 + */ +lay.unescape = function (html) { + if (html === undefined || html === null) return ''; + + return String(html) + .replace(/"/g, '"') + .replace(/'/g, "'") + .replace(/>/g, '>') + .replace(/</g, '<') + .replace(/&/g, '&'); +}; + +/** + * 将字符串编码为 base64 + * 在 btoa 的基础上,增加对 Unicode、编码模式的支持 + * @param {string} str - 待编码的二进制字符串 + * @param {'url'} [mode] - 编码模式,设为 `url` 时表示输出为 base64url 安全编码 + * @returns {string} 编码后的字符串 + * @see + * - https://developer.mozilla.org/docs/Web/API/Window/btoa + * - https://datatracker.ietf.org/doc/html/rfc4648#section-5 + */ +lay.btoa = (str, mode) => { + const bytes = new TextEncoder().encode(str); + const chunkSize = 1024 * 32; // 用于对大字符串进行分块处理 + let binary = ''; + + for (let i = 0; i < bytes.length; i += chunkSize) { + binary += String.fromCharCode(...bytes.subarray(i, i + chunkSize)); + } + + let encodedStr = btoa(binary); + + // 是否编码为 base64url + if (mode === 'url') { + return encodedStr + .replace(/\+/g, '-') + .replace(/\//g, '_') + .replace(/=+$/, ''); + } + + return encodedStr; +}; + +/** + * 生成唯一的 ID 字符串 + * @param {string} prefix ID 前缀,默认为'id' + * @returns {string} 唯一 ID 字符串 + */ +var generateUniqueId = (function () { + var counter = 0; + var lastTimestamp = null; + + return function (prefix) { + prefix = prefix || 'id'; + var timestamp = new Date().getTime(); + + // 如果时间戳与上一次相同,增加计数器 + // 否则重置计数器 + if (timestamp === lastTimestamp) { + counter++; + } else { + counter = 0; + lastTimestamp = timestamp; + } + + // 结合时间戳、随机数和计数器生成 ID + var random = Math.floor(Math.random() * 10000); + + return prefix + '-' + timestamp + '-' + random + '-' + counter; + }; +})(); + +/** + * 创建共享的 ResizeObserver 实例 + * @param {string} namespace 命名空间,用于区分不同的 ResizeObserver 实例 + * @returns {ResizeObserver | null} ResizeObserver 实例或 null(如果不支持) + */ +lay.createSharedResizeObserver = function (namespace) { + if (typeof window.ResizeObserver === 'undefined') { + console.warn('ResizeObserver is not supported in this browser.'); + return null; + } + + namespace = namespace || ''; + var ATTR_NAME = 'lay-' + namespace + '-resizeobserver-key'; + var handlerCache = {}; + + var o = new ResizeObserver(function (entries) { + for (var i = 0; i < entries.length; i++) { + var attrValue = entries[i].target.getAttribute(ATTR_NAME); + + if (attrValue) { + var callback = handlerCache[attrValue]; + if (typeof callback === 'function') { + callback(entries[i]); + } + } + } + }); + + return Object.freeze({ + observe: function (element, callback) { + if (!element || !(element instanceof Element)) { + console.warn('createSharedResizeObserver: Cannot observe non-Element.'); + return; + } + + var attrValue = element.getAttribute(ATTR_NAME); + if (!attrValue) { + attrValue = generateUniqueId(namespace); + element.setAttribute(ATTR_NAME, attrValue); + } + + // 使用同一个观察者实例多次观察同一个元素,不会重复添加 + handlerCache[attrValue] = callback; + o.observe(element); + }, + unobserve: function (element) { + if (!element || !(element instanceof Element)) { + console.warn( + 'createSharedResizeObserver: Cannot unobserve non-Element.', + ); + return; + } + + var attrValue = element.getAttribute(ATTR_NAME); + if (!attrValue) { + return; + } + + // 清除相关回调 + if (handlerCache[attrValue]) { + delete handlerCache[attrValue]; + } + + element.removeAttribute(ATTR_NAME); + o.unobserve(element); + }, + disconnect: function () { + for (var key in handlerCache) { + if (lay.hasOwn(handlerCache, key)) { + delete handlerCache[key]; + var elem = document.querySelector( + '[' + ATTR_NAME + '="' + key + '"]', + ); + if (elem) { + elem.removeAttribute(ATTR_NAME); + } + } + } + o.disconnect(); + }, + }); +}; + +/** + * 树状数据转平铺 + * @param {Object[]} data - 树状数据 + * @param {Object} options - 可选项 + * @param {string} [options.childrenKey='children'] - 子节点字段名 + * @param {string} [options.idKey='id'] - 节点 id 字段名 + * @param {string} [options.parentKey='parentId'] - 父节点 id 字段名 + * @param {boolean} [options.keepChildren=true] - 是否保留子节点数据 + * @returns {Object[]} 返回平铺数据 + */ +lay.treeToFlat = function (data, options) { + options = Object.assign( + { + childrenKey: 'children', + idKey: 'id', + parentKey: 'parentId', + keepChildren: true, + }, + options, + ); + + // 展平 + var toFlat = function (initData, nodes, parentId) { + return nodes.reduce(function (acc, currNode) { + var children = currNode[options.childrenKey]; + + if (!options.keepChildren) { + delete currNode[options.childrenKey]; + } + + currNode[options.parentKey] = parentId; // 设置父节点 id + acc.push(currNode); + + // 递归子节点 + if (children && children.length) { + return toFlat(acc, children, currNode[options.idKey]); + } + + return acc; + }, initData); + }; + + return toFlat([], JSON.parse(JSON.stringify(data)), null); +}; + +/** + * 平铺数据转树状 + * @param {Array} data - 平铺数据 + * @param {Object} options - 可选项 + * @param {string} [options.childrenKey='children'] - 子节点字段名 + * @param {string} [options.idKey='id'] - 节点 id 字段名 + * @param {string} [options.parentKey='parentId'] - 父节点 id 字段名 + */ +lay.flatToTree = function (data, options) { + options = Object.assign( + { + childrenKey: 'children', + idKey: 'id', + parentKey: 'parentId', + }, + options, + ); + + data = JSON.parse(JSON.stringify(data)); // 深拷贝,防止修改原数据 + + // 先创建节点映射,确保无论平铺数据的顺序如何,组装树时都能正确匹配 + var map = data.reduce(function (acc, currNode) { + var id = currNode[options.idKey]; + acc[id] = currNode; + acc[id][options.childrenKey] = []; + return acc; + }, {}); + + // 组装树 + return data.reduce(function (acc, currNode) { + var id = currNode[options.idKey]; + var parentId = currNode[options.parentKey]; + + // 根节点 + if (parentId === null || !map[parentId]) { + acc.push(map[id]); + } else { + // 子节点 + map[parentId][options.childrenKey].push(currNode); + } + + return acc; + }, []); +}; + +export { lay, use, version }; diff --git a/src/core/laytpl.js b/src/core/laytpl.js new file mode 100644 index 000000000..ad0aa33dd --- /dev/null +++ b/src/core/laytpl.js @@ -0,0 +1,523 @@ +/** + * laytpl + * 轻量级通用模板引擎 + */ + +// 实例接口 +var thisModule = function () { + var that = this; + var options = that.config; + + return { + config: options, + + /** + * 渲染模板 + * @param {Object} data - 模板数据 + * @param {Function} callback - 回调函数 + * @returns {string} 渲染后的模板 + */ + render: function (data, callback) { + options.data = data; + var html = that.render(); + + // 如果传入目标元素选择器,则直接将模板渲染到目标元素中 + if (options.target) { + var elem = document.querySelector(options.target); + if (elem) { + elem.innerHTML = html; + } + } + + // 返回结果 + return typeof callback === 'function' ? (callback(html), this) : html; + }, + + /** + * 编译新的模板 + * @param {string} template - 模板 + * @returns {this} + */ + compile: function (template) { + options.template = template; + delete that.compilerCache; // 清除模板缓存 + // that.compile(template); + return this; + }, + + /** + * 模板编译错误事件 + * @param {Function} callback + * @returns {this} + */ + error: function (callback) { + callback && (options.error = callback); + return this; + }, + + /** + * 以下为兼容旧版本相关方法 + */ + + // 解析并渲染模板 + parse: function (template, data) { + return this.compile(template).render(data); + }, + }; +}; + +// 模板内部变量 +var vars = { + // 字符转义 + escape: function (html) { + var exp = /[<"'>]|&(?=#?[a-zA-Z0-9]+)/g; + if (html === undefined || html === null) return ''; + html += ''; + if (!exp.test(html)) return html; + return html.replace(exp, function (str) { + return '&#' + str.charCodeAt(0) + ';'; + }); + }, +}; + +// 组件工具类方法 +var tools = { + /** + * 创建动态正则表达式 + * @param {string} str - 表达式字符 + * @param {string} mod - 修饰符 + * @returns {RegExp} - 正则表达式 + */ + regex: function (str, mod) { + return new RegExp(str, mod || 'g'); + }, + + /** + * 错误提示 + * @param {string} e - 原始错误信息 + * @param {Object} opts - 自定义选项 + * @param {Function} error - 错误回调 + * @returns {string} - 错误提示 + */ + error: function (e, opts, error) { + opts = opts || {}; + opts = Object.assign( + { + errorContext: '', + }, + opts, + ); + + // 向控制台输出错误信息 + var message = 'Laytpl ' + (opts.type || '') + 'Error: ' + e; + var errorContext = opts.errorContext; + + delete opts.errorContext; + typeof console === 'object' && + console.error(message, '\n', errorContext, '\n', opts); + typeof error === 'function' && error(opts); // 执行错误回调 + return message; // 向视图返回错误提示 + }, +}; + +// 默认配置 +var config = { + open: '{{', // 起始界定符 + close: '}}', // 结束界定符 + cache: true, // 是否开启模板缓存,以便下次渲染时不重新编译模板 + condense: true, // 是否压缩模板空白符,如:将多个连续的空白符压缩为单个空格 +}; + +// 构造器 +var Class = function (template, options) { + var that = this; + + // 选项合并 + options = that.config = Object.assign( + { + template: template, + }, + config, + options, + ); + + // 当前实例的模板内工具 + that.vars = Object.assign( + { + /** + * 引用外部模板。若在 Node.js 环境,可通过重置该方法实现模板文件导入 + * @param {string} id - 模板 ID + * @param {Object} data - 模板数据 + * @returns {string} 模板渲染后内容 + */ + include: function (id, data) { + var elem = document.getElementById(id); + var template = elem ? elem.innerHTML : ''; + return template ? that.render(template, data) : ''; + }, + }, + vars, + ); + + // 编译模板 + that.compile(options.template); +}; + +/** + * 渲染 + * @param {Object} template - 模板 + * @param {Object} data - 数据 + * @returns {string} 渲染后的模板内容 + */ +Class.prototype.render = function (template, data) { + var that = this; + var options = that.config; + + // 获得模板渲染函数 + var compiler = template + ? that.compile(template) + : that.compilerCache || that.compile(options.template); + + // 获取渲染后的字符 + var html = (function () { + data = data || options.data || {}; + try { + return compiler(data); + } catch (e) { + template = template || options.template; + return tools.error( + e, + { + errorContext: that.extractErrorContext(template, data), + template: template, + type: 'Render', + }, + options.error, + ); + } + })(); + + // 缓存编译器 + if (options.cache && !template) { + that.compilerCache = compiler; + } + + return html; // 返回渲染后的字符 +}; + +/** + * 编译模板 + * @param {string} template - 原始模板 + * @returns {Function} 模板编译器,用于后续数据渲染 + */ +Class.prototype.compile = function (template) { + var that = this; + var options = that.config; + var openDelimiter = options.open; + var closeDelimiter = options.close; + var condense = options.condense; + var regex = tools.regex; + var placeholder = '\u2028'; // Unicode 行分隔符 + + // console.log('compile'); + + // 模板必须为 string 类型,且不能为空 + if (typeof template !== 'string' || !template) { + return function () { + return ''; + }; + } + + /** + * 完整标签正则 + * @param {string[]} cores - 标签内部核心表达式,含:前置、主体、后置 + * @param {Object} sides - 标签两侧外部表达式 + * @returns {RegExp} + */ + var tagRegex = function (cores, sides) { + var arr = [ + '(?:' + openDelimiter + (cores[0] || '') + '\\s*)', // 界定符前置 + '(' + (cores[1] || '[\\s\\S]') + '*?)', // 标签主体 + '(?:\\s*' + (cores[2] || '') + closeDelimiter + ')', // 界定符后置 + ]; + sides = sides || {}; + sides.before && arr.unshift(sides.before); // 标签前面的表达式 + sides.after && arr.push(sides.after); // 标签后面的表达式 + return regex(arr.join('')); + }; + + // 匹配非输出类型标签两侧的换行符和空白符,避免渲染后占用一行 + var sidesRegex = condense ? ['', ''] : ['(?:(?:\\n)*\\s*)', '(?:\\s*?)']; + var delimSides = { + before: sidesRegex[0], + after: sidesRegex[1], + }; + + /** + * 清理多余符号 + * @param {string} body - 标签主体字符 + * @param {boolean} nowrap - 是否强制不换行 + * @returns {string} 清理后的字符 + */ + var clear = function (body, nowrap) { + if (!condense) { + // 还原语句中的 Unicode 行分隔符 + body = body.replace(regex(placeholder), nowrap ? '' : '\n'); + } + body = body.replace(/\\(\\|")/g, '$1'); // 去除多余反斜杠 + return body; + }; + + // 纠正标签结构 + var correct = function (tpl) { + return tpl.replace( + regex('([}\\]])' + closeDelimiter), + '$1 ' + closeDelimiter, + ); + }; + + // 模板解析 + var parse = (that.parse = function (tpl) { + tpl = tpl || ''; + if (!tpl) return tpl; + + // 压缩连续空白符 + if (condense) { + tpl = tpl.replace(/\t/g, ' ').replace(/\s+/g, ' '); + } + + // 初始整理 + tpl = correct(tpl) // 纠正标签 + .replace(/(?=\\|")/g, '\\') // 转义反斜杠和双引号 + .replace(/\r?\n/g, condense ? '' : placeholder); // 整理换行符 + + // 忽略标签 - 即区域中的内容不进行标签解析 + tpl = tpl.replace( + tagRegex(['!', '', '!'], delimSides), + function (str, body) { + body = body.replace( + regex(openDelimiter + '|' + closeDelimiter), + function (tag) { + return tag.replace(/(?=.)/g, '\\'); + }, + ); + return body; + }, + ); + + // 模板字符拼接 + var strConcatenation = function (body) { + // 通过对 20k+ 行的模板进行编译测试, 发现 Chrome `+=` 性能竟优于 `push` + // 1k 次循环 + 1k 行数据量进行模板编译+渲染,发现 `+=` 性能仍然优于 `push` + // 考虑可能是 V8 做了 Ropes 结构优化? 或跟模板采用「静态拼接」的实现有关(可能性更大) + return ['";', body, '__laytpl__+="'].join('\n'); + // return ['");', body, '__laytpl__.push("'].join('\n'); + }; + + // 解析输出标签 + var output = function (str, delimiter, body) { + var _escape; + + if (!body) return ''; + body = clear(body, true); + + // 输出方式 + if (delimiter === '-') { + // 原文输出,即不对 HTML 原文进行转义 + _escape = ''; + } else { + // 转义输出 + _escape = '_escape'; + } + + return body + ? strConcatenation( + '__laytpl__+=' + _escape + '(' + body + ');', + // '__laytpl__.push('+ _escape +'('+ body +'));' + ) + : ''; + }; + + // 解析 Scriptlet + var statement = function (str, body) { + if (!body) return ''; + body = clear(body); + return strConcatenation(body); + }; + + // 注释标签 - 仅在模板中显示,不进行解析,也不在视图中输出 + tpl = tpl.replace(tagRegex(['#'], delimSides), ''); + // 输出标签 + tpl = tpl.replace(tagRegex(['(=|-)']), output); + // Scriptlet 标签 + tpl = tpl.replace(tagRegex([], delimSides), statement); + + // 恢复换行符 + if (!condense) { + tpl = tpl.replace(regex(placeholder), '\\n'); + } + + return tpl; + }); + + /** + * 创建模板编译器 + * 请注意: 开发者在使用模板语法时,需确保模板中的 JS 语句不来自于页面用户输入。 + * 即模板中的 JS 语句必须在页面开发者自身的可控范围内,否则请避免使用该模板解析。 + */ + var createCompiler = (that.createCompiler = function (template, builder) { + builder = builder || createBuilder(template); + return new Function('laytpl', 'return ' + builder)(that.vars); + }); + var createBuilder = (that.createBuilder = function (template, builder) { + builder = + builder || + [ + 'function(d){', + '"use strict";', + 'var __laytpl__="",' + + (function () { + // 内部变量 + // 内部方法 + var arr = []; + for (var key in that.vars) { + arr.push((key === 'escape' ? '_' : '') + key + '=laytpl.' + key); + } + return arr.join(','); + })() + + ';', + '__laytpl__="' + parse(template) + '";', + 'return __laytpl__;', + // '__laytpl__.push("'+ parse(template) +'");', + // 'return __laytpl__.join("");', + '};', + ].join('\n'); + // console.log(builder); + return builder; + }); + + try { + return createCompiler(template); // 返回编译器 + } catch (e) { + delete that.compilerCache; + return function () { + return tools.error( + e, + { + errorContext: that.extractErrorContext(template), + template: template, + type: 'Compile', + }, + options.error, + ); + }; + } +}; + +/** + * 获取模板出错行上下文 + * @param {string} template - 原始模板 + * @param {Object} data - 数据 + * @returns {string} + */ +Class.prototype.extractErrorContext = function (template, data) { + var that = this; + + // 给模板每行开头添加行号标记 + var lineNum = 1; // 行号 + var templateArr = template.split(/\r?\n/g); + + template = template.replace(/(?=^)/gm, function () { + return '/*LINE:' + lineNum++ + '*/'; + }); + + var builder = that.createBuilder(template); + var builderArr = builder.split(/\r?\n/); + var sourceURL = 'laytpl.builder.map'; + + // 模板出错行上下文 + var errorContext = function (errLineNum) { + errLineNum = parseInt(errLineNum) - 1; + + var arr = ['']; + var contextLines = 3; // 错误行上下延伸的行数 + var start = Math.max(0, errLineNum - contextLines); + var end = Math.min(templateArr.length, errLineNum + contextLines); + + for (; start <= end; start++) { + arr.push( + (start == errLineNum ? '? ' : ' ') + + (start + 1 + '| ') + + templateArr[start], + ); + } + + return arr.join('\n') + '\n'; + }; + + try { + builder += '\n//# sourceURL=' + sourceURL; // 添加映射 + var compiler = that.createCompiler(template, builder); + if (data) compiler(data); + } catch (e) { + // 提取堆栈报错行号 + var stackLineNumRegxp = tools.regex( + sourceURL.replace(/\./g, '\\.') + ':(\\d+)', + 'i', + ); + var stackLineNum = (e.stack.match(stackLineNumRegxp) || [])[1] || 0; + + // 提取模板实际行号 + var extractErrLineNum = function (stackLineNum, isRecursion) { + var lineNumRegxp = isRecursion + ? /\/\*LINE:(\d+)\*\/[^*]*$/ + : /\/\*LINE:(\d+)\*\//; + var errLineNum = + String(builderArr[stackLineNum - 1]).match(lineNumRegxp) || []; + errLineNum = errLineNum[1]; + + // 若当前行未找到行号映射,则递归查找上一行 + if (!errLineNum && stackLineNum > 0) { + return extractErrLineNum(stackLineNum - 1, true); + } + + return errLineNum; + }; + + // 此处减去 anonymous 开头占用的 2 行 + var errLineNum = extractErrLineNum(stackLineNum - 2); + + // 若未找到映射行号,则直接返回 SyntaxError 对象(通过 DevTools 映射源查看模板行号标记) + return errLineNum ? errorContext(errLineNum) : e; + } +}; + +/** + * 创建实例 + * @param {string} template - 模板 + * @param {Object} options - 选项 + * @returns {Object} + */ +var laytpl = function (template, options) { + var inst = new Class(template, options); + return thisModule.call(inst); +}; + +/** + * 扩展模板内部变量 + * @param {Object} variables - 扩展内部变量,变量值通常为函数 + */ +laytpl.extendVars = function (variables) { + Object.assign(vars, variables); +}; + +/** + * 设置默认配置 + * @param {Object} options - 选项 + */ +laytpl.config = laytpl.set = function (options) { + Object.assign(config, options); +}; + +// 输出接口 +export { laytpl }; diff --git a/src/core/loader.js b/src/core/loader.js new file mode 100644 index 000000000..fc41bd992 --- /dev/null +++ b/src/core/loader.js @@ -0,0 +1,376 @@ +/** + * loader + * 加载器 + */ + +import { lay } from './lay.js'; + +// 生成 URL Key +const createUrlKey = (url) => { + const u = new URL(url, location.href); + return u.host + u.pathname; +}; + +/** + * 资源加载器 + * @param {string} url - 资源路径 + * @param {Object} opts - 配置项 + * @param {HTMLElement} opts.elem - 资源 DOM 元素 + * @param {string} [opts.id] - 资源元素 ID,若未提供且 opts.autoId 为 true,则自动生成 + * @param {boolean} [opts.autoId=false] - 是否根据 url 自动生成元素唯一 ID + * @param {Function} [opts.success] - 加载成功的回调函数 + * @param {Function} [opts.error] - 加载失败的回调函数 + * @param {Function} [opts.done] - 资源加载完成后的回调函数 + * @param {Function} [opts.afterCreate] - 资源元素创建后、插入 DOM 前的钩子函数 + * @returns {Promise} 加载结果对象 + * @example + * // 一、传统回调方式 + * + * // 加载单个资源 + * loadResource('url', { + * elem: document.createElement('link'), + * success(elem) { + * // 资源加载成功 + * }, + * error(e) { + * // 资源加载失败 + * }, + * }); + * // 加载多个资源 + * loadResource(['url1', 'url2'], opts); + * + * // 二、Promise 方式 + * + * // 链式调用 + * loadResource('url', opts).then((result) => {}); + * // async/await + * const result = await loadResource('url', opts); + */ +const loadResource = async (url, opts = {}) => { + // 根据 url 生成唯一 id + const generateId = (url) => { + const base64Id = lay.btoa(createUrlKey(url), 'url'); + return `LAY-LOADER-${base64Id}`; + }; + + // 元素唯一 id + const id = opts.id || (opts.autoId ? generateId(url) : undefined); + // console.log(`${url} → ${id}`); + + // 元素是否已存在 + const existingElem = document.getElementById(id); + + if (existingElem) { + opts.elem = existingElem; + } + + return new Promise((resolve) => { + const { elem } = opts; + const result = { elem, id, url }; + + // 加载完成的标记,用于幂等保护 + let complete = false; + + // 加载完成后的相关处理 + const done = (ret) => { + complete = true; + opts.done?.(ret); + resolve(ret); + }; + + const controller = new AbortController(); + const { signal } = controller; + + // 加载成功 handler + const onLoad = function (e) { + controller.abort(); + if (complete) return; + + // 给元素标记加载完成状态,避免重复调用方法时的回调问题 + elem.__lay_state__ = 'complete'; + + // 执行回调 + opts.success?.(result, e); + done(result); + }; + // 加载失败 handler + const onError = function (e) { + controller.abort(); + if (complete) return; + + const ret = { + ...result, + error: new Error(`Failed to load resource: ${url}`), + }; + + // 清除加载状态标记 + delete elem.__lay_state__; + + opts.error?.(ret, e); + done(ret); + }; + + // 在外链资源前绑定事件,避免「竞态条件」导致事件错过触发 + elem.addEventListener('load', onLoad, { signal }); + elem.addEventListener('error', onError, { signal }); + + // 创建元素之后的回调函数,用于处理后续逻辑 + opts.afterCreate?.(result, onLoad, onError); + + // 若元素的「加载状态」已完成 + if (elem.__lay_state__ === 'complete') { + onLoad(); + } + }); +}; + +/** + * 加载多个资源 + * @param {Array} urls - 资源路径数组列表 + * @param {Object} opts - 参数结构同 {@link loadResource} + * @param {Function} resourceLoader - 资源加载函数(必填),应为 loader.script | loader.css | loader.image + * @returns {Promise} 加载结果集对象 + */ +const loadAll = async (urls, opts = {}, resourceLoader = loadResource) => { + let successful = 0; + let completed = 0; + const results = {}; + + // 处理成结果集 + const aggregateResults = (result) => { + for (const [key, value] of Object.entries(result)) { + const values = results[key] || []; + values.push(value); + results[key] = values; + } + }; + + // 并行加载所有资源 + await Promise.all( + urls.map((u) => + resourceLoader(u, { + ...opts, + success(result, ...args) { + aggregateResults(result); + + // 所有资源加载成功后执行 success 回调 + if (++successful === urls.length) { + opts.success?.(results, ...args); + } + }, + error(result) { + aggregateResults(result); + }, + done(_result, ...args) { + if (++completed === urls.length) { + // 任意资源加载失败即执行 error 回调 + if (results.error?.length) { + opts.error?.(results, ...args); + } + opts.done?.(results, ...args); + } + }, + }), + ), + ); + + return Promise.resolve(results); +}; + +// 核心类 +class Loader { + constructor(options) { + this.config(options); + } + + // 默认配置项 + static options = { + alias: {}, // script、link 资源路径别名 + urlParams: '', // 加载 script、link 资源时,是否在 URL 后添加一个参数,避免浏览器缓存 + debug: false, // 是否开启调试模式,若开启,不会移除已加载的 script 节点 + // timeout: 10, // 请求最长等待秒数 + }; + + // 模块加载缓存信息 + #cache = { + status: {}, // script 资源加载状态集 + }; + + /** + * 设置选项 + * @param {Object} options + */ + config(options) { + this.options = lay.extend({}, Loader.options, options); + } + + /** + * 外部 script 加载器 + * @param {string} url - 外部 script 文件路径 + * @param {Object} [opts] - 加载配置项(可选),参数结构同 {@link loadResource} + * @returns {Object} 加载结果 + */ + async script(url, opts = {}) { + const { options } = this; + const cache = this.#cache; + const head = document.head; + + // 若批量加载 + if (Array.isArray(url) && url.length) { + return await loadAll(url, opts, this.script.bind(this)); + } + + // 匹配别名 + if (options.alias[url]) { + url = options.alias[url]; + } + + const urlKey = opts.id || createUrlKey(url); + + return await loadResource(url, { + elem: document.createElement('script'), + ...opts, + autoId: true, + success(result, e) { + cache.status[urlKey] = true; + + // 保证文档加载完毕再执行回调 + lay.use(() => { + opts.success?.(result, e); + }); + }, + error(result, e) { + // 加载失败,清除加载状态 + delete cache.status[urlKey]; + opts.error?.(result, e); + }, + done(result) { + // 加载完成,移除节点 + if (!options.debug) { + if (document.contains(result.elem)) { + head.removeChild(result.elem); + } + } + opts.done?.(result); + }, + afterCreate: (result, onLoad) => { + const { elem, id } = result; + + // 是否已加载 + if (cache.status[urlKey]) { + onLoad(); + } else { + // 首次加载,创建节点 + if (!elem.__lay_state__) { + const src = this.#normalizeUrl(url); + + Object.assign(elem, { src, async: true, id }); + head.appendChild(elem); + + // 资源开始加载的标记 + elem.__lay_state__ = 'loading'; + } + } + }, + }); + } + + /** + * 外部 CSS 加载器 + * @param {string} url - 外部 CSS 文件路径 + * @param {Object} [opts] - 加载配置项(可选),参数结构同 {@link loadResource} + * @returns {Promise} 加载完成的 `` 元素 + */ + async css(url, opts = {}) { + const { options } = this; + const head = document.head; + + // 若批量加载 + if (Array.isArray(url) && url.length) { + return await loadAll(url, opts, this.css.bind(this)); + } + + // 匹配别名 + if (options.alias[url]) { + url = options.alias[url]; + } + + // 若第二个参数为 string 类型,则该参数为 opts.id + if (typeof opts === 'string') { + opts = { id: opts }; + } + + return await loadResource(url, { + elem: document.createElement('link'), + ...opts, + autoId: true, + error(result, e) { + // 加载失败,移除节点 + if (document.contains(result.elem)) { + head.removeChild(result.elem); + } + opts.error?.(result, e); + }, + afterCreate: (result) => { + const { elem, id } = result; + const href = this.#normalizeUrl(url); + + // 初始创建节点 + if (!document.contains(elem)) { + Object.assign(elem, { href, rel: 'stylesheet', id }); + head.appendChild(elem); + } + + // 若目标 href 与当前节点 href 值不同(一般为参数差异),则重新赋值 + if (href !== elem.getAttribute('href')) { + elem.href = href; + } + }, + }); + } + + /** + * 图片加载器 + * @param {string|string[]} url - 图片路径 + * @param {Object} [opts] - 加载配置项,参数结构同 {@link loadResource} + * @returns {Promise} 加载完成的 `` 元素 + */ + async image(url, opts = {}) { + // 若批量加载 + if (Array.isArray(url) && url.length) { + return await loadAll(url, opts, this.image.bind(this)); + } + + return await loadResource(url, { + elem: new Image(), + ...opts, + afterCreate(result, onLoad, onError) { + const { elem } = result; + + elem.src = url; + + // 若元素的「加载状态」已完成,则根据 naturalWidth 执行相应的回调函数 + if (elem.complete) { + elem.naturalWidth > 0 ? onLoad() : onError(); + } + }, + }); + } + + /** + * 规范化 URL + * @param {string} url - 原始 URL + * @return {string} 规范化后的 URL + */ + #normalizeUrl(url) { + const urlParams = this.options.urlParams.trim?.().replace(/^(\?|&)/, ''); + if (!urlParams) return url; + const u = new URL(url, location.href); + return `${url}${u.search ? '&' : '?'}${urlParams}`; + } +} + +// 内置实例 +const loader = new Loader(); + +export { loadResource, Loader, loader }; diff --git a/src/core/logger.js b/src/core/logger.js new file mode 100644 index 000000000..90e3115b4 --- /dev/null +++ b/src/core/logger.js @@ -0,0 +1,37 @@ +/** + * logger + */ + +let warned = Object.create(null); + +/** + * 控制台日志消息提示 + * @param {string} message - 消息内容 + * @param {'warn'|'error'} [level='warn'] - 消息级别 + */ +export function log(message, level = 'warn') { + // 限定消息级别 + if (!/^(warn|error)$/.test(level.trim())) { + level = 'warn'; + } + message = `[Layui ${level}]: ${message}`; + window.console[level](message); +} + +/** + * 一次性「日志提示」 + * @param {...Parameters} args + */ +export function logOnce(...args) { + const [message] = args; + + if (warned._size > 100) { + warned = Object.create(null); + warned._size = 0; + } + if (!warned[message]) { + warned[message] = true; + warned._size = (warned._size || 0) + 1; + log(...args); + } +} diff --git a/src/core/router.js b/src/core/router.js new file mode 100644 index 000000000..f7ae53b66 --- /dev/null +++ b/src/core/router.js @@ -0,0 +1,149 @@ +/** + * router + * 前端路由管理器 + */ + +class Router { + constructor(options) { + this.config(options); + } + + // 默认配置项 + static options = { + mode: 'hash', // 路由模式。可选项:'hash' | 'history' + }; + + /** + * 设置选项 + * @param {Object} options + */ + config(options) { + this.options = { ...Router.options, ...options }; + } + + /** + * URL 锚路由解析 + * @param {string} [hash] - URL 锚字符串 + * @returns {Object} + * @example + * hash('#/user/profile?tab=info#section1') // 返回结果同 `new URL()` + */ + hash(anchor = location.hash) { + // 去除锚字符开头的空白和 # 号。为空时视为 '/'(见 normalizeUrl 约定) + const url = String(anchor ?? '').replace(/^\s*#?/, '') || '/'; + return new URL(url, location.href); + } + + url(url = location.href) { + return new URL(url, location.href); + } + + /** + * 标准化 URL + * @param {string} url - 原始 URL + * @returns {string} 标准化后的 URL + */ + normalizeUrl(url = '') { + const { options } = this; + const currentUrl = this.url(); + const isProtocolRelative = /^\/\//.test(url); + const isExplicitAbsolute = /^[a-zA-Z][\w+.-]*:/.test(url); + + if (!url) { + return options.mode === 'hash' ? '/' : ''; + } + + // hash 模式下,保持 `/` 开头 + if (options.mode === 'hash' && !isExplicitAbsolute && !isProtocolRelative) { + if (!/^\//.test(url)) { + url = '/' + url; + } + } + + const parsedUrl = this.url(url); + const normalizedPathname = parsedUrl.pathname.replace(/(\/+)/g, '/'); + const normalizedPath = + normalizedPathname + parsedUrl.search + parsedUrl.hash; + + if (isProtocolRelative) { + return '//' + parsedUrl.host + normalizedPath; + } + + if (isExplicitAbsolute || parsedUrl.origin !== currentUrl.origin) { + return parsedUrl.origin + normalizedPath; + } + + return normalizedPath; + } + + /** + * 执行路由跳转 + * @param {string} url - 目标路径,支持相对或绝对路径(会自动标准化) + * @param {Object} [opts] - 跳转选项 + * @param {boolean} [opts.replaceState=false] - 是否使用 replaceState 方式跳转(仅 history 模式有效) + * @param {*} [opts.state=null] - 传递给 history 的状态对象(仅 history 模式有效) + * @param {string} [opts.title=''] - 页面标题(部分浏览器忽略,仅 history 模式传入) + * @param {string} [opts.target='_self'] - url 跨域时 window.open 的打开方式 + * @param {Function} [opts.done] - 跳转后的回调函数 + * @returns {void} + * @example + * router.navigate('/user/profile'); + */ + navigate(url, opts = {}) { + const { options } = this; + + if (!url) return; + url = this.normalizeUrl(url); + + // 默认值 + opts = { + mode: options.mode, + state: null, + title: '', + target: '_self', + ...opts, + }; + + // 路由跳转方式 + if (opts.mode === 'hash') { + location.hash = url; + } else { + const { href } = this.url(); + + try { + // 使用 replaceState 的任一条件: + // - 目标 url 与当前页面 url 相同 + // - opts.replaceState 为 true + const historyMethod = + this.url(url).href === href || opts.replaceState + ? 'replaceState' + : 'pushState'; + + history[historyMethod](opts.state, opts.title, url); + } catch { + // url 跨域等异常时的降级处理 + window.open(url, opts.target); + } + } + + opts.done?.({ url }); + } + + /** + * 路由变化事件 + * @param {Function} callback - 路由变化时的回调函数 + * @returns {Function} 清除事件的函数 + */ + onRouteChange(callback) { + const { options } = this; + const type = options.mode === 'hash' ? 'hashchange' : 'popstate'; + + window.addEventListener(type, callback); + return () => window.removeEventListener(type, callback); + } +} + +// 内置实例 +const router = new Router(); + +export { Router, router }; diff --git a/src/css/base.css b/src/css/base.css new file mode 100644 index 000000000..4c007a424 --- /dev/null +++ b/src/css/base.css @@ -0,0 +1,198 @@ +/** 初始化 **/ +body, +div, +dl, +dt, +dd, +ul, +ol, +li, +h1, +h2, +h3, +h4, +h5, +h6, +input, +button, +textarea, +p, +blockquote, +th, +td, +form, +pre { + margin: 0; + padding: 0; + -webkit-tap-highlight-color: rgba(0, 0, 0, 0); +} +a:active, +a:hover { + outline: 0; +} +img { + display: inline-block; + border: none; + vertical-align: middle; +} +li { + list-style: none; +} +table { + border-collapse: collapse; + border-spacing: 0; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-weight: 700; +} +h5, +h6 { + font-size: 100%; +} +button, +input, +select, +textarea { + font-size: 100%; +} +input, +button, +textarea, +select, +optgroup, +option { + font-family: inherit; + font-size: inherit; + font-style: inherit; + font-weight: inherit; + outline: 0; +} +pre { + white-space: pre-wrap; + word-wrap: break-word; +} + +/** 初始化全局标签 **/ +body { + line-height: 1.6; + color: rgba(0, 0, 0, 0.85); + font-size: 14px; + font-family: var(--lay-font-family); +} +hr { + height: 0; + line-height: 0; + margin: 10px 0; + padding: 0; + border: none; + border-bottom: 1px solid var(--lay-border-color); + clear: both; + overflow: hidden; + background: none; +} +a { + color: #333; + text-decoration: none; +} +a cite { + font-style: normal; +} + +/** 基础通用 **/ +.lay-border-box, +.lay-border-box * { + box-sizing: border-box; +} +/* 消除第三方 ui 可能造成的冲突 */ +.lay-box, +.lay-box * { + box-sizing: content-box; +} +.lay-clear { + clear: both; +} +.lay-clear:after { + content: '\20'; + clear: both; + display: block; + height: 0; +} +.lay-clear-space { + word-spacing: -5px; +} +.lay-inline { + position: relative; + display: inline-block; + vertical-align: middle; +} +/* 三角形 */ +.lay-edge { + position: relative; + display: inline-block; + vertical-align: middle; + width: 0; + height: 0; + border-width: 6px; + border-style: dashed; + border-color: transparent; + overflow: hidden; +} +.lay-edge-top { + top: -4px; + border-bottom-color: #999; + border-bottom-style: solid; +} +.lay-edge-right { + border-left-color: #999; + border-left-style: solid; +} +.lay-edge-bottom { + top: 2px; + border-top-color: #999; + border-top-style: solid; +} +.lay-edge-left { + border-right-color: #999; + border-right-style: solid; +} +/* 单行溢出省略 */ +.lay-ellipsis { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +/* 屏蔽选中 */ +.lay-unselect, +.lay-icon, +.lay-disabled { + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +/* 禁用 */ +.lay-disabled, +.lay-disabled:hover { + color: var(--lay-gray-400) !important; + cursor: not-allowed !important; +} +/* 纯圆角 */ +.lay-circle { + border-radius: 100%; +} +.lay-show { + display: block !important; +} +.lay-hide { + display: none !important; +} +.lay-show-v { + visibility: visible !important; +} +.lay-hide-v { + visibility: hidden !important; +} diff --git a/src/css/index.css b/src/css/index.css new file mode 100644 index 000000000..7c993a596 --- /dev/null +++ b/src/css/index.css @@ -0,0 +1,36 @@ +/** + * Layui + * MIT Licensed + */ + +@import url('./var.css'); +@import url('./base.css'); +@import url('./modules/icon.css'); +@import url('./modules/layout.css'); +@import url('./modules/auxiliary.css'); +@import url('./modules/progress.css'); +@import url('./modules/panel.css'); +@import url('./modules/theme.css'); +@import url('./modules/text.css'); +@import url('./modules/button.css'); +@import url('./modules/form.css'); +@import url('./modules/laypage.css'); +@import url('./modules/flow.css'); +@import url('./modules/table.css'); +@import url('./modules/upload.css'); +@import url('./modules/menu.css'); +@import url('./modules/tabs.css'); +@import url('./modules/nav.css'); +@import url('./modules/timeline.css'); +@import url('./modules/badge.css'); +@import url('./modules/carousel.css'); +@import url('./modules/floatbar.css'); +@import url('./modules/transfer.css'); +@import url('./modules/rate.css'); +@import url('./modules/colorpicker.css'); +@import url('./modules/slider.css'); +@import url('./modules/tree.css'); +@import url('./modules/anim.css'); +@import url('./modules/code.css'); +@import url('./modules/laydate.css'); +@import url('./modules/layer.css'); diff --git a/src/css/layui.css b/src/css/layui.css deleted file mode 100644 index 1660c90ff..000000000 --- a/src/css/layui.css +++ /dev/null @@ -1,546 +0,0 @@ -/** - - @Name: layui - @Author: 贤心 - @Site: www.layui.com - - */ - - -/** 初始化 **/ -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,input,button,textarea,p,blockquote,th,td,form,pre{margin: 0; padding: 0; -webkit-tap-highlight-color:rgba(0,0,0,0)} -a:active,a:hover{outline:0} -img{display: inline-block; border: none; vertical-align: middle;} -li{list-style:none;} -table{border-collapse: collapse; border-spacing: 0;} -h1,h2,h3{font-size: 14px; font-weight: 400;} -h4, h5, h6{font-size: 100%; font-weight: 400;} -button,input,select,textarea{font-size: 100%; } -input,button,textarea,select,optgroup,option{font-family: inherit; font-size: inherit; font-style: inherit; font-weight: inherit; outline: 0;} -pre{white-space: pre-wrap; white-space: -moz-pre-wrap; white-space: -pre-wrap; white-space: -o-pre-wrap; word-wrap: break-word;} - -/** 滚动条 **/ -::-webkit-scrollbar{width: 10px; height: 10px;} -::-webkit-scrollbar-button:vertical{display: none;} -::-webkit-scrollbar-track, ::-webkit-scrollbar-corner{background-color: #e2e2e2;} -::-webkit-scrollbar-thumb{border-radius: 0; background-color: rgba(0,0,0,.3);} -::-webkit-scrollbar-thumb:vertical:hover{background-color: rgba(0,0,0,.35);} -::-webkit-scrollbar-thumb:vertical:active{background-color: rgba(0,0,0,.38);} - -/** 图标字体 **/ -@font-face {font-family: 'layui-icon'; - src: url('../font/iconfont.eot?v=1.0.9'); - src: url('../font/iconfont.eot?v=1.0.9#iefix') format('embedded-opentype'), - url('../font/iconfont.svg?v=1.0.9#iconfont') format('svg'), - url('../font/iconfont.woff?v=1.0.9') format('woff'), - url('../font/iconfont.ttf?v=1.0.9') format('truetype'); - -} - -.layui-icon{ - font-family:"layui-icon" !important; - font-size: 16px; - font-style: normal; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -/** 初始化全局标签 **/ -body{line-height: 24px; font: 14px Helvetica Neue,Helvetica,PingFang SC,\5FAE\8F6F\96C5\9ED1,Tahoma,Arial,sans-serif;} -hr{height: 1px; margin: 10px 0; border: 0; background-color: #e2e2e2; clear: both;} -a{color: #333; text-decoration:none; } -a:hover{color: #777;} -a cite{font-style: normal; *cursor:pointer;} - -/** 基础通用 **/ -/* 消除第三方ui可能造成的冲突 */.layui-box, .layui-box *{-webkit-box-sizing: content-box !important; -moz-box-sizing: content-box !important; box-sizing: content-box !important;} -.layui-border-box, .layui-border-box *{-webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;} -.layui-clear{clear: both; *zoom: 1;} -.layui-clear:after{content:'\20'; clear:both; *zoom:1; display:block; height:0;} -.layui-inline{position: relative; display: inline-block; *display:inline; *zoom:1; vertical-align: middle;} -/* 三角形 */.layui-edge{position: absolute; width: 0; height: 0; border-style: dashed; border-color: transparent; overflow: hidden;} -/* 单行溢出省略 */.layui-elip{text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} -/* 屏蔽选中 */.layui-unselect{-moz-user-select: none; -webkit-user-select: none; -ms-user-select: none;} -.layui-disabled,.layui-disabled:hover{color: #d2d2d2 !important; cursor: not-allowed !important;} -/* 纯圆角 */.layui-circle{border-radius: 100%;} -.layui-show{display: block !important;} -.layui-hide{display: none !important;} - - -/* 布局 */ -.layui-main{position: relative; width: 1140px; margin: 0 auto;} -.layui-header{position: relative; z-index: 1000; height: 60px;} -.layui-header a:hover{transition: all .5s; -webkit-transition: all .5s;} -.layui-side{position: fixed; top: 0; bottom: 0; z-index: 999; width: 200px; overflow-x: hidden;} -.layui-side-scroll{width: 220px; height: 100%; overflow-x: hidden;} -.layui-body{position: absolute; left: 200px; right: 0; top: 0; bottom: 0; z-index: 998; width: auto; overflow: hidden; overflow-y: auto; -webkit-box-sizing: border-box; -moz-box-sizing: border-box; box-sizing: border-box;} - -/* 后台布局风格 */.layui-layout-admin .layui-header{background-color: #23262E;} -.layui-layout-admin .layui-side{top: 60px; width: 200px; overflow-x: hidden;} -.layui-layout-admin .layui-body{top: 60px; bottom: 44px;} -.layui-layout-admin .layui-main{width: auto; margin: 0 15px;} -.layui-layout-admin .layui-footer{position: fixed; left: 200px; right: 0; bottom: 0; height: 44px; background-color: #eee;} - - -/** 页面元素 **/ -.layui-btn, .layui-input, .layui-textarea, .layui-upload-button, .layui-select{outline: none; -webkit-transition: border-color .3s cubic-bezier(.65,.05,.35,.5); transition: border-color .3s cubic-bezier(.65,.05,.35,.5); -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;} - -/* 引用 */.layui-elem-quote{margin-bottom: 10px; padding: 15px; line-height: 22px; border-left: 5px solid #009688; border-radius: 0 2px 2px 0; background-color: #f2f2f2;} -.layui-quote-nm{border-color: #e2e2e2; border-style: solid; border-width: 1px; border-left-width: 5px; background: none;} -/* 字段集合 */.layui-elem-field{margin-bottom: 10px; padding: 0; border: 1px solid #e2e2e2;} -.layui-elem-field legend{margin-left: 20px; padding: 0 10px; font-size: 20px; font-weight: 300;} -.layui-field-title{margin: 10px 0 20px; border: none; border-top: 1px solid #e2e2e2;} -.layui-field-box{padding: 10px 15px;} -.layui-field-title .layui-field-box{padding: 10px 0;} - -/* 进度条 */ -.layui-progress{position: relative; height: 6px; border-radius: 20px; background-color: #e2e2e2;} -.layui-progress-bar{position: absolute; width: 0; max-width: 100%; height: 6px; border-radius: 20px; text-align: right; background-color: #5FB878; transition: all .3s; -webkit-transition: all .3s;} -.layui-progress-big, -.layui-progress-big .layui-progress-bar{height: 18px; line-height: 18px;} -.layui-progress-text{position: relative; top: -18px; line-height: 18px; font-size: 12px; color: #666} -.layui-progress-big .layui-progress-text{position: static; padding: 0 10px; color: #fff;} - -/* 折叠面板 */ -.layui-collapse{border: 1px solid #e2e2e2; border-radius: 2px;} -.layui-colla-item{border-top: 1px solid #e2e2e2} -.layui-colla-item:first-child{border-top: none;} -.layui-colla-title{position: relative; height: 42px; line-height: 42px; padding: 0 15px 0 35px; color: #333; background-color: #f2f2f2; cursor: pointer;} -.layui-colla-content{display: none; padding: 10px 15px; line-height: 22px; border-top: 1px solid #e2e2e2; color: #666;} -.layui-colla-icon{position: absolute; left: 15px; top: 0; font-size: 14px;} - - -/* 背景颜色 */ -.layui-bg-red{background-color: #FF5722;} /*赤*/ -.layui-bg-orange{background-color: #F7B824;} /*橙*/ -.layui-bg-green{background-color: #009688;} /*绿*/ -.layui-bg-cyan{background-color: #2F4056;} /*青*/ -.layui-bg-blue{background-color: #1E9FFF;} /*蓝*/ -.layui-bg-black{background-color: #393D49;} /*黑*/ -.layui-bg-gray{background-color: #eee;} /*灰*/ - - -/* 文字 */ -.layui-word-aux{font-size: 12px; color: #999; padding: 0 5px;} - -/* 按钮 */ -.layui-btn{display: inline-block; vertical-align: middle; height: 38px; line-height: 38px; padding: 0 18px; background-color: #009688; color: #fff; white-space: nowrap; text-align: center; font-size: 14px; border: none; border-radius: 2px; cursor: pointer; opacity: 0.9; filter:alpha(opacity=90); -moz-user-select: none; -webkit-user-select: none; -ms-user-select: none;} -.layui-btn:hover{opacity: 0.8; filter:alpha(opacity=80); color: #fff;} -.layui-btn:active{opacity: 1; filter:alpha(opacity=100);} -.layui-btn+.layui-btn{margin-left: 10px;} -/* 圆角 */.layui-btn-radius{border-radius: 100px;} -.layui-btn .layui-icon{font-size: 18px; vertical-align: bottom;} - -/* 原始 */.layui-btn-primary{border: 1px solid #C9C9C9; background-color: #fff; color: #555;} -.layui-btn-primary:hover{border-color: #009688; color: #333} -/* 百搭 */.layui-btn-normal{background-color: #1E9FFF;} -/* 暖色 */.layui-btn-warm{background-color: #F7B824;} -/* 警告 */.layui-btn-danger{background-color: #FF5722;} -/* 禁用 */.layui-btn-disabled,.layui-btn-disabled:hover,.layui-btn-disabled:active{border: 1px solid #e6e6e6; background-color: #FBFBFB; color: #C9C9C9; cursor: not-allowed; opacity: 1;} - -/* 大型 */.layui-btn-big{height: 44px; line-height: 44px; padding: 0 25px; font-size: 16px;} -/* 小型 */.layui-btn-small{height: 30px; line-height: 30px; padding: 0 10px; font-size: 12px;} -.layui-btn-small i{font-size: 16px !important;} -/* 迷你 */.layui-btn-mini{height: 22px; line-height: 22px; padding: 0 5px; font-size: 12px;} -.layui-btn-mini i{font-size: 14px !important;} -/* 按钮组 */.layui-btn-group{display: inline-block; vertical-align: middle; font-size: 0;} -.layui-btn-group .layui-btn{margin-left: 0!important; margin-right: 0!important; border-left: 1px solid rgba(255,255,255,.5); border-radius: 0;} -.layui-btn-group .layui-btn-primary{border-left: none;} -.layui-btn-group .layui-btn-primary:hover{border-color: #C9C9C9; color: #009688;} -.layui-btn-group .layui-btn:first-child{border-left: none; border-radius: 2px 0 0 2px;} -.layui-btn-group .layui-btn-primary:first-child{border-left: 1px solid #c9c9c9;} -.layui-btn-group .layui-btn:last-child{border-radius: 0 2px 2px 0;} -.layui-btn-group .layui-btn+.layui-btn{margin-left: 0;} -.layui-btn-group+.layui-btn-group{margin-left: 10px;} - -/** 表单 **/ -.layui-input, .layui-textarea, .layui-select{height: 38px; line-height: 38px; line-height: 36px\9; border: 1px solid #e6e6e6; background-color: #fff; border-radius: 2px;} -.layui-input, .layui-textarea{display: block; width: 100%; padding-left: 10px;} -.layui-input:hover, .layui-textarea:hover{border-color: #D2D2D2 !important;} -.layui-input:focus, .layui-textarea:focus{border-color: #C9C9C9 !important;} -.layui-textarea{position: relative; min-height: 100px; height: auto; line-height: 20px; padding: 6px 10px; resize: vertical;} -.layui-select{padding: 0 10px;} -.layui-form select, -.layui-form input[type=checkbox], -.layui-form input[type=radio]{display: none;} - -.layui-form-item{margin-bottom: 15px; clear: both; *zoom: 1;} -.layui-form-item:after{content:'\20'; clear: both; *zoom: 1; display: block; height:0;} -.layui-form-label{position: relative; float: left; display: block; padding: 9px 15px; width: 80px; font-weight:normal;line-height: 20px; text-align: right;} -.layui-form-item .layui-inline{margin-bottom: 5px; margin-right: 10px;} -.layui-input-block, .layui-input-inline{position: relative;} -.layui-input-block{margin-left: 110px; min-height: 36px;} -.layui-input-inline{display: inline-block; vertical-align: middle;} -.layui-form-item .layui-input-inline{float: left; width: 190px; margin-right: 10px;} -.layui-form-text .layui-input-inline{width: auto;} - -/* 分割块 */.layui-form-mid{position: relative; float: left; display: block; padding: 8px 0; line-height: 20px; margin-right: 10px;} -/* 警告域 */.layui-form-danger:focus -,.layui-form-danger+.layui-form-select .layui-input{border: 1px solid #FF5722 !important;} - - -/* 下拉选择 */.layui-form-select{position: relative;} -.layui-form-select .layui-input{padding-right: 30px; cursor: pointer;} -.layui-form-select .layui-edge{position: absolute; right: 10px; top: 50%; margin-top: -3px; cursor: pointer; border-width: 6px; border-top-color: #c2c2c2; border-top-style: solid; transition: all .3s; -webkit-transition: all .3s;} -.layui-form-select dl{display: none; position: absolute; left: 0; top: 42px; padding: 5px 0; z-index: 999; min-width: 100%; border: 1px solid #d2d2d2; max-height: 300px; overflow-y: auto; background-color: #fff; border-radius: 2px; box-shadow: 0 2px 4px rgba(0,0,0,.12); box-sizing: border-box;} -.layui-form-select dl dt, -.layui-form-select dl dd{padding: 0 10px; line-height: 36px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis;} -.layui-form-select dl dt{font-size: 12px; color: #999;} -.layui-form-select dl dd{cursor: pointer;} -.layui-form-select dl dd:hover{background-color: #f2f2f2;} -.layui-form-select .layui-select-group dd{padding-left: 20px;} -.layui-form-select dl dd.layui-this{background-color: #5FB878; color: #fff;} -.layui-form-select dl dd.layui-disabled{background-color: #fff;} -.layui-form-selected dl{display: block;} -.layui-form-selected .layui-edge{margin-top: -9px; -webkit-transform:rotate(180deg); transform: rotate(180deg);} -.layui-form-selected .layui-edge{margin-top: -3px\0; } -:root .layui-form-selected .layui-edge{margin-top: -9px\0/IE9;} -.layui-select-none{margin: 5px 0; text-align: center; color: #999;} - -.layui-select-disabled .layui-disabled{border-color: #eee !important;} -.layui-select-disabled .layui-edge{border-top-color: #d2d2d2} - -/* 复选框 */.layui-form-checkbox{position: relative; display: inline-block; vertical-align: middle; height: 30px; line-height: 28px; margin-right: 10px; padding-right: 30px; border: 1px solid #d2d2d2; background-color: #fff; cursor: pointer; font-size: 0; border-radius: 2px; -webkit-transition: .1s linear; transition: .1s linear; box-sizing: border-box !important;} -.layui-form-checkbox:hover{border: 1px solid #c2c2c2;} -.layui-form-checkbox *{display: inline-block; vertical-align: middle;} -.layui-form-checkbox span{padding: 0 10px; height: 100%; font-size: 14px; background-color: #d2d2d2; color: #fff; overflow: hidden; white-space: nowrap; text-overflow: ellipsis;} -.layui-form-checkbox:hover span{background-color: #c2c2c2;} -.layui-form-checkbox i{position: absolute; right: 0; width: 30px; color: #fff; font-size: 20px; text-align: center;} -.layui-form-checkbox:hover i{color: #c2c2c2;} -.layui-form-checked, .layui-form-checked:hover{border-color: #5FB878;} -.layui-form-checked span, .layui-form-checked:hover span{background-color: #5FB878;} -.layui-form-checked i, .layui-form-checked:hover i{color: #5FB878;} -.layui-form-item .layui-form-checkbox{margin-top: 4px;} - -/* 复选框-原始风格 */.layui-form-checkbox[lay-skin="primary"]{height: auto!important; line-height: normal!important; border: none!important; margin-right: 0; padding-right: 0; background: none;} -.layui-form-checkbox[lay-skin="primary"] span{float: right; padding-right: 15px; line-height: 18px; background: none; color: #666;} -.layui-form-checkbox[lay-skin="primary"] i{position: relative; top: 0; width: 16px; line-height: 16px; border: 1px solid #d2d2d2; font-size: 12px; border-radius: 2px; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;} -.layui-form-checkbox[lay-skin="primary"]:hover i{border-color: #5FB878; color: #fff;} -.layui-form-checked[lay-skin="primary"] i{border-color: #5FB878; background-color: #5FB878; color: #fff;} -.layui-checkbox-disbaled[lay-skin="primary"] span{background: none!important;} -.layui-checkbox-disbaled[lay-skin="primary"]:hover i{border-color: #d2d2d2;} -.layui-form-item .layui-form-checkbox[lay-skin="primary"]{margin-top: 10px;} - -/* 复选框-开关风格 */.layui-form-switch{position: relative; display: inline-block; vertical-align: middle; height: 22px; line-height: 22px; width: 42px; padding: 0 5px; margin-top: 8px; border: 1px solid #d2d2d2; border-radius: 20px; cursor: pointer; background-color: #fff; -webkit-transition: .1s linear; transition: .1s linear;} -.layui-form-switch i{position: absolute; left: 5px; top: 3px; width: 16px; height: 16px; border-radius: 20px; background-color: #d2d2d2; -webkit-transition: .1s linear; transition: .1s linear;} -.layui-form-switch em{position: absolute; right: 5px; top: 0; width: 25px; padding: 0!important; text-align: center!important; color: #999!important; font-style: normal!important; font-size: 12px;} -.layui-form-onswitch{border-color: #5FB878; background-color: #5FB878;} -.layui-form-onswitch i{left: 32px; background-color: #fff;} -.layui-form-onswitch em{left: 5px; right: auto; color: #fff!important;} - -.layui-checkbox-disbaled{border-color: #e2e2e2 !important;} -.layui-checkbox-disbaled span{background-color: #e2e2e2 !important;} -.layui-checkbox-disbaled:hover i{color: #fff !important;} - -/* 单选框 */ -.layui-form-radio{display: inline-block; vertical-align: middle; line-height: 28px; margin: 6px 10px 0 0; padding-right: 10px; cursor: pointer; font-size: 0;} -.layui-form-radio *{display: inline-block; vertical-align: middle;} -.layui-form-radio i{margin-right: 8px; font-size: 22px; color: #c2c2c2;} -.layui-form-radio span{font-size: 14px;} -.layui-form-radioed i,.layui-form-radio i:hover{color: #5FB878;} -.layui-radio-disbaled i{color: #e2e2e2 !important;} - -/* 表单方框风格 */.layui-form-pane .layui-form-label{width: 110px; padding: 8px 15px; height: 38px; line-height: 20px; border: 1px solid #e6e6e6; border-radius: 2px 0 0 2px; text-align: center; background-color: #FBFBFB; overflow: hidden; white-space: nowrap; text-overflow: ellipsis; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;} -.layui-form-pane .layui-input-inline{margin-left: -1px;} -.layui-form-pane .layui-input-block{margin-left: 110px; left: -1px;} -.layui-form-pane .layui-input{border-radius: 0 2px 2px 0;} -.layui-form-pane .layui-form-text .layui-form-label{float: none; width: 100%; border-right: 1px solid #e6e6e6; border-radius: 2px; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important; text-align: left;} -.layui-form-pane .layui-form-text .layui-input-inline{display: block; margin: 0; top: -1px; clear: both;} -.layui-form-pane .layui-form-text .layui-input-block{margin: 0; left: 0; top: -1px;} -.layui-form-pane .layui-form-text .layui-textarea{min-height: 100px; border-radius: 0 0 2px 2px;} -.layui-form-pane .layui-form-checkbox{margin: 4px 0 4px 10px;} -.layui-form-pane .layui-form-switch, -.layui-form-pane .layui-form-radio{margin-top: 6px; margin-left: 10px; } -.layui-form-pane .layui-form-item[pane]{position: relative; border: 1px solid #e6e6e6;} -.layui-form-pane .layui-form-item[pane] .layui-form-label{position: absolute; left: 0; top: 0; height: 100%; border-width: 0px; border-right-width: 1px;} -.layui-form-pane .layui-form-item[pane] .layui-input-inline{margin-left: 110px;} - -/** 富文本编辑器 **/ -.layui-layedit{border: 1px solid #d2d2d2; border-radius: 2px;} -.layui-layedit-tool{padding: 3px 5px; border-bottom: 1px solid #e2e2e2; font-size: 0;} -.layedit-tool-fixed{position: fixed; top: 0; border-top: 1px solid #e2e2e2;} -.layui-layedit-tool .layedit-tool-mid, -.layui-layedit-tool .layui-icon{display: inline-block; vertical-align: middle; text-align: center; font-size: 14px;} -.layui-layedit-tool .layui-icon{position: relative; width: 32px; height: 30px; line-height: 30px; margin: 3px 5px; border-radius: 2px; color: #777; cursor: pointer; border-radius: 2px;} -.layui-layedit-tool .layui-icon:hover{color: #393D49;} -.layui-layedit-tool .layui-icon:active{color: #000;} -.layui-layedit-tool .layedit-tool-active{background-color: #e2e2e2; color: #000;} -.layui-layedit-tool .layui-disabled, -.layui-layedit-tool .layui-disabled:hover{color: #d2d2d2; cursor: not-allowed;} -.layui-layedit-tool .layedit-tool-mid{width: 1px; height: 18px; margin: 0 10px; background-color: #d2d2d2;} - -.layedit-tool-html{width: 50px !important; font-size: 30px !important;} -.layedit-tool-b, -.layedit-tool-code, -.layedit-tool-help{font-size: 16px !important;} -.layedit-tool-d, -.layedit-tool-unlink, -.layedit-tool-face, -.layedit-tool-image{font-size: 18px !important;} -.layedit-tool-image input{position: absolute; font-size: 0; left: 0; top: 0; width: 100%; height: 100%; opacity: 0.01; filter: Alpha(opacity=1); cursor: pointer;} - -.layui-layedit-iframe iframe{display: block; width: 100%;} -#LAY_layedit_code{overflow: hidden;} - -/** 表格修饰 **/ -.layui-table{width: 100%; margin: 10px 0; background-color: #fff;} -.layui-table tr{transition: all .3s; -webkit-transition: all .3s;} -.layui-table thead tr{background-color: #f2f2f2;} -.layui-table th{text-align: left;} -.layui-table th, .layui-table td{padding: 9px 15px; min-height: 20px; line-height: 20px; border: 1px solid #e2e2e2; font-size: 14px;} -.layui-table[lay-even] tr:nth-child(even), -.layui-table tr:hover{background-color: #f8f8f8;} - -.layui-table[lay-skin="line"], .layui-table[lay-skin="row"]{border: 1px solid #e2e2e2;} -.layui-table[lay-skin="line"] th, .layui-table[lay-skin="line"] td{border: none; border-bottom: 1px solid #e2e2e2} -.layui-table[lay-skin="row"] th, .layui-table[lay-skin="row"] td{border: none; border-right: 1px solid #e2e2e2} -.layui-table[lay-skin="nob"] th, .layui-table[lay-skin="nob"] td{border: none;} - -/** 文件上传 **/ -.layui-upload-button{position: relative; display: inline-block; vertical-align: middle; min-width: 60px; height: 38px; line-height: 38px; border: 1px solid #DFDFDF; border-radius: 2px; overflow: hidden; background-color: #fff; color: #666;} -.layui-upload-button:hover{border: 1px solid #aaa; color: #333;} -.layui-upload-button:active{border: 1px solid #4CAF50; color: #000;} -.layui-upload-file, -.layui-upload-button input{opacity: 0.01; filter: Alpha(opacity=1); cursor: pointer;} -.layui-upload-button input{position: absolute; left: 0; top: 0; z-index: 10; font-size: 100px; width: 100%; height: 100%;} -.layui-upload-icon{display:block; margin: 0 15px; text-align: center;} -.layui-upload-icon i{margin-right: 5px; vertical-align: top; font-size: 20px; color: #5FB878} -.layui-upload-iframe{position: absolute; width: 0px; height: 0px; border: 0px; visibility: hidden;} -.layui-upload-enter{border: 1px solid #009E94; background-color: #009E94; color: #fff; -webkit-transform: scale(1.1); transform: scale(1.1);} -.layui-upload-enter .layui-upload-icon, -.layui-upload-enter .layui-upload-icon i{color: #fff;} - -/** 流加载 **/ -.layui-flow-more{margin: 10px 0; text-align: center; color: #999; font-size: 14px;} -.layui-flow-more a{ height: 32px; line-height: 32px; } -.layui-flow-more a *{display: inline-block; vertical-align: top;} -.layui-flow-more a cite{padding: 0 20px; border-radius: 3px; background-color: #eee; color: #333; font-style: normal;} -.layui-flow-more a cite:hover{opacity: 0.8;} -.layui-flow-more a i{font-size: 30px; color: #737383;} - -/** 分页 **/ -.layui-laypage{display: inline-block; *display: inline; *zoom: 1; vertical-align: middle; margin: 10px 0; font-size: 0;} -.layui-laypage>*:first-child, -.layui-laypage>*:first-child em{border-radius: 2px 0 0 2px;} -.layui-laypage>*:last-child, -.layui-laypage>*:last-child em{border-radius: 0 2px 2px 0;} -.layui-laypage span, -.layui-laypage a{display: inline-block; *display: inline; *zoom: 1; vertical-align: middle; padding: 0 15px; border: 1px solid #e2e2e2; height: 28px; line-height: 28px; margin: 0 -1px 5px 0; background-color: #fff; color: #333; font-size: 12px;} -.layui-laypage em{font-style: normal;} -.layui-laypage span{color:#999; font-weight: 700;} -.layui-laypage a{ text-decoration: none;} -.layui-laypage .layui-laypage-curr{position: relative;} -.layui-laypage .layui-laypage-curr em{position: relative; color: #fff; font-weight: 400;} -.layui-laypage .layui-laypage-curr .layui-laypage-em{position: absolute; left: -1px; top: -1px; padding: 1px; width: 100%; height: 100%; background-color: #009688; } -.layui-laypage-em{border-radius: 2px;} -.layui-laypage-prev em, -.layui-laypage-next em{font-family: Sim sun; font-size: 16px;} - -.layui-laypage .layui-laypage-total{height: 30px; line-height: 30px; margin-left: 1px; border: none;font-weight: 400;} -.layui-laypage input, .layui-laypage button{height: 30px; line-height: 30px; border:1px solid #e2e2e2; border-radius: 2px; vertical-align: top; background-color: #fff; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;} -.layui-laypage input{width: 50px; margin: 0 5px; text-align: center;} -.layui-laypage button{margin-left: 5px; padding:0 15px; cursor: pointer;} - - -/** 代码修饰器 **/ -.layui-code{position: relative; margin: 10px 0; padding: 15px; line-height: 20px; border: 1px solid #ddd; border-left-width: 6px; background-color: #F2F2F2; color: #333; font-family: Courier New; font-size: 12px;} - - -/** 树组件 **/ -.layui-tree{line-height: 26px;} -.layui-tree li{text-overflow: ellipsis; overflow:hidden; white-space: nowrap;} -.layui-tree li a, -.layui-tree li .layui-tree-spread{display: inline-block; vertical-align: top; height: 26px; *display: inline; *zoom:1; cursor: pointer;} -.layui-tree li a{font-size: 0;} -.layui-tree li a i{font-size: 16px;} -.layui-tree li a cite{padding: 0 6px; font-size: 14px; font-style: normal;} -.layui-tree li i{padding-left: 6px; color: #333; -moz-user-select: none;} -.layui-tree li .layui-tree-check{font-size: 13px;} -.layui-tree li .layui-tree-check:hover{color: #009E94;} -.layui-tree li ul{display: none; margin-left: 20px;} -.layui-tree li .layui-tree-enter{line-height: 24px; border: 1px dotted #000;} -.layui-tree-drag{display: none; position: absolute; left: -666px; top: -666px; background-color: #f2f2f2; padding: 5px 10px; border: 1px dotted #000; white-space: nowrap} -.layui-tree-drag i{padding-right: 5px;} - -/** 导航菜单 **/ -.layui-nav{position: relative; padding: 0 20px; background-color: #393D49; color: #c2c2c2; border-radius: 2px; font-size: 0; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;} -.layui-nav *{font-size: 14px;} -.layui-nav .layui-nav-item{position: relative; display: inline-block; *display: inline; *zoom: 1; vertical-align: middle; line-height: 60px;} -.layui-nav .layui-nav-item a{display: block; padding: 0 20px; color: #c2c2c2; transition: all .3s; -webkit-transition: all .3s;} -.layui-nav-bar, -.layui-nav .layui-this:after, -.layui-nav-tree .layui-nav-itemed:after{position: absolute; left: 0; top: 0; width: 0; height: 5px; background-color: #5FB878; transition: all .2s; -webkit-transition: all .2s;} -.layui-nav-bar{z-index: 1000;} -.layui-nav .layui-this a -,.layui-nav .layui-nav-item a:hover{color: #fff;} -.layui-nav .layui-this:after{content: ''; top: auto; bottom: 0; width: 100%;} - -.layui-nav .layui-nav-more{content:''; width: 0; height: 0; border-style: dashed; border-color: transparent; overflow: hidden; cursor: pointer; transition: all .2s; -webkit-transition: all .2s;} -.layui-nav .layui-nav-more{position: absolute; top: 28px; right: 3px; border-width: 6px; border-top-style: solid; border-top-color: #c2c2c2;} -.layui-nav .layui-nav-mored, -.layui-nav-itemed .layui-nav-more{top: 22px; border-style: dashed; border-color: transparent; border-bottom-style: solid; border-bottom-color: #c2c2c2;} - -.layui-nav-child{display: none; position: absolute; left: 0; top: 65px; min-width: 100%; line-height: 36px; padding: 5px 0; box-shadow: 0 2px 4px rgba(0,0,0,.12); border: 1px solid #d2d2d2; background-color: #fff; z-index: 100; border-radius: 2px; white-space: nowrap;} -.layui-nav .layui-nav-child a{color: #333;} -.layui-nav .layui-nav-child a:hover{background-color: #f2f2f2; color: #333;} -.layui-nav-child dd{position: relative;} -.layui-nav-child dd.layui-this{background-color: #5FB878; color: #fff;} -.layui-nav-child dd.layui-this a{color: #fff;} -.layui-nav-child dd.layui-this:after{display: none;} - -/* 垂直导航菜单 */.layui-nav-tree{width: 200px; padding: 0;} -.layui-nav-tree .layui-nav-item{display: block; width: 100%; line-height: 45px;} -.layui-nav-tree .layui-nav-item a{height: 45px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} -.layui-nav-tree .layui-nav-item a:hover{background-color: #4E5465;} -.layui-nav-tree .layui-nav-bar{width: 5px; height: 0;} -.layui-nav-tree .layui-this, -.layui-nav-tree .layui-this>a, -.layui-nav-tree .layui-this>a:hover, -.layui-nav-tree .layui-nav-child dd.layui-this{background-color: #009688; color: #fff;} -.layui-nav-tree .layui-this:after{display: none;} -.layui-nav-tree .layui-nav-title a, -.layui-nav-tree .layui-nav-title a:hover, -.layui-nav-itemed>a{background-color: #2B2E37 !important; color: #fff !important;} -.layui-nav-tree .layui-nav-bar{background-color: #009688;} - -.layui-nav-tree .layui-nav-child{position: relative; z-index: 0; top: 0; border: none; box-shadow: none;} -.layui-nav-tree .layui-nav-child a{height: 40px; line-height: 40px;} -.layui-nav-tree .layui-nav-child a{color: #c2c2c2;} -.layui-nav-tree .layui-nav-child a:hover, -.layui-nav-tree .layui-nav-child{background: none; color: #fff;} -.layui-nav-tree .layui-nav-more{top: 20px; right: 10px;} -.layui-nav-itemed .layui-nav-more{top: 14px;} -.layui-nav-itemed .layui-nav-child{display: block; padding: 0;} - -/* 侧边 */.layui-nav-side{position: fixed; top: 0; bottom: 0; left: 0; overflow-x: hidden; z-index: 999;} - -/** 面包屑 **/ -.layui-breadcrumb{visibility: hidden; font-size: 0;} -.layui-breadcrumb a{padding-right: 8px; line-height: 22px; font-size: 14px; color: #333 !important;} -.layui-breadcrumb a:hover{color: #01AAED !important;} -.layui-breadcrumb a span, -.layui-breadcrumb a cite{ color: #666; cursor: text; font-style: normal;} -.layui-breadcrumb a span{padding-left: 8px; font-family: Sim sun;} - -/** Tab选项卡 **/ -.layui-tab{margin: 10px 0; text-align: left !important;} -.layui-tab[overflow]>.layui-tab-title{overflow: hidden;} -.layui-tab-title{position: relative; left: 0; height: 40px; white-space: nowrap; font-size: 0; border-bottom: 1px solid #e2e2e2; transition: all .2s; -webkit-transition: all .2s;} -.layui-tab-title li{display: inline-block; *display: inline; *zoom: 1; vertical-align: middle; font-size: 14px; transition: all .2s; -webkit-transition: all .2s;} -.layui-tab-title li{position: relative; line-height: 40px; min-width: 65px; padding: 0 10px; text-align: center; cursor: pointer;} -.layui-tab-title li a{display: block;} -.layui-tab-title .layui-this{color: #000;} - -.layui-tab-title .layui-this:after{position: absolute; left:0; top: 0; content: ''; width:100%; height: 41px; border: 1px solid #e2e2e2; border-bottom-color: #fff; border-radius: 2px 2px 0 0; -webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important; pointer-events: none;} -.layui-tab-bar{position: absolute; right: 0; top: 0; z-index: 10; width: 30px; height: 39px; line-height: 39px; border: 1px solid #e2e2e2; border-radius: 2px; text-align: center; background-color: #fff; cursor: pointer;} -.layui-tab-bar .layui-icon{position: relative; display: inline-block; top: 3px; transition: all .3s; -webkit-transition: all .3s;} -.layui-tab-item{display: none;} -.layui-tab-more{padding-right: 30px; height: auto; white-space: normal;} -.layui-tab-more li.layui-this:after{border-bottom-color: #e2e2e2; border-radius: 2px;} -.layui-tab-more .layui-tab-bar .layui-icon{top: -2px; top: 3px\0; -webkit-transform: rotate(180deg); transform: rotate(180deg);} -:root .layui-tab-more .layui-tab-bar .layui-icon{top: -2px\0/IE9;} - -.layui-tab-content{padding: 10px;} - -/* Tab关闭 */.layui-tab-title li .layui-tab-close{ position: relative; margin-left: 8px; top: 1px; color: #c2c2c2; transition: all .2s; -webkit-transition: all .2s;} -.layui-tab-title li .layui-tab-close:hover{border-radius: 2px; background-color: #FF5722; color: #fff;} - -/* Tab简洁风格 */.layui-tab-brief > .layui-tab-title .layui-this{color: #009688;} -.layui-tab-brief > .layui-tab-title .layui-this:after -,.layui-tab-brief > .layui-tab-more li.layui-this:after{border: none; border-radius: 0; border-bottom: 3px solid #5FB878;} -.layui-tab-brief[overflow] > .layui-tab-title .layui-this:after{top: -1px;} - -/* Tab卡片风格 */.layui-tab-card{border: 1px solid #e2e2e2; border-radius: 2px; box-shadow: 0 2px 5px 0 rgba(0,0,0,.1);} -.layui-tab-card > .layui-tab-title{ background-color: #f2f2f2;} -.layui-tab-card > .layui-tab-title li{margin-right: -1px; margin-left: -1px;} -.layui-tab-card > .layui-tab-title .layui-this{background-color: #fff; } -.layui-tab-card > .layui-tab-title .layui-this:after{border-top: none; border-width: 1px; border-bottom-color: #fff;} -.layui-tab-card > .layui-tab-title .layui-tab-bar{height: 40px; line-height: 40px; border-radius: 0; border-top: none; border-right: none;} -.layui-tab-card > .layui-tab-more .layui-this{background: none; color: #5FB878;} -.layui-tab-card > .layui-tab-more .layui-this:after{border: none;} - -/** fixbar **/ -.layui-fixbar{position: fixed; right: 15px; bottom: 15px; z-index: 9999;} -.layui-fixbar li{width: 50px; height: 50px; line-height: 50px; margin-bottom: 1px; text-align:center; cursor: pointer; font-size:30px; background-color: #9F9F9F; color:#fff; border-radius: 2px; opacity: 0.95;} -.layui-fixbar li:hover{opacity: 0.85;} -.layui-fixbar li:active{opacity: 1;} -.layui-fixbar .layui-fixbar-top{display: none; font-size: 40px;} - -/** 表情面板 **/ -body .layui-util-face{border: none; background: none;} -body .layui-util-face .layui-layer-content{padding:0; background-color:#fff; color:#666; box-shadow:none} -.layui-util-face .layui-layer-TipsG{display:none;} -.layui-util-face ul{position:relative; width:372px; padding:10px; border:1px solid #D9D9D9; background-color:#fff; box-shadow: 0 0 20px rgba(0,0,0,.2);} -.layui-util-face ul li{cursor: pointer; float: left; border: 1px solid #e8e8e8; height: 22px; width: 26px; overflow: hidden; margin: -1px 0 0 -1px; padding: 4px 2px; text-align: center;} -.layui-util-face ul li:hover{position: relative; z-index: 2; border: 1px solid #eb7350; background: #fff9ec;} - -/** 动画 **/ -.layui-anim{-webkit-animation-duration: 0.3s; animation-duration: 0.3s; -webkit-animation-fill-mode: both; animation-fill-mode: both;} -.layui-anim-loop{-webkit-animation-iteration-count: infinite; animation-iteration-count: infinite;} - -@-webkit-keyframes layui-rotate{ /* 循环旋转 */ - from {-webkit-transform: rotate(0deg);} - to {-webkit-transform: rotate(360deg);} -} -@keyframes layui-rotate{ - from {transform: rotate(0deg);} - to {transform: rotate(360deg);} -} -.layui-anim-rotate{-webkit-animation-name: layui-rotate; animation-name: layui-rotate; -webkit-animation-duration: 1s; animation-duration: 1s; -webkit-animation-timing-function: linear; animation-timing-function: linear;} - -@-webkit-keyframes layui-up{ /* 从最底部往上滑入 */ - from {-webkit-transform: translate3d(0, 100%, 0); opacity: 0.3;} - to {-webkit-transform: translate3d(0, 0, 0); opacity: 1;} -} -@keyframes layui-up{ - from {transform: translate3d(0, 100%, 0); opacity: 0.3;} - to {transform: translate3d(0, 0, 0); opacity: 1;} -} -.layui-anim-up{-webkit-animation-name: layui-up; animation-name: layui-up;} - -@-webkit-keyframes layui-upbit{ /* 微微往上滑入 */ - from {-webkit-transform: translate3d(0, 30px, 0); opacity: 0.3;} - to {-webkit-transform: translate3d(0, 0, 0); opacity: 1;} -} -@keyframes layui-upbit{ - from {transform: translate3d(0, 30px, 0); opacity: 0.3;} - to {transform: translate3d(0, 0, 0); opacity: 1;} -} -.layui-anim-upbit{-webkit-animation-name: layui-upbit; animation-name: layui-upbit;} - -@-webkit-keyframes layui-scale { /* 放大 */ - 0% {opacity: 0.3; -webkit-transform: scale(.5);} - 100% {opacity: 1; -webkit-transform: scale(1);} -} -@keyframes layui-scale { - 0% {opacity: 0.3; -ms-transform: scale(.5); transform: scale(.5);} - 100% {opacity: 1; -ms-transform: scale(1); transform: scale(1);} -} -.layui-anim-scale{-webkit-animation-name: layui-scale; animation-name: layui-scale} - -@-webkit-keyframes layui-scale-spring { /* 弹簧式放大 */ - 0% {opacity: 0.5; -webkit-transform: scale(.5);} - 80% {opacity: 0.8; -webkit-transform: scale(1.1);} - 100% {opacity: 1; -webkit-transform: scale(1);} -} -@keyframes layui-scale-spring { - 0% {opacity: 0.5; -ms-transform: scale(.5); transform: scale(.5);} - 80% {opacity: 0.8; -ms-transform: scale(1.1); transform: scale(1.1);} - 100% {opacity: 1; -ms-transform: scale(1); transform: scale(1);} -} -.layui-anim-scaleSpring{-webkit-animation-name: layui-scale-spring; animation-name: layui-scale-spring} - - -/** 响应式(前期不作为重心) **/ -@media screen and (max-width: 450px) { - /** 表单 **/ - .layui-form-item .layui-form-label{text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} - .layui-form-item .layui-inline{display: block; margin-right: 0; margin-bottom: 20px; clear: both;} - .layui-form-item .layui-inline:after{content:'\20'; clear:both; display:block; height:0;} - .layui-form-item .layui-input-inline{display: block; float: none; left: -3px; width: auto; margin: 0 0 10px 112px; } - .layui-form-item .layui-input-inline+.layui-form-mid{margin-left: 110px; top: -5px; padding: 0;} - .layui-form-item .layui-form-checkbox{margin-right: 5px; margin-bottom: 5px;} -} - - - diff --git a/src/css/layui.mobile.css b/src/css/layui.mobile.css deleted file mode 100644 index a58b2941e..000000000 --- a/src/css/layui.mobile.css +++ /dev/null @@ -1,191 +0,0 @@ -/** - - @Name: layui mobile - @Author: 贤心 - @Site: http://www.layui.com/mobile/ - - */ - -/* reset */ -body,div,dl,dt,dd,ul,ol,li,h1,h2,h3,h4,h5,h6,input,button,textarea,p,blockquote,th,td,form,legend{margin:0; padding:0; -webkit-tap-highlight-color:rgba(0,0,0,0)} -html{font:12px 'Helvetica Neue','PingFang SC',STHeitiSC-Light,Helvetica,Arial,sans-serif; -ms-text-size-adjust:100%;-webkit-text-size-adjust:100%;} -a,button,input{-webkit-tap-highlight-color:rgba(255,0,0,0);} -a{text-decoration: none; background:transparent} -a:active,a:hover{outline:0} -table{border-collapse:collapse;border-spacing:0} -li{list-style:none;} -b,strong{font-weight:700;} -h1, h2, h3, h4, h5, h6{font-weight:500;} -address,cite,dfn,em,var{font-style:normal;} -dfn{font-style:italic} -sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline} -img{border:0; vertical-align: bottom} -button,input,optgroup,select,textarea{color:inherit;font:inherit;margin:0; outline: 0;} -button,select{text-transform:none} -select{-webkit-appearance: none; border:none;} -input{line-height:normal; } -input[type=checkbox],input[type=radio]{box-sizing:border-box;padding:0} -input[type=number]::-webkit-inner-spin-button,input[type=number]::-webkit-outer-spin-button{height:auto} -input[type=search]{-webkit-appearance:textfield;-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box} -input[type=search]::-webkit-search-cancel-button,input[type=search]::-webkit-search-decoration{-webkit-appearance:none} -label,input{vertical-align: middle;} - - -/** 图标字体 **/ -@font-face {font-family: 'layui-icon'; - src: url('../font/iconfont.eot?v=1.0.7'); - src: url('../font/iconfont.eot?v=1.0.7#iefix') format('embedded-opentype'), - url('../font/iconfont.woff?v=1.0.7') format('woff'), - url('../font/iconfont.ttf?v=1.0.7') format('truetype'), - url('../font/iconfont.svg?v=1.0.7#iconfont') format('svg'); -} - -.layui-icon{ - font-family:"layui-icon" !important; - font-size: 16px; - font-style: normal; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - - -/** 基础通用 **/ -/* 消除第三方ui可能造成的冲突 */.layui-box, .layui-box *{-webkit-box-sizing: content-box !important; -moz-box-sizing: content-box !important; box-sizing: content-box !important;} -.layui-border-box, .layui-border-box *{-webkit-box-sizing: border-box !important; -moz-box-sizing: border-box !important; box-sizing: border-box !important;} -.layui-inline{position: relative; display: inline-block; *display:inline; *zoom:1; vertical-align: middle;} -/* 三角形 */.layui-edge{position: absolute; width: 0; height: 0; border-style: dashed; border-color: transparent; overflow: hidden;} -/* 单行溢出省略 */.layui-elip{text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} -/* 屏蔽选中 */.layui-unselect{-moz-user-select: none; -webkit-user-select: none; -ms-user-select: none;} -.layui-disabled,.layui-disabled:active{background-color: #d2d2d2 !important; color: #fff !important; cursor: not-allowed !important;} -/* 纯圆角 */.layui-circle{border-radius: 100%;} -.layui-show{display: block !important;} -.layui-hide{display: none !important;} - - -.layui-upload-iframe{position: absolute; width: 0px; height: 0px; border: 0px; visibility: hidden;} -.layui-upload-enter{border: 1px solid #009E94; background-color: #009E94; color: #fff; -webkit-transform: scale(1.1); transform: scale(1.1);} - - -/* 弹出动画 */ -@-webkit-keyframes layui-m-anim-scale { /* 默认 */ - 0% {opacity: 0; -webkit-transform: scale(.5); transform: scale(.5)} - 100% {opacity: 1; -webkit-transform: scale(1); transform: scale(1)} -} -@keyframes layui-m-anim-scale { /* 由小到大 */ - 0% {opacity: 0; -webkit-transform: scale(.5); transform: scale(.5)} - 100% {opacity: 1; -webkit-transform: scale(1); transform: scale(1)} -} -.layui-m-anim-scale{animation-name: layui-m-anim-scale; -webkit-animation-name: layui-m-anim-scale;} - -@-webkit-keyframes layui-m-anim-up{ /* 从下往上 */ - 0%{opacity: 0; -webkit-transform: translateY(800px); transform: translateY(800px)} - 100%{opacity: 1; -webkit-transform: translateY(0); transform: translateY(0)} -} -@keyframes layui-m-anim-up{ - 0%{opacity: 0; -webkit-transform: translateY(800px); transform: translateY(800px)} - 100%{opacity: 1; -webkit-transform: translateY(0); transform: translateY(0)} -} -.layui-m-anim-up{-webkit-animation-name: layui-m-anim-up; animation-name: layui-m-anim-up} - -@-webkit-keyframes layui-m-anim-left{ /* 从右往左 */ - 0%{-webkit-transform: translateX(100%); transform: translateX(100%)} - 100%{-webkit-transform: translateX(0); transform: translateX(0)} -} -@keyframes layui-m-anim-left{ - 0%{-webkit-transform: translateX(100%); transform: translateX(100%)} - 100%{-webkit-transform: translateX(0); transform: translateX(0)} -} -.layui-m-anim-left{-webkit-animation-name: layui-m-anim-left; animation-name: layui-m-anim-left} - -@-webkit-keyframes layui-m-anim-right{ /* 从左往右 */ - 0%{-webkit-transform: translateX(-100%); transform: translateX(-100%)} - 100%{-webkit-transform: translateX(0); transform: translateX(0)} -} -@keyframes layui-m-anim-right{ - 0%{-webkit-transform: translateX(-100%); transform: translateX(-100%)} - 100%{-webkit-transform: translateX(0); transform: translateX(0)} -} -.layui-m-anim-right{-webkit-animation-name: layui-m-anim-right; animation-name: layui-m-anim-right} - -@-webkit-keyframes layui-m-anim-lout{ /* 往左收缩 */ - 0%{-webkit-transform: translateX(0); transform: translateX(0)} - 100%{-webkit-transform: translateX(-100%); transform: translateX(-100%)} -} -@keyframes layui-m-anim-lout{ - 0%{-webkit-transform: translateX(0); transform: translateX(0)} - 100%{-webkit-transform: translateX(-100%); transform: translateX(-100%)} -} -.layui-m-anim-lout{-webkit-animation-name: layui-m-anim-lout; animation-name: layui-m-anim-lout} - -@-webkit-keyframes layui-m-anim-rout{ /* 往右收缩 */ - 0%{-webkit-transform: translateX(0); transform: translateX(0)} - 100%{-webkit-transform: translateX(100%); transform: translateX(100%)} -} -@keyframes layui-m-anim-rout{ - 0%{-webkit-transform: translateX(0); transform: translateX(0)} - 100%{-webkit-transform: translateX(100%); transform: translateX(100%)} -} -.layui-m-anim-rout{-webkit-animation-name: layui-m-anim-rout; animation-name: layui-m-anim-rout} - - -/** layer mobile */ -.layui-m-layer{position:relative; z-index: 19891014;} -.layui-m-layer *{-webkit-box-sizing: content-box; -moz-box-sizing: content-box; box-sizing: content-box;} -.layui-m-layershade, -.layui-m-layermain{position:fixed; left:0; top:0; width:100%; height:100%;} -.layui-m-layershade{background-color:rgba(0,0,0, .7); pointer-events:auto;} -.layui-m-layermain{display:table; font-family: Helvetica, arial, sans-serif; pointer-events: none;} -.layui-m-layermain .layui-m-layersection{display:table-cell; vertical-align:middle; text-align:center;} -.layui-m-layerchild{position:relative; display:inline-block; text-align:left; background-color:#fff; font-size:14px; border-radius: 5px; box-shadow: 0 0 8px rgba(0, 0, 0, 0.1); pointer-events:auto; -webkit-overflow-scrolling: touch;} -.layui-m-layerchild{-webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration: .2s; animation-duration: .2s;} - -.layui-m-layer0 .layui-m-layerchild{width: 90%; max-width: 640px;} -.layui-m-layer1 .layui-m-layerchild{border:none; border-radius:0;} -.layui-m-layer2 .layui-m-layerchild{width:auto; max-width:260px; min-width:40px; border:none; background: none; box-shadow: none; color:#fff;} -.layui-m-layerchild h3{padding: 0 10px; height: 60px; line-height: 60px; font-size:16px; font-weight: 400; border-radius: 5px 5px 0 0; text-align: center;} -.layui-m-layerchild h3, -.layui-m-layerbtn span{ text-overflow:ellipsis; overflow:hidden; white-space:nowrap;} -.layui-m-layercont{padding: 50px 30px; line-height: 22px; text-align:center;} -.layui-m-layer1 .layui-m-layercont{padding:0; text-align:left;} -.layui-m-layer2 .layui-m-layercont{text-align:center; padding: 0; line-height: 0;} -.layui-m-layer2 .layui-m-layercont i{width:25px; height:25px; margin-left:8px; display:inline-block; background-color:#fff; border-radius:100%;} -.layui-m-layer2 .layui-m-layercont p{margin-top: 20px;} - -/* loading */ -@-webkit-keyframes layui-m-anim-loading{ - 0%,80%,100%{transform:scale(0); -webkit-transform:scale(0)} - 40%{transform:scale(1); -webkit-transform:scale(1)} -} -@keyframes layui-m-anim-loading{ - 0%,80%,100%{transform:scale(0); -webkit-transform:scale(0)} - 40%{transform:scale(1); -webkit-transform:scale(1)} -} -.layui-m-layer2 .layui-m-layercont i{-webkit-animation: layui-m-anim-loading 1.4s infinite ease-in-out; animation: layui-m-anim-loading 1.4s infinite ease-in-out; -webkit-animation-fill-mode: both; animation-fill-mode: both;} - -.layui-m-layer2 .layui-m-layercont i:first-child{margin-left:0; -webkit-animation-delay: -.32s; animation-delay: -.32s;} -.layui-m-layer2 .layui-m-layercont i.layui-m-layerload{-webkit-animation-delay: -.16s; animation-delay: -.16s;} -.layui-m-layer2 .layui-m-layercont>div{line-height:22px; padding-top:7px; margin-bottom:20px; font-size: 14px;} -.layui-m-layerbtn{display: box; display: -moz-box; display: -webkit-box; width: 100%; position:relative; height: 50px; line-height: 50px; font-size: 0; text-align:center; border-top:1px solid #D0D0D0; background-color: #F2F2F2; border-radius: 0 0 5px 5px;} -.layui-m-layerbtn span{position:relative; display: block; -moz-box-flex: 1; box-flex: 1; -webkit-box-flex: 1; text-align:center; font-size:14px; border-radius: 0 0 5px 5px; cursor:pointer;} -.layui-m-layerbtn span[yes]{color: #40AFFE;} -.layui-m-layerbtn span[no]{border-right: 1px solid #D0D0D0; border-radius: 0 0 0 5px;} -.layui-m-layerbtn span:active{background-color: #F6F6F6;} -.layui-m-layerend{position:absolute; right:7px; top:10px; width:30px; height:30px; border: 0; font-weight:400; background: transparent; cursor: pointer; -webkit-appearance: none; font-size:30px;} -.layui-m-layerend::before, .layui-m-layerend::after{position:absolute; left:5px; top:15px; content:''; width:18px; height:1px; background-color:#999; transform:rotate(45deg); -webkit-transform:rotate(45deg); border-radius: 3px;} -.layui-m-layerend::after{transform:rotate(-45deg); -webkit-transform:rotate(-45deg);} - -/* 底部对话框风格 */ -body .layui-m-layer .layui-m-layer-footer{position: fixed; width: 95%; max-width: 100%; margin: 0 auto; left:0; right: 0; bottom: 10px; background: none;} -.layui-m-layer-footer .layui-m-layercont{padding: 20px; border-radius: 5px 5px 0 0; background-color: rgba(255,255,255,.8);} -.layui-m-layer-footer .layui-m-layerbtn{display: block; height: auto; background: none; border-top: none;} -.layui-m-layer-footer .layui-m-layerbtn span{background-color: rgba(255,255,255,.8);} -.layui-m-layer-footer .layui-m-layerbtn span[no]{color: #FD482C; border-top: 1px solid #c2c2c2; border-radius: 0 0 5px 5px;} -.layui-m-layer-footer .layui-m-layerbtn span[yes]{margin-top: 10px; border-radius: 5px;} - -/* 通用提示 */ -body .layui-m-layer .layui-m-layer-msg{width: auto; max-width: 90%; margin: 0 auto; bottom: -150px; background-color: rgba(0,0,0,.7); color: #fff;} -.layui-m-layer-msg .layui-m-layercont{padding: 10px 20px;} - - - - diff --git a/src/css/modules/anim.css b/src/css/modules/anim.css new file mode 100644 index 000000000..2b50db555 --- /dev/null +++ b/src/css/modules/anim.css @@ -0,0 +1,265 @@ +/** 动画 **/ +.lay-anim { + -webkit-animation-duration: 0.3s; + -webkit-animation-fill-mode: both; + animation-duration: 0.3s; + animation-fill-mode: both; +} +.lay-anim.lay-icon { + display: inline-block; +} +.lay-anim-loop { + -webkit-animation-iteration-count: infinite; + animation-iteration-count: infinite; +} +.lay-trans, +.lay-trans a { + -webkit-transition: all 0.2s; + transition: all 0.2s; +} /* 过渡变换 */ + +/* 循环旋转 */ +@-webkit-keyframes lay-rotate { + from { + -webkit-transform: rotate(0deg); + } + to { + -webkit-transform: rotate(360deg); + } +} +@keyframes lay-rotate { + from { + transform: rotate(0deg); + } + to { + transform: rotate(360deg); + } +} +.lay-anim-rotate { + -webkit-animation-name: lay-rotate; + animation-name: lay-rotate; + -webkit-animation-duration: 1s; + animation-duration: 1s; + -webkit-animation-timing-function: linear; + animation-timing-function: linear; +} + +/* 从最底部往上滑入 */ +@-webkit-keyframes lay-up { + from { + -webkit-transform: translate3d(0, 100%, 0); + opacity: 0.3; + } + to { + -webkit-transform: translate3d(0, 0, 0); + opacity: 1; + } +} +@keyframes lay-up { + from { + transform: translate3d(0, 100%, 0); + opacity: 0.3; + } + to { + transform: translate3d(0, 0, 0); + opacity: 1; + } +} +.lay-anim-up { + -webkit-animation-name: lay-up; + animation-name: lay-up; +} + +/* 微微往上滑入 */ +@-webkit-keyframes lay-upbit { + from { + -webkit-transform: translate3d(0, 15px, 0); + opacity: 0.3; + } + to { + -webkit-transform: translate3d(0, 0, 0); + opacity: 1; + } +} +@keyframes lay-upbit { + from { + transform: translate3d(0, 15px, 0); + opacity: 0.3; + } + to { + transform: translate3d(0, 0, 0); + opacity: 1; + } +} +.lay-anim-upbit { + -webkit-animation-name: lay-upbit; + animation-name: lay-upbit; +} + +/* 从最顶部往下滑入 */ +@keyframes lay-down { + 0% { + opacity: 0.3; + transform: translate3d(0, -100%, 0); + } + 100% { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} +.lay-anim-down { + animation-name: lay-down; +} + +/* 微微往下滑入 */ +@keyframes lay-downbit { + 0% { + opacity: 0.3; + transform: translate3d(0, -5px, 0); + } + 100% { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} +.lay-anim-downbit { + animation-name: lay-downbit; +} + +/* 放大 */ +@-webkit-keyframes lay-scale { + 0% { + opacity: 0.3; + -webkit-transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + } +} +@keyframes lay-scale { + 0% { + opacity: 0.3; + transform: scale(0.5); + } + 100% { + opacity: 1; + transform: scale(1); + } +} +.lay-anim-scale { + -webkit-animation-name: lay-scale; + animation-name: lay-scale; +} + +/* 弹簧式放大 */ +@-webkit-keyframes lay-scale-spring { + 0% { + opacity: 0.5; + -webkit-transform: scale(0.5); + } + 80% { + opacity: 0.8; + -webkit-transform: scale(1.1); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + } +} +@keyframes lay-scale-spring { + 0% { + opacity: 0.5; + transform: scale(0.5); + } + 80% { + opacity: 0.8; + transform: scale(1.1); + } + 100% { + opacity: 1; + transform: scale(1); + } +} +.lay-anim-scaleSpring { + -webkit-animation-name: lay-scale-spring; + animation-name: lay-scale-spring; +} + +/* 放小 */ +@keyframes lay-scalesmall { + 0% { + opacity: 0.3; + transform: scale(1.5); + } + 100% { + opacity: 1; + transform: scale(1); + } +} +.lay-anim-scalesmall { + animation-name: lay-scalesmall; +} + +/* 弹簧式放小 */ +@keyframes lay-scalesmall-spring { + 0% { + opacity: 0.3; + transform: scale(1.5); + } + 80% { + opacity: 0.8; + transform: scale(0.9); + } + 100% { + opacity: 1; + transform: scale(1); + } +} +.lay-anim-scalesmall-spring { + animation-name: lay-scalesmall-spring; +} + +/* 渐显 */ +@-webkit-keyframes lay-fadein { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes lay-fadein { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +.lay-anim-fadein { + -webkit-animation-name: lay-fadein; + animation-name: lay-fadein; +} + +/* 渐隐 */ +@-webkit-keyframes lay-fadeout { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +@keyframes lay-fadeout { + 0% { + opacity: 1; + } + 100% { + opacity: 0; + } +} +.lay-anim-fadeout { + -webkit-animation-name: lay-fadeout; + animation-name: lay-fadeout; +} diff --git a/src/css/modules/auxiliary.css b/src/css/modules/auxiliary.css new file mode 100644 index 000000000..02a49a777 --- /dev/null +++ b/src/css/modules/auxiliary.css @@ -0,0 +1,76 @@ +/* + * 辅助类 + */ + +.lay-btn, +.lay-input, +.lay-select, +.lay-textarea, +.lay-upload-button { + outline: none; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + -webkit-transition: all 0.3s; + transition: all 0.3s; + box-sizing: border-box; +} + +/* 引用 */ +.lay-elem-quote { + margin-bottom: 10px; + padding: var(--lay-spacing); + line-height: 1.8; + border-left: 5px solid var(--lay-color-accent); + border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0; + background-color: var(--lay-color-gray); +} +.lay-quote-nm { + border-style: solid; + border-width: 1px; + border-left-width: 5px; + background: none; +} + +/* 字段集合 */ +.lay-elem-field { + margin-bottom: 10px; + padding: 0; + border-width: 1px; + border-style: solid; +} +.lay-elem-field legend { + margin-left: 20px; + padding: 0 10px; + font-size: 20px; +} +.lay-field-title { + margin: var(--lay-spacing) 0; + border-width: 0; + border-top-width: 1px; +} +.lay-field-box { + padding: var(--lay-spacing); +} +.lay-field-title .lay-field-box { + padding: 10px 0; +} + +/* 其它辅助 */ +.lay-auxiliar-moving { + position: fixed; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + background: none; + z-index: 9999999999; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} +.lay-scrollbar-hide { + overflow: hidden !important; +} diff --git a/src/css/modules/badge.css b/src/css/modules/badge.css new file mode 100644 index 000000000..d4882031a --- /dev/null +++ b/src/css/modules/badge.css @@ -0,0 +1,50 @@ +/* 小徽章 */ +.lay-badge, +.lay-badge-dot, +.lay-badge-rim { + position: relative; + display: inline-block; + padding: 0 6px; + font-size: 12px; + text-align: center; + background-color: var(--lay-color-red); + color: #fff; + border-radius: var(--lay-border-radius); +} +.lay-badge { + height: 18px; + line-height: 18px; +} +.lay-badge-dot { + width: 8px; + height: 8px; + padding: 0; + border-radius: 50%; +} +.lay-badge-rim { + height: 18px; + line-height: 18px; + border-width: 1px; + border-style: solid; + background-color: #fff; + color: #5f5f5f; +} + +.lay-btn .lay-badge, +.lay-btn .lay-badge-dot { + margin-left: 5px; +} +.lay-nav .lay-badge, +.lay-nav .lay-badge-dot { + position: absolute; + top: 50%; + margin: -5px 6px 0; +} +.lay-nav .lay-badge { + margin-top: -10px; +} +.lay-tab-title .lay-badge, +.lay-tab-title .lay-badge-dot { + left: 5px; + top: -2px; +} diff --git a/src/css/modules/button.css b/src/css/modules/button.css new file mode 100644 index 000000000..e2ae61cfb --- /dev/null +++ b/src/css/modules/button.css @@ -0,0 +1,158 @@ +/* + * 按钮 + */ + +.lay-btn { + display: inline-block; + vertical-align: middle; + height: 38px; + line-height: 36px; + border: 1px solid transparent; + padding: 0 18px; + background-color: var(--lay-color-primary); + color: #fff; + white-space: nowrap; + text-align: center; + font-size: 14px; + border-radius: var(--lay-border-radius); + cursor: pointer; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.lay-btn:hover { + opacity: 0.8; + color: #fff; +} +.lay-btn:active { + opacity: 1; +} +.lay-btn + .lay-btn { + margin-left: 10px; +} + +/* 按钮容器 */ +.lay-btn-container { + word-spacing: -5px; +} +.lay-btn-container .lay-btn { + margin-right: 10px; + margin-bottom: 10px; + word-spacing: normal; +} +.lay-btn-container .lay-btn + .lay-btn { + margin-left: 0; +} +.lay-table .lay-btn-container .lay-btn { + margin-bottom: 9px; +} + +/* 圆角 */ +.lay-btn-radius { + border-radius: 100px; +} +.lay-btn .lay-icon { + padding: 0 2px; + vertical-align: bottom; +} + +/* 原始 */ +.lay-btn-primary { + border-color: var(--lay-border-color-accent); + background: none; + color: #5f5f5f; +} +.lay-btn-primary:hover { + border-color: var(--lay-color-primary); + color: #333; +} +/* 百搭 */ +.lay-btn-normal { + background-color: var(--lay-color-blue); +} +/* 暖色 */ +.lay-btn-warm { + background-color: var(--lay-color-orange); +} +/* 警告 */ +.lay-btn-danger { + background-color: var(--lay-color-red); +} +/* 选中 */ +.lay-btn-checked { + background-color: var(--lay-color-accent); +} +/* 禁用 */ +.lay-btn-disabled, +.lay-btn-disabled:hover, +.lay-btn-disabled:active { + border-color: var(--lay-border-color) !important; + background-color: #fbfbfb !important; + color: var(--lay-gray-400) !important; + cursor: not-allowed !important; + opacity: 1; +} + +/* 大型 */ +.lay-btn-lg { + height: 44px; + line-height: 44px; + padding: 0 25px; + font-size: 16px; +} +/* 小型 */ +.lay-btn-sm { + height: 30px; + line-height: 30px; + padding: 0 10px; + font-size: 12px; +} +/* 超小 */ +.lay-btn-xs { + height: 22px; + line-height: 22px; + padding: 0 5px; + font-size: 12px; +} +.lay-btn-xs i { + font-size: 12px !important; +} +/* 按钮组 */ +.lay-btn-group { + display: inline-block; + vertical-align: middle; + font-size: 0; +} +.lay-btn-group .lay-btn { + margin-left: 0 !important; + margin-right: 0 !important; + border-left: 1px solid rgba(255, 255, 255, 0.5); + border-radius: 0; +} +.lay-btn-group .lay-btn-primary { + border-left: none; +} +.lay-btn-group .lay-btn-primary:hover { + border-color: var(--lay-border-color-accent); + color: var(--lay-color-primary); +} +.lay-btn-group .lay-btn:first-child { + border-left: none; + border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius); +} +.lay-btn-group .lay-btn-primary:first-child { + border-left: 1px solid var(--lay-gray-400); +} +.lay-btn-group .lay-btn:last-child { + border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0; +} +.lay-btn-group .lay-btn + .lay-btn { + margin-left: 0; +} +.lay-btn-group + .lay-btn-group { + margin-left: 10px; +} +/* 流体 */ +.lay-btn-fluid { + width: 100%; +} diff --git a/src/css/modules/carousel.css b/src/css/modules/carousel.css new file mode 100644 index 000000000..30627fdc2 --- /dev/null +++ b/src/css/modules/carousel.css @@ -0,0 +1,251 @@ +/* carousel 轮播 */ +.lay-carousel { + position: relative; + left: 0; + top: 0; + background-color: #f8f8f8; +} +.lay-carousel > *[carousel-item] { + position: relative; + width: 100%; + height: 100%; + overflow: hidden; +} +.lay-carousel > *[carousel-item]:before { + position: absolute; + content: '\e63d'; + left: 50%; + top: 50%; + width: 100px; + line-height: 20px; + margin: -10px 0 0 -50px; + text-align: center; + color: #c2c2c2; + font-family: 'lay-icon' !important; + font-size: 30px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} +.lay-carousel > *[carousel-item] > * { + display: none; + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + background-color: #f8f8f8; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; +} +.lay-carousel-updown > * { + -webkit-transition: 0.3s ease-in-out up; + transition: 0.3s ease-in-out up; +} +.lay-carousel-arrow { + opacity: 0; + position: absolute; + left: 10px; + top: 50%; + margin-top: -18px; + width: 36px; + height: 36px; + line-height: 36px; + text-align: center; + font-size: 20px; + border: none 0; + border-radius: 50%; + background-color: rgba(0, 0, 0, 0.2); + color: #fff; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; + cursor: pointer; +} +.lay-carousel-arrow[lay-type='add'] { + left: auto !important; + right: 10px; +} +.lay-carousel[lay-arrow='always'] .lay-carousel-arrow { + opacity: 1; + left: 20px; +} +.lay-carousel[lay-arrow='always'] .lay-carousel-arrow[lay-type='add'] { + right: 20px; +} +.lay-carousel[lay-arrow='none'] .lay-carousel-arrow { + display: none; +} +.lay-carousel-arrow:hover, +.lay-carousel-ind ul:hover { + background-color: rgba(0, 0, 0, 0.35); +} +.lay-carousel:hover .lay-carousel-arrow { + opacity: 1; + left: 20px; +} +.lay-carousel:hover .lay-carousel-arrow[lay-type='add'] { + right: 20px; +} +.lay-carousel-ind { + position: relative; + top: -35px; + width: 100%; + line-height: 0 !important; + text-align: center; + font-size: 0; +} +.lay-carousel[lay-indicator='outside'] { + margin-bottom: 30px; +} +.lay-carousel[lay-indicator='outside'] .lay-carousel-ind { + top: 10px; +} +.lay-carousel[lay-indicator='outside'] .lay-carousel-ind ul { + background-color: rgba(0, 0, 0, 0.5); +} +.lay-carousel[lay-indicator='none'] .lay-carousel-ind { + display: none; +} +.lay-carousel-ind ul { + display: inline-block; + padding: 5px; + background-color: rgba(0, 0, 0, 0.2); + border-radius: 10px; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; +} +.lay-carousel-ind ul li { + display: inline-block; + width: 10px; + height: 10px; + margin: 0 3px; + font-size: 14px; + background-color: var(--lay-gray-300); + background-color: rgba(255, 255, 255, 0.5); + border-radius: 50%; + cursor: pointer; + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; +} +.lay-carousel-ind ul li:hover { + background-color: rgba(255, 255, 255, 0.7); +} +.lay-carousel-ind ul li.lay-this { + background-color: #fff; +} +.lay-carousel > *[carousel-item] > .lay-this, +.lay-carousel > *[carousel-item] > .lay-carousel-prev, +.lay-carousel > *[carousel-item] > .lay-carousel-next { + display: block; +} +.lay-carousel > *[carousel-item] > .lay-this { + -webkit-transform: translateX(0); + transform: translateX(0); +} +.lay-carousel > *[carousel-item] > .lay-carousel-prev { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} +.lay-carousel > *[carousel-item] > .lay-carousel-next { + -webkit-transform: translateX(100%); + transform: translateX(100%); +} +.lay-carousel > *[carousel-item] > .lay-carousel-prev.lay-carousel-right, +.lay-carousel > *[carousel-item] > .lay-carousel-next.lay-carousel-left { + -webkit-transform: translateX(0); + transform: translateX(0); +} +.lay-carousel > *[carousel-item] > .lay-this.lay-carousel-left { + -webkit-transform: translateX(-100%); + transform: translateX(-100%); +} +.lay-carousel > *[carousel-item] > .lay-this.lay-carousel-right { + -webkit-transform: translateX(100%); + transform: translateX(100%); +} + +/* 上下切换 */ +.lay-carousel[lay-anim='updown'] .lay-carousel-arrow { + left: 50% !important; + top: 20px; + margin: 0 0 0 -18px; +} +.lay-carousel[lay-anim='updown'] .lay-carousel-arrow[lay-type='add'] { + top: auto !important; + bottom: 20px; +} +.lay-carousel[lay-anim='updown'] .lay-carousel-ind { + position: absolute; + top: 50%; + right: 20px; + width: auto; + height: auto; +} +.lay-carousel[lay-anim='updown'] .lay-carousel-ind ul { + padding: 3px 5px; +} +.lay-carousel[lay-anim='updown'] .lay-carousel-ind li { + display: block; + margin: 6px 0; +} + +.lay-carousel[lay-anim='updown'] > *[carousel-item] > * { + left: 0 !important; +} +.lay-carousel[lay-anim='updown'] > *[carousel-item] > .lay-this { + -webkit-transform: translateY(0); + transform: translateY(0); +} +.lay-carousel[lay-anim='updown'] > *[carousel-item] > .lay-carousel-prev { + -webkit-transform: translateY(-100%); + transform: translateY(-100%); +} +.lay-carousel[lay-anim='updown'] > *[carousel-item] > .lay-carousel-next { + -webkit-transform: translateY(100%); + transform: translateY(100%); +} +.lay-carousel[lay-anim='updown'] + > *[carousel-item] + > .lay-carousel-prev.lay-carousel-right, +.lay-carousel[lay-anim='updown'] + > *[carousel-item] + > .lay-carousel-next.lay-carousel-left { + -webkit-transform: translateY(0); + transform: translateY(0); +} +.lay-carousel[lay-anim='updown'] + > *[carousel-item] + > .lay-this.lay-carousel-left { + -webkit-transform: translateY(-100%); + transform: translateY(-100%); +} +.lay-carousel[lay-anim='updown'] + > *[carousel-item] + > .lay-this.lay-carousel-right { + -webkit-transform: translateY(100%); + transform: translateY(100%); +} + +/* 渐显切换 */ +.lay-carousel[lay-anim='fade'] > *[carousel-item] > * { + -webkit-transform: translateX(0) !important; + transform: translateX(0) !important; +} +.lay-carousel[lay-anim='fade'] > *[carousel-item] > .lay-carousel-prev, +.lay-carousel[lay-anim='fade'] > *[carousel-item] > .lay-carousel-next { + opacity: 0; +} +.lay-carousel[lay-anim='fade'] + > *[carousel-item] + > .lay-carousel-prev.lay-carousel-right, +.lay-carousel[lay-anim='fade'] + > *[carousel-item] + > .lay-carousel-next.lay-carousel-left { + opacity: 1; +} +.lay-carousel[lay-anim='fade'] > *[carousel-item] > .lay-this.lay-carousel-left, +.lay-carousel[lay-anim='fade'] + > *[carousel-item] + > .lay-this.lay-carousel-right { + opacity: 0; +} diff --git a/src/css/modules/code.css b/src/css/modules/code.css index 643c6d4ff..9d7162ff7 100644 --- a/src/css/modules/code.css +++ b/src/css/modules/code.css @@ -1,23 +1,293 @@ /** - - @Name: layui.code - @Author: 贤心 - @Site: http://www.layui.com - + * code */ -/* 加载就绪标志 */ -html #layuicss-skincodecss{display:none; position: absolute; width:1989px;} - -/* 默认风格 */ -.layui-code-view{display: block; position: relative; margin: 10px 0; padding: 0; border: 1px solid #ddd; border-left-width: 6px; background-color: #F2F2F2; color: #333; font-family: Courier New; font-size: 12px;} -.layui-code-h3{position: relative; padding: 0 10px; height: 30px; line-height: 30px; border-bottom: 1px solid #ddd; font-size: 12px;} -.layui-code-h3 a{position: absolute; right: 10px; top: 0; color: #999;} -.layui-code-view .layui-code-ol{position: relative; overflow: auto;} -.layui-code-view .layui-code-ol li{position: relative; margin-left: 45px; line-height: 20px; padding: 0 5px; border-left: 1px solid #ddd; list-style-type: decimal-leading-zero; *list-style-type: decimal; background-color: #fff;} -.layui-code-view pre{margin: 0;} - -/* notepadd++风格 */ -.layui-code-notepad{border: 1px solid #0C0C0C; border-left-color: #3F3F3F; background-color: #0C0C0C; color: #C2BE9E} -.layui-code-notepad .layui-code-h3{border-bottom: none;} -.layui-code-notepad .layui-code-ol li{background-color: #3F3F3F; border-left: none;} \ No newline at end of file +/** 代码文本修饰 **/ +.lay-code { + display: block; + position: relative; + padding: 15px; + line-height: 20px; + border: 1px solid var(--lay-border-color); + border-left-width: 6px; + background-color: var(--lay-gray-100); + font-family: var(--lay-font-monospace); + font-size: 12px; +} + +/* 字体 */ +.lay-code-wrap { + font-size: 0.875rem; + font-family: var(--lay-font-monospace); +} + +/* 基础结构 */ +.lay-code-view { + display: block; + position: relative; + padding: 0 !important; + border: 1px solid var(--lay-border-color); + border-left-width: 6px; + background-color: var(--lay-gray-100); + + --lay-code-side-width: 45px; +} +.lay-code-view pre { + margin: 0 !important; +} + +.lay-code-header { + position: relative; + z-index: 3; + padding: 0 11px; + height: 40px; + line-height: 40px; + border-bottom: 1px solid var(--lay-border-color); + background-color: var(--lay-color-gray); + font-size: 12px; +} +.lay-code-header > .lay-code-header-about { + position: absolute; + right: 11px; + top: 0; + color: #b7b7b7; +} +.lay-code-header-about > a { + padding-left: 10px; +} + +.lay-code-wrap { + position: relative; + display: block; + z-index: 1; + margin: 0 !important; + padding: 11px 0 !important; + overflow-x: hidden; + overflow-y: auto; +} +.lay-code-line { + position: relative; + line-height: inherit; + margin: 0 !important; +} +.lay-code-line-number { + position: absolute; + left: 0; + top: 0; + padding: 0 8px; + min-width: var(--lay-code-side-width); + height: 100%; + text-align: right; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; + white-space: nowrap; + overflow: hidden; +} +.lay-code-line-content { + padding: 0 11px; + word-wrap: break-word; + white-space: pre-wrap; +} + +.lay-code-ln-mode > .lay-code-wrap > .lay-code-line { + padding-left: var(--lay-code-side-width); +} +.lay-code-ln-side { + position: absolute; + left: 0; + top: 0; + bottom: 0; + z-index: 0; + width: var(--lay-code-side-width); + border-right: 1px solid var(--lay-border-color); + border-color: rgb(126 122 122 / 15%); + background-color: var(--lay-color-gray); + pointer-events: none; +} + +/* 不自动换行 */ +.lay-code-nowrap > .lay-code-wrap { + overflow: auto; +} +.lay-code-nowrap > .lay-code-wrap > .lay-code-line > .lay-code-line-content { + white-space: pre; + word-wrap: normal; +} +.lay-code-nowrap > .lay-code-ln-side { + border-right-width: 0 !important; + background: none !important; +} + +.lay-code-fixbar { + position: absolute; + top: 8px; + right: 11px; + padding-right: var(--lay-code-side-width); + z-index: 5; +} +.lay-code-fixbar > span { + position: absolute; + right: 0; + top: 0; + padding: 0 8px; + color: #777; + transition: all 0.3s; +} +.lay-code-fixbar > span:hover { + color: var(--lay-color-accent); +} +.lay-code-copy { + display: none; + cursor: pointer; +} +.lay-code-preview > .lay-code-view > .lay-code-fixbar .lay-code-copy { + display: none !important; +} +.lay-code-preview > .lay-tabs .lay-tabs-header li { + min-width: 58px; +} +.lay-code-view:hover > .lay-code-fixbar .lay-code-copy { + display: block; +} +.lay-code-view:hover > .lay-code-fixbar .lay-code-lang-marker { + display: none; +} + +/* 深色主题 */ +.lay-code-theme-dark, +.lay-code-theme-dark > .lay-code-header { + border-color: rgb(126 122 122 / 15%); + background-color: #1f1f1f; +} +.lay-code-theme-dark { + border-width: 1px; + color: #ccc; +} +.lay-code-theme-dark > .lay-code-ln-side { + border-right-color: #2a2a2a; + background: none; + color: #6e7681; +} + +/* 代码预览 */ +.lay-code textarea { + display: none; +} +.lay-code-preview > .lay-code, +.lay-code-preview > .lay-code-view { + margin: 0; +} +.lay-code-preview > .lay-tab { + position: relative; + z-index: 1; + margin-bottom: 0; +} +.lay-code-preview .lay-code-item { + display: none; + border-top-width: 0; +} +.lay-code-item-preview { + position: relative; + padding: var(--lay-spacing); +} +.lay-code-item-preview > iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + border: none; +} + +/* 工具栏 */ +.lay-code-tools { + position: absolute; + right: 11px; + top: 8px; + line-height: normal; +} +.lay-code-tools > i { + display: inline-block; + margin-left: 6px; + padding: 3px; + cursor: pointer; +} +.lay-code-tools > i.lay-icon-file-b { + color: #999; +} +.lay-code-tools > i:hover { + color: var(--lay-color-accent); +} + +/* 全屏风格 */ +.lay-code-full { + position: fixed; + left: 0; + top: 0; + z-index: 1111111; + width: 100%; + height: 100%; + background-color: #fff; +} +.lay-code-full .lay-code-item { + width: 100% !important; + border-width: 0 !important; +} +.lay-code-full .lay-code-item, +.lay-code-full .lay-code-view, +.lay-code-full .lay-code-wrap { + height: calc(100vh - 40px) !important; + box-sizing: border-box; +} +.lay-code-full .lay-code-item-preview { + overflow: auto; +} + +/* 代码高亮重置 */ +.lay-code-view.lay-code-hl { + line-height: 20px !important; + border-left-width: 1px; +} +.lay-code-view.lay-code-hl > .lay-code-ln-side { + background-color: transparent; +} +.lay-code-theme-dark.lay-code-hl, +.lay-code-theme-dark.lay-code-hl > .lay-code-ln-side { + border-color: rgb(126 122 122 / 15%); +} + +/*行高亮*/ +.lay-code-line-highlighted { + background-color: rgba(142, 150, 170, 0.14); +} +.lay-code-line-diff-add { + background-color: rgba(16, 185, 129, 0.14); +} +.lay-code-line-diff-remove { + background-color: rgba(244, 63, 94, 0.14); +} +.lay-code-line-diff-add:before { + position: absolute; + content: '+'; + color: #18794e; +} +.lay-code-line-diff-remove:before { + position: absolute; + content: '-'; + color: #b8272c; +} +.lay-code-has-focused-lines .lay-code-line:not(.lay-code-line-has-focus) { + filter: blur(0.095rem); + opacity: 0.7; + -webkit-transition: + filter 0.35s, + opacity 0.35s; + transition: + filter 0.35s, + opacity 0.35s; +} +.lay-code-has-focused-lines:hover .lay-code-line:not(.lay-code-line-has-focus) { + filter: blur(); + opacity: 1; +} diff --git a/src/css/modules/colorpicker.css b/src/css/modules/colorpicker.css new file mode 100644 index 000000000..4da204046 --- /dev/null +++ b/src/css/modules/colorpicker.css @@ -0,0 +1,192 @@ +/** 颜色选择器 **/ +.lay-colorpicker { + width: 38px; + height: 38px; + border: 1px solid var(--lay-border-color); + padding: 5px; + border-radius: var(--lay-border-radius); + line-height: 24px; + display: inline-block; + cursor: pointer; + -webkit-transition: all 0.3s; + transition: all 0.3s; + box-sizing: border-box; +} +.lay-colorpicker:hover { + border-color: var(--lay-gray-400); +} +.lay-colorpicker.lay-colorpicker-lg { + width: 44px; + height: 44px; + line-height: 30px; +} +.lay-colorpicker.lay-colorpicker-sm { + width: 30px; + height: 30px; + line-height: 20px; + padding: 3px; +} +.lay-colorpicker.lay-colorpicker-xs { + width: 22px; + height: 22px; + line-height: 16px; + padding: 1px; +} + +.lay-colorpicker-trigger-bgcolor { + display: block; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); + border-radius: var(--lay-border-radius); +} +.lay-colorpicker-trigger-span { + display: block; + height: 100%; + box-sizing: border-box; + border: 1px solid rgba(0, 0, 0, 0.15); + border-radius: var(--lay-border-radius); + text-align: center; +} +.lay-colorpicker-trigger-i { + display: inline-block; + color: #fff; + font-size: 12px; +} +.lay-colorpicker-trigger-i.lay-icon-close { + color: #999; +} + +.lay-colorpicker-main { + position: absolute; + left: -999999px; + top: -999999px; + z-index: 77777777; + width: 280px; + margin: 5px 0; + padding: 7px; + background: #fff; + border: 1px solid var(--lay-border-color); + border-radius: var(--lay-border-radius); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); +} +.lay-colorpicker-main-wrapper { + height: 180px; + position: relative; +} +.lay-colorpicker-basis { + width: 260px; + height: 100%; + position: relative; + overflow: hidden; +} +.lay-colorpicker-basis-white { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: linear-gradient(90deg, #fff, hsla(0, 0%, 100%, 0)); +} +.lay-colorpicker-basis-black { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background: linear-gradient(0deg, #000, transparent); +} +.lay-colorpicker-basis-cursor { + width: 10px; + height: 10px; + border: 1px solid #fff; + border-radius: 50%; + position: absolute; + top: 0%; + right: 100%; + cursor: pointer; + transform: translate(-50%, -50%); +} +.lay-colorpicker-side { + position: absolute; + top: 0; + right: 0; + width: 12px; + height: 100%; + background: linear-gradient(#f00, #ff0, #0f0, #0ff, #00f, #f0f, #f00); +} +.lay-colorpicker-side-slider { + width: 100%; + height: 5px; + box-shadow: 0 0 1px #888888; + box-sizing: border-box; + background: #fff; + border-radius: 1px; + border: 1px solid #f0f0f0; + cursor: pointer; + position: absolute; + left: 0; +} +.lay-colorpicker-main-alpha { + display: none; + height: 12px; + margin-top: 7px; + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); +} +.lay-colorpicker-alpha-bgcolor { + height: 100%; + position: relative; +} +.lay-colorpicker-alpha-slider { + width: 5px; + height: 100%; + box-shadow: 0 0 1px #888888; + box-sizing: border-box; + background: #fff; + border-radius: 1px; + border: 1px solid #f0f0f0; + cursor: pointer; + position: absolute; + top: 0; +} +.lay-colorpicker-main-pre { + padding-top: 7px; + font-size: 0; +} +.lay-colorpicker-pre { + width: 20px; + height: 20px; + border-radius: var(--lay-border-radius); + display: inline-block; + margin-left: 6px; + margin-bottom: 7px; + cursor: pointer; +} +.lay-colorpicker-pre:nth-child(11n + 1) { + margin-left: 0; +} +.lay-colorpicker-pre-isalpha { + background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==); +} +.lay-colorpicker-pre.lay-this { + box-shadow: 0 0 3px 2px rgba(0, 0, 0, 0.15); +} +.lay-colorpicker-pre > div { + height: 100%; + border-radius: var(--lay-border-radius); +} +.lay-colorpicker-main-input { + text-align: right; + padding-top: 7px; +} +.lay-colorpicker-main-input .lay-btn-container .lay-btn { + margin: 0 0 0 10px; +} +.lay-colorpicker-main-input div.lay-inline { + float: left; + font-size: 14px; +} +.lay-colorpicker-main-input input.lay-input { + width: 168px; + height: 30px; + color: #5f5f5f; + padding-left: 5px; +} diff --git a/src/css/modules/floatbar.css b/src/css/modules/floatbar.css new file mode 100644 index 000000000..dbfe1bf4a --- /dev/null +++ b/src/css/modules/floatbar.css @@ -0,0 +1,36 @@ +/** floatbar **/ +.lay-floatbar { + position: fixed; + right: 16px; + bottom: 16px; + z-index: 999999; + display: flex; + flex-direction: column; + gap: 1px; +} +.lay-floatbar-item { + width: 48px; + height: 48px; + line-height: 48px; + text-align: center; + cursor: pointer; + background-color: #9f9f9f; + color: #fff; + border-radius: var(--lay-border-radius); + opacity: 0.95; +} +.lay-floatbar-item > .lay-icon { + font-size: 24px; +} +.lay-floatbar-item:hover { + opacity: 0.85; +} +.lay-floatbar-item:active { + opacity: 1; +} +.lay-floatbar-item[data-type='top'] { + display: none; +} +.lay-floatbar-item[data-type='top'] > .lay-icon { + font-size: 32px; +} diff --git a/src/css/modules/flow.css b/src/css/modules/flow.css new file mode 100644 index 000000000..ca0c2a35d --- /dev/null +++ b/src/css/modules/flow.css @@ -0,0 +1,30 @@ +/** 流加载 **/ +.lay-flow-more { + margin: 10px 0; + text-align: center; + color: #999; + font-size: 14px; + clear: both; +} +.lay-flow-more a { + height: 32px; + line-height: 32px; +} +.lay-flow-more a * { + display: inline-block; + vertical-align: top; +} +.lay-flow-more a cite { + padding: 0 20px; + border-radius: var(--lay-border-radius); + background-color: var(--lay-gray-300); + color: #333; + font-style: normal; +} +.lay-flow-more a cite:hover { + opacity: 0.8; +} +.lay-flow-more a i { + font-size: 30px; + color: #737383; +} diff --git a/src/css/modules/form.css b/src/css/modules/form.css new file mode 100644 index 000000000..88cbd6206 --- /dev/null +++ b/src/css/modules/form.css @@ -0,0 +1,799 @@ +/** 表单 **/ +.lay-input, +.lay-textarea, +.lay-select { + height: 38px; + line-height: 1.3; + border-width: 1px; + border-style: solid; + background-color: #fff; + color: rgba(0, 0, 0, 0.85); + border-radius: var(--lay-border-radius); +} +.lay-input::-webkit-input-placeholder, +.lay-textarea::-webkit-input-placeholder, +.lay-select::-webkit-input-placeholder { + line-height: 1.3; +} +.lay-input, +.lay-textarea { + display: block; + width: 100%; + padding-left: 10px; +} +.lay-input:hover, +.lay-textarea:hover { + border-color: var(--lay-border-color-accent) !important; +} +.lay-input:focus, +.lay-textarea:focus { + border-color: var(--lay-color-accent) !important; + box-shadow: 0 0 0 3px rgba(22, 183, 119, 0.08); +} +.lay-textarea { + position: relative; + min-height: 100px; + height: auto; + line-height: 20px; + padding: 6px 10px; + resize: vertical; +} +.lay-input[disabled], +.lay-textarea[disabled] { + background-color: var(--lay-color-gray); +} +.lay-select { + padding: 0 10px; +} +.lay-form select, +.lay-form input[type='checkbox'], +.lay-form input[type='radio'] { + display: none; +} +.lay-form *[lay-ignore] { + display: initial; +} + +.lay-form-item { + position: relative; + margin-bottom: 15px; + clear: both; +} +.lay-form-item:after { + content: '\20'; + clear: both; + display: block; + height: 0; +} +.lay-form-label { + position: relative; + float: left; + display: block; + padding: 9px 15px; + width: 80px; + font-weight: 400; + line-height: 20px; + text-align: right; +} +.lay-form-label-col { + display: block; + float: none; + padding: 9px 0; + line-height: 20px; + text-align: left; +} +.lay-form-item .lay-inline { + margin-bottom: 5px; + margin-right: 10px; +} +.lay-input-block, +.lay-input-inline { + position: relative; +} +.lay-input-block { + margin-left: 110px; + min-height: 36px; +} +.lay-input-inline { + display: inline-block; + vertical-align: middle; +} +.lay-form-item .lay-input-inline { + float: left; + width: 190px; + margin-right: 10px; +} +.lay-form-text .lay-input-inline { + width: auto; +} + +/* 分割块 */ +.lay-form-mid { + position: relative; + float: left; + display: block; + padding: 9px 0 !important; + line-height: 20px; + margin-right: 10px; +} + +/* 警告条 */ +.lay-form-danger:focus, +.lay-form-danger + .lay-form-select .lay-input { + border-color: var(--lay-color-red) !important; + box-shadow: 0 0 0 3px rgba(255, 87, 34, 0.08); +} + +/* 输入框点缀 */ +.lay-input-prefix, +.lay-input-suffix, +.lay-input-split, +.lay-input-suffix .lay-input-affix { + position: absolute; + right: 0; + top: 0; + padding: 0 10px; + width: 35px; + height: 100%; + text-align: center; + transition: all 0.3s; + box-sizing: border-box; +} +.lay-input-prefix { + left: 0; + border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius); +} +.lay-input-suffix { + right: 0; + border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0; +} +.lay-input-split { + border-width: 1px; + border-style: solid; +} +.lay-input-prefix .lay-icon, +.lay-input-suffix .lay-icon, +.lay-input-split .lay-icon { + position: relative; + font-size: 16px; + color: #5f5f5f; + transition: all 0.3s; +} + +/* 输入框前后置容器 */ +.lay-input-group { + position: relative; + display: table; + box-sizing: border-box; +} +.lay-input-group > * { + display: table-cell; + vertical-align: middle; + position: relative; +} +.lay-input-group .lay-input { + padding-right: 15px; +} +.lay-input-group > .lay-input-prefix { + width: auto; + border-right: 0; +} +.lay-input-group > .lay-input-suffix { + width: auto; + border-left: 0; +} +.lay-input-group .lay-input-split { + white-space: nowrap; +} + +/* 输入框前后缀容器 */ +.lay-input-wrap { + position: relative; + line-height: 38px; +} +.lay-input-wrap .lay-input { + padding-right: 35px; +} +.lay-input-wrap .lay-input-prefix + .lay-input, +.lay-input-wrap .lay-input-prefix ~ * .lay-input { + padding-left: 35px; +} +.lay-input-wrap .lay-input-split + .lay-input, +.lay-input-wrap .lay-input-split ~ * .lay-input { + padding-left: 45px; +} +.lay-input-wrap .lay-input-prefix ~ .lay-form-select { + position: static; +} +.lay-input-wrap .lay-input-prefix, +.lay-input-wrap .lay-input-suffix, +.lay-input-wrap .lay-input-split { + pointer-events: none; +} +.lay-input-wrap .lay-input:hover + .lay-input-split { + border-color: var(--lay-border-color-accent); +} +.lay-input-wrap .lay-input:focus + .lay-input-split { + border-color: var(--lay-color-accent); +} +.lay-input-wrap .lay-input.lay-form-danger:focus + .lay-input-split { + border-color: var(--lay-color-red); +} +.lay-input-wrap .lay-input-prefix.lay-input-split { + border-width: 0; + border-right-width: 1px; +} +.lay-input-wrap .lay-input-suffix.lay-input-split { + border-width: 0; + border-left-width: 1px; +} + +/* 输入框动态点缀 */ +.lay-input-affix { + line-height: 38px; +} +.lay-input-suffix .lay-input-affix { + right: auto; + left: -35px; +} +.lay-input-affix .lay-icon { + color: rgba(0, 0, 0, 0.8); + pointer-events: auto !important; + cursor: pointer; +} +.lay-input-affix .lay-icon-clear { + color: rgba(0, 0, 0, 0.3); +} +.lay-input-affix .lay-icon:hover { + color: rgba(0, 0, 0, 0.6); +} + +/* 数字输入框动态点缀 */ +.lay-input-wrap .lay-input-number { + width: 24px; + padding: 0; +} +.lay-input-wrap .lay-input-number .lay-icon { + position: absolute; + right: 0; + width: 100%; + height: 50%; + line-height: normal; + font-size: 12px; +} +.lay-input-wrap .lay-input-number .lay-icon:before { + position: absolute; + left: 50%; + top: 50%; + margin-top: -6px; + margin-left: -6px; +} +.lay-input-wrap .lay-input-number .lay-icon-up { + top: 0; + border-bottom: 1px solid var(--lay-border-color); +} +.lay-input-wrap .lay-input-number .lay-icon-down { + bottom: 0; +} +.lay-input-wrap .lay-input-number .lay-icon:hover { + font-weight: 700; +} +.lay-input-wrap .lay-input[type='number']::-webkit-outer-spin-button, +.lay-input-wrap .lay-input[type='number']::-webkit-inner-spin-button { + -webkit-appearance: none !important; +} +.lay-input-wrap .lay-input[type='number'] { + -moz-appearance: textfield; + -webkit-appearance: textfield; + appearance: textfield; +} +.lay-input-wrap .lay-input.lay-input-number-out-of-range, +.lay-input-wrap .lay-input.lay-input-number-invalid { + color: var(--lay-color-red); +} + +/* 下拉选择 */ +.lay-form-select { + position: relative; + color: #5f5f5f; +} +.lay-form-select .lay-input { + padding-right: 30px; + cursor: pointer; +} +.lay-form-select .lay-edge { + position: absolute; + right: 10px; + top: 50%; + margin-top: -3px; + cursor: pointer; + border-width: 6px; + border-top-color: #c2c2c2; + border-top-style: solid; + -webkit-transition: all 0.3s; + transition: all 0.3s; +} +.lay-form-select dl { + display: none; + position: absolute; + left: 0; + top: 42px; + padding: 5px 0; + z-index: 899; + min-width: 100%; + border: 1px solid var(--lay-border-color); + max-height: 300px; + overflow-y: auto; + background-color: #fff; + border-radius: var(--lay-border-radius); + box-shadow: 1px 1px 4px rgb(0 0 0 / 8%); + box-sizing: border-box; +} +.lay-form-select dl dt, +.lay-form-select dl dd { + padding: 0 10px; + line-height: 36px; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} +.lay-form-select dl dt { + font-size: 12px; + color: #999; +} +.lay-form-select dl dd { + cursor: pointer; +} +.lay-form-select dl dd:hover { + background-color: #f8f8f8; + -webkit-transition: 0.5s all; + transition: 0.5s all; +} +.lay-form-select .lay-select-group dd { + padding-left: 20px; +} +.lay-form-select dl dd.lay-select-tips { + padding-left: 10px !important; + color: #999; +} +.lay-form-select dl dd.lay-this { + background-color: #f8f8f8; + color: var(--lay-color-accent); + font-weight: 700; +} +/*.lay-form-select dl dd.lay-this{background-color: #f8f8f8; color: var(--lay-color-accent); font-weight: 700;}*/ +.lay-form-select dl dd.lay-disabled { + background-color: #fff; +} +.lay-form-selected dl { + display: block; +} +.lay-form-selected .lay-edge { + margin-top: -9px; + -webkit-transform: rotate(180deg); + transform: rotate(180deg); +} +.lay-form-selectup dl { + top: auto; + bottom: 42px; +} +.lay-select-none { + margin: 5px 0; + text-align: center; + color: #999; +} +.lay-select-panel-wrap { + position: absolute; + z-index: 99999999; +} +.lay-select-panel-wrap dl { + position: relative; + display: block; + top: 0; +} + +.lay-select-disabled .lay-disabled { + border-color: var(--lay-border-color) !important; +} +.lay-select-disabled .lay-edge { + border-top-color: var(--lay-border-color-accent); +} + +/* 复选框 */ +.lay-form-checkbox { + position: relative; + display: inline-block; + vertical-align: middle; + height: 30px; + line-height: 30px; + margin-right: 10px; + padding-right: 30px; + background-color: #fff; + cursor: pointer; + font-size: 0; + -webkit-transition: 0.1s linear; + transition: 0.1s linear; + box-sizing: border-box; +} +.lay-form-checkbox > * { + display: inline-block; + vertical-align: middle; +} +.lay-form-checkbox > div { + padding: 0 11px; + font-size: 14px; + border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius); + background-color: var(--lay-gray-400); + color: #fff; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; +} +.lay-form-checkbox > div > .lay-icon { + line-height: normal; +} +.lay-form-checkbox:hover > div { + background-color: #c2c2c2; +} +.lay-form-checkbox > i { + position: absolute; + right: 0; + top: 0; + width: 30px; + height: 100%; + border: 1px solid var(--lay-border-color-accent); + border-left: none; + border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0; + color: #fff; + color: rgba(255, 255, 255, 0); + font-size: 20px; + text-align: center; + box-sizing: border-box; +} +.lay-form-checkbox:hover > i { + border-color: #c2c2c2; + color: #c2c2c2; +} +.lay-form-checked, +.lay-form-checked:hover { + border-color: var(--lay-color-accent); +} +.lay-form-checked > div, +.lay-form-checked:hover > div { + background-color: var(--lay-color-accent); +} +.lay-form-checked > i, +.lay-form-checked:hover > i { + color: var(--lay-color-accent); +} +.lay-form-item .lay-form-checkbox { + margin-top: 4px; +} +.lay-form-checkbox.lay-checkbox-disabled > div { + background-color: var(--lay-gray-300) !important; +} +.lay-form *[lay-checkbox] { + display: none; +} + +/* 复选框-默认风格 */ +.lay-form-checkbox[lay-skin='primary'] { + height: auto !important; + line-height: normal !important; + min-width: 18px; + min-height: 18px; + border: none !important; + margin-right: 0; + padding-left: 24px; + padding-right: 0; + background: none; +} +.lay-form-checkbox[lay-skin='primary'] > div { + margin-top: -1px; + padding-left: 0; + padding-right: 15px; + line-height: 18px; + background: none; + color: #5f5f5f; +} +.lay-form-checkbox[lay-skin='primary'] > i { + right: auto; + left: 0; + width: 16px; + height: 16px; + line-height: 14px; + border: 1px solid #d2d2d2; + font-size: 12px; + border-radius: var(--lay-border-radius); + background-color: #fff; + -webkit-transition: 0.1s linear; + transition: 0.1s linear; +} +.lay-form-checkbox[lay-skin='primary']:hover > i { + border-color: var(--lay-color-accent); + color: #fff; +} +.lay-form-checked[lay-skin='primary'] > i { + border-color: var(--lay-color-accent) !important; + background-color: var(--lay-color-accent); + color: #fff; +} +.lay-checkbox-disabled[lay-skin='primary'] > div { + background: none !important; +} +.lay-form-checked.lay-checkbox-disabled[lay-skin='primary'] > i { + background: var(--lay-gray-300) !important; + border-color: var(--lay-gray-300) !important; +} +.lay-checkbox-disabled[lay-skin='primary']:hover > i { + border-color: var(--lay-border-color-accent); +} +.lay-form-item .lay-form-checkbox[lay-skin='primary'] { + margin-top: 10px; +} +.lay-form-checkbox[lay-skin='primary'] > .lay-icon-indeterminate { + border-color: var(--lay-color-accent); + background-color: #fff; +} +.lay-form-checkbox[lay-skin='primary'] > .lay-icon-indeterminate:before { + content: ''; + display: inline-block; + vertical-align: middle; + position: relative; + width: 50%; + height: 1px; + margin: -1px auto 0; + background-color: var(--lay-color-accent); +} + +/* 复选框-开关风格 */ +.lay-form-switch { + position: relative; + display: inline-block; + vertical-align: middle; + height: 24px; + line-height: 22px; + min-width: 44px; + padding: 0 5px; + margin-top: 8px; + border: 1px solid #d2d2d2; + border-radius: 20px; + cursor: pointer; + box-sizing: border-box; + background-color: #fff; + -webkit-transition: 0.1s linear; + transition: 0.1s linear; +} +.lay-form-switch > i { + position: absolute; + left: 5px; + top: 3px; + width: 16px; + height: 16px; + border-radius: 20px; + background-color: var(--lay-gray-400); + -webkit-transition: 0.1s linear; + transition: 0.1s linear; +} +.lay-form-switch > div { + position: relative; + top: 0; + margin-left: 21px; + padding: 0 !important; + text-align: center !important; + color: #999 !important; + font-style: normal !important; + font-size: 12px; +} +.lay-form-onswitch { + border-color: var(--lay-color-accent); + background-color: var(--lay-color-accent); +} +.lay-form-onswitch > i { + left: 100%; + margin-left: -21px; + background-color: #fff; +} +.lay-form-onswitch > div { + margin-left: 0; + margin-right: 21px; + color: #fff !important; +} + +/* 无样式风格-根据模板自定义样式*/ +.lay-form-checkbox[lay-skin='none'] *, +.lay-form-radio[lay-skin='none'] * { + box-sizing: border-box; +} +.lay-form-checkbox[lay-skin='none'], +.lay-form-radio[lay-skin='none'] { + position: relative; + min-height: 20px; + margin: 0; + padding: 0; + height: auto; + line-height: normal; +} +.lay-form-checkbox[lay-skin='none'] > div, +.lay-form-radio[lay-skin='none'] > div { + position: relative; + top: 0; + left: 0; + cursor: pointer; + z-index: 10; + color: inherit; + background-color: inherit; +} +.lay-form-checkbox[lay-skin='none'] > i, +.lay-form-radio[lay-skin='none'] > i { + display: none; +} +.lay-form-checkbox[lay-skin='none'].lay-checkbox-disabled > div, +.lay-form-radio[lay-skin='none'].lay-radio-disabled > div { + cursor: not-allowed; +} + +.lay-checkbox-disabled { + border-color: var(--lay-border-color) !important; +} +.lay-checkbox-disabled > div { + color: #c2c2c2 !important; +} +.lay-checkbox-disabled > i { + border-color: var(--lay-border-color) !important; +} +.lay-checkbox-disabled:hover > i { + color: #fff !important; +} +.lay-form-checkbox[lay-skin='tag'].lay-form-checked.lay-checkbox-disabled > i { + color: #c2c2c2; +} +.lay-form-checkbox[lay-skin='tag'].lay-form-checked.lay-checkbox-disabled:hover + > i { + color: #c2c2c2 !important; +} + +/* 单选框 */ +.lay-form-radio { + display: inline-block; + vertical-align: middle; + line-height: 28px; + margin: 6px 10px 0 0; + padding-right: 10px; + cursor: pointer; + font-size: 0; +} +.lay-form-radio > * { + display: inline-block; + vertical-align: middle; + font-size: 14px; +} +.lay-form-radio > i { + margin-right: 8px; + font-size: 22px; + color: #c2c2c2; +} +.lay-form-radioed, +.lay-form-radioed > i, +.lay-form-radio:hover > * { + color: var(--lay-color-accent); +} +.lay-radio-disabled > i { + color: var(--lay-gray-300) !important; +} +.lay-radio-disabled > * { + color: #c2c2c2 !important; +} +.lay-form *[lay-radio] { + display: none; +} + +/* 表单方框风格 */ +.lay-form-pane .lay-form-label { + width: 110px; + padding: 8px 15px; + height: 38px; + line-height: 20px; + border-width: 1px; + border-style: solid; + border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius); + text-align: center; + background-color: var(--lay-color-gray); + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + box-sizing: border-box; +} +.lay-form-pane .lay-input-inline { + margin-left: -1px; +} +.lay-form-pane .lay-input-block { + margin-left: 110px; + left: -1px; +} +.lay-form-pane .lay-input { + border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0; +} +.lay-form-pane .lay-form-text .lay-form-label { + float: none; + width: 100%; + border-radius: var(--lay-border-radius); + box-sizing: border-box; + text-align: left; +} +.lay-form-pane .lay-form-text .lay-input-inline { + display: block; + margin: 0; + top: -1px; + clear: both; +} +.lay-form-pane .lay-form-text .lay-input-block { + margin: 0; + left: 0; + top: -1px; +} +.lay-form-pane .lay-form-text .lay-textarea { + min-height: 100px; + border-radius: 0 0 var(--lay-border-radius) var(--lay-border-radius); +} +.lay-form-pane .lay-form-checkbox { + margin: 4px 0 4px 10px; +} +.lay-form-pane .lay-form-switch, +.lay-form-pane .lay-form-radio { + margin-top: 6px; + margin-left: 10px; +} +.lay-form-pane .lay-form-item[pane] { + position: relative; + border-width: 1px; + border-style: solid; +} +.lay-form-pane .lay-form-item[pane] .lay-form-label { + position: absolute; + left: 0; + top: 0; + height: 100%; + border-width: 0px; + border-right-width: 1px; +} +.lay-form-pane .lay-form-item[pane] .lay-input-inline { + margin-left: 110px; +} + +/** 表单响应式 **/ +@media screen and (max-width: 450px) { + .lay-form-item .lay-form-label { + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + } + .lay-form-item .lay-inline { + display: block; + margin-right: 0; + margin-bottom: 20px; + clear: both; + } + .lay-form-item .lay-inline:after { + content: '\20'; + clear: both; + display: block; + height: 0; + } + .lay-form-item .lay-input-inline { + display: block; + float: none; + left: -3px; + width: auto !important; + margin: 0 0 10px 112px; + } + .lay-form-item .lay-input-inline + .lay-form-mid { + margin-left: 110px; + top: -5px; + padding: 0; + } + .lay-form-item .lay-form-checkbox { + margin-right: 5px; + margin-bottom: 5px; + } +} diff --git a/src/css/modules/icon.css b/src/css/modules/icon.css new file mode 100644 index 000000000..c0eb2f385 --- /dev/null +++ b/src/css/modules/icon.css @@ -0,0 +1,600 @@ +/** 图标字体 **/ +@font-face { + font-family: 'lay-icon'; + src: url('iconfont.woff2') format('woff2'); +} + +.lay-icon { + font-family: 'lay-icon' !important; + font-size: 16px; + font-style: normal; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +/* font-class */ +.lay-icon-sound:before { + content: '\e69d'; +} +.lay-icon-bot:before { + content: '\e7d6'; +} +.lay-icon-leaf:before { + content: '\e701'; +} +.lay-icon-folder:before { + content: '\eabe'; +} +.lay-icon-folder-open:before { + content: '\eac1'; +} +.lay-icon-gitee:before { + content: '\e69b'; +} +.lay-icon-github:before { + content: '\e6a7'; +} +.lay-icon-disabled:before { + content: '\e6cc'; +} +.lay-icon-moon:before { + content: '\e6c2'; +} +.lay-icon-error:before { + content: '\e693'; +} +.lay-icon-success:before { + content: '\e697'; +} +.lay-icon-question:before { + content: '\e699'; +} +.lay-icon-lock:before { + content: '\e69a'; +} +.lay-icon-eye:before { + content: '\e695'; +} +.lay-icon-eye-invisible:before { + content: '\e696'; +} +.lay-icon-backspace:before { + content: '\e694'; +} +.lay-icon-tips-fill:before { + content: '\eb2e'; +} +.lay-icon-test:before { + content: '\e692'; +} +.lay-icon-clear:before { + content: '\e788'; +} +.lay-icon-heart-fill:before { + content: '\e68f'; +} +.lay-icon-light:before { + content: '\e748'; +} +.lay-icon-music:before { + content: '\e690'; +} +.lay-icon-time:before { + content: '\e68d'; +} +.lay-icon-ie:before { + content: '\e7bb'; +} +.lay-icon-firefox:before { + content: '\e686'; +} +.lay-icon-at:before { + content: '\e687'; +} +.lay-icon-bluetooth:before { + content: '\e689'; +} +.lay-icon-chrome:before { + content: '\e68a'; +} +.lay-icon-edge:before { + content: '\e68b'; +} +.lay-icon-heart:before { + content: '\e68c'; +} +.lay-icon-key:before { + content: '\e683'; +} +.lay-icon-android:before { + content: '\e684'; +} +.lay-icon-mike:before { + content: '\e6dc'; +} +.lay-icon-mute:before { + content: '\e685'; +} +.lay-icon-gift:before { + content: '\e627'; +} +.lay-icon-windows:before { + content: '\e67f'; +} +.lay-icon-ios:before { + content: '\e680'; +} +.lay-icon-logout:before { + content: '\e682'; +} +.lay-icon-wifi:before { + content: '\e7e0'; +} +.lay-icon-rss:before { + content: '\e808'; +} +.lay-icon-email:before { + content: '\e618'; +} +.lay-icon-reduce-circle:before { + content: '\e616'; +} +.lay-icon-transfer:before { + content: '\e691'; +} +.lay-icon-service:before { + content: '\e626'; +} +.lay-icon-addition:before { + content: '\e624'; +} +.lay-icon-subtraction:before { + content: '\e67e'; +} +.lay-icon-slider:before { + content: '\e714'; +} +.lay-icon-print:before { + content: '\e66d'; +} +.lay-icon-export:before { + content: '\e67d'; +} +.lay-icon-cols:before { + content: '\e610'; +} +.lay-icon-screen-full:before { + content: '\e622'; +} +.lay-icon-screen-restore:before { + content: '\e758'; +} +.lay-icon-rate-half:before { + content: '\e6c9'; +} +.lay-icon-rate-solid:before { + content: '\e67a'; +} +.lay-icon-rate:before { + content: '\e67b'; +} +.lay-icon-cellphone:before { + content: '\e678'; +} +.lay-icon-vercode:before { + content: '\e679'; +} +.lay-icon-login-weibo:before { + content: '\e675'; +} +.lay-icon-login-qq:before { + content: '\e676'; +} +.lay-icon-login-wechat:before { + content: '\e677'; +} +.lay-icon-username:before { + content: '\e66f'; +} +.lay-icon-password:before { + content: '\e673'; +} +.lay-icon-refresh-3:before { + content: '\e9aa'; +} +.lay-icon-auz:before { + content: '\e672'; +} +.lay-icon-shrink-right:before { + content: '\e668'; +} +.lay-icon-spread-left:before { + content: '\e66b'; +} +.lay-icon-snowflake:before { + content: '\e6b1'; +} +.lay-icon-tips:before { + content: '\e702'; +} +.lay-icon-note:before { + content: '\e66e'; +} +.lay-icon-senior:before { + content: '\e674'; +} +.lay-icon-refresh-1:before { + content: '\e666'; +} +.lay-icon-refresh:before { + content: '\e669'; +} +.lay-icon-flag:before { + content: '\e66c'; +} +.lay-icon-theme:before { + content: '\e66a'; +} +.lay-icon-notice:before { + content: '\e667'; +} +.lay-icon-console:before { + content: '\e665'; +} +.lay-icon-website:before { + content: '\e7ae'; +} +.lay-icon-face-surprised:before { + content: '\e664'; +} +.lay-icon-set:before { + content: '\e716'; +} +.lay-icon-template:before { + content: '\e663'; +} +.lay-icon-app:before { + content: '\e653'; +} +.lay-icon-template-1:before { + content: '\e656'; +} +.lay-icon-home:before { + content: '\e68e'; +} +.lay-icon-female:before { + content: '\e661'; +} +.lay-icon-male:before { + content: '\e662'; +} +.lay-icon-tread:before { + content: '\e6c5'; +} +.lay-icon-praise:before { + content: '\e6c6'; +} +.lay-icon-rmb:before { + content: '\e65e'; +} +.lay-icon-more:before { + content: '\e65f'; +} +.lay-icon-camera:before { + content: '\e660'; +} +.lay-icon-cart-simple:before { + content: '\e698'; +} +.lay-icon-face-cry:before { + content: '\e69c'; +} +.lay-icon-face-smile:before { + content: '\e6af'; +} +.lay-icon-survey:before { + content: '\e6b2'; +} +.lay-icon-read:before { + content: '\e705'; +} +.lay-icon-location:before { + content: '\e715'; +} +.lay-icon-dollar:before { + content: '\e659'; +} +.lay-icon-diamond:before { + content: '\e735'; +} +.lay-icon-return:before { + content: '\e65c'; +} +.lay-icon-camera-fill:before { + content: '\e65d'; +} +.lay-icon-fire:before { + content: '\e756'; +} +.lay-icon-more-vertical:before { + content: '\e671'; +} +.lay-icon-cart:before { + content: '\e657'; +} +.lay-icon-star-fill:before { + content: '\e658'; +} +.lay-icon-prev:before { + content: '\e65a'; +} +.lay-icon-next:before { + content: '\e65b'; +} +.lay-icon-upload:before { + content: '\e67c'; +} +.lay-icon-upload-drag:before { + content: '\e681'; +} +.lay-icon-user:before { + content: '\e770'; +} +.lay-icon-file-b:before { + content: '\e655'; +} +.lay-icon-component:before { + content: '\e857'; +} +.lay-icon-find-fill:before { + content: '\e670'; +} +.lay-icon-loading:before { + content: '\e63d'; +} +.lay-icon-loading-1:before { + content: '\e63e'; +} +.lay-icon-add-1:before { + content: '\e654'; +} +.lay-icon-pause:before { + content: '\e651'; +} +.lay-icon-play:before { + content: '\e652'; +} +.lay-icon-video:before { + content: '\e6ed'; +} +.lay-icon-headset:before { + content: '\e6fc'; +} +.lay-icon-voice:before { + content: '\e688'; +} +.lay-icon-speaker:before { + content: '\e645'; +} +.lay-icon-fonts-del:before { + content: '\e64f'; +} +.lay-icon-fonts-html:before { + content: '\e64b'; +} +.lay-icon-fonts-code:before { + content: '\e64e'; +} +.lay-icon-fonts-strong:before { + content: '\e62b'; +} +.lay-icon-unlink:before { + content: '\e64d'; +} +.lay-icon-picture:before { + content: '\e64a'; +} +.lay-icon-link:before { + content: '\e64c'; +} +.lay-icon-face-smile-b:before { + content: '\e650'; +} +.lay-icon-align-center:before { + content: '\e647'; +} +.lay-icon-align-right:before { + content: '\e648'; +} +.lay-icon-align-left:before { + content: '\e649'; +} +.lay-icon-fonts-u:before { + content: '\e646'; +} +.lay-icon-fonts-i:before { + content: '\e644'; +} +.lay-icon-tabs:before { + content: '\e62a'; +} +.lay-icon-circle:before { + content: '\e63f'; +} +.lay-icon-radio:before { + content: '\e643'; +} +.lay-icon-share:before { + content: '\e641'; +} +.lay-icon-edit:before { + content: '\e642'; +} +.lay-icon-delete:before { + content: '\e640'; +} +.lay-icon-engine:before { + content: '\e628'; +} +.lay-icon-chart-screen:before { + content: '\e629'; +} +.lay-icon-chart:before { + content: '\e62c'; +} +.lay-icon-table:before { + content: '\e62d'; +} +.lay-icon-tree:before { + content: '\e62e'; +} +.lay-icon-upload-circle:before { + content: '\e62f'; +} +.lay-icon-templeate-1:before { + content: '\e630'; +} +.lay-icon-util:before { + content: '\e631'; +} +.lay-icon-layouts:before { + content: '\e632'; +} +.lay-icon-prev-circle:before { + content: '\e633'; +} +.lay-icon-carousel:before { + content: '\e634'; +} +.lay-icon-code-circle:before { + content: '\e635'; +} +.lay-icon-water:before { + content: '\e636'; +} +.lay-icon-date:before { + content: '\e637'; +} +.lay-icon-layer:before { + content: '\e638'; +} +.lay-icon-fonts-clear:before { + content: '\e639'; +} +.lay-icon-dialogue:before { + content: '\e63a'; +} +.lay-icon-cellphone-fine:before { + content: '\e63b'; +} +.lay-icon-form:before { + content: '\e63c'; +} +.lay-icon-file:before { + content: '\e621'; +} +.lay-icon-triangle-r:before { + content: '\e623'; +} +.lay-icon-triangle-d:before { + content: '\e625'; +} +.lay-icon-set-sm:before { + content: '\e620'; +} +.lay-icon-add-circle:before { + content: '\e61f'; +} +.lay-icon-layim-download:before { + content: '\e61e'; +} +.lay-icon-layim-uploadfile:before { + content: '\e61d'; +} +.lay-icon-404:before { + content: '\e61c'; +} +.lay-icon-about:before { + content: '\e60b'; +} +.lay-icon-layim-theme:before { + content: '\e61b'; +} +.lay-icon-down:before { + content: '\e61a'; +} +.lay-icon-up:before { + content: '\e619'; +} +.lay-icon-circle-dot:before { + content: '\e617'; +} +.lay-icon-set-fill:before { + content: '\e614'; +} +.lay-icon-search:before { + content: '\e615'; +} +.lay-icon-friends:before { + content: '\e612'; +} +.lay-icon-group:before { + content: '\e613'; +} +.lay-icon-reply-fill:before { + content: '\e611'; +} +.lay-icon-menu-fill:before { + content: '\e60f'; +} +.lay-icon-face-smile-fine:before { + content: '\e60c'; +} +.lay-icon-picture-fine:before { + content: '\e60d'; +} +.lay-icon-log:before { + content: '\e60e'; +} +.lay-icon-list:before { + content: '\e60a'; +} +.lay-icon-release:before { + content: '\e609'; +} +.lay-icon-add-circle-fine:before { + content: '\e608'; +} +.lay-icon-ok:before { + content: '\e605'; +} +.lay-icon-help:before { + content: '\e607'; +} +.lay-icon-chat:before { + content: '\e606'; +} +.lay-icon-top:before { + content: '\e604'; +} +.lay-icon-right:before { + content: '\e602'; +} +.lay-icon-left:before { + content: '\e603'; +} +.lay-icon-star:before { + content: '\e600'; +} +.lay-icon-download-circle:before { + content: '\e601'; +} +.lay-icon-close:before { + content: '\1006'; +} +.lay-icon-close-fill:before { + content: '\1007'; +} +.lay-icon-ok-circle:before { + content: '\1005'; +} diff --git a/src/css/modules/iconfont.woff2 b/src/css/modules/iconfont.woff2 new file mode 100644 index 000000000..a3d87744d Binary files /dev/null and b/src/css/modules/iconfont.woff2 differ diff --git a/src/css/modules/laydate.css b/src/css/modules/laydate.css new file mode 100644 index 000000000..331385f99 --- /dev/null +++ b/src/css/modules/laydate.css @@ -0,0 +1,615 @@ +/** + * laydate style + */ + +/* 初始化 */ +.lay-laydate * { + margin: 0; + padding: 0; +} + +/* 主体结构 */ +.lay-laydate, +.lay-laydate * { + box-sizing: border-box; +} +.lay-laydate { + position: absolute; + z-index: 99999999; + margin: 5px 0; + border-radius: var(--lay-border-radius); + font-size: 14px; + line-height: normal; + -webkit-animation-duration: 0.2s; + animation-duration: 0.2s; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; +} +.lay-laydate-main { + width: 272px; +} +.lay-laydate-header *, +.lay-laydate-content td, +.lay-laydate-list li { + -webkit-transition-duration: 0.3s; + transition-duration: 0.3s; +} +.lay-laydate-shade { + top: 0; + left: 0; + width: 100%; + height: 100%; + position: fixed; + pointer-events: auto; +} + +/* 微微往下滑入 */ +@keyframes laydate-downbit { + 0% { + opacity: 0.3; + transform: translate3d(0, -5px, 0); + } + 100% { + opacity: 1; + transform: translate3d(0, 0, 0); + } +} + +.lay-laydate { + animation-name: laydate-downbit; +} +.lay-laydate-static { + position: relative; + z-index: 0; + display: inline-block; + margin: 0; + -webkit-animation: none; + animation: none; +} + +/* 展开年月列表时 */ +.laydate-ym-show .laydate-prev-m, +.laydate-ym-show .laydate-next-m { + display: none !important; +} +.laydate-ym-show .laydate-prev-y, +.laydate-ym-show .laydate-next-y { + display: inline-block !important; +} +.laydate-ym-show .laydate-set-ym span[lay-type='month'] { + display: none !important; +} + +/* 展开时间列表时 */ +.laydate-time-show .lay-laydate-header .lay-icon, +.laydate-time-show .laydate-set-ym span[lay-type='year'], +.laydate-time-show .laydate-set-ym span[lay-type='month'] { + display: none !important; +} + +/* 头部结构 */ +.lay-laydate-header { + position: relative; + line-height: 30px; + padding: 10px 70px 5px; +} +.lay-laydate-header * { + display: inline-block; + vertical-align: bottom; +} +.lay-laydate-header i { + position: absolute; + top: 10px; + padding: 0 5px; + color: #999; + font-size: 18px; + cursor: pointer; +} +.lay-laydate-header i.laydate-prev-y { + left: 15px; +} +.lay-laydate-header i.laydate-prev-m { + left: 45px; +} +.lay-laydate-header i.laydate-next-y { + right: 15px; +} +.lay-laydate-header i.laydate-next-m { + right: 45px; +} +.laydate-time-show .lay-laydate-header { + padding-left: 10px; + padding-right: 10px; +} +.laydate-set-ym { + width: 100%; + text-align: center; + box-sizing: border-box; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.laydate-set-ym span { + padding: 0 10px; + cursor: pointer; +} +.laydate-time-text { + cursor: default !important; +} + +/* 主体结构 */ +.lay-laydate-content { + position: relative; + padding: 10px; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} +.lay-laydate-content table { + border-collapse: collapse; + border-spacing: 0; +} +.lay-laydate-content th, +.lay-laydate-content td { + width: 36px; + height: 30px; + padding: 0; + text-align: center; +} +.lay-laydate-content th { + font-weight: 400; +} +.lay-laydate-content td { + position: relative; + cursor: pointer; +} +.laydate-day-mark { + position: absolute; + left: 0; + top: 0; + width: 100%; + line-height: 30px; + font-size: 12px; + overflow: hidden; +} +.laydate-day-mark::after { + position: absolute; + content: ''; + right: 2px; + top: 2px; + width: 5px; + height: 5px; + border-radius: 50%; +} +.laydate-day-holidays:before { + position: absolute; + left: 0; + top: 0; + font-size: 12px; + transform: scale(0.7); +} +.laydate-day-holidays:before { + content: '\4F11'; + color: #ff5722; +} +.laydate-day-holidays[type='workdays']:before { + content: '\73ED'; + color: inherit; +} +.lay-laydate .lay-this .laydate-day-holidays:before { + color: #fff; +} + +/* 底部结构 */ +.lay-laydate-footer { + position: relative; + height: 46px; + line-height: 26px; + padding: 10px; +} +.lay-laydate-footer span { + display: inline-block; + vertical-align: top; + height: 26px; + line-height: 24px; + padding: 0 10px; + border: 1px solid #c9c9c9; + border-radius: var(--lay-border-radius); + background-color: #fff; + font-size: 12px; + cursor: pointer; + white-space: nowrap; + transition: all 0.3s; +} +.lay-laydate-footer span:hover { + color: var(--lay-color-accent); +} +.lay-laydate-footer span.lay-laydate-preview { + cursor: default; + border-color: transparent !important; +} +.lay-laydate-footer span.lay-laydate-preview:hover { + color: #777; +} +.lay-laydate-footer span:first-child.lay-laydate-preview { + padding-left: 0; +} +.laydate-footer-btns { + position: absolute; + right: 10px; + top: 10px; +} +.laydate-footer-btns span { + margin: 0 0 0 -1px; + border-radius: 0px; +} +.laydate-footer-btns span:first-child { + border-radius: var(--lay-border-radius) 0px 0px var(--lay-border-radius); +} +.laydate-footer-btns span:last-child { + border-radius: 0px var(--lay-border-radius) var(--lay-border-radius) 0px; +} + +/* 快捷栏 */ +.lay-laydate-shortcut { + width: 80px; + padding: 6px 0; + display: inline-block; + vertical-align: top; + overflow: auto; + max-height: 276px; + text-align: center; +} +.lay-laydate-shortcut + .lay-laydate-main { + display: inline-block; + border-left: 1px solid #e2e2e2; +} +.lay-laydate-shortcut > li { + padding: 5px 8px; + cursor: pointer; + line-height: 18px; +} + +/* 年月列表 */ +.lay-laydate .lay-laydate-list { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 10px; + box-sizing: border-box; + background-color: #fff; +} +.lay-laydate .lay-laydate-list > li { + position: relative; + display: inline-block; + width: 33.3%; + height: 36px; + line-height: 36px; + margin: 3px 0; + vertical-align: middle; + text-align: center; + cursor: pointer; + list-style: none; +} +.lay-laydate .laydate-month-list > li { + width: 25%; + margin: 17px 0; +} +.laydate-time-list { + display: table; +} +.lay-laydate .laydate-time-list > li { + display: table-cell; + height: 100%; + margin: 0; + line-height: normal; + cursor: default; +} +.lay-laydate .laydate-time-list p { + position: relative; + top: -4px; + margin: 0; + line-height: 29px; +} +.lay-laydate .laydate-time-list ol { + height: 181px; + overflow: hidden; +} +.lay-laydate .laydate-time-list > li:hover ol { + overflow-y: auto; +} +.lay-laydate .laydate-time-list ol li { + width: 130%; + padding-left: 33px; + height: 30px; + line-height: 30px; + text-align: left; + cursor: pointer; +} +.lay-laydate .laydate-time-list-hide-1 ol li { + padding-left: 53px; +} +.lay-laydate .laydate-time-list-hide-2 ol li { + padding-left: 117px; +} + +/* 提示 */ +.lay-laydate-hint { + position: absolute; + top: 115px; + left: 50%; + width: 250px; + margin-left: -125px; + line-height: 20px; + padding: 15px; + text-align: center; + font-size: 12px; + color: #ff5722; + white-space: pre-line; +} + +/* 双日历 */ +.lay-laydate-range { + width: 546px; +} +.lay-laydate-range .lay-laydate-main { + display: inline-block; + vertical-align: middle; + max-width: 50%; +} +.lay-laydate-range .laydate-main-list-1 .lay-laydate-header, +.lay-laydate-range .laydate-main-list-1 .lay-laydate-content { + border-left: 1px solid #e2e2e2; +} +.lay-laydate-range.lay-laydate-linkage .laydate-main-list-0 .laydate-next-m, +.lay-laydate-range.lay-laydate-linkage .laydate-main-list-0 .laydate-next-y, +.lay-laydate-range.lay-laydate-linkage .laydate-main-list-1 .laydate-prev-m, +.lay-laydate-range.lay-laydate-linkage .laydate-main-list-1 .laydate-prev-y { + display: none; +} +.lay-laydate-range.lay-laydate-linkage .laydate-main-list-1 .lay-laydate-header, +.lay-laydate-range.lay-laydate-linkage + .laydate-main-list-1 + .lay-laydate-content { + border-left-style: dashed; +} + +/* 默认简约主题 */ +.lay-laydate, +.lay-laydate-hint { + border: 1px solid var(--lay-border-color-accent); + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); + background-color: #fff; + color: #777; +} +.lay-laydate-header { + border-bottom: 1px solid #e2e2e2; +} +.lay-laydate-header i:hover, +.lay-laydate-header span:hover { + color: var(--lay-color-accent); +} +.lay-laydate-content { + border-top: none 0; + border-bottom: none 0; +} +.lay-laydate-content th { + color: #333; +} +.lay-laydate-content td { + color: #777; +} +.lay-laydate-content td.laydate-day-now { + color: var(--lay-color-accent); +} +.lay-laydate-content td.laydate-day-now:after { + content: ''; + position: absolute; + width: 100%; + height: 30px; + left: 0; + top: 0; + border: 1px solid var(--lay-color-accent); + box-sizing: border-box; +} +.lay-laydate-linkage .lay-laydate-content td.laydate-selected > div { + background-color: #cffae9; + transition: all 0.3s; +} +.lay-laydate-linkage .laydate-selected:hover > div { + background-color: #cffae9 !important; +} +.lay-laydate-content td:hover:after, +.lay-laydate-content td.laydate-selected:after { + content: none; +} +.lay-laydate-content td > div:hover, +.lay-laydate-list li:hover, +.lay-laydate-shortcut > li:hover { + background-color: var(--lay-gray-300); + color: #333; + transition: all 0.3s; +} +.laydate-time-list li ol { + margin: 0; + padding: 0; + border: 1px solid #e2e2e2; + border-left-width: 0; +} +.laydate-time-list li:first-child ol { + border-left-width: 1px; +} +.laydate-time-list > li:hover { + background: none; +} +.lay-laydate-content .laydate-day-prev, +.lay-laydate-content .laydate-day-next { + color: var(--lay-gray-400); +} +.lay-laydate-linkage .laydate-selected.laydate-day-prev > div, +.lay-laydate-linkage .laydate-selected.laydate-day-next > div { + background: none !important; +} +.lay-laydate-footer { + border-top: 1px solid #e2e2e2; +} +.lay-laydate-hint { + color: #ff5722; +} +.laydate-day-mark::after { + background-color: var(--lay-color-accent); +} +.lay-laydate-content td.lay-this .laydate-day-mark::after { + display: none; +} +.lay-laydate-footer span[lay-type='date'] { + color: var(--lay-color-accent); +} +.lay-laydate .lay-this, +.lay-laydate .lay-this > div { + background-color: var(--lay-color-accent) !important; + color: #fff !important; +} +.lay-laydate .laydate-disabled, +.lay-laydate .laydate-disabled:hover { + background: none !important; + color: var(--lay-gray-400) !important; + cursor: not-allowed !important; + -moz-user-select: none; + -webkit-user-select: none; + user-select: none; +} +.lay-laydate .lay-this.laydate-disabled, +.lay-laydate .lay-this.laydate-disabled > div { + background-color: var(--lay-gray-300) !important; +} +.lay-laydate-content td > div { + padding: 7px 0; + height: 100%; +} + +/* 墨绿/自定义背景色主题 */ +.laydate-theme-molv { + border: none; +} +.laydate-theme-molv.lay-laydate-range { + width: 548px; +} +.laydate-theme-molv .lay-laydate-main { + width: 274px; +} +.laydate-theme-molv .lay-laydate-header { + border: none; + background-color: var(--lay-color-primary); +} +.laydate-theme-molv .lay-laydate-header i, +.laydate-theme-molv .lay-laydate-header span { + color: #f6f6f6; +} +.laydate-theme-molv .lay-laydate-header i:hover, +.laydate-theme-molv .lay-laydate-header span:hover { + color: #fff; +} +.laydate-theme-molv .lay-laydate-content { + border: 1px solid #e2e2e2; + border-top: none; + border-bottom: none; +} +.laydate-theme-molv .laydate-main-list-1 .lay-laydate-content { + border-left: none; +} +.laydate-theme-molv .lay-this, +.laydate-theme-molv .lay-this > div { + background-color: var(--lay-color-primary) !important; +} +.laydate-theme-molv .lay-laydate-footer { + border: 1px solid #e2e2e2; +} + +/* 格子主题 */ +.laydate-theme-grid .lay-laydate-content td, +.laydate-theme-grid .lay-laydate-content thead, +.laydate-theme-grid .laydate-year-list > li, +.laydate-theme-grid .laydate-month-list > li { + border: 1px solid #e2e2e2; +} +.lay-laydate-linkage.laydate-theme-grid .laydate-selected, +.lay-laydate-linkage.laydate-theme-grid .laydate-selected:hover { + background-color: #f2f2f2 !important; + color: var(--lay-color-primary) !important; +} +.lay-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-prev, +.lay-laydate-linkage.laydate-theme-grid .laydate-selected.laydate-day-next { + color: var(--lay-gray-400) !important; +} +.laydate-theme-grid .laydate-year-list, +.laydate-theme-grid .laydate-month-list { + margin: 1px 0 0 1px; +} +.laydate-theme-grid .laydate-year-list > li, +.laydate-theme-grid .laydate-month-list > li { + margin: 0 -1px -1px 0; +} +.laydate-theme-grid .laydate-year-list > li { + height: 43px; + line-height: 43px; +} +.laydate-theme-grid .laydate-month-list > li { + height: 71px; + line-height: 71px; +} +.laydate-theme-grid .lay-laydate-content td > div { + height: 29px; + margin-top: -1px; +} + +/* 圆圈高亮主题 */ +.laydate-theme-circle .lay-laydate-content td > div, +.laydate-theme-circle .lay-laydate-content td.lay-this > div { + width: 28px; + height: 28px; + line-height: 28px; + border-radius: 14px; + margin: 0 4px; + padding: 0; +} +.lay-laydate.laydate-theme-circle .lay-laydate-content table td.lay-this { + background-color: transparent !important; +} +.laydate-theme-grid.laydate-theme-circle .lay-laydate-content td > div { + margin: 0 3.5px; +} + +/* 全面板 */ +.laydate-theme-fullpanel .lay-laydate-main { + width: 526px; +} +.laydate-theme-fullpanel .lay-laydate-list { + width: 252px; + left: 272px; +} +.laydate-theme-fullpanel .laydate-set-ym span { + display: none; +} +.laydate-theme-fullpanel .laydate-time-show .lay-laydate-header .lay-icon, +.laydate-theme-fullpanel + .laydate-time-show + .laydate-set-ym + span[lay-type='year'], +.laydate-theme-fullpanel + .laydate-time-show + .laydate-set-ym + span[lay-type='month'] { + display: inline-block !important; +} +.laydate-theme-fullpanel .laydate-btns-time { + display: none; +} +.laydate-theme-fullpanel .laydate-time-list-hide-1 ol li { + padding-left: 49px; +} +.laydate-theme-fullpanel .laydate-time-list-hide-2 ol li { + padding-left: 107px; +} diff --git a/src/css/modules/laydate/icon.png b/src/css/modules/laydate/icon.png deleted file mode 100644 index 5a50673e0..000000000 Binary files a/src/css/modules/laydate/icon.png and /dev/null differ diff --git a/src/css/modules/laydate/laydate.css b/src/css/modules/laydate/laydate.css deleted file mode 100644 index 80190be09..000000000 --- a/src/css/modules/laydate/laydate.css +++ /dev/null @@ -1,136 +0,0 @@ -/** - - @Name: laydate 核心样式 - @Author:贤心 - @Site:http://sentsin.com/layui/laydate - -**/ - - -#layuicss-laydatecss{display: none; position: absolute; width: 1989px;} - -.laydate_body .laydate_box, .laydate_body .laydate_box *{margin:0; padding:0;box-sizing:content-box;} -.laydate-icon, -.laydate-icon-default, -.laydate-icon-danlan, -.laydate-icon-dahong, -.laydate-icon-molv{height:22px; line-height:22px; padding-right:20px; border:1px solid #C6C6C6; background-repeat:no-repeat; background-position:right center; background-color:#fff; outline:0;} -.laydate-icon-default{ background-image:url(../skins/default/icon.png)} -.laydate-icon-danlan{border:1px solid #B1D2EC; background-image:url(../skins/danlan/icon.png)} -.laydate-icon-dahong{background-image:url(../skins/dahong/icon.png)} -.laydate-icon-molv{background-image:url(../skins/molv/icon.png)} -.laydate_body .laydate_box{width:240px; font:12px '\5B8B\4F53'; z-index:99999999; *margin:-2px 0 0 -2px; *overflow:hidden; _margin:0; _position:absolute!important; background-color:#fff;} -.laydate_body .laydate_box li{list-style:none;} -.laydate_body .laydate_box .laydate_void{cursor:text!important;} -.laydate_body .laydate_box a, .laydate_body .laydate_box a:hover{text-decoration:none; blr:expression(this.onFocus=this.blur()); cursor:pointer;} -.laydate_body .laydate_box a:hover{text-decoration:none;} -.laydate_body .laydate_box cite, .laydate_body .laydate_box label{position:absolute; width:0; height:0; border-width:5px; border-style:dashed; border-color:transparent; overflow:hidden; cursor:pointer;} -.laydate_body .laydate_box .laydate_yms, .laydate_body .laydate_box .laydate_time{display:none;} -.laydate_body .laydate_box .laydate_show{display:block;} -.laydate_body .laydate_box input{outline:0; font-size:14px; background-color:#fff;} -.laydate_body .laydate_top{position:relative; height:26px; padding:5px; *width:100%; z-index:99;} -.laydate_body .laydate_ym{position:relative; float:left; height:24px; cursor:pointer;} -.laydate_body .laydate_ym input{float:left; height:24px; line-height:24px; text-align:center; border:none; cursor:pointer;} -.laydate_body .laydate_ym .laydate_yms{position:absolute; left: -1px; top: 24px; height:181px;} -.laydate_body .laydate_y{width:121px; margin-right:6px;} -.laydate_body .laydate_y input{width:64px; margin-right:15px;} -.laydate_body .laydate_y .laydate_yms{width:121px; text-align:center;} -.laydate_body .laydate_y .laydate_yms a{position:relative; display:block; height:20px;} -.laydate_body .laydate_y .laydate_yms ul{height:139px; padding:0; *overflow:hidden;} -.laydate_body .laydate_y .laydate_yms ul li{float:left; width:60px; height:20px; line-height: 20px; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} -.laydate_body .laydate_m{width:99px;} -.laydate_body .laydate_m .laydate_yms{width:99px; padding:0;} -.laydate_body .laydate_m input{width:42px; margin-right:15px;} -.laydate_body .laydate_m .laydate_yms span{display:block; float:left; width:42px; margin: 5px 0 0 5px; line-height:24px; text-align:center; _display:inline;} -.laydate_body .laydate_choose{display:block; float:left; position:relative; width:20px; height:24px;} -.laydate_body .laydate_choose cite, .laydate_body .laydate_tab cite{left:50%; top:50%;} -.laydate_body .laydate_chtop cite{margin:-7px 0 0 -5px; border-bottom-style:solid;} -.laydate_body .laydate_chdown cite, .laydate_body .laydate_ym label{top:50%; margin:-2px 0 0 -5px; border-top-style:solid;} -.laydate_body .laydate_chprev cite{margin:-5px 0 0 -7px;} -.laydate_body .laydate_chnext cite{margin:-5px 0 0 -2px;} -.laydate_body .laydate_ym label{right:28px;} -.laydate_body .laydate_table{ width:230px; margin:0 5px; border-collapse:collapse; border-spacing:0px; } -.laydate_body .laydate_table td{width:31px; height:19px; line-height:19px; text-align: center; cursor:pointer; font-size: 12px;} -.laydate_body .laydate_table thead{height:22px; line-height:22px;} -.laydate_body .laydate_table thead th{font-weight:400; font-size:12px; text-align:center;} -.laydate_body .laydate_bottom{position:relative; height:22px; line-height:20px; padding:5px; font-size:12px;} -.laydate_body .laydate_bottom #laydate_hms{position: relative; z-index: 1; float:left; } -.laydate_body .laydate_time{ position:absolute; left:5px; bottom: 26px; width:129px; height:125px; *overflow:hidden;} -.laydate_body .laydate_time .laydate_hmsno{ padding:5px 0 0 5px;} -.laydate_body .laydate_time .laydate_hmsno span{display:block; float:left; width:24px; height:19px; line-height:19px; text-align:center; cursor:pointer; *margin-bottom:-5px;} -.laydate_body .laydate_time1{width:228px; height:154px;} -.laydate_body .laydate_time1 .laydate_hmsno{padding: 6px 0 0 8px;} -.laydate_body .laydate_time1 .laydate_hmsno span{width:21px; height:20px; line-height:20px;} -.laydate_body .laydate_msg{left:49px; bottom:67px; width:141px; height:auto; overflow: hidden;} -.laydate_body .laydate_msg p{padding:5px 10px;} -.laydate_body .laydate_bottom li{float:left; height:20px; line-height:20px; border-right:none; font-weight:900;} -.laydate_body .laydate_bottom .laydate_sj{width:33px; text-align:center; font-weight:400;} -.laydate_body .laydate_bottom input{float:left; width:21px; height:20px; line-height:20px; border:none; text-align:center; cursor:pointer; font-size:12px; font-weight:400;} -.laydate_body .laydate_bottom .laydte_hsmtex{height:20px; line-height:20px; text-align:center;} -.laydate_body .laydate_bottom .laydte_hsmtex span{position:absolute; width:20px; top:0; right:0px; cursor:pointer;} -.laydate_body .laydate_bottom .laydte_hsmtex span:hover{font-size:14px;} -.laydate_body .laydate_bottom .laydate_btn{position:absolute; right:5px; top:5px;} -.laydate_body .laydate_bottom .laydate_btn a{float:left; height:20px; padding:0 6px; _padding:0 5px;} -.laydate_body .laydate_bottom .laydate_v{position:absolute; left:10px; top:6px; font-family:Courier; z-index:0;} - - - - -.laydate-icon{border:1px solid #C6C6C6; background-image:url(icon.png)} - -.laydate_body .laydate_box, -.laydate_body .laydate_ym, -.laydate_body .laydate_ym .laydate_yms, -.laydate_body .laydate_table, -.laydate_body .laydate_table td, -.laydate_body .laydate_bottom #laydate_hms, -.laydate_body .laydate_time, -.laydate_body .laydate_bottom .laydate_btn a{border:1px solid #ccc;} - -.laydate_body .laydate_y .laydate_yms a, -.laydate_body .laydate_choose, -.laydate_body .laydate_table thead, -.laydate_body .laydate_bottom .laydte_hsmtex{background-color:#F6F6F6;} - -.laydate_body .laydate_box, -.laydate_body .laydate_ym .laydate_yms, -.laydate_body .laydate_time{box-shadow: 2px 2px 5px rgba(0,0,0,.1);} - -.laydate_body .laydate_box{border-top:none; border-bottom:none; background-color:#fff; color:#333;} -.laydate_body .laydate_box input{color:#333;} -.laydate_body .laydate_box .laydate_void{color:#ccc!important; /*text-decoration:line-through;*/} -.laydate_body .laydate_box .laydate_void:hover{background-color:#fff!important} -.laydate_body .laydate_box a, .laydate_body .laydate_box a:hover{color:#333;} -.laydate_body .laydate_box a:hover{color:#666;} -.laydate_body .laydate_click{background-color:#eee!important;} -.laydate_body .laydate_top{border-top:1px solid #C6C6C6;} -.laydate_body .laydate_ym .laydate_yms{border:1px solid #C6C6C6; background-color:#fff;} -.laydate_body .laydate_y .laydate_yms a{border-bottom:1px solid #C6C6C6;} -.laydate_body .laydate_y .laydate_yms .laydate_chdown{border-top:1px solid #C6C6C6; border-bottom:none;} -.laydate_body .laydate_choose{border-left:1px solid #C6C6C6;} -.laydate_body .laydate_chprev{border-left:none; border-right:1px solid #C6C6C6;} -.laydate_body .laydate_choose:hover, -.laydate_body .laydate_y .laydate_yms a:hover{background-color:#fff;} -.laydate_body .laydate_chtop cite{border-bottom-color:#666;} -.laydate_body .laydate_chdown cite, .laydate_body .laydate_ym label{border-top-color:#666;} -.laydate_body .laydate_chprev cite{border-right-style:solid; border-right-color:#666;} -.laydate_body .laydate_chnext cite{border-left-style:solid; border-left-color:#666;} -.laydate_body .laydate_table td{border:none; height:21px!important; line-height:21px!important; background-color:#fff;} -.laydate_body .laydate_table .laydate_nothis{color:#999;} -.laydate_body .laydate_table thead{height:21px!important; line-height:21px!important;} -.laydate_body .laydate_table thead th{border-bottom:1px solid #ccc;} -.laydate_body .laydate_bottom{border-bottom:1px solid #C6C6C6;} -.laydate_body .laydate_bottom #laydate_hms{background-color:#fff;} -.laydate_body .laydate_time{background-color:#fff;} -.laydate_body .laydate_bottom .laydate_sj{border-right:1px solid #C6C6C6; background-color:#F6F6F6;} -.laydate_body .laydate_bottom input{background-color:#fff;} -.laydate_body .laydate_bottom .laydte_hsmtex{border-bottom:1px solid #C6C6C6;} -.laydate_body .laydate_bottom .laydate_btn{border-right:1px solid #C6C6C6;} -.laydate_body .laydate_bottom .laydate_v{color:#999} -.laydate_body .laydate_bottom .laydate_btn a{border-right:none; background-color:#F6F6F6;} -.laydate_body .laydate_bottom .laydate_btn a:hover{color:#000; background-color:#fff;} - -.laydate_body .laydate_m .laydate_yms span:hover, -.laydate_body .laydate_y .laydate_yms ul li:hover, -.laydate_body .laydate_table td:hover, -.laydate_body .laydate_time .laydate_hmsno span:hover{background-color:#F3F3F3} diff --git a/src/css/modules/layer.css b/src/css/modules/layer.css new file mode 100644 index 000000000..f3a76d209 --- /dev/null +++ b/src/css/modules/layer.css @@ -0,0 +1,1044 @@ +/** + * layer style + */ + +/* common */ +.lay-layer-shade, +.lay-layer { + position: fixed; + pointer-events: auto; +} +.lay-layer-shade { + opacity: 0; + transition: opacity 0.35s cubic-bezier(0.34, 0.69, 0.1, 1); + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.lay-layer { + top: 150px; + left: 0; + margin: 0; + padding: 0; + background-color: #fff; + -webkit-background-clip: content; + background-clip: content; + border-radius: var(--lay-border-radius); + box-shadow: 1px 1px 50px rgba(0, 0, 0, 0.3); +} +.lay-layer-close { + position: absolute; +} +.lay-layer-content { + position: relative; +} +.lay-layer-border { + border: 1px solid #b2b2b2; + border: 1px solid rgba(0, 0, 0, 0.1); + box-shadow: 1px 1px 5px rgba(0, 0, 0, 0.2); +} +.lay-layer-load { + background: url('data:image/gif;base64,R0lGODlhJQAlAJECAL3L2AYrTv///wAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQFCgACACwAAAAAJQAlAAACi5SPqcvtDyGYIFpF690i8xUw3qJBwUlSadmcLqYmGQu6KDIeM13beGzYWWy3DlB4IYaMk+Dso2RWkFCfLPcRvFbZxFLUDTt21BW56TyjRep1e20+i+eYMR145W2eefj+6VFmgTQi+ECVY8iGxcg35phGo/iDFwlTyXWphwlm1imGRdcnuqhHeop6UAAAIfkEBQoAAgAsEAACAAQACwAAAgWMj6nLXAAh+QQFCgACACwVAAUACgALAAACFZQvgRi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwXABEADAADAAACBYyPqcsFACH5BAUKAAIALBUAFQAKAAsAAAITlGKZwWoMHYxqtmplxlNT7ixGAQAh+QQFCgACACwQABgABAALAAACBYyPqctcACH5BAUKAAIALAUAFQAKAAsAAAIVlC+BGL3Z3IlxUmUuhtR2LzHhsiEFACH5BAUKAAIALAEAEQAMAAMAAAIFjI+pywUAIfkEBQoAAgAsBQAFAAoACwAAAhOUYJnAagwdjGq2amXGU1PuLEYBACH5BAUKAAIALBAAAgAEAAsAAAIFhI+py1wAIfkEBQoAAgAsFQAFAAoACwAAAhWUL4AIvdnciXFSZS6G1HYvMeGyIQUAIfkEBQoAAgAsFwARAAwAAwAAAgWEj6nLBQAh+QQFCgACACwVABUACgALAAACE5RgmcBqDB2MarZqZcZTU+4sRgEAIfkEBQoAAgAsEAAYAAQACwAAAgWEj6nLXAAh+QQFCgACACwFABUACgALAAACFZQvgAi92dyJcVJlLobUdi8x4bIhBQAh+QQFCgACACwBABEADAADAAACBYSPqcsFADs=') + #fff center center no-repeat; +} +.lay-layer-setwin span, +.lay-layer-btn a { + display: inline-block; + vertical-align: middle; +} + +.lay-layer-move { + display: none; + position: fixed; + left: 0px; + top: 0px; + width: 100%; + height: 100%; + cursor: move; + opacity: 0; + background-color: #fff; + z-index: 2147483647; +} +.lay-layer-resize { + position: absolute; + width: 15px; + height: 15px; + right: 0; + bottom: 0; + cursor: se-resize; +} + +/* 动画 */ +.layer-anim { + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation-duration: 0.3s; + animation-duration: 0.3s; +} + +@-webkit-keyframes layer-bounceIn { + /* 默认 */ + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} +@keyframes layer-bounceIn { + 0% { + opacity: 0; + -webkit-transform: scale(0.5); + transform: scale(0.5); + } + 100% { + opacity: 1; + -webkit-transform: scale(1); + transform: scale(1); + } +} +.layer-anim-00 { + -webkit-animation-name: layer-bounceIn; + animation-name: layer-bounceIn; +} + +@-webkit-keyframes layer-zoomInDown { + 0% { + opacity: 0; + -webkit-transform: scale(0.1) translateY(-2000px); + transform: scale(0.1) translateY(-2000px); + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + 60% { + opacity: 1; + -webkit-transform: scale(0.475) translateY(60px); + transform: scale(0.475) translateY(60px); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } +} +@keyframes layer-zoomInDown { + 0% { + opacity: 0; + -webkit-transform: scale(0.1) translateY(-2000px); + transform: scale(0.1) translateY(-2000px); + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + 60% { + opacity: 1; + -webkit-transform: scale(0.475) translateY(60px); + transform: scale(0.475) translateY(60px); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } +} +.layer-anim-01 { + -webkit-animation-name: layer-zoomInDown; + animation-name: layer-zoomInDown; +} + +@-webkit-keyframes layer-fadeInUpBig { + 0% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} +@keyframes layer-fadeInUpBig { + 0% { + opacity: 0; + -webkit-transform: translateY(2000px); + transform: translateY(2000px); + } + 100% { + opacity: 1; + -webkit-transform: translateY(0); + transform: translateY(0); + } +} +.layer-anim-02 { + -webkit-animation-name: layer-fadeInUpBig; + animation-name: layer-fadeInUpBig; +} + +@-webkit-keyframes layer-zoomInLeft { + 0% { + opacity: 0; + -webkit-transform: scale(0.1) translateX(-2000px); + transform: scale(0.1) translateX(-2000px); + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + 60% { + opacity: 1; + -webkit-transform: scale(0.475) translateX(48px); + transform: scale(0.475) translateX(48px); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } +} +@keyframes layer-zoomInLeft { + 0% { + opacity: 0; + -webkit-transform: scale(0.1) translateX(-2000px); + transform: scale(0.1) translateX(-2000px); + -webkit-animation-timing-function: ease-in-out; + animation-timing-function: ease-in-out; + } + 60% { + opacity: 1; + -webkit-transform: scale(0.475) translateX(48px); + transform: scale(0.475) translateX(48px); + -webkit-animation-timing-function: ease-out; + animation-timing-function: ease-out; + } +} +.layer-anim-03 { + -webkit-animation-name: layer-zoomInLeft; + animation-name: layer-zoomInLeft; +} + +@-webkit-keyframes layer-rollIn { + 0% { + opacity: 0; + -webkit-transform: translateX(-100%) rotate(-120deg); + transform: translateX(-100%) rotate(-120deg); + } + 100% { + opacity: 1; + -webkit-transform: translateX(0px) rotate(0deg); + transform: translateX(0px) rotate(0deg); + } +} +@keyframes layer-rollIn { + 0% { + opacity: 0; + -webkit-transform: translateX(-100%) rotate(-120deg); + transform: translateX(-100%) rotate(-120deg); + } + 100% { + opacity: 1; + -webkit-transform: translateX(0px) rotate(0deg); + transform: translateX(0px) rotate(0deg); + } +} +.layer-anim-04 { + -webkit-animation-name: layer-rollIn; + animation-name: layer-rollIn; +} + +@-webkit-keyframes layer-fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +@keyframes layer-fadeIn { + 0% { + opacity: 0; + } + 100% { + opacity: 1; + } +} +.layer-anim-05 { + -webkit-animation-name: layer-fadeIn; + animation-name: layer-fadeIn; +} + +@-webkit-keyframes layer-shake { + 0%, + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 10%, + 30%, + 50%, + 70%, + 90% { + -webkit-transform: translateX(-10px); + transform: translateX(-10px); + } + 20%, + 40%, + 60%, + 80% { + -webkit-transform: translateX(10px); + transform: translateX(10px); + } +} +@keyframes layer-shake { + 0%, + 100% { + -webkit-transform: translateX(0); + transform: translateX(0); + } + 10%, + 30%, + 50%, + 70%, + 90% { + -webkit-transform: translateX(-10px); + transform: translateX(-10px); + } + 20%, + 40%, + 60%, + 80% { + -webkit-transform: translateX(10px); + transform: translateX(10px); + } +} +.layer-anim-06 { + -webkit-animation-name: layer-shake; + animation-name: layer-shake; +} + +/* 从上往下 */ +@keyframes layer-slide-down { + from { + transform: translate3d(0, -100%, 0); + } + to { + transform: translate3d(0, 0, 0); + } +} +@keyframes layer-slide-down-out { + from { + transform: translate3d(0, 0, 0); + } + to { + transform: translate3d(0, -100%, 0); + } +} +.layer-anim-slide-down { + animation-name: layer-slide-down; +} +.layer-anim-slide-down-out { + animation-name: layer-slide-down-out; +} + +/* 从右往左 */ +@keyframes layer-slide-left { + from { + transform: translate3d(100%, 0, 0); + } + to { + transform: translate3d(0, 0, 0); + } +} +@keyframes layer-slide-left-out { + from { + transform: translate3d(0, 0, 0); + } + to { + transform: translate3d(100%, 0, 0); + } +} +.layer-anim-slide-left { + animation-name: layer-slide-left; +} +.layer-anim-slide-left-out { + animation-name: layer-slide-left-out; +} + +/* 从下往上 */ +@keyframes layer-slide-up { + from { + transform: translate3d(0, 100%, 0); + } + to { + transform: translate3d(0, 0, 0); + } +} +@keyframes layer-slide-up-out { + from { + transform: translate3d(0, 0, 0); + } + to { + transform: translate3d(0, 100%, 0); + } +} +.layer-anim-slide-up { + animation-name: layer-slide-up; +} +.layer-anim-slide-up-out { + animation-name: layer-slide-up-out; +} + +/* 从左往右 */ +@keyframes layer-slide-right { + from { + transform: translate3d(-100%, 0, 0); + } + to { + transform: translate3d(0, 0, 0); + } +} +@keyframes layer-slide-right-out { + from { + transform: translate3d(0, 0, 0); + } + to { + transform: translate3d(-100%, 0, 0); + } +} +.layer-anim-slide-right { + animation-name: layer-slide-right; +} +.layer-anim-slide-right-out { + animation-name: layer-slide-right-out; +} + +/* 标题栏 */ +.lay-layer-title { + padding: 0 81px 0 16px; + height: 50px; + line-height: 50px; + border-bottom: 1px solid #f0f0f0; + font-size: 14px; + color: #333; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + border-radius: var(--lay-border-radius) var(--lay-border-radius) 0 0; +} +.lay-layer-setwin { + position: absolute; + right: 15px; + top: 16px; + font-size: 0; + line-height: initial; +} +.lay-layer-setwin span { + position: relative; + width: 16px; + height: 16px; + line-height: 18px; + margin-left: 10px; + text-align: center; + font-size: 16px; + cursor: pointer; + color: #000; + box-sizing: border-box; +} +.lay-layer-setwin .lay-layer-min:before { + content: ''; + position: absolute; + width: 12px; + border-bottom: 1px solid #2e2d3c; + left: 50%; + top: 50%; + margin: -0.5px 0 0 -6px; + cursor: pointer; +} +.lay-layer-setwin .lay-layer-min:hover:before { + background-color: #2d93ca; +} +.lay-layer-setwin .lay-layer-max:before, +.lay-layer-setwin .lay-layer-max:after { + content: ''; + position: absolute; + left: 50%; + top: 50%; + z-index: 1; + width: 9px; + height: 9px; + margin: -5px 0 0 -5px; + border: 1px solid #2e2d3c; +} +.lay-layer-setwin .lay-layer-max:hover:before, +.lay-layer-setwin .lay-layer-max:hover:after { + border-color: #2d93ca; +} +.lay-layer-setwin .lay-layer-min:hover:before { + background-color: #2d93ca; +} +.lay-layer-setwin .lay-layer-maxmin:before, +.lay-layer-setwin .lay-layer-maxmin:after { + width: 7px; + height: 7px; + margin: -3px 0 0 -3px; + background-color: #fff; +} +.lay-layer-setwin .lay-layer-maxmin:after { + z-index: 0; + margin: -5px 0 0 -1px; +} +.lay-layer-setwin .lay-layer-close { + cursor: pointer; +} +.lay-layer-setwin .lay-layer-close:hover { + opacity: 0.7; +} +.lay-layer-setwin .lay-layer-close2 { + position: absolute; + right: -28px; + top: -28px; + color: #fff; + background-color: #787878; + padding: 3px; + border: 3px solid; + width: 28px; + height: 28px; + font-size: 16px; + font-weight: bolder; + border-radius: 50%; + margin-left: 0; +} +.lay-layer-setwin .lay-layer-close2:hover { + opacity: unset; + background-color: #3888f6; +} + +/* 按钮栏 */ +.lay-layer-btn { + text-align: right; + padding: 0 15px 12px; + pointer-events: auto; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.lay-layer-btn a { + height: 30px; + line-height: 30px; + margin: 5px 5px 0; + padding: 0 var(--lay-spacing); + border: 1px solid #dedede; + background-color: #fff; + color: #333; + border-radius: var(--lay-border-radius); + font-weight: 400; + cursor: pointer; + text-decoration: none; + box-sizing: border-box; +} +.lay-layer-btn a:hover { + opacity: 0.9; + text-decoration: none; +} +.lay-layer-btn a:active { + opacity: 0.8; +} +.lay-layer-btn .lay-layer-btn0 { + border-color: transparent; + background-color: #1e9fff; + color: #fff; +} +.lay-layer-btn-l { + text-align: left; +} +.lay-layer-btn-c { + text-align: center; +} +.lay-layer-btn-is-loading { + opacity: 0.5 !important; + cursor: not-allowed !important; + cursor: wait !important; + overflow: hidden; + white-space: nowrap; + -webkit-user-select: none; + user-select: none; +} +.lay-layer-btn-is-loading .lay-layer-btn-loading-icon { + margin-right: 8px; + font-size: 14px; +} + +/* 定制化 */ +.lay-layer-dialog { + min-width: 240px; +} +.lay-layer-dialog .lay-layer-content { + position: relative; + padding: 16px; + line-height: 24px; + word-break: break-all; + overflow: hidden; + font-size: 14px; + overflow-x: hidden; + overflow-y: auto; +} +.lay-layer-dialog .lay-layer-content .lay-layer-face { + position: absolute; + top: 18px; + left: 16px; + color: #959595; + font-size: 32px; +} +.lay-layer-dialog .lay-layer-content .lay-icon-tips { + color: #f39b12; +} +.lay-layer-dialog .lay-layer-content .lay-icon-success { + color: var(--lay-color-accent); +} +.lay-layer-dialog .lay-layer-content .lay-icon-error { + top: 19px; + color: #ff5722; +} +.lay-layer-dialog .lay-layer-content .lay-icon-question { + color: #ffb800; +} +.lay-layer-dialog .lay-layer-content .lay-icon-lock { + color: #787878; +} +.lay-layer-dialog .lay-layer-content .lay-icon-face-cry { + color: #ff5722; +} +.lay-layer-dialog .lay-layer-content .lay-icon-face-smile { + color: var(--lay-color-accent); +} + +.lay-layer-rim { + border: 6px solid #8d8d8d; + border: 6px solid rgba(0, 0, 0, 0.3); + border-radius: 5px; + box-shadow: none; +} +.lay-layer-msg { + min-width: 180px; + border: 1px solid #d3d4d3; + box-shadow: none; +} +.lay-layer-hui { + min-width: 100px; + background-color: rgba(0, 0, 0, 0.6); + color: #fff; + border: none; +} +.lay-layer-hui .lay-layer-close { + color: #fff; +} +.lay-layer-hui .lay-layer-content { + padding: 11px 24px; + text-align: center; +} +.lay-layer-dialog .lay-layer-padding { + padding: 18px 24px 18px 58px; + text-align: left; +} +.lay-layer-page .lay-layer-content { + position: relative; + overflow: auto; +} +.lay-layer-page .lay-layer-btn, +.lay-layer-iframe .lay-layer-btn { + padding-top: 10px; +} +.lay-layer-nobg { + background: none; +} +.lay-layer-iframe iframe { + display: block; + width: 100%; +} + +.lay-layer-loading { + border-radius: 100%; + background: none; + box-shadow: none; + border: none; +} +.lay-layer-loading .lay-layer-content { + width: 76px; + height: 38px; + line-height: 38px; + text-align: center; +} +.lay-layer-loading-icon { + font-size: 38px; + color: #959595; +} +.lay-layer-loading2 { + text-align: center; +} +.lay-layer-loading-2 { + position: relative; + height: 38px; +} +.lay-layer-loading-2:before, +.lay-layer-loading-2:after { + content: ''; + position: absolute; + left: 50%; + top: 50%; + width: 38px; + height: 38px; + margin: -19px 0 0 -19px; + border-radius: 50%; + border: 3px solid var(--lay-border-color-accent); + box-sizing: border-box; +} +.lay-layer-loading-2:after { + border-color: transparent; + border-left-color: #1e9fff; +} + +.lay-layer-tips { + background: none; + box-shadow: none; + border: none; +} +.lay-layer-tips .lay-layer-content { + position: relative; + line-height: 22px; + min-width: 12px; + padding: 8px 15px; + font-size: 12px; + border-radius: var(--lay-border-radius); + box-shadow: 1px 1px 3px rgba(0, 0, 0, 0.2); + background-color: #000; + color: #fff; +} +.lay-layer-tips .lay-layer-close { + right: -2px; + top: -1px; +} +.lay-layer-tips i.lay-layer-TipsG { + position: absolute; + width: 0; + height: 0; + border-width: 8px; + border-color: transparent; + border-style: dashed; +} +.lay-layer-tips i.lay-layer-TipsT, +.lay-layer-tips i.lay-layer-TipsB { + left: 5px; + border-right-style: solid; + border-right-color: #000; +} +.lay-layer-tips i.lay-layer-TipsT { + bottom: -8px; +} +.lay-layer-tips i.lay-layer-TipsB { + top: -8px; +} +.lay-layer-tips i.lay-layer-TipsR, +.lay-layer-tips i.lay-layer-TipsL { + top: 5px; + border-bottom-style: solid; + border-bottom-color: #000; +} +.lay-layer-tips i.lay-layer-TipsR { + left: -8px; +} +.lay-layer-tips i.lay-layer-TipsL { + right: -8px; +} + +/* 内置 skin */ +.lay-layer-lan .lay-layer-title { + background: #4476a7; + color: #fff; + border: none; +} +.lay-layer-lan .lay-layer-btn { + padding: 5px 10px 10px; + border-top: 1px solid #e9e7e7; +} +.lay-layer-lan .lay-layer-btn a { + background: #fff; + border-color: #e9e7e7; + color: #333; +} +.lay-layer-lan .lay-layer-btn .lay-layer-btn1 { + background: #c9c5c5; +} +.lay-layer-molv .lay-layer-title { + background: #009f95; + color: #fff; + border: none; +} +.lay-layer-molv .lay-layer-btn a { + background: #009f95; + border-color: #009f95; +} +.lay-layer-molv .lay-layer-btn .lay-layer-btn1 { + background: #92b8b1; +} +.lay-layer-lan .lay-layer-setwin .lay-icon, +.lay-layer-molv .lay-layer-setwin .lay-icon { + color: #fff; +} + +/* Windows 10 风格主题 */ +.lay-layer-win10 { + border: 1px solid #aaa; + box-shadow: 1px 1px 6px rgba(0, 0, 0, 0.3); + border-radius: none; +} +.lay-layer-win10 .lay-layer-title { + height: 32px; + line-height: 32px; + padding-left: 8px; + border-bottom: none; + font-size: 12px; +} +.lay-layer-win10 .lay-layer-setwin { + right: 0; + top: 0; +} +.lay-layer-win10 .lay-layer-setwin span { + margin-left: 0; + width: 32px; + height: 32px; + padding: 8px; +} +.lay-layer-win10.lay-layer-page .lay-layer-setwin span { + width: 38px; +} +.lay-layer-win10 .lay-layer-setwin span:hover { + background-color: #e5e5e5; +} +.lay-layer-win10 .lay-layer-setwin span.lay-icon-close:hover { + background-color: #e81123; + color: #fff; +} +.lay-layer-win10.lay-layer-dialog .lay-layer-content { + padding: var(--lay-spacing-sm) var(--lay-spacing) var(--lay-spacing-lg); + color: #0033bc; +} +.lay-layer-win10.lay-layer-dialog .lay-layer-padding { + padding-top: 18px; + padding-left: 58px; +} +.lay-layer-win10 .lay-layer-btn { + padding: 5px 5px 10px; + border-top: 1px solid #dfdfdf; + background-color: #f0f0f0; +} +.lay-layer-win10 .lay-layer-btn a { + height: 20px; + line-height: 18px; + background-color: #e1e1e1; + border-color: #adadad; + color: #000; + font-size: 12px; + transition: all 0.3s; +} +.lay-layer-win10 .lay-layer-btn a:hover { + border-color: #2a8edd; + background-color: #e5f1fb; +} +.lay-layer-win10 .lay-layer-btn .lay-layer-btn0 { + border-color: #0078d7; +} + +/** + * layer 拓展层 + */ + +/* prompt */ +.lay-layer-prompt .lay-layer-input { + display: block; + width: 260px; + height: 36px; + margin: 0 auto; + line-height: 30px; + padding-left: 10px; + border: 1px solid #e6e6e6; + color: #333; +} +.lay-layer-prompt textarea.lay-layer-input { + width: 300px; + height: 100px; + line-height: 20px; + padding: 6px 10px; +} +.lay-layer-prompt .lay-layer-content { + padding: var(--lay-spacing); +} +.lay-layer-prompt .lay-layer-btn { + padding-top: 0; +} + +/* tab */ +.lay-layer-tab { + box-shadow: 1px 1px 50px rgba(0, 0, 0, 0.4); +} +.lay-layer-tab .lay-layer-title { + padding-left: 0; + overflow: visible; +} +.lay-layer-tab .lay-layer-title span { + position: relative; + display: inline-block; + vertical-align: top; + border-left: 1px solid transparent; + border-right: 1px solid transparent; + min-width: 80px; + max-width: 300px; + padding: 0 var(--lay-spacing); + text-align: center; + cursor: default; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + cursor: pointer; +} +.lay-layer-tab .lay-layer-title span.lay-this { + height: 51px; + border-left-color: var(--lay-border-color); + border-right-color: var(--lay-border-color); + background-color: #fff; + z-index: 10; +} +.lay-layer-tab .lay-layer-title span:first-child { + border-left-color: transparent; +} +.lay-layer-tabmain { + line-height: 24px; + clear: both; +} +.lay-layer-tabmain .lay-layer-tabli { + display: none; +} +.lay-layer-tabmain .lay-layer-tabli.lay-this { + display: block; +} + +/* photos */ +.lay-layer-photos { + background: none; + box-shadow: none; +} +.lay-layer-photos .lay-layer-content { + overflow: visible; + text-align: center; +} +.lay-layer-photos .layer-layer-photos-main img { + position: relative; + width: 100%; + display: inline-block; + vertical-align: top; +} +.lay-layer-photos-prev, +.lay-layer-photos-next { + position: fixed; + top: 50%; + width: 52px; + height: 52px; + line-height: 52px; + margin-top: -26px; + cursor: pointer; + font-size: 52px; + color: #717171; +} +.lay-layer-photos-prev { + left: 32px; +} +.lay-layer-photos-next { + right: 32px; +} +.lay-layer-photos-prev:hover, +.lay-layer-photos-next:hover { + color: #959595; +} + +.lay-layer-photos-toolbar { + position: fixed; + left: 0; + right: 0; + bottom: 0; + width: 100%; + height: 52px; + line-height: 52px; + background-color: rgba(0, 0, 0, 0.32); + color: #fff; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + font-size: 0; +} +.lay-layer-photos-toolbar > * { + display: inline-block; + vertical-align: top; + padding: 0 var(--lay-spacing); + font-size: 12px; + color: #fff; +} +.lay-layer-photos-toolbar * { + font-size: 12px; +} +.lay-layer-photos-header { + top: 0; + bottom: auto; +} +.lay-layer-photos-header > span { + cursor: pointer; +} +.lay-layer-photos-header > span:hover { + background-color: rgba(51, 51, 51, 0.32); +} +.lay-layer-photos-header .lay-icon { + font-size: 18px; +} +.lay-layer-photos-footer > h3 { + max-width: 65%; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.lay-layer-photos-footer a:hover { + text-decoration: underline; +} +.lay-layer-photos-footer em { + font-style: normal; +} + +/* 关闭动画 */ +@-webkit-keyframes layer-bounceOut { + 100% { + opacity: 0; + -webkit-transform: scale(0.7); + transform: scale(0.7); + } + 30% { + -webkit-transform: scale(1.05); + transform: scale(1.05); + } + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } +} +@keyframes layer-bounceOut { + 100% { + opacity: 0; + -webkit-transform: scale(0.7); + transform: scale(0.7); + } + 30% { + -webkit-transform: scale(1.05); + transform: scale(1.05); + } + 0% { + -webkit-transform: scale(1); + transform: scale(1); + } +} +.layer-anim-close { + -webkit-animation-name: layer-bounceOut; + animation-name: layer-bounceOut; + -webkit-animation-fill-mode: both; + animation-fill-mode: both; + -webkit-animation-duration: 0.2s; + animation-duration: 0.2s; +} diff --git a/src/css/modules/layer/default/icon-ext.png b/src/css/modules/layer/default/icon-ext.png deleted file mode 100644 index bbbb669bb..000000000 Binary files a/src/css/modules/layer/default/icon-ext.png and /dev/null differ diff --git a/src/css/modules/layer/default/icon.png b/src/css/modules/layer/default/icon.png deleted file mode 100644 index 3e17da8b1..000000000 Binary files a/src/css/modules/layer/default/icon.png and /dev/null differ diff --git a/src/css/modules/layer/default/layer.css b/src/css/modules/layer/default/layer.css deleted file mode 100644 index 5fc667e27..000000000 --- a/src/css/modules/layer/default/layer.css +++ /dev/null @@ -1,183 +0,0 @@ -/** - - @Name: layer - @Author: 贤心 - - **/ - -*html{background-image: url(about:blank); background-attachment: fixed;} -html #layuicss-skinlayercss{display: none; position: absolute; width: 1989px;} - -/* common */ -.layui-layer-shade, .layui-layer{position:fixed; _position:absolute; pointer-events: auto;} -.layui-layer-shade{top:0; left:0; width:100%; height:100%; _height:expression(document.body.offsetHeight+"px");} -.layui-layer{-webkit-overflow-scrolling: touch;} -.layui-layer{top:150px; left: 0; margin:0; padding:0; background-color:#fff; -webkit-background-clip: content; box-shadow: 1px 1px 50px rgba(0,0,0,.3);} -.layui-layer-close{position:absolute;} -.layui-layer-content{position:relative;} -.layui-layer-border{border: 1px solid #B2B2B2; border: 1px solid rgba(0,0,0,.1); box-shadow: 1px 1px 5px rgba(0,0,0,.2);} -.layui-layer-load{background:url(loading-1.gif) #eee center center no-repeat;} -.layui-layer-ico{ background:url(icon.png) no-repeat;} -.layui-layer-dialog .layui-layer-ico, -.layui-layer-setwin a, -.layui-layer-btn a{display:inline-block; *display:inline; *zoom:1; vertical-align:top;} - -.layui-layer-move{display: none; position: fixed; *position: absolute; left: 0px; top: 0px; width: 100%; height: 100%; cursor: move; opacity: 0; filter:alpha(opacity=0); background-color: #fff; z-index: 2147483647;} -.layui-layer-resize{position: absolute; width: 15px; height: 15px; right: 0; bottom: 0; cursor: se-resize;} - -/* 动画 */ -.layui-layer{border-radius: 2px; -webkit-animation-fill-mode: both; animation-fill-mode: both; -webkit-animation-duration:.3s; animation-duration:.3s;} - -@-webkit-keyframes layer-bounceIn { /* 默认 */ - 0% {opacity: 0; -webkit-transform: scale(.5); transform: scale(.5)} - 100% {opacity: 1; -webkit-transform: scale(1); transform: scale(1)} -} -@keyframes layer-bounceIn { - 0% {opacity: 0; -webkit-transform: scale(.5); -ms-transform: scale(.5); transform: scale(.5)} - 100% {opacity: 1; -webkit-transform: scale(1); -ms-transform: scale(1); transform: scale(1)} -} -.layer-anim{-webkit-animation-name: layer-bounceIn;animation-name: layer-bounceIn} - -@-webkit-keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInDown{0%{opacity:0;-webkit-transform:scale(.1) translateY(-2000px);-ms-transform:scale(.1) translateY(-2000px);transform:scale(.1) translateY(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateY(60px);-ms-transform:scale(.475) translateY(60px);transform:scale(.475) translateY(60px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-01{-webkit-animation-name:layer-zoomInDown;animation-name:layer-zoomInDown} - -@-webkit-keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);transform:translateY(0)}}@keyframes layer-fadeInUpBig{0%{opacity:0;-webkit-transform:translateY(2000px);-ms-transform:translateY(2000px);transform:translateY(2000px)}100%{opacity:1;-webkit-transform:translateY(0);-ms-transform:translateY(0);transform:translateY(0)}}.layer-anim-02{-webkit-animation-name:layer-fadeInUpBig;animation-name:layer-fadeInUpBig} - -@-webkit-keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}@keyframes layer-zoomInLeft{0%{opacity:0;-webkit-transform:scale(.1) translateX(-2000px);-ms-transform:scale(.1) translateX(-2000px);transform:scale(.1) translateX(-2000px);-webkit-animation-timing-function:ease-in-out;animation-timing-function:ease-in-out}60%{opacity:1;-webkit-transform:scale(.475) translateX(48px);-ms-transform:scale(.475) translateX(48px);transform:scale(.475) translateX(48px);-webkit-animation-timing-function:ease-out;animation-timing-function:ease-out}}.layer-anim-03{-webkit-animation-name:layer-zoomInLeft;animation-name:layer-zoomInLeft} - -@-webkit-keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}@keyframes layer-rollIn{0%{opacity:0;-webkit-transform:translateX(-100%) rotate(-120deg);-ms-transform:translateX(-100%) rotate(-120deg);transform:translateX(-100%) rotate(-120deg)}100%{opacity:1;-webkit-transform:translateX(0px) rotate(0deg);-ms-transform:translateX(0px) rotate(0deg);transform:translateX(0px) rotate(0deg)}}.layer-anim-04{-webkit-animation-name:layer-rollIn;animation-name:layer-rollIn} - -@keyframes layer-fadeIn{0%{opacity:0}100%{opacity:1}}.layer-anim-05{-webkit-animation-name:layer-fadeIn;animation-name:layer-fadeIn} - -@-webkit-keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);transform:translateX(10px)}}@keyframes layer-shake{0%,100%{-webkit-transform:translateX(0);-ms-transform:translateX(0);transform:translateX(0)}10%,30%,50%,70%,90%{-webkit-transform:translateX(-10px);-ms-transform:translateX(-10px);transform:translateX(-10px)}20%,40%,60%,80%{-webkit-transform:translateX(10px);-ms-transform:translateX(10px);transform:translateX(10px)}}.layer-anim-06{-webkit-animation-name:layer-shake;animation-name:layer-shake}@-webkit-keyframes fadeIn{0%{opacity:0}100%{opacity:1}} - -/* 标题栏 */ -.layui-layer-title{padding:0 80px 0 20px; height:42px; line-height:42px; border-bottom:1px solid #eee; font-size:14px; color:#333; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; background-color: #F8F8F8; border-radius: 2px 2px 0 0;} -.layui-layer-setwin{position:absolute; right:15px; *right:0; top:15px; font-size:0; line-height: initial;} -.layui-layer-setwin a{position:relative; width: 16px; height:16px; margin-left:10px; font-size:12px; _overflow:hidden;} -.layui-layer-setwin .layui-layer-min cite{position:absolute; width:14px; height:2px; left:0; top:50%; margin-top:-1px; background-color:#2E2D3C; cursor:pointer; _overflow:hidden;} -.layui-layer-setwin .layui-layer-min:hover cite{background-color:#2D93CA; } -.layui-layer-setwin .layui-layer-max{background-position:-32px -40px;} -.layui-layer-setwin .layui-layer-max:hover{background-position:-16px -40px;} -.layui-layer-setwin .layui-layer-maxmin{background-position:-65px -40px;} -.layui-layer-setwin .layui-layer-maxmin:hover{background-position:-49px -40px;} -.layui-layer-setwin .layui-layer-close1{background-position: 1px -40px; cursor: pointer;} -.layui-layer-setwin .layui-layer-close1:hover{opacity:0.7;} -.layui-layer-setwin .layui-layer-close2{position:absolute; right:-28px; top:-28px; width:30px; height:30px; margin-left:0; background-position:-149px -31px; *right:-18px; _display:none;} -.layui-layer-setwin .layui-layer-close2:hover{ background-position:-180px -31px;} - -/* 按钮栏 */ -.layui-layer-btn{text-align: right; padding:0 10px 12px; pointer-events: auto; user-select: none; -webkit-user-select: none;} -.layui-layer-btn a{height: 28px; line-height: 28px; margin: 6px 6px 0; padding: 0 15px; border:1px #dedede solid; background-color:#f1f1f1; color: #333; border-radius: 2px; font-weight:400; cursor:pointer; text-decoration: none;} -.layui-layer-btn a:hover{opacity: 0.9; text-decoration: none;} -.layui-layer-btn a:active{opacity: 0.8;} -.layui-layer-btn .layui-layer-btn0{border-color: #4898d5; background-color: #2e8ded; color:#fff;} -.layui-layer-btn-l{text-align: left;} -.layui-layer-btn-c{text-align: center;} - -/* 定制化 */ -.layui-layer-dialog{min-width:260px;} -.layui-layer-dialog .layui-layer-content{position: relative; padding:20px; line-height:24px; word-break: break-all; overflow:hidden; font-size:14px; overflow-x: hidden; overflow-y:auto;} -.layui-layer-dialog .layui-layer-content .layui-layer-ico{position:absolute; top:16px; left:15px; _left:-40px; width:30px; height:30px;} -.layui-layer-ico1{background-position:-30px 0 } -.layui-layer-ico2{background-position:-60px 0;} -.layui-layer-ico3{background-position:-90px 0;} -.layui-layer-ico4{background-position:-120px 0;} -.layui-layer-ico5{background-position:-150px 0;} -.layui-layer-ico6{background-position:-180px 0;} -.layui-layer-rim{border:6px solid #8D8D8D; border:6px solid rgba(0,0,0,.3); border-radius:5px; box-shadow: none;} -.layui-layer-msg{min-width:180px; border:1px solid #D3D4D3; box-shadow: none;} -.layui-layer-hui{min-width:100px; background-color: #000; filter:alpha(opacity=60); background-color: rgba(0,0,0,0.6); color: #fff; border:none;} -.layui-layer-hui .layui-layer-content{padding:12px 25px; text-align:center;} -.layui-layer-dialog .layui-layer-padding{padding: 20px 20px 20px 55px; text-align: left;} -.layui-layer-page .layui-layer-content{position:relative; overflow:auto;} -.layui-layer-page .layui-layer-btn,.layui-layer-iframe .layui-layer-btn{padding-top:10px;} -.layui-layer-nobg{background:none;} -.layui-layer-iframe iframe{display: block; width: 100%;} - -.layui-layer-loading{border-radius:100%; background:none; box-shadow:none; border:none;} -.layui-layer-loading .layui-layer-content{width:60px; height:24px; background:url(loading-0.gif) no-repeat;} -.layui-layer-loading .layui-layer-loading1{width:37px; height:37px; background:url(loading-1.gif) no-repeat;} -.layui-layer-loading .layui-layer-loading2, .layui-layer-ico16{width:32px; height:32px; background:url(loading-2.gif) no-repeat;} -.layui-layer-tips{background: none; box-shadow:none; border:none;} -.layui-layer-tips .layui-layer-content{position: relative; line-height: 22px; min-width: 12px; padding: 5px 10px; font-size: 12px; _float:left; border-radius: 2px; box-shadow: 1px 1px 3px rgba(0,0,0,.2); background-color: #000; color: #fff;} -.layui-layer-tips .layui-layer-close{right:-2px; top:-1px;} -.layui-layer-tips i.layui-layer-TipsG{ position:absolute; width:0; height:0; border-width:8px; border-color:transparent; border-style:dashed; *overflow:hidden;} -.layui-layer-tips i.layui-layer-TipsT, .layui-layer-tips i.layui-layer-TipsB{left:5px; border-right-style:solid; border-right-color: #000;} -.layui-layer-tips i.layui-layer-TipsT{bottom:-8px;} -.layui-layer-tips i.layui-layer-TipsB{top:-8px;} -.layui-layer-tips i.layui-layer-TipsR, .layui-layer-tips i.layui-layer-TipsL{top:1px; border-bottom-style:solid; border-bottom-color: #000;} -.layui-layer-tips i.layui-layer-TipsR{left:-8px;} -.layui-layer-tips i.layui-layer-TipsL{right:-8px;} - -/* skin */ -.layui-layer-lan[type="dialog"]{min-width:280px;} -.layui-layer-lan .layui-layer-title{background:#4476A7; color:#fff; border: none;} -.layui-layer-lan .layui-layer-btn{padding: 5px 10px 10px; text-align: right; border-top:1px solid #E9E7E7} -.layui-layer-lan .layui-layer-btn a{background:#BBB5B5; border:none;} -.layui-layer-lan .layui-layer-btn .layui-layer-btn1{background:#C9C5C5;} -.layui-layer-molv .layui-layer-title{background:#009f95; color:#fff; border: none;} -.layui-layer-molv .layui-layer-btn a{background:#009f95;} -.layui-layer-molv .layui-layer-btn .layui-layer-btn1{background:#92B8B1;} - - - -/** - - @Name: layer拓展样式 - - */ - -.layui-layer-iconext{background:url(icon-ext.png) no-repeat;} - -/* prompt模式 */ -.layui-layer-prompt .layui-layer-input{display:block; width:220px; height:30px; margin:0 auto; line-height:30px; padding: 0 5px; border: 1px solid #ccc; box-shadow: 1px 1px 5px rgba(0,0,0,.1) inset; color:#333;} -.layui-layer-prompt textarea.layui-layer-input{width:300px; height:100px; line-height:20px;} -.layui-layer-prompt .layui-layer-content{padding: 20px;} -.layui-layer-prompt .layui-layer-btn{padding-top: 0;} - -/* tab模式 */ -.layui-layer-tab{box-shadow:1px 1px 50px rgba(0,0,0,.4);} -.layui-layer-tab .layui-layer-title{padding-left:0; border-bottom:1px solid #ccc; background-color:#eee; overflow: visible;} -.layui-layer-tab .layui-layer-title span{position:relative; float:left; min-width:80px; max-width:260px; padding:0 20px; text-align:center; cursor:default; text-overflow: ellipsis; overflow: hidden; white-space: nowrap;} -.layui-layer-tab .layui-layer-title span.layui-layer-tabnow{height:43px; border-left:1px solid #ccc; border-right:1px solid #ccc; background-color:#fff; z-index:10;} -.layui-layer-tab .layui-layer-title span:first-child{border-left:none;} -.layui-layer-tabmain{line-height:24px; clear:both;} -.layui-layer-tabmain .layui-layer-tabli{display:none;} -.layui-layer-tabmain .layui-layer-tabli.xubox_tab_layer{display:block;} -.xubox_tabclose{position:absolute; right:10px; top:5px; cursor:pointer;} - -/* photo模式 */ -.layui-layer-photos{-webkit-animation-duration: .8s; animation-duration: .8s;} -.layui-layer-photos .layui-layer-content{overflow:hidden; text-align: center;} -.layui-layer-photos .layui-layer-phimg img{position: relative; width:100%; display: inline-block; *display:inline; *zoom:1; vertical-align:top;} -.layui-layer-imguide,.layui-layer-imgbar{display:none;} -.layui-layer-imgprev, .layui-layer-imgnext{position:absolute; top:50%; width:27px; _width:44px; height:44px; margin-top:-22px; outline:none;blr:expression(this.onFocus=this.blur());} -.layui-layer-imgprev{left:10px; background-position:-5px -5px; _background-position:-70px -5px;} -.layui-layer-imgprev:hover{background-position:-33px -5px; _background-position:-120px -5px;} -.layui-layer-imgnext{right:10px; _right:8px; background-position:-5px -50px; _background-position:-70px -50px;} -.layui-layer-imgnext:hover{background-position:-33px -50px; _background-position:-120px -50px;} -.layui-layer-imgbar{position:absolute; left:0; bottom:0; width:100%; height:32px; line-height:32px; background-color:rgba(0,0,0,.8); background-color:#000\9; filter:Alpha(opacity=80); color:#fff; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size:0;} -.layui-layer-imgtit{/*position:absolute; left:20px;*/} -.layui-layer-imgtit *{display:inline-block; *display:inline; *zoom:1; vertical-align:top; font-size:12px;} -.layui-layer-imgtit a{max-width:65%; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; color:#fff;} -.layui-layer-imgtit a:hover{color:#fff; text-decoration:underline;} -.layui-layer-imgtit em{padding-left:10px; font-style: normal;} - -/* 关闭动画 */ -@-webkit-keyframes layer-bounceOut { - 100% {opacity: 0; -webkit-transform: scale(.7); transform: scale(.7)} - 30% {-webkit-transform: scale(1.05); transform: scale(1.05)} - 0% {-webkit-transform: scale(1); transform: scale(1);} -} -@keyframes layer-bounceOut { - 100% {opacity: 0; -webkit-transform: scale(.7); -ms-transform: scale(.7); transform: scale(.7);} - 30% {-webkit-transform: scale(1.05); -ms-transform: scale(1.05); transform: scale(1.05);} - 0% {-webkit-transform: scale(1); -ms-transform: scale(1);transform: scale(1);} -} -.layer-anim-close{-webkit-animation-name: layer-bounceOut;animation-name: layer-bounceOut; -webkit-animation-duration:.2s; animation-duration:.2s;} - -@media screen and (max-width: 1100px) { - .layui-layer-iframe{overflow-y: auto; -webkit-overflow-scrolling: touch;} -} - - diff --git a/src/css/modules/layer/default/loading-0.gif b/src/css/modules/layer/default/loading-0.gif deleted file mode 100644 index 6f3c9539a..000000000 Binary files a/src/css/modules/layer/default/loading-0.gif and /dev/null differ diff --git a/src/css/modules/layer/default/loading-1.gif b/src/css/modules/layer/default/loading-1.gif deleted file mode 100644 index db3a483e4..000000000 Binary files a/src/css/modules/layer/default/loading-1.gif and /dev/null differ diff --git a/src/css/modules/layer/default/loading-2.gif b/src/css/modules/layer/default/loading-2.gif deleted file mode 100644 index 5bb90fd6a..000000000 Binary files a/src/css/modules/layer/default/loading-2.gif and /dev/null differ diff --git a/src/css/modules/layout.css b/src/css/modules/layout.css new file mode 100644 index 000000000..5375d2c9d --- /dev/null +++ b/src/css/modules/layout.css @@ -0,0 +1,877 @@ +/* 基本布局 */ +.lay-main { + position: relative; + width: 1160px; + margin: 0 auto; +} +.lay-header { + position: relative; + z-index: 1000; + height: 60px; +} +.lay-header a:hover { + -webkit-transition: all 0.5s; + transition: all 0.5s; +} +.lay-side { + position: fixed; + left: 0; + top: 0; + bottom: 0; + z-index: 999; + width: 200px; + overflow-x: hidden; +} +.lay-side-scroll { + position: relative; + width: 220px; + height: 100%; + overflow-x: hidden; +} +.lay-body { + position: relative; + left: 200px; + right: 0; + top: 0; + bottom: 0; + width: auto; + box-sizing: border-box; +} + +/* 后台框架大布局 */ +.lay-layout-body { + overflow-x: hidden; +} +.lay-layout-admin .lay-header { + position: fixed; + top: 0; + left: 0; + right: 0; + background-color: #23292e; +} +.lay-layout-admin .lay-side { + top: 60px; + width: 200px; + overflow-x: hidden; +} +.lay-layout-admin .lay-body { + position: absolute; + top: 60px; + padding-bottom: 44px; +} +.lay-layout-admin .lay-main { + width: auto; + margin: 0 15px; +} +.lay-layout-admin .lay-footer { + position: fixed; + left: 200px; + right: 0; + bottom: 0; + z-index: 990; + height: 44px; + line-height: 44px; + padding: 0 15px; + box-shadow: -1px 0 4px rgb(0 0 0 / 12%); + background-color: var(--lay-color-gray); +} +.lay-layout-admin .lay-logo { + position: absolute; + left: 0; + top: 0; + width: 200px; + height: 100%; + line-height: 60px; + text-align: center; + color: var(--lay-color-primary); + font-size: 16px; + box-shadow: 0 1px 2px 0 rgb(0 0 0 / 15%); +} +.lay-layout-admin .lay-header .lay-nav { + background: none; +} +.lay-layout-left { + position: absolute !important; + left: 200px; + top: 0; +} +.lay-layout-right { + position: absolute !important; + right: 0; + top: 0; +} + +/* 栅格布局 */ +.lay-container { + position: relative; + margin: 0 auto; + box-sizing: border-box; +} +.lay-fluid { + position: relative; + margin: 0 auto; + padding: 0 15px; +} + +.lay-row:before, +.lay-row:after { + content: ''; + display: block; + clear: both; +} +.lay-col-xs1, +.lay-col-xs2, +.lay-col-xs3, +.lay-col-xs4, +.lay-col-xs5, +.lay-col-xs6, +.lay-col-xs7, +.lay-col-xs8, +.lay-col-xs9, +.lay-col-xs10, +.lay-col-xs11, +.lay-col-xs12, +.lay-col-sm1, +.lay-col-sm2, +.lay-col-sm3, +.lay-col-sm4, +.lay-col-sm5, +.lay-col-sm6, +.lay-col-sm7, +.lay-col-sm8, +.lay-col-sm9, +.lay-col-sm10, +.lay-col-sm11, +.lay-col-sm12, +.lay-col-md1, +.lay-col-md2, +.lay-col-md3, +.lay-col-md4, +.lay-col-md5, +.lay-col-md6, +.lay-col-md7, +.lay-col-md8, +.lay-col-md9, +.lay-col-md10, +.lay-col-md11, +.lay-col-md12, +.lay-col-lg1, +.lay-col-lg2, +.lay-col-lg3, +.lay-col-lg4, +.lay-col-lg5, +.lay-col-lg6, +.lay-col-lg7, +.lay-col-lg8, +.lay-col-lg9, +.lay-col-lg10, +.lay-col-lg11, +.lay-col-lg12, +.lay-col-xl1, +.lay-col-xl2, +.lay-col-xl3, +.lay-col-xl4, +.lay-col-xl5, +.lay-col-xl6, +.lay-col-xl7, +.lay-col-xl8, +.lay-col-xl9, +.lay-col-xl10, +.lay-col-xl11, +.lay-col-xl12 { + position: relative; + display: block; + box-sizing: border-box; +} + +.lay-col-xs1, +.lay-col-xs2, +.lay-col-xs3, +.lay-col-xs4, +.lay-col-xs5, +.lay-col-xs6, +.lay-col-xs7, +.lay-col-xs8, +.lay-col-xs9, +.lay-col-xs10, +.lay-col-xs11, +.lay-col-xs12 { + float: left; +} +.lay-col-xs1 { + width: 8.33333333%; +} +.lay-col-xs2 { + width: 16.66666667%; +} +.lay-col-xs3 { + width: 25%; +} +.lay-col-xs4 { + width: 33.33333333%; +} +.lay-col-xs5 { + width: 41.66666667%; +} +.lay-col-xs6 { + width: 50%; +} +.lay-col-xs7 { + width: 58.33333333%; +} +.lay-col-xs8 { + width: 66.66666667%; +} +.lay-col-xs9 { + width: 75%; +} +.lay-col-xs10 { + width: 83.33333333%; +} +.lay-col-xs11 { + width: 91.66666667%; +} +.lay-col-xs12 { + width: 100%; +} + +.lay-col-xs-offset1 { + margin-left: 8.33333333%; +} +.lay-col-xs-offset2 { + margin-left: 16.66666667%; +} +.lay-col-xs-offset3 { + margin-left: 25%; +} +.lay-col-xs-offset4 { + margin-left: 33.33333333%; +} +.lay-col-xs-offset5 { + margin-left: 41.66666667%; +} +.lay-col-xs-offset6 { + margin-left: 50%; +} +.lay-col-xs-offset7 { + margin-left: 58.33333333%; +} +.lay-col-xs-offset8 { + margin-left: 66.66666667%; +} +.lay-col-xs-offset9 { + margin-left: 75%; +} +.lay-col-xs-offset10 { + margin-left: 83.33333333%; +} +.lay-col-xs-offset11 { + margin-left: 91.66666667%; +} +.lay-col-xs-offset12 { + margin-left: 100%; +} + +/* 超小屏幕 */ +@media screen and (max-width: 767.98px) { + .lay-container { + padding: 0 15px; + } + .lay-hide-xs { + display: none !important; + } + .lay-show-xs-block { + display: block !important; + } + .lay-show-xs-inline { + display: inline !important; + } + .lay-show-xs-inline-block { + display: inline-block !important; + } +} + +/* 小型屏幕 */ +@media screen and (min-width: 768px) { + .lay-container { + width: 720px; + } + .lay-hide-sm { + display: none !important; + } + .lay-show-sm-block { + display: block !important; + } + .lay-show-sm-inline { + display: inline !important; + } + .lay-show-sm-inline-block { + display: inline-block !important; + } + + .lay-col-sm1, + .lay-col-sm2, + .lay-col-sm3, + .lay-col-sm4, + .lay-col-sm5, + .lay-col-sm6, + .lay-col-sm7, + .lay-col-sm8, + .lay-col-sm9, + .lay-col-sm10, + .lay-col-sm11, + .lay-col-sm12 { + float: left; + } + .lay-col-sm1 { + width: 8.33333333%; + } + .lay-col-sm2 { + width: 16.66666667%; + } + .lay-col-sm3 { + width: 25%; + } + .lay-col-sm4 { + width: 33.33333333%; + } + .lay-col-sm5 { + width: 41.66666667%; + } + .lay-col-sm6 { + width: 50%; + } + .lay-col-sm7 { + width: 58.33333333%; + } + .lay-col-sm8 { + width: 66.66666667%; + } + .lay-col-sm9 { + width: 75%; + } + .lay-col-sm10 { + width: 83.33333333%; + } + .lay-col-sm11 { + width: 91.66666667%; + } + .lay-col-sm12 { + width: 100%; + } + /* 列偏移 */ + .lay-col-sm-offset1 { + margin-left: 8.33333333%; + } + .lay-col-sm-offset2 { + margin-left: 16.66666667%; + } + .lay-col-sm-offset3 { + margin-left: 25%; + } + .lay-col-sm-offset4 { + margin-left: 33.33333333%; + } + .lay-col-sm-offset5 { + margin-left: 41.66666667%; + } + .lay-col-sm-offset6 { + margin-left: 50%; + } + .lay-col-sm-offset7 { + margin-left: 58.33333333%; + } + .lay-col-sm-offset8 { + margin-left: 66.66666667%; + } + .lay-col-sm-offset9 { + margin-left: 75%; + } + .lay-col-sm-offset10 { + margin-left: 83.33333333%; + } + .lay-col-sm-offset11 { + margin-left: 91.66666667%; + } + .lay-col-sm-offset12 { + margin-left: 100%; + } +} +/* 中型屏幕 */ +@media screen and (min-width: 992px) { + .lay-container { + width: 960px; + } + .lay-hide-md { + display: none !important; + } + .lay-show-md-block { + display: block !important; + } + .lay-show-md-inline { + display: inline !important; + } + .lay-show-md-inline-block { + display: inline-block !important; + } + + .lay-col-md1, + .lay-col-md2, + .lay-col-md3, + .lay-col-md4, + .lay-col-md5, + .lay-col-md6, + .lay-col-md7, + .lay-col-md8, + .lay-col-md9, + .lay-col-md10, + .lay-col-md11, + .lay-col-md12 { + float: left; + } + .lay-col-md1 { + width: 8.33333333%; + } + .lay-col-md2 { + width: 16.66666667%; + } + .lay-col-md3 { + width: 25%; + } + .lay-col-md4 { + width: 33.33333333%; + } + .lay-col-md5 { + width: 41.66666667%; + } + .lay-col-md6 { + width: 50%; + } + .lay-col-md7 { + width: 58.33333333%; + } + .lay-col-md8 { + width: 66.66666667%; + } + .lay-col-md9 { + width: 75%; + } + .lay-col-md10 { + width: 83.33333333%; + } + .lay-col-md11 { + width: 91.66666667%; + } + .lay-col-md12 { + width: 100%; + } + /* 列偏移 */ + .lay-col-md-offset1 { + margin-left: 8.33333333%; + } + .lay-col-md-offset2 { + margin-left: 16.66666667%; + } + .lay-col-md-offset3 { + margin-left: 25%; + } + .lay-col-md-offset4 { + margin-left: 33.33333333%; + } + .lay-col-md-offset5 { + margin-left: 41.66666667%; + } + .lay-col-md-offset6 { + margin-left: 50%; + } + .lay-col-md-offset7 { + margin-left: 58.33333333%; + } + .lay-col-md-offset8 { + margin-left: 66.66666667%; + } + .lay-col-md-offset9 { + margin-left: 75%; + } + .lay-col-md-offset10 { + margin-left: 83.33333333%; + } + .lay-col-md-offset11 { + margin-left: 91.66666667%; + } + .lay-col-md-offset12 { + margin-left: 100%; + } +} +/* 大型屏幕 */ +@media screen and (min-width: 1200px) { + .lay-container { + width: 1150px; + } + .lay-hide-lg { + display: none !important; + } + .lay-show-lg-block { + display: block !important; + } + .lay-show-lg-inline { + display: inline !important; + } + .lay-show-lg-inline-block { + display: inline-block !important; + } + + .lay-col-lg1, + .lay-col-lg2, + .lay-col-lg3, + .lay-col-lg4, + .lay-col-lg5, + .lay-col-lg6, + .lay-col-lg7, + .lay-col-lg8, + .lay-col-lg9, + .lay-col-lg10, + .lay-col-lg11, + .lay-col-lg12 { + float: left; + } + .lay-col-lg1 { + width: 8.33333333%; + } + .lay-col-lg2 { + width: 16.66666667%; + } + .lay-col-lg3 { + width: 25%; + } + .lay-col-lg4 { + width: 33.33333333%; + } + .lay-col-lg5 { + width: 41.66666667%; + } + .lay-col-lg6 { + width: 50%; + } + .lay-col-lg7 { + width: 58.33333333%; + } + .lay-col-lg8 { + width: 66.66666667%; + } + .lay-col-lg9 { + width: 75%; + } + .lay-col-lg10 { + width: 83.33333333%; + } + .lay-col-lg11 { + width: 91.66666667%; + } + .lay-col-lg12 { + width: 100%; + } + /* 列偏移 */ + .lay-col-lg-offset1 { + margin-left: 8.33333333%; + } + .lay-col-lg-offset2 { + margin-left: 16.66666667%; + } + .lay-col-lg-offset3 { + margin-left: 25%; + } + .lay-col-lg-offset4 { + margin-left: 33.33333333%; + } + .lay-col-lg-offset5 { + margin-left: 41.66666667%; + } + .lay-col-lg-offset6 { + margin-left: 50%; + } + .lay-col-lg-offset7 { + margin-left: 58.33333333%; + } + .lay-col-lg-offset8 { + margin-left: 66.66666667%; + } + .lay-col-lg-offset9 { + margin-left: 75%; + } + .lay-col-lg-offset10 { + margin-left: 83.33333333%; + } + .lay-col-lg-offset11 { + margin-left: 91.66666667%; + } + .lay-col-lg-offset12 { + margin-left: 100%; + } +} +/* 超大屏幕 */ +@media screen and (min-width: 1400px) { + .lay-container { + width: 1330px; + } + .lay-hide-xl { + display: none !important; + } + .lay-show-xl-block { + display: block !important; + } + .lay-show-xl-inline { + display: inline !important; + } + .lay-show-xl-inline-block { + display: inline-block !important; + } + + .lay-col-xl1, + .lay-col-xl2, + .lay-col-xl3, + .lay-col-xl4, + .lay-col-xl5, + .lay-col-xl6, + .lay-col-xl7, + .lay-col-xl8, + .lay-col-xl9, + .lay-col-xl10, + .lay-col-xl11, + .lay-col-xl12 { + float: left; + } + .lay-col-xl1 { + width: 8.33333333%; + } + .lay-col-xl2 { + width: 16.66666667%; + } + .lay-col-xl3 { + width: 25%; + } + .lay-col-xl4 { + width: 33.33333333%; + } + .lay-col-xl5 { + width: 41.66666667%; + } + .lay-col-xl6 { + width: 50%; + } + .lay-col-xl7 { + width: 58.33333333%; + } + .lay-col-xl8 { + width: 66.66666667%; + } + .lay-col-xl9 { + width: 75%; + } + .lay-col-xl10 { + width: 83.33333333%; + } + .lay-col-xl11 { + width: 91.66666667%; + } + .lay-col-xl12 { + width: 100%; + } + /* 列偏移 */ + .lay-col-xl-offset1 { + margin-left: 8.33333333%; + } + .lay-col-xl-offset2 { + margin-left: 16.66666667%; + } + .lay-col-xl-offset3 { + margin-left: 25%; + } + .lay-col-xl-offset4 { + margin-left: 33.33333333%; + } + .lay-col-xl-offset5 { + margin-left: 41.66666667%; + } + .lay-col-xl-offset6 { + margin-left: 50%; + } + .lay-col-xl-offset7 { + margin-left: 58.33333333%; + } + .lay-col-xl-offset8 { + margin-left: 66.66666667%; + } + .lay-col-xl-offset9 { + margin-left: 75%; + } + .lay-col-xl-offset10 { + margin-left: 83.33333333%; + } + .lay-col-xl-offset11 { + margin-left: 91.66666667%; + } + .lay-col-xl-offset12 { + margin-left: 100%; + } +} + +/* 列间隔 */ +.lay-col-space1 { + margin: -0.5px; +} +.lay-col-space1 > * { + padding: 0.5px; +} +.lay-col-space2 { + margin: -1px; +} +.lay-col-space2 > * { + padding: 1px; +} +.lay-col-space4 { + margin: -2px; +} +.lay-col-space4 > * { + padding: 2px; +} +.lay-col-space5 { + margin: -2.5px; +} +.lay-col-space5 > * { + padding: 2.5px; +} +.lay-col-space6 { + margin: -3px; +} +.lay-col-space6 > * { + padding: 3px; +} +.lay-col-space8 { + margin: -4px; +} +.lay-col-space8 > * { + padding: 4px; +} +.lay-col-space10 { + margin: -5px; +} +.lay-col-space10 > * { + padding: 5px; +} +.lay-col-space12 { + margin: -6px; +} +.lay-col-space12 > * { + padding: 6px; +} +.lay-col-space14 { + margin: -7px; +} +.lay-col-space14 > * { + padding: 7px; +} +.lay-col-space15 { + margin: -7.5px; +} +.lay-col-space15 > * { + padding: 7.5px; +} +.lay-col-space16 { + margin: -8px; +} +.lay-col-space16 > * { + padding: 8px; +} +.lay-col-space18 { + margin: -9px; +} +.lay-col-space18 > * { + padding: 9px; +} +.lay-col-space20 { + margin: -10px; +} +.lay-col-space20 > * { + padding: 10px; +} +.lay-col-space22 { + margin: -11px; +} +.lay-col-space22 > * { + padding: 11px; +} +.lay-col-space24 { + margin: -12px; +} +.lay-col-space24 > * { + padding: 12px; +} +.lay-col-space25 { + margin: -12.5px; +} +.lay-col-space25 > * { + padding: 12.5px; +} +.lay-col-space26 { + margin: -13px; +} +.lay-col-space26 > * { + padding: 13px; +} +.lay-col-space28 { + margin: -14px; +} +.lay-col-space28 > * { + padding: 14px; +} +.lay-col-space30 { + margin: -15px; +} +.lay-col-space30 > * { + padding: 15px; +} +.lay-col-space32 { + margin: -16px; +} +.lay-col-space32 > * { + padding: 16px; +} + +/* + * 内边距 + */ +.lay-padding-1 { + padding: var(--lay-spacing-xs) !important; +} +.lay-padding-2 { + padding: var(--lay-spacing-sm) !important; +} +.lay-padding-3 { + padding: var(--lay-spacing) !important; +} +.lay-padding-4 { + padding: var(--lay-spacing-lg) !important; +} +.lay-padding-5 { + padding: var(--lay-spacing-xl) !important; +} + +/* + * 外边距 + */ +.lay-margin-1 { + margin: var(--lay-spacing-xs) !important; +} +.lay-margin-2 { + margin: var(--lay-spacing-sm) !important; +} +.lay-margin-3 { + margin: var(--lay-spacing) !important; +} +.lay-margin-4 { + margin: var(--lay-spacing-lg) !important; +} +.lay-margin-5 { + margin: var(--lay-spacing-xl) !important; +} diff --git a/src/css/modules/laypage.css b/src/css/modules/laypage.css new file mode 100644 index 000000000..3f25a5128 --- /dev/null +++ b/src/css/modules/laypage.css @@ -0,0 +1,136 @@ +/** 分页 **/ +.lay-laypage { + display: inline-block; + vertical-align: middle; + margin: 10px 0; + font-size: 0; +} +.lay-laypage > a:first-child, +.lay-laypage > a:first-child em { + border-radius: var(--lay-border-radius) 0 0 var(--lay-border-radius); +} +.lay-laypage > a:last-child, +.lay-laypage > a:last-child em { + border-radius: 0 var(--lay-border-radius) var(--lay-border-radius) 0; +} +.lay-laypage > *:first-child { + margin-left: 0 !important; +} +.lay-laypage > *:last-child { + margin-right: 0 !important; +} +.lay-laypage a, +.lay-laypage span, +.lay-laypage input, +.lay-laypage button, +.lay-laypage select { + border: 1px solid var(--lay-border-color); +} +.lay-laypage a, +.lay-laypage span { + display: inline-block; + vertical-align: middle; + padding: 0 15px; + height: 28px; + line-height: 28px; + margin: 0 -1px 5px 0; + background-color: #fff; + color: #333; + font-size: 12px; +} +.lay-laypage a[data-page] { + color: #333; +} +.lay-laypage a { + text-decoration: none !important; + cursor: pointer; +} +.lay-laypage a:hover { + color: var(--lay-color-primary); +} +.lay-laypage em { + font-style: normal; +} +.lay-laypage .lay-laypage-spr { + color: #999; + font-weight: 700; +} +.lay-laypage .lay-laypage-curr { + position: relative; +} +.lay-laypage .lay-laypage-curr em { + position: relative; + color: #fff; +} +.lay-laypage .lay-laypage-curr .lay-laypage-em { + position: absolute; + left: -1px; + top: -1px; + padding: 1px; + width: 100%; + height: 100%; + background-color: var(--lay-color-primary); +} +.lay-laypage-em { + border-radius: var(--lay-border-radius); +} +.lay-laypage-prev em, +.lay-laypage-next em { + font-family: Sim sun; + font-size: 16px; +} + +.lay-laypage .lay-laypage-count, +.lay-laypage .lay-laypage-limits, +.lay-laypage .lay-laypage-refresh, +.lay-laypage .lay-laypage-skip { + margin-left: 10px; + margin-right: 10px; + padding: 0; + border: none; +} +.lay-laypage .lay-laypage-limits, +.lay-laypage .lay-laypage-refresh { + vertical-align: top; +} +.lay-laypage .lay-laypage-refresh i { + font-size: 18px; + cursor: pointer; +} +.lay-laypage select { + height: 22px; + padding: 3px; + border-radius: var(--lay-border-radius); + cursor: pointer; +} +.lay-laypage .lay-laypage-skip { + height: 30px; + line-height: 30px; + color: #999; +} +.lay-laypage input, +.lay-laypage button { + height: 30px; + line-height: 30px; + border-radius: var(--lay-border-radius); + vertical-align: top; + background-color: #fff; + box-sizing: border-box; +} +.lay-laypage input { + display: inline-block; + width: 40px; + margin: 0 10px; + padding: 0 3px; + text-align: center; + transition: none; +} +.lay-laypage input:focus, +.lay-laypage select:focus { + border-color: var(--lay-color-primary) !important; +} +.lay-laypage button { + margin-left: 10px; + padding: 0 10px; + cursor: pointer; +} diff --git a/src/css/modules/menu.css b/src/css/modules/menu.css new file mode 100644 index 000000000..b4eefa1e1 --- /dev/null +++ b/src/css/modules/menu.css @@ -0,0 +1,224 @@ +/* 基础菜单元素 */ +.lay-menu { + position: relative; + margin: 5px 0; + background-color: #fff; + box-sizing: border-box; +} +.lay-menu * { + box-sizing: border-box; +} +.lay-menu li, +.lay-menu-body-title, +.lay-menu-body-title a { + padding: 5px 15px; + color: initial; +} +.lay-menu li { + position: relative; + margin: 0 0 1px; + line-height: 26px; + color: rgba(0, 0, 0, 0.8); + font-size: 14px; + white-space: nowrap; + cursor: pointer; + transition: all 0.3s; +} +.lay-menu li:hover { + background-color: #f8f8f8; +} +.lay-menu li.lay-disabled, +.lay-menu li.lay-disabled * { + background: none !important; + color: #d2d2d2 !important; + cursor: not-allowed !important; +} + +.lay-menu-item-parent:hover > .lay-menu-body-panel { + display: block; + animation-name: lay-fadein; + animation-duration: 0.3s; + animation-fill-mode: both; + animation-delay: 0.2s; +} +.lay-menu-item-parent > .lay-menu-body-title, +.lay-menu-item-group > .lay-menu-body-title { + padding-right: 38px; +} + +.lay-menu .lay-menu-item-group:hover, +.lay-menu .lay-menu-item-none:hover, +.lay-menu .lay-menu-item-divider:hover { + background: none; + cursor: default; +} +.lay-menu .lay-menu-item-group > ul { + margin: 5px 0 -5px; +} +.lay-menu .lay-menu-item-group > .lay-menu-body-title { + color: rgba(0, 0, 0, 0.35); + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.lay-menu .lay-menu-item-none { + color: rgba(0, 0, 0, 0.35); + cursor: default; +} + +.lay-menu .lay-menu-item-none { + text-align: center; +} +.lay-menu .lay-menu-item-divider { + margin: 5px 0; + padding: 0; + height: 0; + line-height: 0; + border-bottom: 1px solid var(--lay-border-color); + overflow: hidden; +} + +.lay-menu .lay-menu-item-up:hover, +.lay-menu .lay-menu-item-down:hover { + cursor: pointer; +} +.lay-menu .lay-menu-item-up > .lay-menu-body-title { + color: rgba(0, 0, 0, 0.8); +} +.lay-menu .lay-menu-item-up > ul { + visibility: hidden; + height: 0; + overflow: hidden; +} +.lay-menu .lay-menu-item-down > .lay-menu-body-title > .lay-icon-down { + transform: rotate(180deg); +} +.lay-menu .lay-menu-item-up > .lay-menu-body-title > .lay-icon-up { + transform: rotate(-180deg); +} +.lay-menu .lay-menu-item-up > .lay-menu-body-title:hover > .lay-icon, +.lay-menu .lay-menu-item-down:hover > .lay-menu-body-title > .lay-icon { + color: rgba(0, 0, 0, 1); +} +.lay-menu .lay-menu-item-down > ul { + visibility: visible; + height: auto; +} + +.lay-menu .lay-menu-item-checked, +.lay-menu .lay-menu-item-checked2 { + background-color: #f8f8f8 !important; + color: var(--lay-color-accent); +} +.lay-menu .lay-menu-item-checked a, +.lay-menu .lay-menu-item-checked2 a { + color: var(--lay-color-accent); +} +.lay-menu .lay-menu-item-checked:after { + position: absolute; + right: -1px; + top: 0; + bottom: 0; + border-right: 3px solid var(--lay-color-accent); + content: ''; +} + +.lay-menu-body-title { + position: relative; + margin: -5px -15px; + overflow: hidden; + text-overflow: ellipsis; +} +.lay-menu-body-title a { + display: block; + margin: -5px -15px; + overflow: hidden; + text-overflow: ellipsis; + color: rgba(0, 0, 0, 0.8); +} +.lay-menu-body-title a:hover { + transition: all 0.3s; +} +.lay-menu-body-title > .lay-icon { + position: absolute; + right: 15px; + top: 50%; + margin-top: -6px; + line-height: normal; + font-size: 14px; + -webkit-transition: all 0.2s; + transition: all 0.2s; +} +.lay-menu-body-title > .lay-icon:hover { + transition: all 0.3s; +} +.lay-menu-body-title > .lay-icon-right { + right: 14px; +} +.lay-menu-body-panel { + display: none; + position: absolute; + top: -7px; + left: 100%; + z-index: 1000; + margin-left: 13px; + padding: 5px 0; +} +.lay-menu-body-panel:before { + content: ''; + position: absolute; + width: 20px; + left: -16px; + top: 0; + bottom: 0; +} +.lay-menu-body-panel-left { + left: auto; + right: 100%; + margin: 0 13px 0; +} +.lay-menu-body-panel-left:before { + left: auto; + right: -16px; +} + +.lay-menu-lg li { + line-height: 32px; +} +.lay-menu-lg li:hover, +.lay-menu-lg .lay-menu-body-title a:hover { + background: none; + color: var(--lay-color-accent); +} +.lay-menu-lg li .lay-menu-body-panel { + margin-left: 14px; +} +.lay-menu-lg li .lay-menu-body-panel-left { + margin: 0 15px 0; +} + +/* 下拉菜单 */ +.lay-dropdown { + position: absolute; + left: -999999px; + top: -999999px; + z-index: 77777777; + margin: 5px 0; + min-width: 100px; +} +.lay-dropdown:before { + content: ''; + position: absolute; + width: 100%; + height: 6px; + left: 0; + top: -6px; +} +.lay-dropdown-shade { + top: 0; + left: 0; + width: 100%; + height: 100%; + position: fixed; + pointer-events: auto; +} diff --git a/src/css/modules/nav.css b/src/css/modules/nav.css new file mode 100644 index 000000000..acf580286 --- /dev/null +++ b/src/css/modules/nav.css @@ -0,0 +1,266 @@ +/** 导航菜单 **/ +.lay-nav { + position: relative; + padding: 0 15px; + background-color: var(--lay-color-black); + color: #fff; + border-radius: var(--lay-border-radius); + font-size: 0; + box-sizing: border-box; +} +.lay-nav * { + font-size: 14px; +} +.lay-nav .lay-nav-item { + position: relative; + display: inline-block; + margin-top: 0; + list-style: none; + vertical-align: middle; + line-height: 60px; +} +.lay-nav .lay-nav-item a { + display: block; + padding: 0 20px; + color: #fff; + color: rgba(255, 255, 255, 0.7); + -webkit-transition: all 0.3s; + transition: all 0.3s; +} +.lay-nav-bar, +.lay-nav .lay-this:after { + content: ''; + position: absolute; + left: 0; + top: 0; + width: 0; + height: 3px; + background-color: var(--lay-color-accent); + -webkit-transition: all 0.2s; + transition: all 0.2s; + pointer-events: none; +} +.lay-nav-bar { + z-index: 1000; +} +.lay-nav[lay-bar='disabled'] .lay-nav-bar { + display: none; +} +.lay-nav .lay-this a, +.lay-nav .lay-nav-item a:hover { + color: #fff; + text-decoration: none; +} +.lay-nav .lay-this:after { + top: auto; + bottom: 0; + width: 100%; +} +.lay-nav-img { + width: 30px; + height: 30px; + margin-right: 10px; + border-radius: 50%; +} + +.lay-nav .lay-nav-more { + position: absolute; + top: 0; + right: 3px; + left: auto !important; + margin-top: 0; + font-size: 12px; + cursor: pointer; + -webkit-transition: all 0.2s; + transition: all 0.2s; +} +.lay-nav .lay-nav-mored, +.lay-nav-itemed > a .lay-nav-more { + transform: rotate(180deg); +} + +.lay-nav-child { + display: none; + position: absolute; + left: 0; + top: 65px; + min-width: 100%; + line-height: 36px; + padding: 5px 0; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); + border: 1px solid var(--lay-border-color); + background-color: #fff; + z-index: 100; + border-radius: var(--lay-border-radius); + white-space: nowrap; + box-sizing: border-box; +} +.lay-nav .lay-nav-child a { + color: #5f5f5f; + color: rgba(0, 0, 0, 0.8); +} +.lay-nav .lay-nav-child a:hover { + background-color: #f8f8f8; + color: rgba(0, 0, 0, 0.8); +} +.lay-nav-child dd { + margin: 1px 0; + position: relative; +} +.lay-nav-child dd.lay-this { + background-color: #f8f8f8; + color: #000; +} +.lay-nav-child dd.lay-this:after { + display: none; +} +.lay-nav-child-r { + left: auto; + right: 0; +} +.lay-nav-child-c { + text-align: center; +} + +/* 垂直导航菜单 */ +.lay-nav.lay-nav-tree { + width: 200px; + padding: 0; +} +.lay-nav-tree .lay-nav-item { + display: block; + width: 100%; + line-height: 40px; +} +.lay-nav-tree .lay-nav-item a { + position: relative; + height: 40px; + line-height: 40px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.lay-nav-tree .lay-nav-item > a { + padding-top: 5px; + padding-bottom: 5px; +} +.lay-nav-tree .lay-nav-more { + right: 15px; +} +.lay-nav-tree .lay-nav-item > a .lay-nav-more { + padding: 5px 0; +} +.lay-nav-tree .lay-nav-bar { + width: 5px; + height: 0; +} +.lay-side .lay-nav-tree .lay-nav-bar { + width: 2px; +} +.lay-nav-tree .lay-this, +.lay-nav-tree .lay-this > a, +.lay-nav-tree .lay-this > a:hover, +.lay-nav-tree .lay-nav-child dd.lay-this, +.lay-nav-tree .lay-nav-child dd.lay-this a { + background-color: var(--lay-color-primary); + color: #fff; +} +.lay-nav-tree .lay-this:after { + display: none; +} +.lay-nav-tree .lay-nav-title a, +.lay-nav-tree .lay-nav-title a:hover, +.lay-nav-itemed > a { + color: #fff !important; +} +.lay-nav-tree .lay-nav-bar { + background-color: var(--lay-color-primary); +} + +.lay-nav-tree .lay-nav-child { + position: relative; + z-index: 0; + top: 0; + border: none; + background: none; + background-color: rgba(0, 0, 0, 0.3); + box-shadow: none; +} +.lay-nav-tree .lay-nav-child dd { + margin: 0; +} +.lay-nav-tree .lay-nav-child a { + color: #fff; + color: rgba(255, 255, 255, 0.7); +} +.lay-nav-tree .lay-nav-child a:hover { + background: none; + color: #fff; +} + +/* 垂直导航 - 展开状态 */ +.lay-nav-itemed > .lay-nav-child, +.lay-nav-itemed > .lay-nav-child > .lay-this > .lay-nav-child { + display: block; +} + +/* 垂直导航 - 侧边 */ +.lay-nav-side { + position: fixed; + top: 0; + bottom: 0; + left: 0; + overflow-x: hidden; + z-index: 999; +} + +/* 导航浅色背景 */ +.lay-nav.lay-bg-gray .lay-nav-item a, +.lay-nav-tree.lay-bg-gray a { + color: #373737; + color: rgba(0, 0, 0, 0.8); +} +.lay-nav-tree.lay-bg-gray .lay-nav-itemed > a { + color: #000 !important; +} +.lay-nav.lay-bg-gray .lay-this a { + color: var(--lay-color-accent); +} +.lay-nav-tree.lay-bg-gray .lay-nav-child { + padding-left: 11px; + background: none; +} +.lay-nav-tree.lay-bg-gray .lay-this, +.lay-nav-tree.lay-bg-gray .lay-this > a, +.lay-nav-tree.lay-bg-gray .lay-nav-child dd.lay-this, +.lay-nav-tree.lay-bg-gray .lay-nav-child dd.lay-this a { + background: none !important; + color: var(--lay-color-accent) !important; + font-weight: 700; +} +.lay-nav-tree.lay-bg-gray .lay-nav-bar { + background-color: var(--lay-color-accent); +} + +/** 面包屑 **/ +.lay-breadcrumb { + visibility: hidden; + font-size: 0; +} +.lay-breadcrumb > * { + font-size: 14px; +} +.lay-breadcrumb a { + color: #999 !important; +} +.lay-breadcrumb a:hover { + color: var(--lay-color-accent) !important; +} +.lay-breadcrumb a cite { + color: #5f5f5f; + font-style: normal; +} +.lay-breadcrumb span[lay-separator] { + margin: 0 10px; + color: #999; +} diff --git a/src/css/modules/panel.css b/src/css/modules/panel.css new file mode 100644 index 000000000..70fb3b722 --- /dev/null +++ b/src/css/modules/panel.css @@ -0,0 +1,98 @@ +/* + * 面板 + */ + +/* 折叠面板 */ +.lay-collapse { + border-width: 1px; + border-style: solid; + border-radius: var(--lay-border-radius); +} +.lay-collapse-item, +.lay-collapse-content { + border-top-width: 1px; + border-top-style: solid; +} +.lay-collapse-item:first-child { + border-top: none; +} +.lay-collapse-title { + position: relative; + height: 42px; + line-height: 42px; + padding: 0 15px 0 35px; + color: #333; + background-color: var(--lay-color-gray); + cursor: pointer; + font-size: 14px; + overflow: hidden; +} +.lay-collapse-content { + display: none; + padding: 10px 15px; + line-height: 1.6; + color: #5f5f5f; +} +.lay-collapse-icon { + position: absolute; + left: 15px; + top: 50%; + margin-top: -7px; + font-size: 14px; + line-height: normal; + transition: all 0.2s; +} +.lay-collapse-item.lay-show > .lay-collapse-title .lay-collapse-icon { + transform: rotate(90deg); +} +.lay-collapse-item.lay-show > .lay-collapse-content { + display: block; +} + +/* 卡片面板 */ +.lay-card { + margin-bottom: 15px; + border-radius: var(--lay-border-radius); + background-color: #fff; + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, 0.05); +} +.lay-card:last-child { + margin-bottom: 0; +} +.lay-card-header, +.lay-card-body { + position: relative; + padding: 10px 15px; +} +.lay-card-header { + border-bottom: 1px solid #f8f8f8; + color: #333; + border-radius: var(--lay-border-radius) 2px 0 0; + font-size: 14px; +} +.lay-card-body .lay-table { + margin: 5px 0; +} +.lay-card .lay-tab { + margin: 0; +} + +/* 常规面板 */ +.lay-panel { + position: relative; + border-width: 1px; + border-style: solid; + border-radius: var(--lay-border-radius); + box-shadow: 1px 1px 4px rgb(0 0 0 / 8%); + background-color: #fff; + color: #5f5f5f; +} + +/* 窗口面板 */ +.lay-panel-window { + position: relative; + padding: 15px; + border-radius: 0; + border-top: 5px solid var(--lay-border-color); + background-color: #fff; +} diff --git a/src/css/modules/progress.css b/src/css/modules/progress.css new file mode 100644 index 000000000..49b29b390 --- /dev/null +++ b/src/css/modules/progress.css @@ -0,0 +1,37 @@ +/* 进度条 */ +.lay-progress { + position: relative; + height: 6px; + border-radius: 20px; + background-color: var(--lay-gray-300); +} +.lay-progress-bar { + position: absolute; + left: 0; + top: 0; + width: 0; + max-width: 100%; + height: 6px; + border-radius: 20px; + text-align: right; + background-color: var(--lay-color-accent); + -webkit-transition: all 0.3s; + transition: all 0.3s; +} +.lay-progress-big, +.lay-progress-big .lay-progress-bar { + height: 18px; + line-height: 18px; +} +.lay-progress-text { + position: relative; + top: -20px; + line-height: 18px; + font-size: 12px; + color: #5f5f5f; +} +.lay-progress-big .lay-progress-text { + position: static; + padding: 0 10px; + color: #fff; +} diff --git a/src/css/modules/rate.css b/src/css/modules/rate.css new file mode 100644 index 000000000..8c8c9571b --- /dev/null +++ b/src/css/modules/rate.css @@ -0,0 +1,32 @@ +/** 评分组件 **/ +.lay-rate, +.lay-rate * { + display: inline-block; + vertical-align: middle; +} +.lay-rate { + padding: 11px 6px 11px 0; + font-size: 0; +} +.lay-rate li { + margin-top: 0 !important; +} +.lay-rate li i.lay-icon { + font-size: 20px; + color: var(--lay-color-orange); +} +.lay-rate li i.lay-icon { + margin-right: 5px; + -webkit-transition: all 0.3s; + transition: all 0.3s; +} +.lay-rate li i:hover, +.lay-rate-hover { + cursor: pointer; + -webkit-transform: scale(1.12); + transform: scale(1.12); +} +.lay-rate[readonly] li i:hover { + cursor: default; + transform: scale(1); +} diff --git a/src/css/modules/slider.css b/src/css/modules/slider.css new file mode 100644 index 000000000..d3fe141cb --- /dev/null +++ b/src/css/modules/slider.css @@ -0,0 +1,154 @@ +/** 滑块 **/ +.lay-slider { + height: 4px; + background: var(--lay-gray-300); + border-radius: var(--lay-border-radius); + position: relative; + cursor: pointer; +} +.lay-slider-bar { + border-radius: var(--lay-border-radius); + position: absolute; + height: 100%; +} +.lay-slider-step { + position: absolute; + top: 0; + width: 4px; + height: 4px; + border-radius: 50%; + background: #fff; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); +} +.lay-slider-wrap { + width: 36px; + height: 36px; + position: absolute; + top: -16px; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + z-index: 10; + text-align: center; +} +.lay-slider-wrap-btn { + width: 12px; + height: 12px; + border-radius: 50%; + background: #fff; + display: inline-block; + vertical-align: middle; + cursor: pointer; + transition: 0.3s; +} +.lay-slider-wrap:after { + content: ''; + height: 100%; + display: inline-block; + vertical-align: middle; +} +.lay-slider-wrap-btn:hover, +.lay-slider-wrap-btn.lay-slider-hover { + transform: scale(1.2); +} +.lay-slider-wrap-btn.lay-disabled:hover { + transform: scale(1) !important; +} +.lay-slider-tips { + position: absolute; + top: -42px; + z-index: 77777777; + white-space: nowrap; + -webkit-transform: translateX(-50%); + transform: translateX(-50%); + color: #fff; + background: #000; + border-radius: var(--lay-border-radius); + height: 25px; + line-height: 25px; + padding: 0 10px; +} +.lay-slider-tips:after { + content: ''; + position: absolute; + bottom: -11px; + left: 50%; + margin-left: -6px; + width: 0; + height: 0; + border-width: 6px; + border-style: solid; + border-color: #000 transparent transparent transparent; +} +.lay-slider-input { + width: 70px; + height: 32px; + border: 1px solid var(--lay-border-color); + border-radius: var(--lay-border-radius); + font-size: 16px; + line-height: 32px; + position: absolute; + right: 0; + top: -14px; + box-sizing: border-box; +} +.lay-slider-input-btn { + position: absolute; + top: 0; + right: 0; + width: 20px; + height: 100%; + border-left: 1px solid var(--lay-border-color); +} +.lay-slider-input-btn i { + cursor: pointer; + position: absolute; + right: 0; + bottom: 0; + width: 20px; + height: 50%; + font-size: 12px; + line-height: 16px; + text-align: center; + color: #999; +} +.lay-slider-input-btn i:first-child { + top: 0; + border-bottom: 1px solid var(--lay-border-color); +} +.lay-slider-input-txt { + height: 100%; + font-size: 14px; +} +.lay-slider-input-txt input { + height: 100%; + border: none; + padding-right: 21px; +} +.lay-slider-input-btn i:hover { + color: var(--lay-color-primary); +} +/*垂直滑块*/ +.lay-slider-vertical { + width: 4px; + margin-left: 33px; +} +.lay-slider-vertical .lay-slider-bar { + width: 4px; +} +.lay-slider-vertical .lay-slider-step { + top: auto; + left: 0px; + -webkit-transform: translateY(50%); + transform: translateY(50%); +} +.lay-slider-vertical .lay-slider-wrap { + top: auto; + left: -16px; + -webkit-transform: translateY(50%); + transform: translateY(50%); +} +.lay-slider-vertical .lay-slider-tips { + top: auto; + left: 2px; +} diff --git a/src/css/modules/table.css b/src/css/modules/table.css new file mode 100644 index 000000000..7e15e31d5 --- /dev/null +++ b/src/css/modules/table.css @@ -0,0 +1,696 @@ +/** 表格 **/ +.lay-table { + width: 100%; + margin: 10px 0; + background-color: #fff; + color: #5f5f5f; +} +.lay-table tr { + -webkit-transition: all 0.3s; + transition: all 0.3s; +} +.lay-table th { + text-align: left; + font-weight: 600; +} + +.lay-table-mend { + background-color: #fff; +} +.lay-table-hover, +.lay-table-click, +.lay-table[lay-even] tbody tr:nth-child(even) { + background-color: #f8f8f8; +} +.lay-table-checked { + background-color: #dbfbf0; +} +.lay-table-checked.lay-table-hover, +.lay-table-checked.lay-table-click, +.lay-table[lay-even] tbody tr:nth-child(even).lay-table-checked { + background-color: #abf8dd; +} +.lay-table-disabled-transition *, +.lay-table-disabled-transition *:before, +.lay-table-disabled-transition *:after { + -webkit-transition: none !important; + -moz-transition: none !important; + -o-transition: none !important; + transition: none !important; +} + +.lay-table th, +.lay-table td, +.lay-table[lay-skin='line'], +.lay-table[lay-skin='row'], +.lay-table-view, +.lay-table-tool, +.lay-table-header, +.lay-table-col-set, +.lay-table-total, +.lay-table-page, +.lay-table-fixed-r, +.lay-table-mend, +.lay-table-tips-main, +.lay-table-grid-down { + border-width: 1px; + border-style: solid; + border-color: var(--lay-border-color); +} + +.lay-table th, +.lay-table td { + position: relative; + padding: 9px 15px; + min-height: 20px; + line-height: 20px; + font-size: 14px; +} + +.lay-table[lay-skin='line'] th, +.lay-table[lay-skin='line'] td { + border-width: 0; + border-bottom-width: 1px; +} +.lay-table[lay-skin='row'] th, +.lay-table[lay-skin='row'] td { + border-width: 0; + border-right-width: 1px; +} +.lay-table[lay-skin='nob'] th, +.lay-table[lay-skin='nob'] td { + border: none; +} + +.lay-table img { + max-width: 100px; +} + +/* 大表格 */ +.lay-table[lay-size='lg'] th, +.lay-table[lay-size='lg'] td { + padding-top: 15px; + padding-right: 30px; + padding-bottom: 15px; + padding-left: 30px; +} +.lay-table-view .lay-table[lay-size='lg'] .lay-table-cell { + height: 50px; + line-height: 40px; +} + +/* 小表格 */ +.lay-table[lay-size='sm'] th, +.lay-table[lay-size='sm'] td { + padding-top: 5px; + padding-right: 10px; + padding-bottom: 5px; + padding-left: 10px; + font-size: 12px; +} +.lay-table-view .lay-table[lay-size='sm'] .lay-table-cell { + height: 30px; + line-height: 20px; + padding-top: 5px; + padding-left: 11px; + padding-right: 11px; +} + +/* 数据表格 */ +.lay-table[lay-data], +.lay-table[lay-options] { + display: none; +} +.lay-table-box { + position: relative; + overflow: hidden; +} +.lay-table-view { + clear: both; + position: relative; + border-right: none; +} +.lay-table-view:after { + content: ''; + position: absolute; + top: 0; + right: 0; + width: 1px; + height: 100%; + background-color: var(--lay-gray-300); + z-index: 101; +} +.lay-table-view .lay-table { + position: relative; + width: auto; + margin: 0; + border: 0; + border-collapse: separate; +} +.lay-table-view .lay-table[lay-skin='line'] { + border-width: 0; + border-right-width: 1px; +} +.lay-table-view .lay-table[lay-skin='row'] { + border-width: 0; + border-bottom-width: 1px; +} +.lay-table-view .lay-table th, +.lay-table-view .lay-table td { + padding: 0; + border-top: none; + border-left: none; +} +.lay-table-view .lay-table th [lay-event], +.lay-table-view .lay-table th.lay-unselect .lay-table-cell span { + cursor: pointer; +} +.lay-table-view .lay-table th span, +.lay-table-view .lay-table td { + cursor: default; +} +.lay-table-view .lay-table td[data-edit] { + cursor: text; +} +.lay-table-view .lay-table td[data-edit]:hover:after { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + box-sizing: border-box; + border: 1px solid #16b777; + pointer-events: none; + content: ''; +} + +.lay-table-view .lay-form-checkbox[lay-skin='primary'] i { + width: 18px; + height: 18px; + line-height: 16px; +} +.lay-table-view .lay-form-radio { + line-height: 0; + padding: 0; +} +.lay-table-view .lay-form-radio > i { + margin: 0; + font-size: 20px; +} +.lay-table-init { + position: absolute; + left: 0; + top: 0; + right: 0; + bottom: 0; + margin: 0; + z-index: 199; + transition: opacity 0.1s; + -webkit-user-select: none; + -moz-user-select: none; + user-select: none; +} +.lay-table-loading-icon { + position: absolute; + left: 50%; + top: 50%; + transform: translate(-50%, -50%); + text-align: center; +} +.lay-table-loading-icon .lay-icon { + font-size: 30px; + color: #c2c2c2; +} +.lay-table-header { + border-width: 0; + border-bottom-width: 1px; + overflow: hidden; +} +.lay-table-header .lay-table { + margin-bottom: -1px; +} + +.lay-table-column { + position: relative; + width: 100%; + min-height: 41px; + padding: 8px 16px; + border-width: 0; + border-bottom-width: 1px; +} +.lay-table-column .lay-btn-container { + margin-bottom: -8px; +} +.lay-table-column .lay-btn-container .lay-btn { + margin-right: 8px; + margin-bottom: 8px; +} + +.lay-table-tool .lay-inline[lay-event] { + position: relative; + width: 26px; + height: 26px; + padding: 5px; + line-height: 16px; + margin-right: 10px; + text-align: center; + color: #333; + border: 1px solid #ccc; + cursor: pointer; + -webkit-transition: 0.5s all; + transition: 0.5s all; +} +.lay-table-tool .lay-inline[lay-event]:hover { + border: 1px solid #999; +} +.lay-table-tool-temp { + padding-right: 120px; +} +.lay-table-tool-self { + position: absolute; + right: 17px; + top: 10px; +} +.lay-table-tool .lay-table-tool-self .lay-inline[lay-event] { + margin: 0 0 0 10px; +} +.lay-table-tool-panel { + position: absolute; + top: 29px; + left: -1px; + z-index: 399; + padding: 5px 0 !important; + min-width: 150px; + min-height: 40px; + border: 1px solid var(--lay-border-color-accent); + text-align: left; + overflow-y: auto; + background-color: #fff; + box-shadow: 0 2px 4px rgba(0, 0, 0, 0.12); +} +.lay-table-tool-panel li { + padding: 0 10px; + margin: 0 !important; + line-height: 30px; + list-style-type: none !important; + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; + -webkit-transition: 0.5s all; + transition: 0.5s all; +} +.lay-table-tool-panel li .lay-form-checkbox[lay-skin='primary'] { + width: 100%; +} +.lay-table-tool-panel li:hover { + background-color: #f8f8f8; +} +.lay-table-tool-panel li .lay-form-checkbox[lay-skin='primary'] { + padding-left: 28px; +} +.lay-table-tool-panel li .lay-form-checkbox[lay-skin='primary'] i { + position: absolute; + left: 0; + top: 0; +} +.lay-table-tool-panel li .lay-form-checkbox[lay-skin='primary'] span { + padding: 0; +} +.lay-table-tool .lay-table-tool-self .lay-table-tool-panel { + left: auto; + right: -1px; +} + +.lay-table-col-set { + position: absolute; + right: 0; + top: 0; + width: 20px; + height: 100%; + border-width: 0; + border-left-width: 1px; + background-color: #fff; +} + +.lay-table-sort { + width: 10px; + height: 20px; + margin-left: 5px; + cursor: pointer !important; +} +.lay-table-sort .lay-edge { + position: absolute; + left: 5px; + border-width: 5px; +} +.lay-table-sort .lay-table-sort-asc { + top: 3px; + border-top: none; + border-bottom-style: solid; + border-bottom-color: #b2b2b2; +} +.lay-table-sort .lay-table-sort-asc:hover { + border-bottom-color: #5f5f5f; +} +.lay-table-sort .lay-table-sort-desc { + bottom: 5px; + border-bottom: none; + border-top-style: solid; + border-top-color: #b2b2b2; +} +.lay-table-sort .lay-table-sort-desc:hover { + border-top-color: #5f5f5f; +} +.lay-table-sort[lay-sort='asc'] .lay-table-sort-asc { + border-bottom-color: #000; +} +.lay-table-sort[lay-sort='desc'] .lay-table-sort-desc { + border-top-color: #000; +} + +.lay-table-cell { + height: 38px; + line-height: 28px; + padding: 6px 15px; + position: relative; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + box-sizing: border-box; +} +.lay-table-cell .lay-form-checkbox[lay-skin='primary'] { + top: -1px; + padding: 0; +} +.lay-table-cell .lay-form-checkbox[lay-skin='primary'] > div { + padding-left: 24px; +} +.lay-table-cell .lay-table-link { + color: #01aaed; +} +.lay-table-cell .lay-btn { + vertical-align: inherit; +} +.lay-table-cell[align='center'] { + -webkit-box-pack: center; +} +.lay-table-cell[align='right'] { + -webkit-box-pack: end; +} + +.laytable-cell-checkbox, +.laytable-cell-radio, +.laytable-cell-space, +.laytable-cell-numbers { + text-align: center; + -webkit-box-pack: center; +} + +.lay-table-body { + position: relative; + overflow: auto; + margin-bottom: -1px; +} +.lay-table-body .lay-none { + line-height: 26px; + padding: 30px 15px; + text-align: center; + color: #999; +} +.lay-table-fixed { + position: absolute; + left: 0; + top: 0; + z-index: 101; +} +.lay-table-fixed .lay-table-body { + overflow: hidden; +} +.lay-table-fixed-l { + box-shadow: 1px 0 8px rgba(0, 0, 0, 0.08); +} +.lay-table-fixed-r { + left: auto; + right: 0px; + border-width: 0; + border-left-width: 1px; + box-shadow: -1px 0 8px rgba(0, 0, 0, 0.08); +} +.lay-table-fixed-r .lay-table-header { + position: relative; + overflow: visible; +} +.lay-table-mend { + position: absolute; + right: -49px; + top: 0; + height: 100%; + width: 50px; + border-width: 0; + border-left-width: 1px; +} + +.lay-table-tool { + position: relative; + width: 100%; + min-height: 50px; + line-height: 30px; + padding: 10px 15px; + border-width: 0; + border-bottom-width: 1px; /*box-shadow: 0 1px 8px 0 rgb(0 0 0 / 8%);*/ +} +.lay-table-tool .lay-btn-container { + margin-bottom: -10px; +} + +.lay-table-total { + margin-bottom: -1px; + border-width: 0; + border-top-width: 1px; + overflow: hidden; +} + +.lay-table-page { + border-width: 0; + border-top-width: 1px; + margin-bottom: -1px; + white-space: nowrap; + overflow: hidden; +} +.lay-table-page > div { + height: 26px; +} +.lay-table-page .lay-laypage { + margin: 0; +} +.lay-table-page .lay-laypage a, +.lay-table-page .lay-laypage span { + height: 26px; + line-height: 26px; + margin-bottom: 10px; + border: none; + background: none; +} +.lay-table-page .lay-laypage a, +.lay-table-page .lay-laypage span.lay-laypage-curr { + padding: 0 12px; +} +.lay-table-page .lay-laypage span { + margin-left: 0; + padding: 0; +} +.lay-table-page .lay-laypage .lay-laypage-prev { + margin-left: -11px !important; +} +.lay-table-page .lay-laypage .lay-laypage-curr .lay-laypage-em { + left: 0; + top: 0; + padding: 0; +} +.lay-table-page .lay-laypage input, +.lay-table-page .lay-laypage button { + height: 26px; + line-height: 26px; +} +.lay-table-page .lay-laypage input { + width: 40px; +} +.lay-table-page .lay-laypage button { + padding: 0 10px; +} +.lay-table-page select { + height: 18px; +} +.lay-table-pagebar { + float: right; + line-height: 23px; +} +.lay-table-pagebar .lay-btn-sm { + margin-top: -1px; +} +.lay-table-pagebar .lay-btn-xs { + margin-top: 2px; +} + +.lay-table-view select[lay-ignore] { + display: inline-block; +} +.lay-table-patch .lay-table-cell { + padding: 0; + width: 30px; +} + +.lay-table-edit { + position: absolute; + left: 0; + top: 0; + z-index: 189; + min-width: 100%; + min-height: 100%; + padding: 5px 14px; + border-radius: 0; + box-shadow: 1px 1px 20px rgba(0, 0, 0, 0.15); + background-color: #fff; +} +.lay-table-edit:focus { + border-color: var(--lay-color-accent) !important; +} +input.lay-input.lay-table-edit { + height: 100%; +} +select.lay-table-edit { + padding: 0 0 0 10px; + border-color: var(--lay-border-color-accent); +} +.lay-table-view .lay-form-switch, +.lay-table-view .lay-form-checkbox, +.lay-table-view .lay-form-radio { + top: 0; + margin: 0; +} +.lay-table-view .lay-form-checkbox { + top: -1px; + height: 26px; + line-height: 26px; +} +.lay-table-view .lay-form-checkbox i { + height: 26px; +} + +/* 展开溢出的单元格 */ +.lay-table-grid .lay-table-cell { + overflow: visible; +} +.lay-table-grid-down { + position: absolute; + top: 0; + right: 0; + width: 24px; + height: 100%; + padding: 5px 0; + border-width: 0; + border-left-width: 1px; + text-align: center; + background-color: #fff; + color: #999; + cursor: pointer; +} +.lay-table-grid-down .lay-icon { + position: absolute; + top: 50%; + left: 50%; + margin: -8px 0 0 -8px; + font-size: 14px; +} +.lay-table-grid-down:hover { + background-color: #fbfbfb; +} + +/* 单元格多行展开风格 */ +.lay-table-expanded { + height: 95px; +} +.lay-table-expanded .lay-table-cell, +.lay-table-view .lay-table[lay-size='sm'] .lay-table-expanded .lay-table-cell, +.lay-table-view .lay-table[lay-size='lg'] .lay-table-expanded .lay-table-cell { + height: auto; + max-height: 94px; + white-space: normal; + text-overflow: clip; +} +.lay-table-cell-c { + position: absolute; + bottom: -10px; + right: 50%; + margin-right: -9px; + width: 20px; + height: 20px; + line-height: 18px; + cursor: pointer; + text-align: center; + background-color: #fff; + border: 1px solid var(--lay-border-color); + border-radius: 50%; + z-index: 1000; + transition: 0.3s all; + font-size: 14px; +} +.lay-table-cell-c:hover { + border-color: var(--lay-color-accent); +} +.lay-table-expanded td:hover .lay-table-cell { + overflow: auto; +} +.lay-table-main > .lay-table > tbody > tr:last-child > td > .lay-table-cell-c { + bottom: 0; +} + +/* 单元格 TIPS 展开风格 */ +body .lay-table-tips .lay-layer-content { + background: none; + padding: 0; + box-shadow: 0 1px 6px rgba(0, 0, 0, 0.12); +} +.lay-table-tips-main { + margin: -49px 0 0 -1px; + max-height: 150px; + padding: 8px 15px; + font-size: 14px; + overflow-y: scroll; + background-color: #fff; + color: #5f5f5f; +} +.lay-table-tips-c { + position: absolute; + right: -3px; + top: -13px; + width: 20px; + height: 20px; + padding: 3px; + cursor: pointer; + background-color: #5f5f5f; + border-radius: 50%; + color: #fff; +} +.lay-table-tips-c:hover { + background-color: #777; +} +.lay-table-tips-c:before { + position: relative; + right: -2px; +} + +/** 树表 **/ +.lay-table-tree-nodeIcon { + max-width: 20px; +} +.lay-table-tree-nodeIcon > * { + width: 100%; +} +.lay-table-tree-flexIcon, +.lay-table-tree-nodeIcon { + margin-right: 2px; +} +.lay-table-tree-flexIcon { + cursor: pointer; +} diff --git a/src/css/modules/tabs.css b/src/css/modules/tabs.css new file mode 100644 index 000000000..cafa346cb --- /dev/null +++ b/src/css/modules/tabs.css @@ -0,0 +1,158 @@ +/* Tabs 标签页 */ +.lay-tabs { + position: relative; +} +.lay-tabs.lay-hide-v { + overflow: hidden; +} +.lay-tabs-header { + position: relative; + left: 0; + height: 40px; + padding: 0 !important; + white-space: nowrap; + font-size: 0; + -webkit-transition: all 0.16s; + transition: all 0.16s; +} +.lay-tabs-header:after, +.lay-tabs-scroll:after { + content: ''; + position: absolute; + left: 0; + bottom: 0; + z-index: 0; + width: 100%; + border-bottom: 1px solid var(--lay-border-color); +} +.lay-tabs-header li { + position: relative; + display: inline-block; + vertical-align: middle; + line-height: 40px; + margin: 0 !important; + padding: 0 16px; + text-align: center; + cursor: pointer; + font-size: 14px; + -webkit-transition: all 0.16s; + transition: all 0.16s; +} +.lay-tabs-header li:first-child { + margin-left: 0; +} +.lay-tabs-header li a { + display: block; + padding: 0 var(--lay-spacing); + margin: 0 calc(-1 * var(--lay-spacing)); + color: inherit; +} +.lay-tabs-header li a:hover { + text-decoration: none; +} +.lay-tabs-header li:hover, +.lay-tabs-header .lay-this { + color: var(--lay-color-primary); +} +.lay-tabs-header .lay-this:after { + content: ''; + position: absolute; + left: 0; + top: 0; + z-index: 1; + width: 100%; + height: 100%; + border-bottom: 3px solid var(--lay-color-primary); + box-sizing: border-box; + pointer-events: none; +} +.lay-tabs-header .lay-badge, +.lay-tabs-header .lay-badge-dot { + left: 5px; + top: -1px; +} + +.lay-tabs-scroll { + position: relative; + overflow: hidden; + padding: 0 40px; +} +.lay-tabs-scroll .lay-tabs-header:after { + display: none; + content: none; + border: 0; +} +.lay-tabs-bar .lay-icon { + position: absolute; + left: 0; + top: 0; + z-index: 3; + width: 40px; + height: 100%; + line-height: 40px; + border: 1px solid var(--lay-border-color); + text-align: center; + cursor: pointer; + box-sizing: border-box; + background-color: #fff; + box-shadow: 2px 0 5px 0 rgb(0 0 0 / 6%); +} +.lay-tabs-bar .lay-icon-next { + left: auto; + right: 0; + box-shadow: -2px 0 5px 0 rgb(0 0 0 / 6%); +} + +.lay-tabs-header li .lay-tabs-close { + position: relative; + display: inline-block; + width: 16px; + height: 16px; + line-height: 18px; + margin-left: 8px; + top: 0px; + text-align: center; + font-size: 12px; + color: #959595; + border-radius: 50%; + font-weight: 700; + -webkit-transition: all 0.16s; + transition: all 0.16s; +} +.lay-tabs-header li .lay-tabs-close:hover { + background-color: var(--lay-color-red); + color: #fff; +} +.lay-tabs-header li[lay-closable='false'] .lay-tabs-close { + display: none; +} + +.lay-tabs-body { + padding: var(--lay-spacing) 0; +} +.lay-tabs-item { + display: none; +} + +/* tabs 卡片风格 */ +.lay-tabs-card > .lay-tabs-header .lay-this { + background-color: #fff; +} +.lay-tabs-card > .lay-tabs-header .lay-this:after { + border: 1px solid var(--lay-border-color); + border-bottom-color: #fff; + border-radius: var(--lay-border-radius) var(--lay-border-radius) 0 0; +} +.lay-tabs-card > .lay-tabs-header li:first-child.lay-this:after { + margin-left: -1px; +} +.lay-tabs-card > .lay-tabs-header li:last-child.lay-this:after { + margin-right: -1px; +} +.lay-tabs-card.lay-panel > .lay-tabs-header .lay-this:after { + border-top: 0; + border-radius: 0; +} +.lay-tabs-card.lay-panel > .lay-tabs-body { + padding: var(--lay-spacing); +} diff --git a/src/css/modules/text.css b/src/css/modules/text.css new file mode 100644 index 000000000..63faf8f80 --- /dev/null +++ b/src/css/modules/text.css @@ -0,0 +1,150 @@ +/* 文本区域 */ +.lay-text { + line-height: 1.8; + font-size: 14px; +} +.lay-text h1 { + margin: 32px 0; + font-size: 32px; +} +.lay-text h2 { + margin: 24px 0; + font-size: 24px; +} +.lay-text h3 { + margin: 16px 0; + font-size: 18px; +} +.lay-text h4 { + margin: 11px 0; + font-size: 16px; +} +.lay-text h5 { + margin: 11px 0; + font-size: 14px; +} +.lay-text h6 { + margin: 11px 0; + font-size: 13px; +} +.lay-text p { + margin: 15px 0; +} +.lay-text p:first-child { + margin-top: 0; +} +.lay-text p:last-child { + margin-bottom: 0; +} +.lay-text hr { + margin: 15px 0; +} +.lay-text ul, +.lay-text ol { + padding-left: 15px; +} +.lay-text ul li { + margin-top: 5px; + list-style-type: disc; +} +.lay-text ol li { + margin-top: 5px; + list-style-type: decimal; +} +.lay-text ul ul > li, +.lay-text ol ul > li { + list-style-type: disc; +} +.lay-text ul li > p:first-child, +.lay-text ol li > p:first-child { + margin-top: 0; + margin-bottom: 0; +} +.lay-text :where(a:not(.lay-btn)) { + color: #01aaed; +} +.lay-text :where(a:not(.lay-btn):hover) { + text-decoration: underline; +} +.lay-text blockquote:not(.lay-elem-quote) { + margin: 15px 0; + padding: 5px 15px; + border-left: 5px solid var(--lay-border-color); +} +.lay-text pre > code:not(.lay-code) { + display: block; + padding: 15px; + font-family: 'Courier New', Consolas, 'Lucida Console', monospace; +} + +/* 文本区域辅助 */ +.lay-text-em, +.lay-word-aux { + color: #999 !important; + padding-left: 5px !important; + padding-right: 5px !important; +} + +/* 字体大小 */ +.lay-font-12 { + font-size: 12px !important; +} +.lay-font-13 { + font-size: 13px !important; +} +.lay-font-14 { + font-size: 14px !important; +} +.lay-font-16 { + font-size: 16px !important; +} +.lay-font-18 { + font-size: 18px !important; +} +.lay-font-20 { + font-size: 20px !important; +} +.lay-font-22 { + font-size: 22px !important; +} +.lay-font-24 { + font-size: 24px !important; +} +.lay-font-26 { + font-size: 26px !important; +} +.lay-font-28 { + font-size: 28px !important; +} +.lay-font-30 { + font-size: 30px !important; +} +.lay-font-32 { + font-size: 32px !important; +} + +/* 字体颜色 */ +.lay-font-red { + color: var(--lay-color-red) !important; +} /*赤*/ +.lay-font-orange { + color: var(--lay-color-orange) !important; +} /*橙*/ +.lay-font-green { + color: var(--lay-color-primary) !important; +} /*绿*/ +.lay-font-cyan { + color: #2f4056 !important; +} /*藏青*/ +.lay-font-blue { + color: #01aaed !important; +} /*蓝*/ +.lay-font-purple { + color: var(--lay-color-purple) !important; +} /*紫*/ +.lay-font-black { + color: #000 !important; +} /*深*/ +.lay-font-gray { + color: #c2c2c2 !important; +} /*浅*/ diff --git a/src/css/modules/theme.css b/src/css/modules/theme.css new file mode 100644 index 000000000..51efaf7a3 --- /dev/null +++ b/src/css/modules/theme.css @@ -0,0 +1,123 @@ +/* + * 默认主题 + */ + +/* 背景颜色 */ +.lay-bg-red { + background-color: var(--lay-color-red) !important; + color: #fff !important; +} /*赤*/ +.lay-bg-orange { + background-color: var(--lay-color-orange) !important; + color: #fff !important; +} /*橙*/ +.lay-bg-green { + background-color: var(--lay-color-primary) !important; + color: #fff !important; +} /*绿*/ +.lay-bg-cyan { + background-color: #2f4056 !important; + color: #fff !important; +} /*藏青*/ +.lay-bg-blue { + background-color: var(--lay-color-blue) !important; + color: #fff !important; +} /*蓝*/ +.lay-bg-purple { + background-color: var(--lay-color-purple) !important; + color: #fff !important; +} /*紫*/ +.lay-bg-black { + background-color: var(--lay-color-black) !important; + color: #fff !important; +} /*深*/ +.lay-bg-gray { + background-color: var(--lay-color-gray) !important; + color: #5f5f5f !important; +} /*浅*/ + +/* 边框 */ +.lay-border, +.lay-quote-nm, +.lay-elem-field, +.lay-collapse, +.lay-panel, +.lay-collapse-item, +.lay-collapse-content, +.lay-badge-rim, +.lay-tab-title, +.lay-tab-title .lay-this:after, +.lay-tab-bar, +.lay-tab-card, +.lay-input, +.lay-textarea, +.lay-select, +.lay-input-split, +.lay-form-pane .lay-form-label, +.lay-form-pane .lay-form-item[pane] { + border-color: var(--lay-border-color); +} + +.lay-border { + border-width: 1px; + border-style: solid; + color: #5f5f5f !important; +} +.lay-border-red { + border-width: 1px; + border-style: solid; + border-color: var(--lay-color-red) !important; + color: var(--lay-color-red) !important; +} +.lay-border-orange { + border-width: 1px; + border-style: solid; + border-color: var(--lay-color-orange) !important; + color: var(--lay-color-orange) !important; +} +.lay-border-green { + border-width: 1px; + border-style: solid; + border-color: var(--lay-color-primary) !important; + color: var(--lay-color-primary) !important; +} +.lay-border-cyan { + border-width: 1px; + border-style: solid; + border-color: #2f4056 !important; + color: #2f4056 !important; +} +.lay-border-blue { + border-width: 1px; + border-style: solid; + border-color: var(--lay-color-blue) !important; + color: var(--lay-color-blue) !important; +} +.lay-border-purple { + border-width: 1px; + border-style: solid; + border-color: var(--lay-color-purple) !important; + color: var(--lay-color-purple) !important; +} +.lay-border-black { + border-width: 1px; + border-style: solid; + border-color: var(--lay-color-black) !important; + color: var(--lay-color-black) !important; +} + +/* 分割线边框 */ +hr.lay-border-red, +hr.lay-border-orange, +hr.lay-border-green, +hr.lay-border-cyan, +hr.lay-border-blue, +hr.lay-border-purple, +hr.lay-border-black { + border-width: 0 0 1px; +} + +/* 背景边框 */ +.lay-timeline-item:before { + background-color: var(--lay-gray-300); +} diff --git a/src/css/modules/timeline.css b/src/css/modules/timeline.css new file mode 100644 index 000000000..c59085ea7 --- /dev/null +++ b/src/css/modules/timeline.css @@ -0,0 +1,49 @@ +/* 时间线 */ +.lay-timeline { + padding-left: 5px; +} +.lay-timeline-item { + position: relative; + padding-bottom: 20px; +} +.lay-timeline-axis { + position: absolute; + left: -5px; + top: 0; + z-index: 10; + width: 20px; + height: 20px; + line-height: 20px; + background-color: #fff; + color: var(--lay-color-accent); + border-radius: 50%; + text-align: center; + cursor: pointer; +} +.lay-timeline-axis:hover { + color: var(--lay-color-red); +} +.lay-timeline-item:before { + content: ''; + position: absolute; + left: 5px; + top: 0; + z-index: 0; + width: 1px; + height: 100%; +} + +.lay-timeline-item:first-child:before { + display: block; +} +.lay-timeline-item:last-child:before { + display: none; +} +.lay-timeline-content { + padding-left: 25px; +} +.lay-timeline-title { + position: relative; + margin-bottom: 10px; + line-height: 22px; +} diff --git a/src/css/modules/transfer.css b/src/css/modules/transfer.css new file mode 100644 index 000000000..3e5daa144 --- /dev/null +++ b/src/css/modules/transfer.css @@ -0,0 +1,91 @@ +/** 穿梭框 **/ +.lay-transfer-box, +.lay-transfer-header, +.lay-transfer-search { + border-width: 0; + border-style: solid; + border-color: var(--lay-border-color); +} +.lay-transfer-box { + position: relative; + display: inline-block; + vertical-align: middle; + border-width: 1px; + width: 200px; + height: 360px; + border-radius: var(--lay-border-radius); + background-color: #fff; +} +.lay-transfer-box .lay-form-checkbox { + width: 100%; + margin: 0 !important; +} +.lay-transfer-header { + height: 38px; + line-height: 38px; + padding: 0 11px; + border-bottom-width: 1px; +} +.lay-transfer-search { + position: relative; + padding: 11px; + border-bottom-width: 1px; +} +.lay-transfer-search .lay-input { + height: 32px; + padding-left: 30px; + font-size: 12px; +} +.lay-transfer-search .lay-icon-search { + position: absolute; + left: 20px; + top: 50%; + line-height: normal; + margin-top: -8px; + color: #5f5f5f; +} +.lay-transfer-active { + margin: 0 15px; + display: inline-block; + vertical-align: middle; +} +.lay-transfer-active .lay-btn { + display: block; + margin: 0; + padding: 0 15px; + background-color: var(--lay-color-accent); + border-color: var(--lay-color-accent); + color: #fff; +} +.lay-transfer-active .lay-btn-disabled { + background-color: #fbfbfb; + border-color: var(--lay-border-color); + color: var(--lay-gray-400); +} +.lay-transfer-active .lay-btn:first-child { + margin-bottom: 15px; +} +.lay-transfer-active .lay-btn .lay-icon { + margin: 0; + font-size: 14px !important; +} +.lay-transfer-data { + padding: 5px 0; + overflow: auto; +} +.lay-transfer-data li { + height: 32px; + line-height: 32px; + margin-top: 0 !important; + padding: 0 11px; + list-style-type: none !important; +} +.lay-transfer-data li:hover { + background-color: #f8f8f8; + transition: 0.5s all; +} +.lay-transfer-data .lay-none { + padding: 15px 11px; + text-align: center; + color: #999; +} diff --git a/src/css/modules/tree.css b/src/css/modules/tree.css new file mode 100644 index 000000000..383663c70 --- /dev/null +++ b/src/css/modules/tree.css @@ -0,0 +1,151 @@ +/** 树组件 **/ +.lay-tree { + line-height: 22px; +} +.lay-tree .lay-form-checkbox { + margin: 0 !important; +} +.lay-tree-set { + width: 100%; + position: relative; +} +.lay-tree-pack { + display: none; + padding-left: 20px; + position: relative; +} +.lay-tree-line .lay-tree-pack { + padding-left: 27px; +} +.lay-tree-line .lay-tree-set .lay-tree-set:after { + content: ''; + position: absolute; + top: 14px; + left: -9px; + width: 17px; + height: 0; + border-top: 1px dotted #c0c4cc; +} +.lay-tree-entry { + position: relative; + padding: 3px 0; + height: 26px; + white-space: nowrap; +} +.lay-tree-entry:hover { + background-color: var(--lay-gray-300); +} +.lay-tree-line .lay-tree-entry:hover { + background-color: rgba(0, 0, 0, 0); +} +.lay-tree-line .lay-tree-entry:hover .lay-tree-txt { + color: #999; + text-decoration: underline; + transition: 0.3s; +} +.lay-tree-main { + display: inline-block; + vertical-align: middle; + cursor: pointer; + padding-right: 10px; +} +.lay-tree-line .lay-tree-set:before { + content: ''; + position: absolute; + top: 0; + left: -9px; + width: 0; + height: 100%; + border-left: 1px dotted #c0c4cc; +} +.lay-tree-line .lay-tree-set.lay-tree-setLineShort:before { + height: 13px; +} +.lay-tree-line .lay-tree-set.lay-tree-setHide:before { + height: 0; +} +.lay-tree-iconClick { + display: inline-block; + vertical-align: middle; + position: relative; + height: 20px; + line-height: 20px; + margin: 0 10px; + color: #c0c4cc; +} +.lay-tree-icon { + height: 14px; + line-height: 10px; + width: 14px; + margin: 0 11px; + text-align: center; + border: 1px solid #c0c4cc; +} +.lay-tree-icon .lay-icon { + font-size: 12px; + color: #5f5f5f; +} +.lay-tree-iconArrow { + padding: 0 5px; +} +.lay-tree-iconArrow:after { + content: ''; + position: absolute; + left: 4px; + top: 3px; + z-index: 100; + width: 0; + height: 0; + border-width: 5px; + border-style: solid; + border-color: transparent transparent transparent #c0c4cc; + transition: 0.5s; +} +.lay-tree-spread + > .lay-tree-entry + .lay-tree-iconClick + > .lay-tree-iconArrow:after { + transform: rotate(90deg) translate(3px, 4px); +} +.lay-tree-txt { + display: inline-block; + vertical-align: middle; + color: #555; +} +.lay-tree-search { + margin-bottom: 15px; + color: #5f5f5f; +} +.lay-tree-btnGroup { + visibility: hidden; + display: inline-block; + vertical-align: middle; + position: relative; +} +.lay-tree-btnGroup .lay-icon { + display: inline-block; + vertical-align: middle; + padding: 0 2px; + cursor: pointer; +} +.lay-tree-btnGroup .lay-icon:hover { + color: #999; + transition: 0.3s; +} +.lay-tree-entry:hover .lay-tree-btnGroup { + visibility: visible; +} +.lay-tree-editInput { + position: relative; + display: inline-block; + vertical-align: middle; + height: 20px; + line-height: 20px; + padding: 0; + border: none; + background-color: rgba(0, 0, 0, 0.05); +} +.lay-tree-emptyText { + text-align: center; + color: #999; +} diff --git a/src/css/modules/upload.css b/src/css/modules/upload.css new file mode 100644 index 000000000..5f679e214 --- /dev/null +++ b/src/css/modules/upload.css @@ -0,0 +1,37 @@ +/** 文件上传 **/ +.lay-upload-file { + display: none !important; + opacity: 0.01; +} +.lay-upload-list { + margin: 11px 0; +} +.lay-upload-choose { + max-width: 200px; + padding: 0 10px; + color: #999; + font-size: 14px; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; +} +.lay-upload-drag { + position: relative; + display: inline-block; + padding: 30px; + border: 1px dashed #e2e2e2; + background-color: #fff; + text-align: center; + cursor: pointer; + color: #999; +} +.lay-upload-drag .lay-icon { + font-size: 50px; + color: var(--lay-color-primary); +} +.lay-upload-drag[lay-over] { + border-color: var(--lay-color-primary); +} +.lay-btn-container .lay-upload-choose { + padding-left: 0; +} diff --git a/src/css/var.css b/src/css/var.css new file mode 100644 index 000000000..9e129ece2 --- /dev/null +++ b/src/css/var.css @@ -0,0 +1,52 @@ +/** + * Layui + */ + +:root, +.light { + /* 默认主题色 */ + --lay-color-primary: #16baaa; + --lay-color-accent: #16b777; + + /* 七色 */ + --lay-color-red: #ff5722; + --lay-color-orange: #ffb800; + --lay-color-green: #16baaa; + --lay-color-blue: #1e9fff; + --lay-color-purple: #a233c6; + --lay-color-black: #2f363c; + --lay-color-gray: #fafafa; + + /* 灰度 */ + --lay-gray-100: #fafafa; + --lay-gray-200: #f7f7f7; + --lay-gray-300: #eeeeee; + --lay-gray-400: #d1d1d1; + --lay-gray-500: #c8c8c8; + --lay-gray-600: #b7b7b7; + --lay-gray-700: #959595; + --lay-gray-800: #777777; + --lay-gray-900: #5a5a5a; + + /* 边框 */ + --lay-border-color: var(--lay-gray-300); + --lay-border-color-accent: var(--lay-gray-400); + --lay-border-radius: 2px; + --lay-box-shadow: 0 1px 2px rgba(0, 0, 0, 0.15); + --lay-box-shadow-sm: 0 0.5px 1px rgba(0, 0, 0, 0.08); + --lay-box-shadow-lg: 0 3px 6px rgba(0, 0, 0, 0.3); + + /* 字体 */ + --lay-font-family: + system-ui, -apple-system, 'Segoe UI', Roboto, 'PingFang SC', + 'Microsoft YaHei', 'Helvetica Neue', Arial, sans-serif, 'Apple Color Emoji', + 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; + --lay-font-monospace: 'Courier New', Consolas, 'Lucida Console', monospace; + + /* 间距 */ + --lay-spacing: 16px; + --lay-spacing-xs: 5px; + --lay-spacing-sm: 8px; + --lay-spacing-lg: 24px; + --lay-spacing-xl: 32px; +} diff --git a/src/font/iconfont.eot b/src/font/iconfont.eot deleted file mode 100644 index c1d7160df..000000000 Binary files a/src/font/iconfont.eot and /dev/null differ diff --git a/src/font/iconfont.svg b/src/font/iconfont.svg deleted file mode 100644 index 5134e3605..000000000 --- a/src/font/iconfont.svg +++ /dev/null @@ -1,402 +0,0 @@ - - - - -Created by FontForge 20120731 at Thu Mar 30 16:49:26 2017 - By admin - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/font/iconfont.ttf b/src/font/iconfont.ttf deleted file mode 100644 index ff4532697..000000000 Binary files a/src/font/iconfont.ttf and /dev/null differ diff --git a/src/font/iconfont.woff b/src/font/iconfont.woff deleted file mode 100644 index 18c4a7c80..000000000 Binary files a/src/font/iconfont.woff and /dev/null differ diff --git a/src/images/face/0.gif b/src/images/face/0.gif deleted file mode 100644 index a63f0d523..000000000 Binary files a/src/images/face/0.gif and /dev/null differ diff --git a/src/images/face/1.gif b/src/images/face/1.gif deleted file mode 100644 index b2b78b218..000000000 Binary files a/src/images/face/1.gif and /dev/null differ diff --git a/src/images/face/10.gif b/src/images/face/10.gif deleted file mode 100644 index 556c7e326..000000000 Binary files a/src/images/face/10.gif and /dev/null differ diff --git a/src/images/face/11.gif b/src/images/face/11.gif deleted file mode 100644 index 2bfc58be8..000000000 Binary files a/src/images/face/11.gif and /dev/null differ diff --git a/src/images/face/12.gif b/src/images/face/12.gif deleted file mode 100644 index 1c321c7eb..000000000 Binary files a/src/images/face/12.gif and /dev/null differ diff --git a/src/images/face/13.gif b/src/images/face/13.gif deleted file mode 100644 index 300bbc2a0..000000000 Binary files a/src/images/face/13.gif and /dev/null differ diff --git a/src/images/face/14.gif b/src/images/face/14.gif deleted file mode 100644 index 43b6d0a43..000000000 Binary files a/src/images/face/14.gif and /dev/null differ diff --git a/src/images/face/15.gif b/src/images/face/15.gif deleted file mode 100644 index c9f25fa1d..000000000 Binary files a/src/images/face/15.gif and /dev/null differ diff --git a/src/images/face/16.gif b/src/images/face/16.gif deleted file mode 100644 index 34f28e4cd..000000000 Binary files a/src/images/face/16.gif and /dev/null differ diff --git a/src/images/face/17.gif b/src/images/face/17.gif deleted file mode 100644 index 39cd03538..000000000 Binary files a/src/images/face/17.gif and /dev/null differ diff --git a/src/images/face/18.gif b/src/images/face/18.gif deleted file mode 100644 index 7bce2997f..000000000 Binary files a/src/images/face/18.gif and /dev/null differ diff --git a/src/images/face/19.gif b/src/images/face/19.gif deleted file mode 100644 index adac542fd..000000000 Binary files a/src/images/face/19.gif and /dev/null differ diff --git a/src/images/face/2.gif b/src/images/face/2.gif deleted file mode 100644 index 7edbb58a8..000000000 Binary files a/src/images/face/2.gif and /dev/null differ diff --git a/src/images/face/20.gif b/src/images/face/20.gif deleted file mode 100644 index 50631a6e3..000000000 Binary files a/src/images/face/20.gif and /dev/null differ diff --git a/src/images/face/21.gif b/src/images/face/21.gif deleted file mode 100644 index b98421282..000000000 Binary files a/src/images/face/21.gif and /dev/null differ diff --git a/src/images/face/22.gif b/src/images/face/22.gif deleted file mode 100644 index 1f0bd8b00..000000000 Binary files a/src/images/face/22.gif and /dev/null differ diff --git a/src/images/face/23.gif b/src/images/face/23.gif deleted file mode 100644 index e05e0f97a..000000000 Binary files a/src/images/face/23.gif and /dev/null differ diff --git a/src/images/face/24.gif b/src/images/face/24.gif deleted file mode 100644 index f35928a26..000000000 Binary files a/src/images/face/24.gif and /dev/null differ diff --git a/src/images/face/25.gif b/src/images/face/25.gif deleted file mode 100644 index 0b4a88322..000000000 Binary files a/src/images/face/25.gif and /dev/null differ diff --git a/src/images/face/26.gif b/src/images/face/26.gif deleted file mode 100644 index 45c4fb556..000000000 Binary files a/src/images/face/26.gif and /dev/null differ diff --git a/src/images/face/27.gif b/src/images/face/27.gif deleted file mode 100644 index 7a4c0131d..000000000 Binary files a/src/images/face/27.gif and /dev/null differ diff --git a/src/images/face/28.gif b/src/images/face/28.gif deleted file mode 100644 index fc5a0cfaf..000000000 Binary files a/src/images/face/28.gif and /dev/null differ diff --git a/src/images/face/29.gif b/src/images/face/29.gif deleted file mode 100644 index 5dd7442b1..000000000 Binary files a/src/images/face/29.gif and /dev/null differ diff --git a/src/images/face/3.gif b/src/images/face/3.gif deleted file mode 100644 index 86df67b7a..000000000 Binary files a/src/images/face/3.gif and /dev/null differ diff --git a/src/images/face/30.gif b/src/images/face/30.gif deleted file mode 100644 index b751f98ab..000000000 Binary files a/src/images/face/30.gif and /dev/null differ diff --git a/src/images/face/31.gif b/src/images/face/31.gif deleted file mode 100644 index c9476d796..000000000 Binary files a/src/images/face/31.gif and /dev/null differ diff --git a/src/images/face/32.gif b/src/images/face/32.gif deleted file mode 100644 index 9931b0636..000000000 Binary files a/src/images/face/32.gif and /dev/null differ diff --git a/src/images/face/33.gif b/src/images/face/33.gif deleted file mode 100644 index 59111a38c..000000000 Binary files a/src/images/face/33.gif and /dev/null differ diff --git a/src/images/face/34.gif b/src/images/face/34.gif deleted file mode 100644 index a334548e8..000000000 Binary files a/src/images/face/34.gif and /dev/null differ diff --git a/src/images/face/35.gif b/src/images/face/35.gif deleted file mode 100644 index a9322643d..000000000 Binary files a/src/images/face/35.gif and /dev/null differ diff --git a/src/images/face/36.gif b/src/images/face/36.gif deleted file mode 100644 index 6de432ae9..000000000 Binary files a/src/images/face/36.gif and /dev/null differ diff --git a/src/images/face/37.gif b/src/images/face/37.gif deleted file mode 100644 index d05f2da45..000000000 Binary files a/src/images/face/37.gif and /dev/null differ diff --git a/src/images/face/38.gif b/src/images/face/38.gif deleted file mode 100644 index 8b1c88a3e..000000000 Binary files a/src/images/face/38.gif and /dev/null differ diff --git a/src/images/face/39.gif b/src/images/face/39.gif deleted file mode 100644 index 38b84a513..000000000 Binary files a/src/images/face/39.gif and /dev/null differ diff --git a/src/images/face/4.gif b/src/images/face/4.gif deleted file mode 100644 index d52200c51..000000000 Binary files a/src/images/face/4.gif and /dev/null differ diff --git a/src/images/face/40.gif b/src/images/face/40.gif deleted file mode 100644 index ae429912d..000000000 Binary files a/src/images/face/40.gif and /dev/null differ diff --git a/src/images/face/41.gif b/src/images/face/41.gif deleted file mode 100644 index b9c715c52..000000000 Binary files a/src/images/face/41.gif and /dev/null differ diff --git a/src/images/face/42.gif b/src/images/face/42.gif deleted file mode 100644 index 0eb1434b4..000000000 Binary files a/src/images/face/42.gif and /dev/null differ diff --git a/src/images/face/43.gif b/src/images/face/43.gif deleted file mode 100644 index ac0b70085..000000000 Binary files a/src/images/face/43.gif and /dev/null differ diff --git a/src/images/face/44.gif b/src/images/face/44.gif deleted file mode 100644 index ad4449769..000000000 Binary files a/src/images/face/44.gif and /dev/null differ diff --git a/src/images/face/45.gif b/src/images/face/45.gif deleted file mode 100644 index 6837fcaf2..000000000 Binary files a/src/images/face/45.gif and /dev/null differ diff --git a/src/images/face/46.gif b/src/images/face/46.gif deleted file mode 100644 index d62916d40..000000000 Binary files a/src/images/face/46.gif and /dev/null differ diff --git a/src/images/face/47.gif b/src/images/face/47.gif deleted file mode 100644 index 58a083611..000000000 Binary files a/src/images/face/47.gif and /dev/null differ diff --git a/src/images/face/48.gif b/src/images/face/48.gif deleted file mode 100644 index 7ffd1613b..000000000 Binary files a/src/images/face/48.gif and /dev/null differ diff --git a/src/images/face/49.gif b/src/images/face/49.gif deleted file mode 100644 index 959b99296..000000000 Binary files a/src/images/face/49.gif and /dev/null differ diff --git a/src/images/face/5.gif b/src/images/face/5.gif deleted file mode 100644 index 4e8b09f15..000000000 Binary files a/src/images/face/5.gif and /dev/null differ diff --git a/src/images/face/50.gif b/src/images/face/50.gif deleted file mode 100644 index 6e22e7ff1..000000000 Binary files a/src/images/face/50.gif and /dev/null differ diff --git a/src/images/face/51.gif b/src/images/face/51.gif deleted file mode 100644 index ad3f4d3a8..000000000 Binary files a/src/images/face/51.gif and /dev/null differ diff --git a/src/images/face/52.gif b/src/images/face/52.gif deleted file mode 100644 index 39f8a2284..000000000 Binary files a/src/images/face/52.gif and /dev/null differ diff --git a/src/images/face/53.gif b/src/images/face/53.gif deleted file mode 100644 index a181ee778..000000000 Binary files a/src/images/face/53.gif and /dev/null differ diff --git a/src/images/face/54.gif b/src/images/face/54.gif deleted file mode 100644 index e289d929b..000000000 Binary files a/src/images/face/54.gif and /dev/null differ diff --git a/src/images/face/55.gif b/src/images/face/55.gif deleted file mode 100644 index 4351083ac..000000000 Binary files a/src/images/face/55.gif and /dev/null differ diff --git a/src/images/face/56.gif b/src/images/face/56.gif deleted file mode 100644 index e0eff222b..000000000 Binary files a/src/images/face/56.gif and /dev/null differ diff --git a/src/images/face/57.gif b/src/images/face/57.gif deleted file mode 100644 index 0bf130f0d..000000000 Binary files a/src/images/face/57.gif and /dev/null differ diff --git a/src/images/face/58.gif b/src/images/face/58.gif deleted file mode 100644 index 0f065087d..000000000 Binary files a/src/images/face/58.gif and /dev/null differ diff --git a/src/images/face/59.gif b/src/images/face/59.gif deleted file mode 100644 index 7081e4f02..000000000 Binary files a/src/images/face/59.gif and /dev/null differ diff --git a/src/images/face/6.gif b/src/images/face/6.gif deleted file mode 100644 index f7715bf52..000000000 Binary files a/src/images/face/6.gif and /dev/null differ diff --git a/src/images/face/60.gif b/src/images/face/60.gif deleted file mode 100644 index 6e15f89d7..000000000 Binary files a/src/images/face/60.gif and /dev/null differ diff --git a/src/images/face/61.gif b/src/images/face/61.gif deleted file mode 100644 index f092d7e35..000000000 Binary files a/src/images/face/61.gif and /dev/null differ diff --git a/src/images/face/62.gif b/src/images/face/62.gif deleted file mode 100644 index 7fe49840b..000000000 Binary files a/src/images/face/62.gif and /dev/null differ diff --git a/src/images/face/63.gif b/src/images/face/63.gif deleted file mode 100644 index cf8e23e5b..000000000 Binary files a/src/images/face/63.gif and /dev/null differ diff --git a/src/images/face/64.gif b/src/images/face/64.gif deleted file mode 100644 index a7797198a..000000000 Binary files a/src/images/face/64.gif and /dev/null differ diff --git a/src/images/face/65.gif b/src/images/face/65.gif deleted file mode 100644 index 7bb98f2d8..000000000 Binary files a/src/images/face/65.gif and /dev/null differ diff --git a/src/images/face/66.gif b/src/images/face/66.gif deleted file mode 100644 index bb6d07750..000000000 Binary files a/src/images/face/66.gif and /dev/null differ diff --git a/src/images/face/67.gif b/src/images/face/67.gif deleted file mode 100644 index 6e33f7c4f..000000000 Binary files a/src/images/face/67.gif and /dev/null differ diff --git a/src/images/face/68.gif b/src/images/face/68.gif deleted file mode 100644 index 1a6c400d2..000000000 Binary files a/src/images/face/68.gif and /dev/null differ diff --git a/src/images/face/69.gif b/src/images/face/69.gif deleted file mode 100644 index a02f0b223..000000000 Binary files a/src/images/face/69.gif and /dev/null differ diff --git a/src/images/face/7.gif b/src/images/face/7.gif deleted file mode 100644 index e6d4db805..000000000 Binary files a/src/images/face/7.gif and /dev/null differ diff --git a/src/images/face/70.gif b/src/images/face/70.gif deleted file mode 100644 index 416c5c14a..000000000 Binary files a/src/images/face/70.gif and /dev/null differ diff --git a/src/images/face/71.gif b/src/images/face/71.gif deleted file mode 100644 index c17d60cbd..000000000 Binary files a/src/images/face/71.gif and /dev/null differ diff --git a/src/images/face/8.gif b/src/images/face/8.gif deleted file mode 100644 index 66f967b48..000000000 Binary files a/src/images/face/8.gif and /dev/null differ diff --git a/src/images/face/9.gif b/src/images/face/9.gif deleted file mode 100644 index 60447400d..000000000 Binary files a/src/images/face/9.gif and /dev/null differ diff --git a/src/index.js b/src/index.js new file mode 100644 index 000000000..dcd328364 --- /dev/null +++ b/src/index.js @@ -0,0 +1,40 @@ +/** + * Layui ESM 入口 + */ + +// 导出核心模块 +export { lay, use, version } from './core/lay.js'; +export { loader } from './core/loader.js'; +export { laytpl } from './core/laytpl.js'; +export { i18n } from './core/i18n.js'; +export { router } from './core/router.js'; +export { default as jquery, default as $ } from 'jquery'; +export { component, componentBuilder } from './core/component.js'; + +// 导出工具模块 +export * as utils from './utils/index.js'; + +// 导出组件模块 +export { layer } from './components/layer.js'; +export { laydate } from './components/laydate.js'; +export { laypage } from './components/laypage.js'; +export { dropdown } from './components/dropdown.js'; +export { slider } from './components/slider.js'; +export { colorpicker } from './components/colorpicker.js'; +export { nav } from './components/nav.js'; +export { breadcrumb } from './components/breadcrumb.js'; +export { progress } from './components/progress.js'; +export { collapse } from './components/collapse.js'; +export { element } from './components/element.js'; +export { upload } from './components/upload.js'; +export { form } from './components/form.js'; +export { table } from './components/table.js'; +export { treeTable } from './components/treeTable.js'; +export { tabs } from './components/tabs.js'; +export { tree } from './components/tree.js'; +export { transfer } from './components/transfer.js'; +export { carousel } from './components/carousel.js'; +export { rate } from './components/rate.js'; +export { flow } from './components/flow.js'; +export { floatbar } from './components/floatbar.js'; +export { code } from './components/code.js'; diff --git a/src/index.umd.js b/src/index.umd.js new file mode 100644 index 000000000..adf18c864 --- /dev/null +++ b/src/index.umd.js @@ -0,0 +1,80 @@ +/** + * Layui UMD 入口 + */ + +// 导入核心模块 +import { lay, use, version } from './core/lay.js'; +import { loader } from './core/loader.js'; +import { laytpl } from './core/laytpl.js'; +import { i18n } from './core/i18n.js'; +import { router } from './core/router.js'; +import { default as jquery, default as $ } from 'jquery'; +import { component, componentBuilder } from './core/component.js'; + +// 导入工具模块 +import * as utils from './utils/index.js'; + +// 导入组件模块 +import { layer } from './components/layer.js'; +import { laydate } from './components/laydate.js'; +import { laypage } from './components/laypage.js'; +import { dropdown } from './components/dropdown.js'; +import { slider } from './components/slider.js'; +import { colorpicker } from './components/colorpicker.js'; +import { nav } from './components/nav.js'; +import { breadcrumb } from './components/breadcrumb.js'; +import { progress } from './components/progress.js'; +import { collapse } from './components/collapse.js'; +import { element } from './components/element.js'; +import { upload } from './components/upload.js'; +import { form } from './components/form.js'; +import { table } from './components/table.js'; +import { treeTable } from './components/treeTable.js'; +import { tabs } from './components/tabs.js'; +import { tree } from './components/tree.js'; +import { transfer } from './components/transfer.js'; +import { carousel } from './components/carousel.js'; +import { rate } from './components/rate.js'; +import { flow } from './components/flow.js'; +import { floatbar } from './components/floatbar.js'; +import { code } from './components/code.js'; + +const layui = { + lay, + use, + version, + loader, + laytpl, + i18n, + router, + $, + jquery, + component, + componentBuilder, + utils, + layer, + laydate, + laypage, + dropdown, + slider, + colorpicker, + nav, + breadcrumb, + progress, + collapse, + element, + upload, + form, + table, + treeTable, + tabs, + tree, + transfer, + carousel, + rate, + flow, + floatbar, + code, +}; + +export default layui; diff --git a/src/lay/all-mobile.js b/src/lay/all-mobile.js deleted file mode 100644 index 3ebb7d2cf..000000000 --- a/src/lay/all-mobile.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - - @Name:用于打包移动完整版 - @Author:贤心 - @License:LGPL - - */ - -layui.define(function(exports){ - exports('layui.mobile', layui.v); -}); diff --git a/src/lay/all.js b/src/lay/all.js deleted file mode 100644 index db17a8ecf..000000000 --- a/src/lay/all.js +++ /dev/null @@ -1,15 +0,0 @@ -/** - - @Name:用于打包PC完整版,即包含layui.js和所有模块的完整合并(该文件不会存在于构建后的目录) - @Author:贤心 - @License:LGPL - - */ - -layui.define(function(exports){ - var cache = layui.cache; - layui.config({ - dir: cache.dir.replace(/lay\/dest\/$/, '') - }); - exports('layui.all', layui.v); -}); diff --git a/src/lay/modules/code.js b/src/lay/modules/code.js deleted file mode 100644 index 654b9dc64..000000000 --- a/src/lay/modules/code.js +++ /dev/null @@ -1,61 +0,0 @@ -/** - - @Name:layui.code 代码修饰器 - @Author:贤心 - @License:MIT - - */ - -layui.define('jquery', function(exports){ - "use strict"; - - var $ = layui.jquery; - var about = 'http://www.layui.com/doc/modules/code.html'; //关于信息 - - exports('code', function(options){ - var elems = []; - options = options || {}; - options.elem = $(options.elem||'.layui-code'); - options.about = 'about' in options ? options.about : true; - - options.elem.each(function(){ - elems.push(this); - }); - - layui.each(elems.reverse(), function(index, item){ - var othis = $(item), html = othis.html(); - - //转义HTML标签 - if(othis.attr('lay-encode') || options.encode){ - html = html.replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&') - .replace(//g, '>').replace(/'/g, ''').replace(/"/g, '"') - } - - othis.html('
                                    1. ' + html.replace(/[\r\t\n]+/g, '
                                    2. ') + '
                                    ') - - if(!othis.find('>.layui-code-h3')[0]){ - othis.prepend('

                                    '+ (othis.attr('lay-title')||options.title||'code') + (options.about ? 'layui.code' : '') + '

                                    '); - } - - var ol = othis.find('>.layui-code-ol'); - othis.addClass('layui-box layui-code-view'); - - //识别皮肤 - if(othis.attr('lay-skin') || options.skin){ - othis.addClass('layui-code-' +(othis.attr('lay-skin') || options.skin)); - } - - //按行数适配左边距 - if((ol.find('li').length/100|0) > 0){ - ol.css('margin-left', (ol.find('li').length/100|0) + 'px'); - } - - //设置最大高度 - if(othis.attr('lay-height') || options.height){ - ol.css('max-height', othis.attr('lay-height') || options.height); - } - - }); - - }); -}).addcss('modules/code.css', 'skincodecss'); \ No newline at end of file diff --git a/src/lay/modules/element.js b/src/lay/modules/element.js deleted file mode 100644 index c6d16b2b7..000000000 --- a/src/lay/modules/element.js +++ /dev/null @@ -1,403 +0,0 @@ -/** - - @Name:layui.element 常用元素操作 - @Author:贤心 - @License:MIT - - */ - -layui.define('jquery', function(exports){ - "use strict"; - - var $ = layui.jquery - ,hint = layui.hint() - ,device = layui.device() - - ,MOD_NAME = 'element', THIS = 'layui-this', SHOW = 'layui-show' - - ,Element = function(){ - this.config = {}; - }; - - //全局设置 - Element.prototype.set = function(options){ - var that = this; - $.extend(true, that.config, options); - return that; - }; - - //表单事件监听 - Element.prototype.on = function(events, callback){ - return layui.onevent(MOD_NAME, events, callback); - }; - - //外部Tab新增 - Element.prototype.tabAdd = function(filter, options){ - var TITLE = '.layui-tab-title' - ,tabElem = $('.layui-tab[lay-filter='+ filter +']') - ,titElem = tabElem.children(TITLE) - ,contElem = tabElem.children('.layui-tab-content'); - titElem.append('
                                  • '+ (options.title||'unnaming') +'
                                  • '); - contElem.append('
                                    '+ (options.content||'') +'
                                    '); - call.hideTabMore(true); - call.tabAuto(); - return this; - }; - - //外部Tab删除 - Element.prototype.tabDelete = function(filter, layid){ - var TITLE = '.layui-tab-title' - ,tabElem = $('.layui-tab[lay-filter='+ filter +']') - ,titElem = tabElem.children(TITLE) - ,liElem = titElem.find('>li[lay-id="'+ layid +'"]'); - call.tabDelete(null, liElem); - return this; - }; - - //外部Tab切换 - Element.prototype.tabChange = function(filter, layid){ - var TITLE = '.layui-tab-title' - ,tabElem = $('.layui-tab[lay-filter='+ filter +']') - ,titElem = tabElem.children(TITLE) - ,liElem = titElem.find('>li[lay-id="'+ layid +'"]'); - call.tabClick(null, null, liElem); - return this; - }; - - //动态改变进度条 - Element.prototype.progress = function(filter, percent){ - var ELEM = 'layui-progress' - ,elem = $('.'+ ELEM +'[lay-filter='+ filter +']') - ,elemBar = elem.find('.'+ ELEM +'-bar') - ,text = elemBar.find('.'+ ELEM +'-text'); - elemBar.css('width', percent); - text.text(percent); - return this; - }; - - var NAV_ELEM = '.layui-nav', NAV_ITEM = 'layui-nav-item', NAV_BAR = 'layui-nav-bar' - ,NAV_TREE = 'layui-nav-tree', NAV_CHILD = 'layui-nav-child', NAV_MORE = 'layui-nav-more' - ,NAV_ANIM = 'layui-anim layui-anim-upbit' - - //基础事件体 - ,call = { - //Tab点击 - tabClick: function(e, index, liElem){ - var othis = liElem || $(this) - ,index = index || othis.parent().children('li').index(othis) - ,parents = othis.parents('.layui-tab').eq(0) - ,item = parents.children('.layui-tab-content').children('.layui-tab-item') - ,filter = parents.attr('lay-filter'); - - othis.addClass(THIS).siblings().removeClass(THIS); - item.eq(index).addClass(SHOW).siblings().removeClass(SHOW); - - layui.event.call(this, MOD_NAME, 'tab('+ filter +')', { - elem: parents - ,index: index - }); - } - - //Tab删除 - ,tabDelete: function(e, othis){ - var li = othis || $(this).parent(), index = li.index(); - var parents = li.parents('.layui-tab').eq(0); - var item = parents.children('.layui-tab-content').children('.layui-tab-item') - - if(li.hasClass(THIS)){ - if(li.next()[0]){ - call.tabClick.call(li.next()[0], null, index + 1); - } else if(li.prev()[0]){ - call.tabClick.call(li.prev()[0], null, index - 1); - } - } - - li.remove(); - item.eq(index).remove(); - setTimeout(function(){ - call.tabAuto(); - }, 50); - } - - //Tab自适应 - ,tabAuto: function(){ - var SCROLL = 'layui-tab-scroll', MORE = 'layui-tab-more', BAR = 'layui-tab-bar' - ,CLOSE = 'layui-tab-close', that = this; - - $('.layui-tab').each(function(){ - var othis = $(this) - ,title = othis.children('.layui-tab-title') - ,item = othis.children('.layui-tab-content').children('.layui-tab-item') - ,STOPE = 'lay-stope="tabmore"' - ,span = $(''); - - if(that === window && device.ie != 8){ - call.hideTabMore(true) - } - - //允许关闭 - if(othis.attr('lay-allowClose')){ - title.find('li').each(function(){ - var li = $(this); - if(!li.find('.'+CLOSE)[0]){ - var close = $(''); - close.on('click', call.tabDelete); - li.append(close); - } - }); - } - - //响应式 - if(title.prop('scrollWidth') > title.outerWidth()+1){ - if(title.find('.'+BAR)[0]) return; - title.append(span); - othis.attr('overflow', ''); - span.on('click', function(e){ - title[this.title ? 'removeClass' : 'addClass'](MORE); - this.title = this.title ? '' : '收缩'; - }); - } else { - title.find('.'+BAR).remove(); - othis.removeAttr('overflow'); - } - }); - } - //隐藏更多Tab - ,hideTabMore: function(e){ - var tsbTitle = $('.layui-tab-title'); - if(e === true || $(e.target).attr('lay-stope') !== 'tabmore'){ - tsbTitle.removeClass('layui-tab-more'); - tsbTitle.find('.layui-tab-bar').attr('title',''); - } - } - - //点击选中 - ,clickThis: function(){ - var othis = $(this), parents = othis.parents(NAV_ELEM) - ,filter = parents.attr('lay-filter'); - - if(othis.find('.'+NAV_CHILD)[0]) return; - parents.find('.'+THIS).removeClass(THIS); - othis.addClass(THIS); - layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis); - } - //点击子菜单选中 - ,clickChild: function(){ - var othis = $(this), parents = othis.parents(NAV_ELEM) - ,filter = parents.attr('lay-filter'); - parents.find('.'+THIS).removeClass(THIS); - othis.addClass(THIS); - layui.event.call(this, MOD_NAME, 'nav('+ filter +')', othis); - } - //展开二级菜单 - ,showChild: function(){ - var othis = $(this), parents = othis.parents(NAV_ELEM); - var parent = othis.parent(), child = othis.siblings('.'+NAV_CHILD); - if(parents.hasClass(NAV_TREE)){ - child.removeClass(NAV_ANIM); - parent[child.css('display') === 'none' ? 'addClass': 'removeClass'](NAV_ITEM+'ed'); - } - } - - //折叠面板 - ,collapse: function(){ - var othis = $(this), icon = othis.find('.layui-colla-icon') - ,elemCont = othis.siblings('.layui-colla-content') - ,parents = othis.parents('.layui-collapse').eq(0) - ,filter = parents.attr('lay-filter') - ,isNone = elemCont.css('display') === 'none'; - //是否手风琴 - if(typeof parents.attr('lay-accordion') === 'string'){ - var show = parents.children('.layui-colla-item').children('.'+SHOW); - show.siblings('.layui-colla-title').children('.layui-colla-icon').html(''); - show.removeClass(SHOW); - } - elemCont[isNone ? 'addClass' : 'removeClass'](SHOW); - icon.html(isNone ? '' : ''); - - layui.event.call(this, MOD_NAME, 'collapse('+ filter +')', { - title: othis - ,content: elemCont - ,show: isNone - }); - } - }; - - //初始化元素操作 - Element.prototype.init = function(type){ - var that = this, items = { - - //Tab选项卡 - tab: function(){ - call.tabAuto.call({}); - } - - //导航菜单 - ,nav: function(){ - var TIME = 200, timer, timerMore, timeEnd, follow = function(bar, nav){ - var othis = $(this), child = othis.find('.'+NAV_CHILD); - - if(nav.hasClass(NAV_TREE)){ - bar.css({ - top: othis.position().top - ,height: othis.children('a').height() - ,opacity: 1 - }); - } else { - child.addClass(NAV_ANIM); - bar.css({ - left: othis.position().left + parseFloat(othis.css('marginLeft')) - ,top: othis.position().top + othis.height() - 5 - }); - - timer = setTimeout(function(){ - bar.css({ - width: othis.width() - ,opacity: 1 - }); - }, device.ie && device.ie < 10 ? 0 : TIME); - - clearTimeout(timeEnd); - if(child.css('display') === 'block'){ - clearTimeout(timerMore); - } - timerMore = setTimeout(function(){ - child.addClass(SHOW) - othis.find('.'+NAV_MORE).addClass(NAV_MORE+'d'); - }, 300); - } - } - - $(NAV_ELEM).each(function(){ - var othis = $(this) - ,bar = $('') - ,itemElem = othis.find('.'+NAV_ITEM); - - //Hover滑动效果 - if(!othis.find('.'+NAV_BAR)[0]){ - othis.append(bar); - itemElem.on('mouseenter', function(){ - follow.call(this, bar, othis); - }).on('mouseleave', function(){ - if(!othis.hasClass(NAV_TREE)){ - clearTimeout(timerMore); - timerMore = setTimeout(function(){ - othis.find('.'+NAV_CHILD).removeClass(SHOW); - othis.find('.'+NAV_MORE).removeClass(NAV_MORE+'d'); - }, 300); - } - }); - othis.on('mouseleave', function(){ - clearTimeout(timer) - timeEnd = setTimeout(function(){ - if(othis.hasClass(NAV_TREE)){ - bar.css({ - height: 0 - ,top: bar.position().top + bar.height()/2 - ,opacity: 0 - }); - } else { - bar.css({ - width: 0 - ,left: bar.position().left + bar.width()/2 - ,opacity: 0 - }); - } - }, TIME); - }); - } - - itemElem.each(function(){ - var oitem = $(this), child = oitem.find('.'+NAV_CHILD); - - //二级菜单 - if(child[0] && !oitem.find('.'+NAV_MORE)[0]){ - var one = oitem.children('a'); - one.append(''); - } - - oitem.off('click', call.clickThis).on('click', call.clickThis); //点击选中 - oitem.children('a').off('click', call.showChild).on('click', call.showChild); //展开二级菜单 - child.children('dd').off('click', call.clickChild).on('click', call.clickChild); //点击子菜单选中 - }); - }); - } - - //面包屑 - ,breadcrumb: function(){ - var ELEM = '.layui-breadcrumb'; - - $(ELEM).each(function(){ - var othis = $(this) - ,separator = othis.attr('lay-separator') || '>' - ,aNode = othis.find('a'); - if(aNode.find('.layui-box')[0]) return; - aNode.each(function(index){ - if(index === aNode.length - 1) return; - $(this).append(''+ separator +''); - }); - othis.css('visibility', 'visible'); - }); - } - - //进度条 - ,progress: function(){ - var ELEM = 'layui-progress'; - - $('.'+ELEM).each(function(){ - var othis = $(this) - ,elemBar = othis.find('.layui-progress-bar') - ,width = elemBar.attr('lay-percent'); - elemBar.css('width', width); - if(othis.attr('lay-showPercent')){ - setTimeout(function(){ - var percent = Math.round(elemBar.width()/othis.width()*100); - if(percent > 100) percent = 100; - elemBar.html(''+ percent +'%'); - },350); - } - }); - } - - //折叠面板 - ,collapse: function(){ - var ELEM = 'layui-collapse'; - - $('.'+ELEM).each(function(){ - var elemItem = $(this).find('.layui-colla-item') - elemItem.each(function(){ - var othis = $(this) - ,elemTitle = othis.find('.layui-colla-title') - ,elemCont = othis.find('.layui-colla-content') - ,isNone = elemCont.css('display') === 'none'; - - //初始状态 - elemTitle.find('.layui-colla-icon').remove(); - elemTitle.append(''+ (isNone ? '' : '') +''); - - //点击标题 - elemTitle.off('click', call.collapse).on('click', call.collapse); - }); - - }); - } - }; - - return layui.each(items, function(index, item){ - item(); - }); - }; - - var element = new Element(), dom = $(document); - element.init(); - - var TITLE = '.layui-tab-title li'; - dom.on('click', TITLE, call.tabClick); //Tab切换 - dom.on('click', call.hideTabMore); //隐藏展开的Tab - $(window).on('resize', call.tabAuto); //自适应 - - exports(MOD_NAME, function(options){ - return element.set(options); - }); -}); - diff --git a/src/lay/modules/flow.js b/src/lay/modules/flow.js deleted file mode 100644 index 1195315b4..000000000 --- a/src/lay/modules/flow.js +++ /dev/null @@ -1,176 +0,0 @@ -/** - - @Name:layui.flow 流加载 - @Author:贤心 - @License:MIT - - */ - - -layui.define('jquery', function(exports){ - "use strict"; - - var $ = layui.jquery, Flow = function(options){} - ,ELEM_MORE = 'layui-flow-more' - ,ELEM_LOAD = ''; - - //主方法 - Flow.prototype.load = function(options){ - var that = this, page = 0, lock, isOver, lazyimg, timer; - options = options || {}; - - var elem = $(options.elem); if(!elem[0]) return; - var scrollElem = $(options.scrollElem || document); //滚动条所在元素 - var mb = options.mb || 50; //与底部的临界距离 - var isAuto = 'isAuto' in options ? options.isAuto : true; //是否自动滚动加载 - var end = options.end || '没有更多了'; //“末页”显示文案 - - //滚动条所在元素是否为document - var notDocment = options.scrollElem && options.scrollElem !== document; - - //加载更多 - var ELEM_TEXT = '加载更多' - ,more = $(''); - - if(!elem.find('.layui-flow-more')[0]){ - elem.append(more); - } - - //加载下一个元素 - var next = function(html, over){ - html = $(html); - more.before(html); - over = over == 0 ? true : null; - over ? more.html(end) : more.find('a').html(ELEM_TEXT); - isOver = over; - lock = null; - lazyimg && lazyimg(); - }; - - //触发请求 - var done = function(){ - lock = true; - more.find('a').html(ELEM_LOAD); - typeof options.done === 'function' && options.done(++page, next); - }; - - done(); - - //不自动滚动加载 - more.find('a').on('click', function(){ - var othis = $(this); - if(isOver) return; - lock || done(); - }); - - //如果允许图片懒加载 - if(options.isLazyimg){ - var lazyimg = that.lazyimg({ - elem: options.elem + ' img' - ,scrollElem: options.scrollElem - }); - } - - if(!isAuto) return that; - - scrollElem.on('scroll', function(){ - var othis = $(this), top = othis.scrollTop(); - - if(timer) clearTimeout(timer); - if(isOver) return; - - timer = setTimeout(function(){ - //计算滚动所在容器的可视高度 - var height = notDocment ? othis.height() : $(window).height(); - - //计算滚动所在容器的实际高度 - var scrollHeight = notDocment - ? othis.prop('scrollHeight') - : document.documentElement.scrollHeight; - - //临界点 - if(scrollHeight - top - height <= mb){ - lock || done(); - } - }, 100); - }); - return that; - }; - - //图片懒加载 - Flow.prototype.lazyimg = function(options){ - var that = this, index = 0, haveScroll; - options = options || {}; - - var scrollElem = $(options.scrollElem || document); //滚动条所在元素 - var elem = options.elem || 'img'; - - //滚动条所在元素是否为document - var notDocment = options.scrollElem && options.scrollElem !== document; - - //显示图片 - var show = function(item, height){ - var start = scrollElem.scrollTop(), end = start + height; - var elemTop = notDocment ? function(){ - return item.offset().top - scrollElem.offset().top + start; - }() : item.offset().top; - - /* 始终只加载在当前屏范围内的图片 */ - if(elemTop >= start && elemTop <= end){ - if(!item.attr('src')){ - var src = item.attr('lay-src'); - layui.img(src, function(){ - var next = that.lazyimg.elem.eq(index); - item.attr('src', src).removeAttr('lay-src'); - - /* 当前图片加载就绪后,检测下一个图片是否在当前屏 */ - next[0] && render(next); - index++; - }); - } - } - }, render = function(othis, scroll){ - - //计算滚动所在容器的可视高度 - var height = notDocment ? (scroll||scrollElem).height() : $(window).height(); - var start = scrollElem.scrollTop(), end = start + height; - - that.lazyimg.elem = $(elem); - - if(othis){ - show(othis, height); - } else { - //计算未加载过的图片 - for(var i = 0; i < that.lazyimg.elem.length; i++){ - var item = that.lazyimg.elem.eq(i), elemTop = notDocment ? function(){ - return item.offset().top - scrollElem.offset().top + start; - }() : item.offset().top; - - show(item, height); - index = i; - - //如果图片的top坐标,超出了当前屏,则终止后续图片的遍历 - if(elemTop > end) break; - } - } - }; - - render(); - - if(!haveScroll){ - var timer; - scrollElem.on('scroll', function(){ - var othis = $(this); - if(timer) clearTimeout(timer) - timer = setTimeout(function(){ - render(null, othis); - }, 50); - }); - haveScroll = true; - } - return render; - }; - - //暴露接口 - exports('flow', new Flow()); -}); diff --git a/src/lay/modules/form.js b/src/lay/modules/form.js deleted file mode 100644 index 87e9fd307..000000000 --- a/src/lay/modules/form.js +++ /dev/null @@ -1,443 +0,0 @@ -/** - - @Name:layui.form 表单组件 - @Author:贤心 - @License:MIT - - */ - -layui.define('layer', function(exports){ - "use strict"; - - var $ = layui.jquery - ,layer = layui.layer - ,hint = layui.hint() - ,device = layui.device() - - ,MOD_NAME = 'form', ELEM = '.layui-form', THIS = 'layui-this', SHOW = 'layui-show', HIDE = 'layui-hide', DISABLED = 'layui-disabled' - - ,Form = function(){ - this.config = { - verify: { - required: [ - /[\S]+/ - ,'必填项不能为空' - ] - ,phone: [ - /^1\d{10}$/ - ,'请输入正确的手机号' - ] - ,email: [ - /^([a-zA-Z0-9_\.\-])+\@(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/ - ,'邮箱格式不正确' - ] - ,url: [ - /(^#)|(^http(s*):\/\/[^\s]+\.[^\s]+)/ - ,'链接格式不正确' - ] - ,number: [ - /^\d+$/ - ,'只能填写数字' - ] - ,date: [ - /^(\d{4})[-\/](\d{1}|0\d{1}|1[0-2])([-\/](\d{1}|0\d{1}|[1-2][0-9]|3[0-1]))*$/ - ,'日期格式不正确' - ] - ,identity: [ - /(^\d{15}$)|(^\d{17}(x|X|\d)$)/ - ,'请输入正确的身份证号' - ] - } - }; - }; - - //全局设置 - Form.prototype.set = function(options){ - var that = this; - $.extend(true, that.config, options); - return that; - }; - - //验证规则设定 - Form.prototype.verify = function(settings){ - var that = this; - $.extend(true, that.config.verify, settings); - return that; - }; - - //表单事件监听 - Form.prototype.on = function(events, callback){ - return layui.onevent(MOD_NAME, events, callback); - }; - - //表单控件渲染 - Form.prototype.render = function(type){ - var that = this, items = { - - //下拉选择框 - select: function(){ - var TIPS = '请选择', CLASS = 'layui-form-select', TITLE = 'layui-select-title' - ,NONE = 'layui-select-none', initValue = '', thatInput - - ,selects = $(ELEM).find('select'), hide = function(e, clear){ - if(!$(e.target).parent().hasClass(TITLE) || clear){ - $('.'+CLASS).removeClass(CLASS+'ed'); - thatInput && initValue && thatInput.val(initValue); - } - thatInput = null; - } - - ,events = function(reElem, disabled, isSearch){ - var select = $(this) - ,title = reElem.find('.' + TITLE) - ,input = title.find('input') - ,dl = reElem.find('dl') - ,dds = dl.children('dd') - - - if(disabled) return; - - //展开下拉 - var showDown = function(){ - reElem.addClass(CLASS+'ed'); - dds.removeClass(HIDE); - }, hideDown = function(){ - reElem.removeClass(CLASS+'ed'); - input.blur(); - - notOption(input.val(), function(none){ - if(none){ - initValue = dl.find('.'+THIS).html(); - input && input.val(initValue); - } - }); - }; - - //点击标题区域 - title.on('click', function(e){ - reElem.hasClass(CLASS+'ed') ? ( - hideDown() - ) : ( - hide(e, true), - showDown() - ); - dl.find('.'+NONE).remove(); - }); - - //点击箭头获取焦点 - title.find('.layui-edge').on('click', function(){ - input.focus(); - }); - - //键盘事件 - input.on('keyup', function(e){ - var keyCode = e.keyCode; - //Tab键 - if(keyCode === 9){ - showDown(); - } - }).on('keydown', function(e){ - var keyCode = e.keyCode; - //Tab键 - if(keyCode === 9){ - hideDown(); - } else if(keyCode === 13){ //回车键 - e.preventDefault(); - } - }); - - //检测值是否不属于select项 - var notOption = function(value, callback, origin){ - var num = 0; - layui.each(dds, function(){ - var othis = $(this) - ,text = othis.text() - ,not = text.indexOf(value) === -1; - if(value === '' || (origin === 'blur') ? value !== text : not) num++; - origin === 'keyup' && othis[not ? 'addClass' : 'removeClass'](HIDE); - }); - var none = num === dds.length; - return callback(none), none; - }; - - //搜索匹配 - var search = function(e){ - var value = this.value, keyCode = e.keyCode; - - if(keyCode === 9 || keyCode === 13 - || keyCode === 37 || keyCode === 38 - || keyCode === 39 || keyCode === 40 - ){ - return false; - } - - notOption(value, function(none){ - if(none){ - dl.find('.'+NONE)[0] || dl.append('

                                    无匹配项

                                    '); - } else { - dl.find('.'+NONE).remove(); - } - }, 'keyup'); - - if(value === ''){ - dl.find('.'+NONE).remove(); - } - }; - if(isSearch){ - input.on('keyup', search).on('blur', function(e){ - thatInput = input; - initValue = dl.find('.'+THIS).html(); - setTimeout(function(){ - notOption(input.val(), function(none){ - if(none && !initValue){ - input.val(''); - } - }, 'blur'); - }, 200); - }); - } - - //选择 - dds.on('click', function(){ - var othis = $(this), value = othis.attr('lay-value'); - var filter = select.attr('lay-filter'); //获取过滤器 - - if(othis.hasClass(DISABLED)) return false; - - select.val(value).removeClass('layui-form-danger'), input.val(othis.text()); - othis.addClass(THIS).siblings().removeClass(THIS); - layui.event.call(this, MOD_NAME, 'select('+ filter +')', { - elem: select[0] - ,value: value - ,othis: reElem - }); - - hideDown(); - - return false; - }); - - reElem.find('dl>dt').on('click', function(e){ - return false; - }); - - //关闭下拉 - $(document).off('click', hide).on('click', hide); - } - - selects.each(function(index, select){ - var othis = $(this), hasRender = othis.next('.'+CLASS), disabled = this.disabled; - var value = select.value, selected = $(select.options[select.selectedIndex]); //获取当前选中项 - - if(typeof othis.attr('lay-ignore') === 'string') return othis.show(); - - var isSearch = typeof othis.attr('lay-search') === 'string'; - - //替代元素 - var reElem = $(['
                                    ' - ,'
                                    ' - ,'
                                    ' - ,'
                                    '+ function(options){ - var arr = []; - layui.each(options, function(index, item){ - if(index === 0 && !item.value) return; - if(item.tagName.toLowerCase() === 'optgroup'){ - arr.push('
                                    '+ item.label +'
                                    '); - } else { - arr.push('
                                    '+ item.innerHTML +'
                                    '); - } - }); - return arr.join(''); - }(othis.find('*')) +'
                                    ' - ,'
                                    '].join('')); - - hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender - othis.after(reElem); - events.call(this, reElem, disabled, isSearch); - }); - } - //复选框/开关 - ,checkbox: function(){ - var CLASS = { - checkbox: ['layui-form-checkbox', 'layui-form-checked', 'checkbox'] - ,_switch: ['layui-form-switch', 'layui-form-onswitch', 'switch'] - } - ,checks = $(ELEM).find('input[type=checkbox]') - - ,events = function(reElem, RE_CLASS){ - var check = $(this); - - //勾选 - reElem.on('click', function(){ - var filter = check.attr('lay-filter') //获取过滤器 - ,text = (check.attr('lay-text')||'').split('|'); - - if(check[0].disabled) return; - - check[0].checked ? ( - check[0].checked = false - ,reElem.removeClass(RE_CLASS[1]).find('em').text(text[1]) - ) : ( - check[0].checked = true - ,reElem.addClass(RE_CLASS[1]).find('em').text(text[0]) - ); - - layui.event.call(check[0], MOD_NAME, RE_CLASS[2]+'('+ filter +')', { - elem: check[0] - ,value: check[0].value - ,othis: reElem - }); - }); - } - - checks.each(function(index, check){ - var othis = $(this), skin = othis.attr('lay-skin') - ,text = (othis.attr('lay-text')||'').split('|'), disabled = this.disabled; - if(skin === 'switch') skin = '_'+skin; - var RE_CLASS = CLASS[skin] || CLASS.checkbox; - - if(typeof othis.attr('lay-ignore') === 'string') return othis.show(); - - //替代元素 - var hasRender = othis.next('.' + RE_CLASS[0]); - var reElem = $(['
                                    ' - ,{ - _switch: ''+ ((check.checked ? text[0] : text[1])||'') +'' - }[skin] || ((check.title.replace(/\s/g, '') ? (''+ check.title +'') : '') +''+ (skin ? '' : '') +'') - ,'
                                    '].join('')); - - hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender - othis.after(reElem); - events.call(this, reElem, RE_CLASS); - }); - } - //单选框 - ,radio: function(){ - var CLASS = 'layui-form-radio', ICON = ['', ''] - ,radios = $(ELEM).find('input[type=radio]') - - ,events = function(reElem){ - var radio = $(this), ANIM = 'layui-anim-scaleSpring'; - - reElem.on('click', function(){ - var name = radio[0].name, forms = radio.parents(ELEM); - var filter = radio.attr('lay-filter'); //获取过滤器 - var sameRadio = forms.find('input[name='+ name.replace(/(\.|#|\[|\])/g, '\\$1') +']'); //找到相同name的兄弟 - - if(radio[0].disabled) return; - - layui.each(sameRadio, function(){ - var next = $(this).next('.'+CLASS); - this.checked = false; - next.removeClass(CLASS+'ed'); - next.find('.layui-icon').removeClass(ANIM).html(ICON[1]); - }); - - radio[0].checked = true; - reElem.addClass(CLASS+'ed'); - reElem.find('.layui-icon').addClass(ANIM).html(ICON[0]); - - layui.event.call(radio[0], MOD_NAME, 'radio('+ filter +')', { - elem: radio[0] - ,value: radio[0].value - ,othis: reElem - }); - }); - }; - - radios.each(function(index, radio){ - var othis = $(this), hasRender = othis.next('.' + CLASS), disabled = this.disabled; - - if(typeof othis.attr('lay-ignore') === 'string') return othis.show(); - - //替代元素 - var reElem = $(['
                                    ' - ,''+ ICON[radio.checked ? 0 : 1] +'' - ,''+ (radio.title||'未命名') +'' - ,'
                                    '].join('')); - - hasRender[0] && hasRender.remove(); //如果已经渲染,则Rerender - othis.after(reElem); - events.call(this, reElem); - }); - } - }; - type ? ( - items[type] ? items[type]() : hint.error('不支持的'+ type + '表单渲染') - ) : layui.each(items, function(index, item){ - item(); - }); - return that; - }; - - //表单提交校验 - var submit = function(){ - var button = $(this), verify = form.config.verify, stop = null - ,DANGER = 'layui-form-danger', field = {} ,elem = button.parents(ELEM) - - ,verifyElem = elem.find('*[lay-verify]') //获取需要校验的元素 - ,formElem = button.parents('form')[0] //获取当前所在的form元素,如果存在的话 - ,fieldElem = elem.find('input,select,textarea') //获取所有表单域 - ,filter = button.attr('lay-filter'); //获取过滤器 - - //开始校验 - layui.each(verifyElem, function(_, item){ - var othis = $(this), ver = othis.attr('lay-verify').split('|'); - var tips = '', value = othis.val(); - othis.removeClass(DANGER); - layui.each(ver, function(_, thisVer){ - var isFn = typeof verify[thisVer] === 'function'; - if(verify[thisVer] && (isFn ? tips = verify[thisVer](value, item) : !verify[thisVer][0].test(value)) ){ - layer.msg(tips || verify[thisVer][1], { - icon: 5 - ,shift: 6 - }); - //非移动设备自动定位焦点 - if(!device.android && !device.ios){ - item.focus(); - } - othis.addClass(DANGER); - return stop = true; - } - }); - if(stop) return stop; - }); - - if(stop) return false; - - layui.each(fieldElem, function(_, item){ - if(!item.name) return; - if(/^checkbox|radio$/.test(item.type) && !item.checked) return; - field[item.name] = item.value; - }); - - //获取字段 - return layui.event.call(this, MOD_NAME, 'submit('+ filter +')', { - elem: this - ,form: formElem - ,field: field - }); - }; - - //自动完成渲染 - var form = new Form(), dom = $(document); - form.render(); - - //表单reset重置渲染 - dom.on('reset', ELEM, function(){ - setTimeout(function(){ - form.render(); - }, 50); - }); - - //表单提交事件 - dom.on('submit', ELEM, submit) - .on('click', '*[lay-submit]', submit); - - exports(MOD_NAME, function(options){ - return form.set(options); - }); -}); - - diff --git a/src/lay/modules/jquery.js b/src/lay/modules/jquery.js deleted file mode 100644 index 92b887530..000000000 --- a/src/lay/modules/jquery.js +++ /dev/null @@ -1,10986 +0,0 @@ -/*! - * jQuery JavaScript Library v1.12.3 - * http://jquery.com/ - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2016-04-05T19:16Z - */ - -(function( global, factory ) { - - if ( typeof module === "object" && typeof module.exports === "object" ) { - // For CommonJS and CommonJS-like environments where a proper `window` - // is present, execute the factory and get jQuery. - // For environments that do not have a `window` with a `document` - // (such as Node.js), expose a factory as module.exports. - // This accentuates the need for the creation of a real `window`. - // e.g. var jQuery = require("jquery")(window); - // See ticket #14549 for more info. - module.exports = global.document ? - factory( global, true ) : - function( w ) { - if ( !w.document ) { - throw new Error( "jQuery requires a window with a document" ); - } - return factory( w ); - }; - } else { - factory( global ); - } - -// Pass this if window is not defined yet -}(typeof window !== "undefined" ? window : this, function( window, noGlobal ) { - -// Support: Firefox 18+ -// Can't be in strict mode, several libs including ASP.NET trace -// the stack via arguments.caller.callee and Firefox dies if -// you try to trace through "use strict" call chains. (#13335) -//"use strict"; -var deletedIds = []; - -var document = window.document; - -var slice = deletedIds.slice; - -var concat = deletedIds.concat; - -var push = deletedIds.push; - -var indexOf = deletedIds.indexOf; - -var class2type = {}; - -var toString = class2type.toString; - -var hasOwn = class2type.hasOwnProperty; - -var support = {}; - - - -var - version = "1.12.3", - - // Define a local copy of jQuery - jQuery = function( selector, context ) { - - // The jQuery object is actually just the init constructor 'enhanced' - // Need init if jQuery is called (just allow error to be thrown if not included) - return new jQuery.fn.init( selector, context ); - }, - - // Support: Android<4.1, IE<9 - // Make sure we trim BOM and NBSP - rtrim = /^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, - - // Matches dashed string for camelizing - rmsPrefix = /^-ms-/, - rdashAlpha = /-([\da-z])/gi, - - // Used by jQuery.camelCase as callback to replace() - fcamelCase = function( all, letter ) { - return letter.toUpperCase(); - }; - -jQuery.fn = jQuery.prototype = { - - // The current version of jQuery being used - jquery: version, - - constructor: jQuery, - - // Start with an empty selector - selector: "", - - // The default length of a jQuery object is 0 - length: 0, - - toArray: function() { - return slice.call( this ); - }, - - // Get the Nth element in the matched element set OR - // Get the whole matched element set as a clean array - get: function( num ) { - return num != null ? - - // Return just the one element from the set - ( num < 0 ? this[ num + this.length ] : this[ num ] ) : - - // Return all the elements in a clean array - slice.call( this ); - }, - - // Take an array of elements and push it onto the stack - // (returning the new matched element set) - pushStack: function( elems ) { - - // Build a new jQuery matched element set - var ret = jQuery.merge( this.constructor(), elems ); - - // Add the old object onto the stack (as a reference) - ret.prevObject = this; - ret.context = this.context; - - // Return the newly-formed element set - return ret; - }, - - // Execute a callback for every element in the matched set. - each: function( callback ) { - return jQuery.each( this, callback ); - }, - - map: function( callback ) { - return this.pushStack( jQuery.map( this, function( elem, i ) { - return callback.call( elem, i, elem ); - } ) ); - }, - - slice: function() { - return this.pushStack( slice.apply( this, arguments ) ); - }, - - first: function() { - return this.eq( 0 ); - }, - - last: function() { - return this.eq( -1 ); - }, - - eq: function( i ) { - var len = this.length, - j = +i + ( i < 0 ? len : 0 ); - return this.pushStack( j >= 0 && j < len ? [ this[ j ] ] : [] ); - }, - - end: function() { - return this.prevObject || this.constructor(); - }, - - // For internal use only. - // Behaves like an Array's method, not like a jQuery method. - push: push, - sort: deletedIds.sort, - splice: deletedIds.splice -}; - -jQuery.extend = jQuery.fn.extend = function() { - var src, copyIsArray, copy, name, options, clone, - target = arguments[ 0 ] || {}, - i = 1, - length = arguments.length, - deep = false; - - // Handle a deep copy situation - if ( typeof target === "boolean" ) { - deep = target; - - // skip the boolean and the target - target = arguments[ i ] || {}; - i++; - } - - // Handle case when target is a string or something (possible in deep copy) - if ( typeof target !== "object" && !jQuery.isFunction( target ) ) { - target = {}; - } - - // extend jQuery itself if only one argument is passed - if ( i === length ) { - target = this; - i--; - } - - for ( ; i < length; i++ ) { - - // Only deal with non-null/undefined values - if ( ( options = arguments[ i ] ) != null ) { - - // Extend the base object - for ( name in options ) { - src = target[ name ]; - copy = options[ name ]; - - // Prevent never-ending loop - if ( target === copy ) { - continue; - } - - // Recurse if we're merging plain objects or arrays - if ( deep && copy && ( jQuery.isPlainObject( copy ) || - ( copyIsArray = jQuery.isArray( copy ) ) ) ) { - - if ( copyIsArray ) { - copyIsArray = false; - clone = src && jQuery.isArray( src ) ? src : []; - - } else { - clone = src && jQuery.isPlainObject( src ) ? src : {}; - } - - // Never move original objects, clone them - target[ name ] = jQuery.extend( deep, clone, copy ); - - // Don't bring in undefined values - } else if ( copy !== undefined ) { - target[ name ] = copy; - } - } - } - } - - // Return the modified object - return target; -}; - -jQuery.extend( { - - // Unique for each copy of jQuery on the page - expando: "jQuery" + ( version + Math.random() ).replace( /\D/g, "" ), - - // Assume jQuery is ready without the ready module - isReady: true, - - error: function( msg ) { - throw new Error( msg ); - }, - - noop: function() {}, - - // See test/unit/core.js for details concerning isFunction. - // Since version 1.3, DOM methods and functions like alert - // aren't supported. They return false on IE (#2968). - isFunction: function( obj ) { - return jQuery.type( obj ) === "function"; - }, - - isArray: Array.isArray || function( obj ) { - return jQuery.type( obj ) === "array"; - }, - - isWindow: function( obj ) { - /* jshint eqeqeq: false */ - return obj != null && obj == obj.window; - }, - - isNumeric: function( obj ) { - - // parseFloat NaNs numeric-cast false positives (null|true|false|"") - // ...but misinterprets leading-number strings, particularly hex literals ("0x...") - // subtraction forces infinities to NaN - // adding 1 corrects loss of precision from parseFloat (#15100) - var realStringObj = obj && obj.toString(); - return !jQuery.isArray( obj ) && ( realStringObj - parseFloat( realStringObj ) + 1 ) >= 0; - }, - - isEmptyObject: function( obj ) { - var name; - for ( name in obj ) { - return false; - } - return true; - }, - - isPlainObject: function( obj ) { - var key; - - // Must be an Object. - // Because of IE, we also have to check the presence of the constructor property. - // Make sure that DOM nodes and window objects don't pass through, as well - if ( !obj || jQuery.type( obj ) !== "object" || obj.nodeType || jQuery.isWindow( obj ) ) { - return false; - } - - try { - - // Not own constructor property must be Object - if ( obj.constructor && - !hasOwn.call( obj, "constructor" ) && - !hasOwn.call( obj.constructor.prototype, "isPrototypeOf" ) ) { - return false; - } - } catch ( e ) { - - // IE8,9 Will throw exceptions on certain host objects #9897 - return false; - } - - // Support: IE<9 - // Handle iteration over inherited properties before own properties. - if ( !support.ownFirst ) { - for ( key in obj ) { - return hasOwn.call( obj, key ); - } - } - - // Own properties are enumerated firstly, so to speed up, - // if last one is own, then all properties are own. - for ( key in obj ) {} - - return key === undefined || hasOwn.call( obj, key ); - }, - - type: function( obj ) { - if ( obj == null ) { - return obj + ""; - } - return typeof obj === "object" || typeof obj === "function" ? - class2type[ toString.call( obj ) ] || "object" : - typeof obj; - }, - - // Workarounds based on findings by Jim Driscoll - // http://weblogs.java.net/blog/driscoll/archive/2009/09/08/eval-javascript-global-context - globalEval: function( data ) { - if ( data && jQuery.trim( data ) ) { - - // We use execScript on Internet Explorer - // We use an anonymous function so that context is window - // rather than jQuery in Firefox - ( window.execScript || function( data ) { - window[ "eval" ].call( window, data ); // jscs:ignore requireDotNotation - } )( data ); - } - }, - - // Convert dashed to camelCase; used by the css and data modules - // Microsoft forgot to hump their vendor prefix (#9572) - camelCase: function( string ) { - return string.replace( rmsPrefix, "ms-" ).replace( rdashAlpha, fcamelCase ); - }, - - nodeName: function( elem, name ) { - return elem.nodeName && elem.nodeName.toLowerCase() === name.toLowerCase(); - }, - - each: function( obj, callback ) { - var length, i = 0; - - if ( isArrayLike( obj ) ) { - length = obj.length; - for ( ; i < length; i++ ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } else { - for ( i in obj ) { - if ( callback.call( obj[ i ], i, obj[ i ] ) === false ) { - break; - } - } - } - - return obj; - }, - - // Support: Android<4.1, IE<9 - trim: function( text ) { - return text == null ? - "" : - ( text + "" ).replace( rtrim, "" ); - }, - - // results is for internal usage only - makeArray: function( arr, results ) { - var ret = results || []; - - if ( arr != null ) { - if ( isArrayLike( Object( arr ) ) ) { - jQuery.merge( ret, - typeof arr === "string" ? - [ arr ] : arr - ); - } else { - push.call( ret, arr ); - } - } - - return ret; - }, - - inArray: function( elem, arr, i ) { - var len; - - if ( arr ) { - if ( indexOf ) { - return indexOf.call( arr, elem, i ); - } - - len = arr.length; - i = i ? i < 0 ? Math.max( 0, len + i ) : i : 0; - - for ( ; i < len; i++ ) { - - // Skip accessing in sparse arrays - if ( i in arr && arr[ i ] === elem ) { - return i; - } - } - } - - return -1; - }, - - merge: function( first, second ) { - var len = +second.length, - j = 0, - i = first.length; - - while ( j < len ) { - first[ i++ ] = second[ j++ ]; - } - - // Support: IE<9 - // Workaround casting of .length to NaN on otherwise arraylike objects (e.g., NodeLists) - if ( len !== len ) { - while ( second[ j ] !== undefined ) { - first[ i++ ] = second[ j++ ]; - } - } - - first.length = i; - - return first; - }, - - grep: function( elems, callback, invert ) { - var callbackInverse, - matches = [], - i = 0, - length = elems.length, - callbackExpect = !invert; - - // Go through the array, only saving the items - // that pass the validator function - for ( ; i < length; i++ ) { - callbackInverse = !callback( elems[ i ], i ); - if ( callbackInverse !== callbackExpect ) { - matches.push( elems[ i ] ); - } - } - - return matches; - }, - - // arg is for internal usage only - map: function( elems, callback, arg ) { - var length, value, - i = 0, - ret = []; - - // Go through the array, translating each of the items to their new values - if ( isArrayLike( elems ) ) { - length = elems.length; - for ( ; i < length; i++ ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - - // Go through every key on the object, - } else { - for ( i in elems ) { - value = callback( elems[ i ], i, arg ); - - if ( value != null ) { - ret.push( value ); - } - } - } - - // Flatten any nested arrays - return concat.apply( [], ret ); - }, - - // A global GUID counter for objects - guid: 1, - - // Bind a function to a context, optionally partially applying any - // arguments. - proxy: function( fn, context ) { - var args, proxy, tmp; - - if ( typeof context === "string" ) { - tmp = fn[ context ]; - context = fn; - fn = tmp; - } - - // Quick check to determine if target is callable, in the spec - // this throws a TypeError, but we will just return undefined. - if ( !jQuery.isFunction( fn ) ) { - return undefined; - } - - // Simulated bind - args = slice.call( arguments, 2 ); - proxy = function() { - return fn.apply( context || this, args.concat( slice.call( arguments ) ) ); - }; - - // Set the guid of unique handler to the same of original handler, so it can be removed - proxy.guid = fn.guid = fn.guid || jQuery.guid++; - - return proxy; - }, - - now: function() { - return +( new Date() ); - }, - - // jQuery.support is not used in Core but other projects attach their - // properties to it so it needs to exist. - support: support -} ); - -// JSHint would error on this code due to the Symbol not being defined in ES5. -// Defining this global in .jshintrc would create a danger of using the global -// unguarded in another place, it seems safer to just disable JSHint for these -// three lines. -/* jshint ignore: start */ -if ( typeof Symbol === "function" ) { - jQuery.fn[ Symbol.iterator ] = deletedIds[ Symbol.iterator ]; -} -/* jshint ignore: end */ - -// Populate the class2type map -jQuery.each( "Boolean Number String Function Array Date RegExp Object Error Symbol".split( " " ), -function( i, name ) { - class2type[ "[object " + name + "]" ] = name.toLowerCase(); -} ); - -function isArrayLike( obj ) { - - // Support: iOS 8.2 (not reproducible in simulator) - // `in` check used to prevent JIT error (gh-2145) - // hasOwn isn't used here due to false negatives - // regarding Nodelist length in IE - var length = !!obj && "length" in obj && obj.length, - type = jQuery.type( obj ); - - if ( type === "function" || jQuery.isWindow( obj ) ) { - return false; - } - - return type === "array" || length === 0 || - typeof length === "number" && length > 0 && ( length - 1 ) in obj; -} -var Sizzle = -/*! - * Sizzle CSS Selector Engine v2.2.1 - * http://sizzlejs.com/ - * - * Copyright jQuery Foundation and other contributors - * Released under the MIT license - * http://jquery.org/license - * - * Date: 2015-10-17 - */ -(function( window ) { - -var i, - support, - Expr, - getText, - isXML, - tokenize, - compile, - select, - outermostContext, - sortInput, - hasDuplicate, - - // Local document vars - setDocument, - document, - docElem, - documentIsHTML, - rbuggyQSA, - rbuggyMatches, - matches, - contains, - - // Instance-specific data - expando = "sizzle" + 1 * new Date(), - preferredDoc = window.document, - dirruns = 0, - done = 0, - classCache = createCache(), - tokenCache = createCache(), - compilerCache = createCache(), - sortOrder = function( a, b ) { - if ( a === b ) { - hasDuplicate = true; - } - return 0; - }, - - // General-purpose constants - MAX_NEGATIVE = 1 << 31, - - // Instance methods - hasOwn = ({}).hasOwnProperty, - arr = [], - pop = arr.pop, - push_native = arr.push, - push = arr.push, - slice = arr.slice, - // Use a stripped-down indexOf as it's faster than native - // http://jsperf.com/thor-indexof-vs-for/5 - indexOf = function( list, elem ) { - var i = 0, - len = list.length; - for ( ; i < len; i++ ) { - if ( list[i] === elem ) { - return i; - } - } - return -1; - }, - - booleans = "checked|selected|async|autofocus|autoplay|controls|defer|disabled|hidden|ismap|loop|multiple|open|readonly|required|scoped", - - // Regular expressions - - // http://www.w3.org/TR/css3-selectors/#whitespace - whitespace = "[\\x20\\t\\r\\n\\f]", - - // http://www.w3.org/TR/CSS21/syndata.html#value-def-identifier - identifier = "(?:\\\\.|[\\w-]|[^\\x00-\\xa0])+", - - // Attribute selectors: http://www.w3.org/TR/selectors/#attribute-selectors - attributes = "\\[" + whitespace + "*(" + identifier + ")(?:" + whitespace + - // Operator (capture 2) - "*([*^$|!~]?=)" + whitespace + - // "Attribute values must be CSS identifiers [capture 5] or strings [capture 3 or capture 4]" - "*(?:'((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\"|(" + identifier + "))|)" + whitespace + - "*\\]", - - pseudos = ":(" + identifier + ")(?:\\((" + - // To reduce the number of selectors needing tokenize in the preFilter, prefer arguments: - // 1. quoted (capture 3; capture 4 or capture 5) - "('((?:\\\\.|[^\\\\'])*)'|\"((?:\\\\.|[^\\\\\"])*)\")|" + - // 2. simple (capture 6) - "((?:\\\\.|[^\\\\()[\\]]|" + attributes + ")*)|" + - // 3. anything else (capture 2) - ".*" + - ")\\)|)", - - // Leading and non-escaped trailing whitespace, capturing some non-whitespace characters preceding the latter - rwhitespace = new RegExp( whitespace + "+", "g" ), - rtrim = new RegExp( "^" + whitespace + "+|((?:^|[^\\\\])(?:\\\\.)*)" + whitespace + "+$", "g" ), - - rcomma = new RegExp( "^" + whitespace + "*," + whitespace + "*" ), - rcombinators = new RegExp( "^" + whitespace + "*([>+~]|" + whitespace + ")" + whitespace + "*" ), - - rattributeQuotes = new RegExp( "=" + whitespace + "*([^\\]'\"]*?)" + whitespace + "*\\]", "g" ), - - rpseudo = new RegExp( pseudos ), - ridentifier = new RegExp( "^" + identifier + "$" ), - - matchExpr = { - "ID": new RegExp( "^#(" + identifier + ")" ), - "CLASS": new RegExp( "^\\.(" + identifier + ")" ), - "TAG": new RegExp( "^(" + identifier + "|[*])" ), - "ATTR": new RegExp( "^" + attributes ), - "PSEUDO": new RegExp( "^" + pseudos ), - "CHILD": new RegExp( "^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\(" + whitespace + - "*(even|odd|(([+-]|)(\\d*)n|)" + whitespace + "*(?:([+-]|)" + whitespace + - "*(\\d+)|))" + whitespace + "*\\)|)", "i" ), - "bool": new RegExp( "^(?:" + booleans + ")$", "i" ), - // For use in libraries implementing .is() - // We use this for POS matching in `select` - "needsContext": new RegExp( "^" + whitespace + "*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\(" + - whitespace + "*((?:-\\d)?\\d*)" + whitespace + "*\\)|)(?=[^-]|$)", "i" ) - }, - - rinputs = /^(?:input|select|textarea|button)$/i, - rheader = /^h\d$/i, - - rnative = /^[^{]+\{\s*\[native \w/, - - // Easily-parseable/retrievable ID or TAG or CLASS selectors - rquickExpr = /^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/, - - rsibling = /[+~]/, - rescape = /'|\\/g, - - // CSS escapes http://www.w3.org/TR/CSS21/syndata.html#escaped-characters - runescape = new RegExp( "\\\\([\\da-f]{1,6}" + whitespace + "?|(" + whitespace + ")|.)", "ig" ), - funescape = function( _, escaped, escapedWhitespace ) { - var high = "0x" + escaped - 0x10000; - // NaN means non-codepoint - // Support: Firefox<24 - // Workaround erroneous numeric interpretation of +"0x" - return high !== high || escapedWhitespace ? - escaped : - high < 0 ? - // BMP codepoint - String.fromCharCode( high + 0x10000 ) : - // Supplemental Plane codepoint (surrogate pair) - String.fromCharCode( high >> 10 | 0xD800, high & 0x3FF | 0xDC00 ); - }, - - // Used for iframes - // See setDocument() - // Removing the function wrapper causes a "Permission Denied" - // error in IE - unloadHandler = function() { - setDocument(); - }; - -// Optimize for push.apply( _, NodeList ) -try { - push.apply( - (arr = slice.call( preferredDoc.childNodes )), - preferredDoc.childNodes - ); - // Support: Android<4.0 - // Detect silently failing push.apply - arr[ preferredDoc.childNodes.length ].nodeType; -} catch ( e ) { - push = { apply: arr.length ? - - // Leverage slice if possible - function( target, els ) { - push_native.apply( target, slice.call(els) ); - } : - - // Support: IE<9 - // Otherwise append directly - function( target, els ) { - var j = target.length, - i = 0; - // Can't trust NodeList.length - while ( (target[j++] = els[i++]) ) {} - target.length = j - 1; - } - }; -} - -function Sizzle( selector, context, results, seed ) { - var m, i, elem, nid, nidselect, match, groups, newSelector, - newContext = context && context.ownerDocument, - - // nodeType defaults to 9, since context defaults to document - nodeType = context ? context.nodeType : 9; - - results = results || []; - - // Return early from calls with invalid selector or context - if ( typeof selector !== "string" || !selector || - nodeType !== 1 && nodeType !== 9 && nodeType !== 11 ) { - - return results; - } - - // Try to shortcut find operations (as opposed to filters) in HTML documents - if ( !seed ) { - - if ( ( context ? context.ownerDocument || context : preferredDoc ) !== document ) { - setDocument( context ); - } - context = context || document; - - if ( documentIsHTML ) { - - // If the selector is sufficiently simple, try using a "get*By*" DOM method - // (excepting DocumentFragment context, where the methods don't exist) - if ( nodeType !== 11 && (match = rquickExpr.exec( selector )) ) { - - // ID selector - if ( (m = match[1]) ) { - - // Document context - if ( nodeType === 9 ) { - if ( (elem = context.getElementById( m )) ) { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( elem.id === m ) { - results.push( elem ); - return results; - } - } else { - return results; - } - - // Element context - } else { - - // Support: IE, Opera, Webkit - // TODO: identify versions - // getElementById can match elements by name instead of ID - if ( newContext && (elem = newContext.getElementById( m )) && - contains( context, elem ) && - elem.id === m ) { - - results.push( elem ); - return results; - } - } - - // Type selector - } else if ( match[2] ) { - push.apply( results, context.getElementsByTagName( selector ) ); - return results; - - // Class selector - } else if ( (m = match[3]) && support.getElementsByClassName && - context.getElementsByClassName ) { - - push.apply( results, context.getElementsByClassName( m ) ); - return results; - } - } - - // Take advantage of querySelectorAll - if ( support.qsa && - !compilerCache[ selector + " " ] && - (!rbuggyQSA || !rbuggyQSA.test( selector )) ) { - - if ( nodeType !== 1 ) { - newContext = context; - newSelector = selector; - - // qSA looks outside Element context, which is not what we want - // Thanks to Andrew Dupont for this workaround technique - // Support: IE <=8 - // Exclude object elements - } else if ( context.nodeName.toLowerCase() !== "object" ) { - - // Capture the context ID, setting it first if necessary - if ( (nid = context.getAttribute( "id" )) ) { - nid = nid.replace( rescape, "\\$&" ); - } else { - context.setAttribute( "id", (nid = expando) ); - } - - // Prefix every selector in the list - groups = tokenize( selector ); - i = groups.length; - nidselect = ridentifier.test( nid ) ? "#" + nid : "[id='" + nid + "']"; - while ( i-- ) { - groups[i] = nidselect + " " + toSelector( groups[i] ); - } - newSelector = groups.join( "," ); - - // Expand context for sibling selectors - newContext = rsibling.test( selector ) && testContext( context.parentNode ) || - context; - } - - if ( newSelector ) { - try { - push.apply( results, - newContext.querySelectorAll( newSelector ) - ); - return results; - } catch ( qsaError ) { - } finally { - if ( nid === expando ) { - context.removeAttribute( "id" ); - } - } - } - } - } - } - - // All others - return select( selector.replace( rtrim, "$1" ), context, results, seed ); -} - -/** - * Create key-value caches of limited size - * @returns {function(string, object)} Returns the Object data after storing it on itself with - * property name the (space-suffixed) string and (if the cache is larger than Expr.cacheLength) - * deleting the oldest entry - */ -function createCache() { - var keys = []; - - function cache( key, value ) { - // Use (key + " ") to avoid collision with native prototype properties (see Issue #157) - if ( keys.push( key + " " ) > Expr.cacheLength ) { - // Only keep the most recent entries - delete cache[ keys.shift() ]; - } - return (cache[ key + " " ] = value); - } - return cache; -} - -/** - * Mark a function for special use by Sizzle - * @param {Function} fn The function to mark - */ -function markFunction( fn ) { - fn[ expando ] = true; - return fn; -} - -/** - * Support testing using an element - * @param {Function} fn Passed the created div and expects a boolean result - */ -function assert( fn ) { - var div = document.createElement("div"); - - try { - return !!fn( div ); - } catch (e) { - return false; - } finally { - // Remove from its parent by default - if ( div.parentNode ) { - div.parentNode.removeChild( div ); - } - // release memory in IE - div = null; - } -} - -/** - * Adds the same handler for all of the specified attrs - * @param {String} attrs Pipe-separated list of attributes - * @param {Function} handler The method that will be applied - */ -function addHandle( attrs, handler ) { - var arr = attrs.split("|"), - i = arr.length; - - while ( i-- ) { - Expr.attrHandle[ arr[i] ] = handler; - } -} - -/** - * Checks document order of two siblings - * @param {Element} a - * @param {Element} b - * @returns {Number} Returns less than 0 if a precedes b, greater than 0 if a follows b - */ -function siblingCheck( a, b ) { - var cur = b && a, - diff = cur && a.nodeType === 1 && b.nodeType === 1 && - ( ~b.sourceIndex || MAX_NEGATIVE ) - - ( ~a.sourceIndex || MAX_NEGATIVE ); - - // Use IE sourceIndex if available on both nodes - if ( diff ) { - return diff; - } - - // Check if b follows a - if ( cur ) { - while ( (cur = cur.nextSibling) ) { - if ( cur === b ) { - return -1; - } - } - } - - return a ? 1 : -1; -} - -/** - * Returns a function to use in pseudos for input types - * @param {String} type - */ -function createInputPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for buttons - * @param {String} type - */ -function createButtonPseudo( type ) { - return function( elem ) { - var name = elem.nodeName.toLowerCase(); - return (name === "input" || name === "button") && elem.type === type; - }; -} - -/** - * Returns a function to use in pseudos for positionals - * @param {Function} fn - */ -function createPositionalPseudo( fn ) { - return markFunction(function( argument ) { - argument = +argument; - return markFunction(function( seed, matches ) { - var j, - matchIndexes = fn( [], seed.length, argument ), - i = matchIndexes.length; - - // Match elements found at the specified indexes - while ( i-- ) { - if ( seed[ (j = matchIndexes[i]) ] ) { - seed[j] = !(matches[j] = seed[j]); - } - } - }); - }); -} - -/** - * Checks a node for validity as a Sizzle context - * @param {Element|Object=} context - * @returns {Element|Object|Boolean} The input node if acceptable, otherwise a falsy value - */ -function testContext( context ) { - return context && typeof context.getElementsByTagName !== "undefined" && context; -} - -// Expose support vars for convenience -support = Sizzle.support = {}; - -/** - * Detects XML nodes - * @param {Element|Object} elem An element or a document - * @returns {Boolean} True iff elem is a non-HTML XML node - */ -isXML = Sizzle.isXML = function( elem ) { - // documentElement is verified for cases where it doesn't yet exist - // (such as loading iframes in IE - #4833) - var documentElement = elem && (elem.ownerDocument || elem).documentElement; - return documentElement ? documentElement.nodeName !== "HTML" : false; -}; - -/** - * Sets document-related variables once based on the current document - * @param {Element|Object} [doc] An element or document object to use to set the document - * @returns {Object} Returns the current document - */ -setDocument = Sizzle.setDocument = function( node ) { - var hasCompare, parent, - doc = node ? node.ownerDocument || node : preferredDoc; - - // Return early if doc is invalid or already selected - if ( doc === document || doc.nodeType !== 9 || !doc.documentElement ) { - return document; - } - - // Update global variables - document = doc; - docElem = document.documentElement; - documentIsHTML = !isXML( document ); - - // Support: IE 9-11, Edge - // Accessing iframe documents after unload throws "permission denied" errors (jQuery #13936) - if ( (parent = document.defaultView) && parent.top !== parent ) { - // Support: IE 11 - if ( parent.addEventListener ) { - parent.addEventListener( "unload", unloadHandler, false ); - - // Support: IE 9 - 10 only - } else if ( parent.attachEvent ) { - parent.attachEvent( "onunload", unloadHandler ); - } - } - - /* Attributes - ---------------------------------------------------------------------- */ - - // Support: IE<8 - // Verify that getAttribute really returns attributes and not properties - // (excepting IE8 booleans) - support.attributes = assert(function( div ) { - div.className = "i"; - return !div.getAttribute("className"); - }); - - /* getElement(s)By* - ---------------------------------------------------------------------- */ - - // Check if getElementsByTagName("*") returns only elements - support.getElementsByTagName = assert(function( div ) { - div.appendChild( document.createComment("") ); - return !div.getElementsByTagName("*").length; - }); - - // Support: IE<9 - support.getElementsByClassName = rnative.test( document.getElementsByClassName ); - - // Support: IE<10 - // Check if getElementById returns elements by name - // The broken getElementById methods don't pick up programatically-set names, - // so use a roundabout getElementsByName test - support.getById = assert(function( div ) { - docElem.appendChild( div ).id = expando; - return !document.getElementsByName || !document.getElementsByName( expando ).length; - }); - - // ID find and filter - if ( support.getById ) { - Expr.find["ID"] = function( id, context ) { - if ( typeof context.getElementById !== "undefined" && documentIsHTML ) { - var m = context.getElementById( id ); - return m ? [ m ] : []; - } - }; - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - return elem.getAttribute("id") === attrId; - }; - }; - } else { - // Support: IE6/7 - // getElementById is not reliable as a find shortcut - delete Expr.find["ID"]; - - Expr.filter["ID"] = function( id ) { - var attrId = id.replace( runescape, funescape ); - return function( elem ) { - var node = typeof elem.getAttributeNode !== "undefined" && - elem.getAttributeNode("id"); - return node && node.value === attrId; - }; - }; - } - - // Tag - Expr.find["TAG"] = support.getElementsByTagName ? - function( tag, context ) { - if ( typeof context.getElementsByTagName !== "undefined" ) { - return context.getElementsByTagName( tag ); - - // DocumentFragment nodes don't have gEBTN - } else if ( support.qsa ) { - return context.querySelectorAll( tag ); - } - } : - - function( tag, context ) { - var elem, - tmp = [], - i = 0, - // By happy coincidence, a (broken) gEBTN appears on DocumentFragment nodes too - results = context.getElementsByTagName( tag ); - - // Filter out possible comments - if ( tag === "*" ) { - while ( (elem = results[i++]) ) { - if ( elem.nodeType === 1 ) { - tmp.push( elem ); - } - } - - return tmp; - } - return results; - }; - - // Class - Expr.find["CLASS"] = support.getElementsByClassName && function( className, context ) { - if ( typeof context.getElementsByClassName !== "undefined" && documentIsHTML ) { - return context.getElementsByClassName( className ); - } - }; - - /* QSA/matchesSelector - ---------------------------------------------------------------------- */ - - // QSA and matchesSelector support - - // matchesSelector(:active) reports false when true (IE9/Opera 11.5) - rbuggyMatches = []; - - // qSa(:focus) reports false when true (Chrome 21) - // We allow this because of a bug in IE8/9 that throws an error - // whenever `document.activeElement` is accessed on an iframe - // So, we allow :focus to pass through QSA all the time to avoid the IE error - // See http://bugs.jquery.com/ticket/13378 - rbuggyQSA = []; - - if ( (support.qsa = rnative.test( document.querySelectorAll )) ) { - // Build QSA regex - // Regex strategy adopted from Diego Perini - assert(function( div ) { - // Select is set to empty string on purpose - // This is to test IE's treatment of not explicitly - // setting a boolean content attribute, - // since its presence should be enough - // http://bugs.jquery.com/ticket/12359 - docElem.appendChild( div ).innerHTML = "" + - ""; - - // Support: IE8, Opera 11-12.16 - // Nothing should be selected when empty strings follow ^= or $= or *= - // The test attribute must be unknown in Opera but "safe" for WinRT - // http://msdn.microsoft.com/en-us/library/ie/hh465388.aspx#attribute_section - if ( div.querySelectorAll("[msallowcapture^='']").length ) { - rbuggyQSA.push( "[*^$]=" + whitespace + "*(?:''|\"\")" ); - } - - // Support: IE8 - // Boolean attributes and "value" are not treated correctly - if ( !div.querySelectorAll("[selected]").length ) { - rbuggyQSA.push( "\\[" + whitespace + "*(?:value|" + booleans + ")" ); - } - - // Support: Chrome<29, Android<4.4, Safari<7.0+, iOS<7.0+, PhantomJS<1.9.8+ - if ( !div.querySelectorAll( "[id~=" + expando + "-]" ).length ) { - rbuggyQSA.push("~="); - } - - // Webkit/Opera - :checked should return selected option elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":checked").length ) { - rbuggyQSA.push(":checked"); - } - - // Support: Safari 8+, iOS 8+ - // https://bugs.webkit.org/show_bug.cgi?id=136851 - // In-page `selector#id sibing-combinator selector` fails - if ( !div.querySelectorAll( "a#" + expando + "+*" ).length ) { - rbuggyQSA.push(".#.+[+~]"); - } - }); - - assert(function( div ) { - // Support: Windows 8 Native Apps - // The type and name attributes are restricted during .innerHTML assignment - var input = document.createElement("input"); - input.setAttribute( "type", "hidden" ); - div.appendChild( input ).setAttribute( "name", "D" ); - - // Support: IE8 - // Enforce case-sensitivity of name attribute - if ( div.querySelectorAll("[name=d]").length ) { - rbuggyQSA.push( "name" + whitespace + "*[*^$|!~]?=" ); - } - - // FF 3.5 - :enabled/:disabled and hidden elements (hidden elements are still enabled) - // IE8 throws error here and will not see later tests - if ( !div.querySelectorAll(":enabled").length ) { - rbuggyQSA.push( ":enabled", ":disabled" ); - } - - // Opera 10-11 does not throw on post-comma invalid pseudos - div.querySelectorAll("*,:x"); - rbuggyQSA.push(",.*:"); - }); - } - - if ( (support.matchesSelector = rnative.test( (matches = docElem.matches || - docElem.webkitMatchesSelector || - docElem.mozMatchesSelector || - docElem.oMatchesSelector || - docElem.msMatchesSelector) )) ) { - - assert(function( div ) { - // Check to see if it's possible to do matchesSelector - // on a disconnected node (IE 9) - support.disconnectedMatch = matches.call( div, "div" ); - - // This should fail with an exception - // Gecko does not error, returns false instead - matches.call( div, "[s!='']:x" ); - rbuggyMatches.push( "!=", pseudos ); - }); - } - - rbuggyQSA = rbuggyQSA.length && new RegExp( rbuggyQSA.join("|") ); - rbuggyMatches = rbuggyMatches.length && new RegExp( rbuggyMatches.join("|") ); - - /* Contains - ---------------------------------------------------------------------- */ - hasCompare = rnative.test( docElem.compareDocumentPosition ); - - // Element contains another - // Purposefully self-exclusive - // As in, an element does not contain itself - contains = hasCompare || rnative.test( docElem.contains ) ? - function( a, b ) { - var adown = a.nodeType === 9 ? a.documentElement : a, - bup = b && b.parentNode; - return a === bup || !!( bup && bup.nodeType === 1 && ( - adown.contains ? - adown.contains( bup ) : - a.compareDocumentPosition && a.compareDocumentPosition( bup ) & 16 - )); - } : - function( a, b ) { - if ( b ) { - while ( (b = b.parentNode) ) { - if ( b === a ) { - return true; - } - } - } - return false; - }; - - /* Sorting - ---------------------------------------------------------------------- */ - - // Document order sorting - sortOrder = hasCompare ? - function( a, b ) { - - // Flag for duplicate removal - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - // Sort on method existence if only one input has compareDocumentPosition - var compare = !a.compareDocumentPosition - !b.compareDocumentPosition; - if ( compare ) { - return compare; - } - - // Calculate position if both inputs belong to the same document - compare = ( a.ownerDocument || a ) === ( b.ownerDocument || b ) ? - a.compareDocumentPosition( b ) : - - // Otherwise we know they are disconnected - 1; - - // Disconnected nodes - if ( compare & 1 || - (!support.sortDetached && b.compareDocumentPosition( a ) === compare) ) { - - // Choose the first element that is related to our preferred document - if ( a === document || a.ownerDocument === preferredDoc && contains(preferredDoc, a) ) { - return -1; - } - if ( b === document || b.ownerDocument === preferredDoc && contains(preferredDoc, b) ) { - return 1; - } - - // Maintain original order - return sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - } - - return compare & 4 ? -1 : 1; - } : - function( a, b ) { - // Exit early if the nodes are identical - if ( a === b ) { - hasDuplicate = true; - return 0; - } - - var cur, - i = 0, - aup = a.parentNode, - bup = b.parentNode, - ap = [ a ], - bp = [ b ]; - - // Parentless nodes are either documents or disconnected - if ( !aup || !bup ) { - return a === document ? -1 : - b === document ? 1 : - aup ? -1 : - bup ? 1 : - sortInput ? - ( indexOf( sortInput, a ) - indexOf( sortInput, b ) ) : - 0; - - // If the nodes are siblings, we can do a quick check - } else if ( aup === bup ) { - return siblingCheck( a, b ); - } - - // Otherwise we need full lists of their ancestors for comparison - cur = a; - while ( (cur = cur.parentNode) ) { - ap.unshift( cur ); - } - cur = b; - while ( (cur = cur.parentNode) ) { - bp.unshift( cur ); - } - - // Walk down the tree looking for a discrepancy - while ( ap[i] === bp[i] ) { - i++; - } - - return i ? - // Do a sibling check if the nodes have a common ancestor - siblingCheck( ap[i], bp[i] ) : - - // Otherwise nodes in our document sort first - ap[i] === preferredDoc ? -1 : - bp[i] === preferredDoc ? 1 : - 0; - }; - - return document; -}; - -Sizzle.matches = function( expr, elements ) { - return Sizzle( expr, null, null, elements ); -}; - -Sizzle.matchesSelector = function( elem, expr ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - // Make sure that attribute selectors are quoted - expr = expr.replace( rattributeQuotes, "='$1']" ); - - if ( support.matchesSelector && documentIsHTML && - !compilerCache[ expr + " " ] && - ( !rbuggyMatches || !rbuggyMatches.test( expr ) ) && - ( !rbuggyQSA || !rbuggyQSA.test( expr ) ) ) { - - try { - var ret = matches.call( elem, expr ); - - // IE 9's matchesSelector returns false on disconnected nodes - if ( ret || support.disconnectedMatch || - // As well, disconnected nodes are said to be in a document - // fragment in IE 9 - elem.document && elem.document.nodeType !== 11 ) { - return ret; - } - } catch (e) {} - } - - return Sizzle( expr, document, null, [ elem ] ).length > 0; -}; - -Sizzle.contains = function( context, elem ) { - // Set document vars if needed - if ( ( context.ownerDocument || context ) !== document ) { - setDocument( context ); - } - return contains( context, elem ); -}; - -Sizzle.attr = function( elem, name ) { - // Set document vars if needed - if ( ( elem.ownerDocument || elem ) !== document ) { - setDocument( elem ); - } - - var fn = Expr.attrHandle[ name.toLowerCase() ], - // Don't get fooled by Object.prototype properties (jQuery #13807) - val = fn && hasOwn.call( Expr.attrHandle, name.toLowerCase() ) ? - fn( elem, name, !documentIsHTML ) : - undefined; - - return val !== undefined ? - val : - support.attributes || !documentIsHTML ? - elem.getAttribute( name ) : - (val = elem.getAttributeNode(name)) && val.specified ? - val.value : - null; -}; - -Sizzle.error = function( msg ) { - throw new Error( "Syntax error, unrecognized expression: " + msg ); -}; - -/** - * Document sorting and removing duplicates - * @param {ArrayLike} results - */ -Sizzle.uniqueSort = function( results ) { - var elem, - duplicates = [], - j = 0, - i = 0; - - // Unless we *know* we can detect duplicates, assume their presence - hasDuplicate = !support.detectDuplicates; - sortInput = !support.sortStable && results.slice( 0 ); - results.sort( sortOrder ); - - if ( hasDuplicate ) { - while ( (elem = results[i++]) ) { - if ( elem === results[ i ] ) { - j = duplicates.push( i ); - } - } - while ( j-- ) { - results.splice( duplicates[ j ], 1 ); - } - } - - // Clear input after sorting to release objects - // See https://github.com/jquery/sizzle/pull/225 - sortInput = null; - - return results; -}; - -/** - * Utility function for retrieving the text value of an array of DOM nodes - * @param {Array|Element} elem - */ -getText = Sizzle.getText = function( elem ) { - var node, - ret = "", - i = 0, - nodeType = elem.nodeType; - - if ( !nodeType ) { - // If no nodeType, this is expected to be an array - while ( (node = elem[i++]) ) { - // Do not traverse comment nodes - ret += getText( node ); - } - } else if ( nodeType === 1 || nodeType === 9 || nodeType === 11 ) { - // Use textContent for elements - // innerText usage removed for consistency of new lines (jQuery #11153) - if ( typeof elem.textContent === "string" ) { - return elem.textContent; - } else { - // Traverse its children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - ret += getText( elem ); - } - } - } else if ( nodeType === 3 || nodeType === 4 ) { - return elem.nodeValue; - } - // Do not include comment or processing instruction nodes - - return ret; -}; - -Expr = Sizzle.selectors = { - - // Can be adjusted by the user - cacheLength: 50, - - createPseudo: markFunction, - - match: matchExpr, - - attrHandle: {}, - - find: {}, - - relative: { - ">": { dir: "parentNode", first: true }, - " ": { dir: "parentNode" }, - "+": { dir: "previousSibling", first: true }, - "~": { dir: "previousSibling" } - }, - - preFilter: { - "ATTR": function( match ) { - match[1] = match[1].replace( runescape, funescape ); - - // Move the given value to match[3] whether quoted or unquoted - match[3] = ( match[3] || match[4] || match[5] || "" ).replace( runescape, funescape ); - - if ( match[2] === "~=" ) { - match[3] = " " + match[3] + " "; - } - - return match.slice( 0, 4 ); - }, - - "CHILD": function( match ) { - /* matches from matchExpr["CHILD"] - 1 type (only|nth|...) - 2 what (child|of-type) - 3 argument (even|odd|\d*|\d*n([+-]\d+)?|...) - 4 xn-component of xn+y argument ([+-]?\d*n|) - 5 sign of xn-component - 6 x of xn-component - 7 sign of y-component - 8 y of y-component - */ - match[1] = match[1].toLowerCase(); - - if ( match[1].slice( 0, 3 ) === "nth" ) { - // nth-* requires argument - if ( !match[3] ) { - Sizzle.error( match[0] ); - } - - // numeric x and y parameters for Expr.filter.CHILD - // remember that false/true cast respectively to 0/1 - match[4] = +( match[4] ? match[5] + (match[6] || 1) : 2 * ( match[3] === "even" || match[3] === "odd" ) ); - match[5] = +( ( match[7] + match[8] ) || match[3] === "odd" ); - - // other types prohibit arguments - } else if ( match[3] ) { - Sizzle.error( match[0] ); - } - - return match; - }, - - "PSEUDO": function( match ) { - var excess, - unquoted = !match[6] && match[2]; - - if ( matchExpr["CHILD"].test( match[0] ) ) { - return null; - } - - // Accept quoted arguments as-is - if ( match[3] ) { - match[2] = match[4] || match[5] || ""; - - // Strip excess characters from unquoted arguments - } else if ( unquoted && rpseudo.test( unquoted ) && - // Get excess from tokenize (recursively) - (excess = tokenize( unquoted, true )) && - // advance to the next closing parenthesis - (excess = unquoted.indexOf( ")", unquoted.length - excess ) - unquoted.length) ) { - - // excess is a negative index - match[0] = match[0].slice( 0, excess ); - match[2] = unquoted.slice( 0, excess ); - } - - // Return only captures needed by the pseudo filter method (type and argument) - return match.slice( 0, 3 ); - } - }, - - filter: { - - "TAG": function( nodeNameSelector ) { - var nodeName = nodeNameSelector.replace( runescape, funescape ).toLowerCase(); - return nodeNameSelector === "*" ? - function() { return true; } : - function( elem ) { - return elem.nodeName && elem.nodeName.toLowerCase() === nodeName; - }; - }, - - "CLASS": function( className ) { - var pattern = classCache[ className + " " ]; - - return pattern || - (pattern = new RegExp( "(^|" + whitespace + ")" + className + "(" + whitespace + "|$)" )) && - classCache( className, function( elem ) { - return pattern.test( typeof elem.className === "string" && elem.className || typeof elem.getAttribute !== "undefined" && elem.getAttribute("class") || "" ); - }); - }, - - "ATTR": function( name, operator, check ) { - return function( elem ) { - var result = Sizzle.attr( elem, name ); - - if ( result == null ) { - return operator === "!="; - } - if ( !operator ) { - return true; - } - - result += ""; - - return operator === "=" ? result === check : - operator === "!=" ? result !== check : - operator === "^=" ? check && result.indexOf( check ) === 0 : - operator === "*=" ? check && result.indexOf( check ) > -1 : - operator === "$=" ? check && result.slice( -check.length ) === check : - operator === "~=" ? ( " " + result.replace( rwhitespace, " " ) + " " ).indexOf( check ) > -1 : - operator === "|=" ? result === check || result.slice( 0, check.length + 1 ) === check + "-" : - false; - }; - }, - - "CHILD": function( type, what, argument, first, last ) { - var simple = type.slice( 0, 3 ) !== "nth", - forward = type.slice( -4 ) !== "last", - ofType = what === "of-type"; - - return first === 1 && last === 0 ? - - // Shortcut for :nth-*(n) - function( elem ) { - return !!elem.parentNode; - } : - - function( elem, context, xml ) { - var cache, uniqueCache, outerCache, node, nodeIndex, start, - dir = simple !== forward ? "nextSibling" : "previousSibling", - parent = elem.parentNode, - name = ofType && elem.nodeName.toLowerCase(), - useCache = !xml && !ofType, - diff = false; - - if ( parent ) { - - // :(first|last|only)-(child|of-type) - if ( simple ) { - while ( dir ) { - node = elem; - while ( (node = node[ dir ]) ) { - if ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) { - - return false; - } - } - // Reverse direction for :only-* (if we haven't yet done so) - start = dir = type === "only" && !start && "nextSibling"; - } - return true; - } - - start = [ forward ? parent.firstChild : parent.lastChild ]; - - // non-xml :nth-child(...) stores cache data on `parent` - if ( forward && useCache ) { - - // Seek `elem` from a previously-cached index - - // ...in a gzip-friendly way - node = parent; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex && cache[ 2 ]; - node = nodeIndex && parent.childNodes[ nodeIndex ]; - - while ( (node = ++nodeIndex && node && node[ dir ] || - - // Fallback to seeking `elem` from the start - (diff = nodeIndex = 0) || start.pop()) ) { - - // When found, cache indexes on `parent` and break - if ( node.nodeType === 1 && ++diff && node === elem ) { - uniqueCache[ type ] = [ dirruns, nodeIndex, diff ]; - break; - } - } - - } else { - // Use previously-cached element index if available - if ( useCache ) { - // ...in a gzip-friendly way - node = elem; - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - cache = uniqueCache[ type ] || []; - nodeIndex = cache[ 0 ] === dirruns && cache[ 1 ]; - diff = nodeIndex; - } - - // xml :nth-child(...) - // or :nth-last-child(...) or :nth(-last)?-of-type(...) - if ( diff === false ) { - // Use the same loop as above to seek `elem` from the start - while ( (node = ++nodeIndex && node && node[ dir ] || - (diff = nodeIndex = 0) || start.pop()) ) { - - if ( ( ofType ? - node.nodeName.toLowerCase() === name : - node.nodeType === 1 ) && - ++diff ) { - - // Cache the index of each encountered element - if ( useCache ) { - outerCache = node[ expando ] || (node[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ node.uniqueID ] || - (outerCache[ node.uniqueID ] = {}); - - uniqueCache[ type ] = [ dirruns, diff ]; - } - - if ( node === elem ) { - break; - } - } - } - } - } - - // Incorporate the offset, then check against cycle size - diff -= last; - return diff === first || ( diff % first === 0 && diff / first >= 0 ); - } - }; - }, - - "PSEUDO": function( pseudo, argument ) { - // pseudo-class names are case-insensitive - // http://www.w3.org/TR/selectors/#pseudo-classes - // Prioritize by case sensitivity in case custom pseudos are added with uppercase letters - // Remember that setFilters inherits from pseudos - var args, - fn = Expr.pseudos[ pseudo ] || Expr.setFilters[ pseudo.toLowerCase() ] || - Sizzle.error( "unsupported pseudo: " + pseudo ); - - // The user may use createPseudo to indicate that - // arguments are needed to create the filter function - // just as Sizzle does - if ( fn[ expando ] ) { - return fn( argument ); - } - - // But maintain support for old signatures - if ( fn.length > 1 ) { - args = [ pseudo, pseudo, "", argument ]; - return Expr.setFilters.hasOwnProperty( pseudo.toLowerCase() ) ? - markFunction(function( seed, matches ) { - var idx, - matched = fn( seed, argument ), - i = matched.length; - while ( i-- ) { - idx = indexOf( seed, matched[i] ); - seed[ idx ] = !( matches[ idx ] = matched[i] ); - } - }) : - function( elem ) { - return fn( elem, 0, args ); - }; - } - - return fn; - } - }, - - pseudos: { - // Potentially complex pseudos - "not": markFunction(function( selector ) { - // Trim the selector passed to compile - // to avoid treating leading and trailing - // spaces as combinators - var input = [], - results = [], - matcher = compile( selector.replace( rtrim, "$1" ) ); - - return matcher[ expando ] ? - markFunction(function( seed, matches, context, xml ) { - var elem, - unmatched = matcher( seed, null, xml, [] ), - i = seed.length; - - // Match elements unmatched by `matcher` - while ( i-- ) { - if ( (elem = unmatched[i]) ) { - seed[i] = !(matches[i] = elem); - } - } - }) : - function( elem, context, xml ) { - input[0] = elem; - matcher( input, null, xml, results ); - // Don't keep the element (issue #299) - input[0] = null; - return !results.pop(); - }; - }), - - "has": markFunction(function( selector ) { - return function( elem ) { - return Sizzle( selector, elem ).length > 0; - }; - }), - - "contains": markFunction(function( text ) { - text = text.replace( runescape, funescape ); - return function( elem ) { - return ( elem.textContent || elem.innerText || getText( elem ) ).indexOf( text ) > -1; - }; - }), - - // "Whether an element is represented by a :lang() selector - // is based solely on the element's language value - // being equal to the identifier C, - // or beginning with the identifier C immediately followed by "-". - // The matching of C against the element's language value is performed case-insensitively. - // The identifier C does not have to be a valid language name." - // http://www.w3.org/TR/selectors/#lang-pseudo - "lang": markFunction( function( lang ) { - // lang value must be a valid identifier - if ( !ridentifier.test(lang || "") ) { - Sizzle.error( "unsupported lang: " + lang ); - } - lang = lang.replace( runescape, funescape ).toLowerCase(); - return function( elem ) { - var elemLang; - do { - if ( (elemLang = documentIsHTML ? - elem.lang : - elem.getAttribute("xml:lang") || elem.getAttribute("lang")) ) { - - elemLang = elemLang.toLowerCase(); - return elemLang === lang || elemLang.indexOf( lang + "-" ) === 0; - } - } while ( (elem = elem.parentNode) && elem.nodeType === 1 ); - return false; - }; - }), - - // Miscellaneous - "target": function( elem ) { - var hash = window.location && window.location.hash; - return hash && hash.slice( 1 ) === elem.id; - }, - - "root": function( elem ) { - return elem === docElem; - }, - - "focus": function( elem ) { - return elem === document.activeElement && (!document.hasFocus || document.hasFocus()) && !!(elem.type || elem.href || ~elem.tabIndex); - }, - - // Boolean properties - "enabled": function( elem ) { - return elem.disabled === false; - }, - - "disabled": function( elem ) { - return elem.disabled === true; - }, - - "checked": function( elem ) { - // In CSS3, :checked should return both checked and selected elements - // http://www.w3.org/TR/2011/REC-css3-selectors-20110929/#checked - var nodeName = elem.nodeName.toLowerCase(); - return (nodeName === "input" && !!elem.checked) || (nodeName === "option" && !!elem.selected); - }, - - "selected": function( elem ) { - // Accessing this property makes selected-by-default - // options in Safari work properly - if ( elem.parentNode ) { - elem.parentNode.selectedIndex; - } - - return elem.selected === true; - }, - - // Contents - "empty": function( elem ) { - // http://www.w3.org/TR/selectors/#empty-pseudo - // :empty is negated by element (1) or content nodes (text: 3; cdata: 4; entity ref: 5), - // but not by others (comment: 8; processing instruction: 7; etc.) - // nodeType < 6 works because attributes (2) do not appear as children - for ( elem = elem.firstChild; elem; elem = elem.nextSibling ) { - if ( elem.nodeType < 6 ) { - return false; - } - } - return true; - }, - - "parent": function( elem ) { - return !Expr.pseudos["empty"]( elem ); - }, - - // Element/input types - "header": function( elem ) { - return rheader.test( elem.nodeName ); - }, - - "input": function( elem ) { - return rinputs.test( elem.nodeName ); - }, - - "button": function( elem ) { - var name = elem.nodeName.toLowerCase(); - return name === "input" && elem.type === "button" || name === "button"; - }, - - "text": function( elem ) { - var attr; - return elem.nodeName.toLowerCase() === "input" && - elem.type === "text" && - - // Support: IE<8 - // New HTML5 attribute values (e.g., "search") appear with elem.type === "text" - ( (attr = elem.getAttribute("type")) == null || attr.toLowerCase() === "text" ); - }, - - // Position-in-collection - "first": createPositionalPseudo(function() { - return [ 0 ]; - }), - - "last": createPositionalPseudo(function( matchIndexes, length ) { - return [ length - 1 ]; - }), - - "eq": createPositionalPseudo(function( matchIndexes, length, argument ) { - return [ argument < 0 ? argument + length : argument ]; - }), - - "even": createPositionalPseudo(function( matchIndexes, length ) { - var i = 0; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "odd": createPositionalPseudo(function( matchIndexes, length ) { - var i = 1; - for ( ; i < length; i += 2 ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "lt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; --i >= 0; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }), - - "gt": createPositionalPseudo(function( matchIndexes, length, argument ) { - var i = argument < 0 ? argument + length : argument; - for ( ; ++i < length; ) { - matchIndexes.push( i ); - } - return matchIndexes; - }) - } -}; - -Expr.pseudos["nth"] = Expr.pseudos["eq"]; - -// Add button/input type pseudos -for ( i in { radio: true, checkbox: true, file: true, password: true, image: true } ) { - Expr.pseudos[ i ] = createInputPseudo( i ); -} -for ( i in { submit: true, reset: true } ) { - Expr.pseudos[ i ] = createButtonPseudo( i ); -} - -// Easy API for creating new setFilters -function setFilters() {} -setFilters.prototype = Expr.filters = Expr.pseudos; -Expr.setFilters = new setFilters(); - -tokenize = Sizzle.tokenize = function( selector, parseOnly ) { - var matched, match, tokens, type, - soFar, groups, preFilters, - cached = tokenCache[ selector + " " ]; - - if ( cached ) { - return parseOnly ? 0 : cached.slice( 0 ); - } - - soFar = selector; - groups = []; - preFilters = Expr.preFilter; - - while ( soFar ) { - - // Comma and first run - if ( !matched || (match = rcomma.exec( soFar )) ) { - if ( match ) { - // Don't consume trailing commas as valid - soFar = soFar.slice( match[0].length ) || soFar; - } - groups.push( (tokens = []) ); - } - - matched = false; - - // Combinators - if ( (match = rcombinators.exec( soFar )) ) { - matched = match.shift(); - tokens.push({ - value: matched, - // Cast descendant combinators to space - type: match[0].replace( rtrim, " " ) - }); - soFar = soFar.slice( matched.length ); - } - - // Filters - for ( type in Expr.filter ) { - if ( (match = matchExpr[ type ].exec( soFar )) && (!preFilters[ type ] || - (match = preFilters[ type ]( match ))) ) { - matched = match.shift(); - tokens.push({ - value: matched, - type: type, - matches: match - }); - soFar = soFar.slice( matched.length ); - } - } - - if ( !matched ) { - break; - } - } - - // Return the length of the invalid excess - // if we're just parsing - // Otherwise, throw an error or return tokens - return parseOnly ? - soFar.length : - soFar ? - Sizzle.error( selector ) : - // Cache the tokens - tokenCache( selector, groups ).slice( 0 ); -}; - -function toSelector( tokens ) { - var i = 0, - len = tokens.length, - selector = ""; - for ( ; i < len; i++ ) { - selector += tokens[i].value; - } - return selector; -} - -function addCombinator( matcher, combinator, base ) { - var dir = combinator.dir, - checkNonElements = base && dir === "parentNode", - doneName = done++; - - return combinator.first ? - // Check against closest ancestor/preceding element - function( elem, context, xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - return matcher( elem, context, xml ); - } - } - } : - - // Check against all ancestor/preceding elements - function( elem, context, xml ) { - var oldCache, uniqueCache, outerCache, - newCache = [ dirruns, doneName ]; - - // We can't set arbitrary data on XML nodes, so they don't benefit from combinator caching - if ( xml ) { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - if ( matcher( elem, context, xml ) ) { - return true; - } - } - } - } else { - while ( (elem = elem[ dir ]) ) { - if ( elem.nodeType === 1 || checkNonElements ) { - outerCache = elem[ expando ] || (elem[ expando ] = {}); - - // Support: IE <9 only - // Defend against cloned attroperties (jQuery gh-1709) - uniqueCache = outerCache[ elem.uniqueID ] || (outerCache[ elem.uniqueID ] = {}); - - if ( (oldCache = uniqueCache[ dir ]) && - oldCache[ 0 ] === dirruns && oldCache[ 1 ] === doneName ) { - - // Assign to newCache so results back-propagate to previous elements - return (newCache[ 2 ] = oldCache[ 2 ]); - } else { - // Reuse newcache so results back-propagate to previous elements - uniqueCache[ dir ] = newCache; - - // A match means we're done; a fail means we have to keep checking - if ( (newCache[ 2 ] = matcher( elem, context, xml )) ) { - return true; - } - } - } - } - } - }; -} - -function elementMatcher( matchers ) { - return matchers.length > 1 ? - function( elem, context, xml ) { - var i = matchers.length; - while ( i-- ) { - if ( !matchers[i]( elem, context, xml ) ) { - return false; - } - } - return true; - } : - matchers[0]; -} - -function multipleContexts( selector, contexts, results ) { - var i = 0, - len = contexts.length; - for ( ; i < len; i++ ) { - Sizzle( selector, contexts[i], results ); - } - return results; -} - -function condense( unmatched, map, filter, context, xml ) { - var elem, - newUnmatched = [], - i = 0, - len = unmatched.length, - mapped = map != null; - - for ( ; i < len; i++ ) { - if ( (elem = unmatched[i]) ) { - if ( !filter || filter( elem, context, xml ) ) { - newUnmatched.push( elem ); - if ( mapped ) { - map.push( i ); - } - } - } - } - - return newUnmatched; -} - -function setMatcher( preFilter, selector, matcher, postFilter, postFinder, postSelector ) { - if ( postFilter && !postFilter[ expando ] ) { - postFilter = setMatcher( postFilter ); - } - if ( postFinder && !postFinder[ expando ] ) { - postFinder = setMatcher( postFinder, postSelector ); - } - return markFunction(function( seed, results, context, xml ) { - var temp, i, elem, - preMap = [], - postMap = [], - preexisting = results.length, - - // Get initial elements from seed or context - elems = seed || multipleContexts( selector || "*", context.nodeType ? [ context ] : context, [] ), - - // Prefilter to get matcher input, preserving a map for seed-results synchronization - matcherIn = preFilter && ( seed || !selector ) ? - condense( elems, preMap, preFilter, context, xml ) : - elems, - - matcherOut = matcher ? - // If we have a postFinder, or filtered seed, or non-seed postFilter or preexisting results, - postFinder || ( seed ? preFilter : preexisting || postFilter ) ? - - // ...intermediate processing is necessary - [] : - - // ...otherwise use results directly - results : - matcherIn; - - // Find primary matches - if ( matcher ) { - matcher( matcherIn, matcherOut, context, xml ); - } - - // Apply postFilter - if ( postFilter ) { - temp = condense( matcherOut, postMap ); - postFilter( temp, [], context, xml ); - - // Un-match failing elements by moving them back to matcherIn - i = temp.length; - while ( i-- ) { - if ( (elem = temp[i]) ) { - matcherOut[ postMap[i] ] = !(matcherIn[ postMap[i] ] = elem); - } - } - } - - if ( seed ) { - if ( postFinder || preFilter ) { - if ( postFinder ) { - // Get the final matcherOut by condensing this intermediate into postFinder contexts - temp = []; - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) ) { - // Restore matcherIn since elem is not yet a final match - temp.push( (matcherIn[i] = elem) ); - } - } - postFinder( null, (matcherOut = []), temp, xml ); - } - - // Move matched elements from seed to results to keep them synchronized - i = matcherOut.length; - while ( i-- ) { - if ( (elem = matcherOut[i]) && - (temp = postFinder ? indexOf( seed, elem ) : preMap[i]) > -1 ) { - - seed[temp] = !(results[temp] = elem); - } - } - } - - // Add elements to results, through postFinder if defined - } else { - matcherOut = condense( - matcherOut === results ? - matcherOut.splice( preexisting, matcherOut.length ) : - matcherOut - ); - if ( postFinder ) { - postFinder( null, results, matcherOut, xml ); - } else { - push.apply( results, matcherOut ); - } - } - }); -} - -function matcherFromTokens( tokens ) { - var checkContext, matcher, j, - len = tokens.length, - leadingRelative = Expr.relative[ tokens[0].type ], - implicitRelative = leadingRelative || Expr.relative[" "], - i = leadingRelative ? 1 : 0, - - // The foundational matcher ensures that elements are reachable from top-level context(s) - matchContext = addCombinator( function( elem ) { - return elem === checkContext; - }, implicitRelative, true ), - matchAnyContext = addCombinator( function( elem ) { - return indexOf( checkContext, elem ) > -1; - }, implicitRelative, true ), - matchers = [ function( elem, context, xml ) { - var ret = ( !leadingRelative && ( xml || context !== outermostContext ) ) || ( - (checkContext = context).nodeType ? - matchContext( elem, context, xml ) : - matchAnyContext( elem, context, xml ) ); - // Avoid hanging onto element (issue #299) - checkContext = null; - return ret; - } ]; - - for ( ; i < len; i++ ) { - if ( (matcher = Expr.relative[ tokens[i].type ]) ) { - matchers = [ addCombinator(elementMatcher( matchers ), matcher) ]; - } else { - matcher = Expr.filter[ tokens[i].type ].apply( null, tokens[i].matches ); - - // Return special upon seeing a positional matcher - if ( matcher[ expando ] ) { - // Find the next relative operator (if any) for proper handling - j = ++i; - for ( ; j < len; j++ ) { - if ( Expr.relative[ tokens[j].type ] ) { - break; - } - } - return setMatcher( - i > 1 && elementMatcher( matchers ), - i > 1 && toSelector( - // If the preceding token was a descendant combinator, insert an implicit any-element `*` - tokens.slice( 0, i - 1 ).concat({ value: tokens[ i - 2 ].type === " " ? "*" : "" }) - ).replace( rtrim, "$1" ), - matcher, - i < j && matcherFromTokens( tokens.slice( i, j ) ), - j < len && matcherFromTokens( (tokens = tokens.slice( j )) ), - j < len && toSelector( tokens ) - ); - } - matchers.push( matcher ); - } - } - - return elementMatcher( matchers ); -} - -function matcherFromGroupMatchers( elementMatchers, setMatchers ) { - var bySet = setMatchers.length > 0, - byElement = elementMatchers.length > 0, - superMatcher = function( seed, context, xml, results, outermost ) { - var elem, j, matcher, - matchedCount = 0, - i = "0", - unmatched = seed && [], - setMatched = [], - contextBackup = outermostContext, - // We must always have either seed elements or outermost context - elems = seed || byElement && Expr.find["TAG"]( "*", outermost ), - // Use integer dirruns iff this is the outermost matcher - dirrunsUnique = (dirruns += contextBackup == null ? 1 : Math.random() || 0.1), - len = elems.length; - - if ( outermost ) { - outermostContext = context === document || context || outermost; - } - - // Add elements passing elementMatchers directly to results - // Support: IE<9, Safari - // Tolerate NodeList properties (IE: "length"; Safari: ) matching elements by id - for ( ; i !== len && (elem = elems[i]) != null; i++ ) { - if ( byElement && elem ) { - j = 0; - if ( !context && elem.ownerDocument !== document ) { - setDocument( elem ); - xml = !documentIsHTML; - } - while ( (matcher = elementMatchers[j++]) ) { - if ( matcher( elem, context || document, xml) ) { - results.push( elem ); - break; - } - } - if ( outermost ) { - dirruns = dirrunsUnique; - } - } - - // Track unmatched elements for set filters - if ( bySet ) { - // They will have gone through all possible matchers - if ( (elem = !matcher && elem) ) { - matchedCount--; - } - - // Lengthen the array for every element, matched or not - if ( seed ) { - unmatched.push( elem ); - } - } - } - - // `i` is now the count of elements visited above, and adding it to `matchedCount` - // makes the latter nonnegative. - matchedCount += i; - - // Apply set filters to unmatched elements - // NOTE: This can be skipped if there are no unmatched elements (i.e., `matchedCount` - // equals `i`), unless we didn't visit _any_ elements in the above loop because we have - // no element matchers and no seed. - // Incrementing an initially-string "0" `i` allows `i` to remain a string only in that - // case, which will result in a "00" `matchedCount` that differs from `i` but is also - // numerically zero. - if ( bySet && i !== matchedCount ) { - j = 0; - while ( (matcher = setMatchers[j++]) ) { - matcher( unmatched, setMatched, context, xml ); - } - - if ( seed ) { - // Reintegrate element matches to eliminate the need for sorting - if ( matchedCount > 0 ) { - while ( i-- ) { - if ( !(unmatched[i] || setMatched[i]) ) { - setMatched[i] = pop.call( results ); - } - } - } - - // Discard index placeholder values to get only actual matches - setMatched = condense( setMatched ); - } - - // Add matches to results - push.apply( results, setMatched ); - - // Seedless set matches succeeding multiple successful matchers stipulate sorting - if ( outermost && !seed && setMatched.length > 0 && - ( matchedCount + setMatchers.length ) > 1 ) { - - Sizzle.uniqueSort( results ); - } - } - - // Override manipulation of globals by nested matchers - if ( outermost ) { - dirruns = dirrunsUnique; - outermostContext = contextBackup; - } - - return unmatched; - }; - - return bySet ? - markFunction( superMatcher ) : - superMatcher; -} - -compile = Sizzle.compile = function( selector, match /* Internal Use Only */ ) { - var i, - setMatchers = [], - elementMatchers = [], - cached = compilerCache[ selector + " " ]; - - if ( !cached ) { - // Generate a function of recursive functions that can be used to check each element - if ( !match ) { - match = tokenize( selector ); - } - i = match.length; - while ( i-- ) { - cached = matcherFromTokens( match[i] ); - if ( cached[ expando ] ) { - setMatchers.push( cached ); - } else { - elementMatchers.push( cached ); - } - } - - // Cache the compiled function - cached = compilerCache( selector, matcherFromGroupMatchers( elementMatchers, setMatchers ) ); - - // Save selector and tokenization - cached.selector = selector; - } - return cached; -}; - -/** - * A low-level selection function that works with Sizzle's compiled - * selector functions - * @param {String|Function} selector A selector or a pre-compiled - * selector function built with Sizzle.compile - * @param {Element} context - * @param {Array} [results] - * @param {Array} [seed] A set of elements to match against - */ -select = Sizzle.select = function( selector, context, results, seed ) { - var i, tokens, token, type, find, - compiled = typeof selector === "function" && selector, - match = !seed && tokenize( (selector = compiled.selector || selector) ); - - results = results || []; - - // Try to minimize operations if there is only one selector in the list and no seed - // (the latter of which guarantees us context) - if ( match.length === 1 ) { - - // Reduce context if the leading compound selector is an ID - tokens = match[0] = match[0].slice( 0 ); - if ( tokens.length > 2 && (token = tokens[0]).type === "ID" && - support.getById && context.nodeType === 9 && documentIsHTML && - Expr.relative[ tokens[1].type ] ) { - - context = ( Expr.find["ID"]( token.matches[0].replace(runescape, funescape), context ) || [] )[0]; - if ( !context ) { - return results; - - // Precompiled matchers will still verify ancestry, so step up a level - } else if ( compiled ) { - context = context.parentNode; - } - - selector = selector.slice( tokens.shift().value.length ); - } - - // Fetch a seed set for right-to-left matching - i = matchExpr["needsContext"].test( selector ) ? 0 : tokens.length; - while ( i-- ) { - token = tokens[i]; - - // Abort if we hit a combinator - if ( Expr.relative[ (type = token.type) ] ) { - break; - } - if ( (find = Expr.find[ type ]) ) { - // Search, expanding context for leading sibling combinators - if ( (seed = find( - token.matches[0].replace( runescape, funescape ), - rsibling.test( tokens[0].type ) && testContext( context.parentNode ) || context - )) ) { - - // If seed is empty or no tokens remain, we can return early - tokens.splice( i, 1 ); - selector = seed.length && toSelector( tokens ); - if ( !selector ) { - push.apply( results, seed ); - return results; - } - - break; - } - } - } - } - - // Compile and execute a filtering function if one is not provided - // Provide `match` to avoid retokenization if we modified the selector above - ( compiled || compile( selector, match ) )( - seed, - context, - !documentIsHTML, - results, - !context || rsibling.test( selector ) && testContext( context.parentNode ) || context - ); - return results; -}; - -// One-time assignments - -// Sort stability -support.sortStable = expando.split("").sort( sortOrder ).join("") === expando; - -// Support: Chrome 14-35+ -// Always assume duplicates if they aren't passed to the comparison function -support.detectDuplicates = !!hasDuplicate; - -// Initialize against the default document -setDocument(); - -// Support: Webkit<537.32 - Safari 6.0.3/Chrome 25 (fixed in Chrome 27) -// Detached nodes confoundingly follow *each other* -support.sortDetached = assert(function( div1 ) { - // Should return 1, but returns 4 (following) - return div1.compareDocumentPosition( document.createElement("div") ) & 1; -}); - -// Support: IE<8 -// Prevent attribute/property "interpolation" -// http://msdn.microsoft.com/en-us/library/ms536429%28VS.85%29.aspx -if ( !assert(function( div ) { - div.innerHTML = ""; - return div.firstChild.getAttribute("href") === "#" ; -}) ) { - addHandle( "type|href|height|width", function( elem, name, isXML ) { - if ( !isXML ) { - return elem.getAttribute( name, name.toLowerCase() === "type" ? 1 : 2 ); - } - }); -} - -// Support: IE<9 -// Use defaultValue in place of getAttribute("value") -if ( !support.attributes || !assert(function( div ) { - div.innerHTML = ""; - div.firstChild.setAttribute( "value", "" ); - return div.firstChild.getAttribute( "value" ) === ""; -}) ) { - addHandle( "value", function( elem, name, isXML ) { - if ( !isXML && elem.nodeName.toLowerCase() === "input" ) { - return elem.defaultValue; - } - }); -} - -// Support: IE<9 -// Use getAttributeNode to fetch booleans when getAttribute lies -if ( !assert(function( div ) { - return div.getAttribute("disabled") == null; -}) ) { - addHandle( booleans, function( elem, name, isXML ) { - var val; - if ( !isXML ) { - return elem[ name ] === true ? name.toLowerCase() : - (val = elem.getAttributeNode( name )) && val.specified ? - val.value : - null; - } - }); -} - -return Sizzle; - -})( window ); - - - -jQuery.find = Sizzle; -jQuery.expr = Sizzle.selectors; -jQuery.expr[ ":" ] = jQuery.expr.pseudos; -jQuery.uniqueSort = jQuery.unique = Sizzle.uniqueSort; -jQuery.text = Sizzle.getText; -jQuery.isXMLDoc = Sizzle.isXML; -jQuery.contains = Sizzle.contains; - - - -var dir = function( elem, dir, until ) { - var matched = [], - truncate = until !== undefined; - - while ( ( elem = elem[ dir ] ) && elem.nodeType !== 9 ) { - if ( elem.nodeType === 1 ) { - if ( truncate && jQuery( elem ).is( until ) ) { - break; - } - matched.push( elem ); - } - } - return matched; -}; - - -var siblings = function( n, elem ) { - var matched = []; - - for ( ; n; n = n.nextSibling ) { - if ( n.nodeType === 1 && n !== elem ) { - matched.push( n ); - } - } - - return matched; -}; - - -var rneedsContext = jQuery.expr.match.needsContext; - -var rsingleTag = ( /^<([\w-]+)\s*\/?>(?:<\/\1>|)$/ ); - - - -var risSimple = /^.[^:#\[\.,]*$/; - -// Implement the identical functionality for filter and not -function winnow( elements, qualifier, not ) { - if ( jQuery.isFunction( qualifier ) ) { - return jQuery.grep( elements, function( elem, i ) { - /* jshint -W018 */ - return !!qualifier.call( elem, i, elem ) !== not; - } ); - - } - - if ( qualifier.nodeType ) { - return jQuery.grep( elements, function( elem ) { - return ( elem === qualifier ) !== not; - } ); - - } - - if ( typeof qualifier === "string" ) { - if ( risSimple.test( qualifier ) ) { - return jQuery.filter( qualifier, elements, not ); - } - - qualifier = jQuery.filter( qualifier, elements ); - } - - return jQuery.grep( elements, function( elem ) { - return ( jQuery.inArray( elem, qualifier ) > -1 ) !== not; - } ); -} - -jQuery.filter = function( expr, elems, not ) { - var elem = elems[ 0 ]; - - if ( not ) { - expr = ":not(" + expr + ")"; - } - - return elems.length === 1 && elem.nodeType === 1 ? - jQuery.find.matchesSelector( elem, expr ) ? [ elem ] : [] : - jQuery.find.matches( expr, jQuery.grep( elems, function( elem ) { - return elem.nodeType === 1; - } ) ); -}; - -jQuery.fn.extend( { - find: function( selector ) { - var i, - ret = [], - self = this, - len = self.length; - - if ( typeof selector !== "string" ) { - return this.pushStack( jQuery( selector ).filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( self[ i ], this ) ) { - return true; - } - } - } ) ); - } - - for ( i = 0; i < len; i++ ) { - jQuery.find( selector, self[ i ], ret ); - } - - // Needed because $( selector, context ) becomes $( context ).find( selector ) - ret = this.pushStack( len > 1 ? jQuery.unique( ret ) : ret ); - ret.selector = this.selector ? this.selector + " " + selector : selector; - return ret; - }, - filter: function( selector ) { - return this.pushStack( winnow( this, selector || [], false ) ); - }, - not: function( selector ) { - return this.pushStack( winnow( this, selector || [], true ) ); - }, - is: function( selector ) { - return !!winnow( - this, - - // If this is a positional/relative selector, check membership in the returned set - // so $("p:first").is("p:last") won't return true for a doc with two "p". - typeof selector === "string" && rneedsContext.test( selector ) ? - jQuery( selector ) : - selector || [], - false - ).length; - } -} ); - - -// Initialize a jQuery object - - -// A central reference to the root jQuery(document) -var rootjQuery, - - // A simple way to check for HTML strings - // Prioritize #id over to avoid XSS via location.hash (#9521) - // Strict HTML recognition (#11290: must start with <) - rquickExpr = /^(?:\s*(<[\w\W]+>)[^>]*|#([\w-]*))$/, - - init = jQuery.fn.init = function( selector, context, root ) { - var match, elem; - - // HANDLE: $(""), $(null), $(undefined), $(false) - if ( !selector ) { - return this; - } - - // init accepts an alternate rootjQuery - // so migrate can support jQuery.sub (gh-2101) - root = root || rootjQuery; - - // Handle HTML strings - if ( typeof selector === "string" ) { - if ( selector.charAt( 0 ) === "<" && - selector.charAt( selector.length - 1 ) === ">" && - selector.length >= 3 ) { - - // Assume that strings that start and end with <> are HTML and skip the regex check - match = [ null, selector, null ]; - - } else { - match = rquickExpr.exec( selector ); - } - - // Match html or make sure no context is specified for #id - if ( match && ( match[ 1 ] || !context ) ) { - - // HANDLE: $(html) -> $(array) - if ( match[ 1 ] ) { - context = context instanceof jQuery ? context[ 0 ] : context; - - // scripts is true for back-compat - // Intentionally let the error be thrown if parseHTML is not present - jQuery.merge( this, jQuery.parseHTML( - match[ 1 ], - context && context.nodeType ? context.ownerDocument || context : document, - true - ) ); - - // HANDLE: $(html, props) - if ( rsingleTag.test( match[ 1 ] ) && jQuery.isPlainObject( context ) ) { - for ( match in context ) { - - // Properties of context are called as methods if possible - if ( jQuery.isFunction( this[ match ] ) ) { - this[ match ]( context[ match ] ); - - // ...and otherwise set as attributes - } else { - this.attr( match, context[ match ] ); - } - } - } - - return this; - - // HANDLE: $(#id) - } else { - elem = document.getElementById( match[ 2 ] ); - - // Check parentNode to catch when Blackberry 4.6 returns - // nodes that are no longer in the document #6963 - if ( elem && elem.parentNode ) { - - // Handle the case where IE and Opera return items - // by name instead of ID - if ( elem.id !== match[ 2 ] ) { - return rootjQuery.find( selector ); - } - - // Otherwise, we inject the element directly into the jQuery object - this.length = 1; - this[ 0 ] = elem; - } - - this.context = document; - this.selector = selector; - return this; - } - - // HANDLE: $(expr, $(...)) - } else if ( !context || context.jquery ) { - return ( context || root ).find( selector ); - - // HANDLE: $(expr, context) - // (which is just equivalent to: $(context).find(expr) - } else { - return this.constructor( context ).find( selector ); - } - - // HANDLE: $(DOMElement) - } else if ( selector.nodeType ) { - this.context = this[ 0 ] = selector; - this.length = 1; - return this; - - // HANDLE: $(function) - // Shortcut for document ready - } else if ( jQuery.isFunction( selector ) ) { - return typeof root.ready !== "undefined" ? - root.ready( selector ) : - - // Execute immediately if ready is not present - selector( jQuery ); - } - - if ( selector.selector !== undefined ) { - this.selector = selector.selector; - this.context = selector.context; - } - - return jQuery.makeArray( selector, this ); - }; - -// Give the init function the jQuery prototype for later instantiation -init.prototype = jQuery.fn; - -// Initialize central reference -rootjQuery = jQuery( document ); - - -var rparentsprev = /^(?:parents|prev(?:Until|All))/, - - // methods guaranteed to produce a unique set when starting from a unique set - guaranteedUnique = { - children: true, - contents: true, - next: true, - prev: true - }; - -jQuery.fn.extend( { - has: function( target ) { - var i, - targets = jQuery( target, this ), - len = targets.length; - - return this.filter( function() { - for ( i = 0; i < len; i++ ) { - if ( jQuery.contains( this, targets[ i ] ) ) { - return true; - } - } - } ); - }, - - closest: function( selectors, context ) { - var cur, - i = 0, - l = this.length, - matched = [], - pos = rneedsContext.test( selectors ) || typeof selectors !== "string" ? - jQuery( selectors, context || this.context ) : - 0; - - for ( ; i < l; i++ ) { - for ( cur = this[ i ]; cur && cur !== context; cur = cur.parentNode ) { - - // Always skip document fragments - if ( cur.nodeType < 11 && ( pos ? - pos.index( cur ) > -1 : - - // Don't pass non-elements to Sizzle - cur.nodeType === 1 && - jQuery.find.matchesSelector( cur, selectors ) ) ) { - - matched.push( cur ); - break; - } - } - } - - return this.pushStack( matched.length > 1 ? jQuery.uniqueSort( matched ) : matched ); - }, - - // Determine the position of an element within - // the matched set of elements - index: function( elem ) { - - // No argument, return index in parent - if ( !elem ) { - return ( this[ 0 ] && this[ 0 ].parentNode ) ? this.first().prevAll().length : -1; - } - - // index in selector - if ( typeof elem === "string" ) { - return jQuery.inArray( this[ 0 ], jQuery( elem ) ); - } - - // Locate the position of the desired element - return jQuery.inArray( - - // If it receives a jQuery object, the first element is used - elem.jquery ? elem[ 0 ] : elem, this ); - }, - - add: function( selector, context ) { - return this.pushStack( - jQuery.uniqueSort( - jQuery.merge( this.get(), jQuery( selector, context ) ) - ) - ); - }, - - addBack: function( selector ) { - return this.add( selector == null ? - this.prevObject : this.prevObject.filter( selector ) - ); - } -} ); - -function sibling( cur, dir ) { - do { - cur = cur[ dir ]; - } while ( cur && cur.nodeType !== 1 ); - - return cur; -} - -jQuery.each( { - parent: function( elem ) { - var parent = elem.parentNode; - return parent && parent.nodeType !== 11 ? parent : null; - }, - parents: function( elem ) { - return dir( elem, "parentNode" ); - }, - parentsUntil: function( elem, i, until ) { - return dir( elem, "parentNode", until ); - }, - next: function( elem ) { - return sibling( elem, "nextSibling" ); - }, - prev: function( elem ) { - return sibling( elem, "previousSibling" ); - }, - nextAll: function( elem ) { - return dir( elem, "nextSibling" ); - }, - prevAll: function( elem ) { - return dir( elem, "previousSibling" ); - }, - nextUntil: function( elem, i, until ) { - return dir( elem, "nextSibling", until ); - }, - prevUntil: function( elem, i, until ) { - return dir( elem, "previousSibling", until ); - }, - siblings: function( elem ) { - return siblings( ( elem.parentNode || {} ).firstChild, elem ); - }, - children: function( elem ) { - return siblings( elem.firstChild ); - }, - contents: function( elem ) { - return jQuery.nodeName( elem, "iframe" ) ? - elem.contentDocument || elem.contentWindow.document : - jQuery.merge( [], elem.childNodes ); - } -}, function( name, fn ) { - jQuery.fn[ name ] = function( until, selector ) { - var ret = jQuery.map( this, fn, until ); - - if ( name.slice( -5 ) !== "Until" ) { - selector = until; - } - - if ( selector && typeof selector === "string" ) { - ret = jQuery.filter( selector, ret ); - } - - if ( this.length > 1 ) { - - // Remove duplicates - if ( !guaranteedUnique[ name ] ) { - ret = jQuery.uniqueSort( ret ); - } - - // Reverse order for parents* and prev-derivatives - if ( rparentsprev.test( name ) ) { - ret = ret.reverse(); - } - } - - return this.pushStack( ret ); - }; -} ); -var rnotwhite = ( /\S+/g ); - - - -// Convert String-formatted options into Object-formatted ones -function createOptions( options ) { - var object = {}; - jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { - object[ flag ] = true; - } ); - return object; -} - -/* - * Create a callback list using the following parameters: - * - * options: an optional list of space-separated options that will change how - * the callback list behaves or a more traditional option object - * - * By default a callback list will act like an event callback list and can be - * "fired" multiple times. - * - * Possible options: - * - * once: will ensure the callback list can only be fired once (like a Deferred) - * - * memory: will keep track of previous values and will call any callback added - * after the list has been fired right away with the latest "memorized" - * values (like a Deferred) - * - * unique: will ensure a callback can only be added once (no duplicate in the list) - * - * stopOnFalse: interrupt callings when a callback returns false - * - */ -jQuery.Callbacks = function( options ) { - - // Convert options from String-formatted to Object-formatted if needed - // (we check in cache first) - options = typeof options === "string" ? - createOptions( options ) : - jQuery.extend( {}, options ); - - var // Flag to know if list is currently firing - firing, - - // Last fire value for non-forgettable lists - memory, - - // Flag to know if list was already fired - fired, - - // Flag to prevent firing - locked, - - // Actual callback list - list = [], - - // Queue of execution data for repeatable lists - queue = [], - - // Index of currently firing callback (modified by add/remove as needed) - firingIndex = -1, - - // Fire callbacks - fire = function() { - - // Enforce single-firing - locked = options.once; - - // Execute callbacks for all pending executions, - // respecting firingIndex overrides and runtime changes - fired = firing = true; - for ( ; queue.length; firingIndex = -1 ) { - memory = queue.shift(); - while ( ++firingIndex < list.length ) { - - // Run callback and check for early termination - if ( list[ firingIndex ].apply( memory[ 0 ], memory[ 1 ] ) === false && - options.stopOnFalse ) { - - // Jump to end and forget the data so .add doesn't re-fire - firingIndex = list.length; - memory = false; - } - } - } - - // Forget the data if we're done with it - if ( !options.memory ) { - memory = false; - } - - firing = false; - - // Clean up if we're done firing for good - if ( locked ) { - - // Keep an empty list if we have data for future add calls - if ( memory ) { - list = []; - - // Otherwise, this object is spent - } else { - list = ""; - } - } - }, - - // Actual Callbacks object - self = { - - // Add a callback or a collection of callbacks to the list - add: function() { - if ( list ) { - - // If we have memory from a past run, we should fire after adding - if ( memory && !firing ) { - firingIndex = list.length - 1; - queue.push( memory ); - } - - ( function add( args ) { - jQuery.each( args, function( _, arg ) { - if ( jQuery.isFunction( arg ) ) { - if ( !options.unique || !self.has( arg ) ) { - list.push( arg ); - } - } else if ( arg && arg.length && jQuery.type( arg ) !== "string" ) { - - // Inspect recursively - add( arg ); - } - } ); - } )( arguments ); - - if ( memory && !firing ) { - fire(); - } - } - return this; - }, - - // Remove a callback from the list - remove: function() { - jQuery.each( arguments, function( _, arg ) { - var index; - while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) { - list.splice( index, 1 ); - - // Handle firing indexes - if ( index <= firingIndex ) { - firingIndex--; - } - } - } ); - return this; - }, - - // Check if a given callback is in the list. - // If no argument is given, return whether or not list has callbacks attached. - has: function( fn ) { - return fn ? - jQuery.inArray( fn, list ) > -1 : - list.length > 0; - }, - - // Remove all callbacks from the list - empty: function() { - if ( list ) { - list = []; - } - return this; - }, - - // Disable .fire and .add - // Abort any current/pending executions - // Clear all callbacks and values - disable: function() { - locked = queue = []; - list = memory = ""; - return this; - }, - disabled: function() { - return !list; - }, - - // Disable .fire - // Also disable .add unless we have memory (since it would have no effect) - // Abort any pending executions - lock: function() { - locked = true; - if ( !memory ) { - self.disable(); - } - return this; - }, - locked: function() { - return !!locked; - }, - - // Call all callbacks with the given context and arguments - fireWith: function( context, args ) { - if ( !locked ) { - args = args || []; - args = [ context, args.slice ? args.slice() : args ]; - queue.push( args ); - if ( !firing ) { - fire(); - } - } - return this; - }, - - // Call all the callbacks with the given arguments - fire: function() { - self.fireWith( this, arguments ); - return this; - }, - - // To know if the callbacks have already been called at least once - fired: function() { - return !!fired; - } - }; - - return self; -}; - - -jQuery.extend( { - - Deferred: function( func ) { - var tuples = [ - - // action, add listener, listener list, final state - [ "resolve", "done", jQuery.Callbacks( "once memory" ), "resolved" ], - [ "reject", "fail", jQuery.Callbacks( "once memory" ), "rejected" ], - [ "notify", "progress", jQuery.Callbacks( "memory" ) ] - ], - state = "pending", - promise = { - state: function() { - return state; - }, - always: function() { - deferred.done( arguments ).fail( arguments ); - return this; - }, - then: function( /* fnDone, fnFail, fnProgress */ ) { - var fns = arguments; - return jQuery.Deferred( function( newDefer ) { - jQuery.each( tuples, function( i, tuple ) { - var fn = jQuery.isFunction( fns[ i ] ) && fns[ i ]; - - // deferred[ done | fail | progress ] for forwarding actions to newDefer - deferred[ tuple[ 1 ] ]( function() { - var returned = fn && fn.apply( this, arguments ); - if ( returned && jQuery.isFunction( returned.promise ) ) { - returned.promise() - .progress( newDefer.notify ) - .done( newDefer.resolve ) - .fail( newDefer.reject ); - } else { - newDefer[ tuple[ 0 ] + "With" ]( - this === promise ? newDefer.promise() : this, - fn ? [ returned ] : arguments - ); - } - } ); - } ); - fns = null; - } ).promise(); - }, - - // Get a promise for this deferred - // If obj is provided, the promise aspect is added to the object - promise: function( obj ) { - return obj != null ? jQuery.extend( obj, promise ) : promise; - } - }, - deferred = {}; - - // Keep pipe for back-compat - promise.pipe = promise.then; - - // Add list-specific methods - jQuery.each( tuples, function( i, tuple ) { - var list = tuple[ 2 ], - stateString = tuple[ 3 ]; - - // promise[ done | fail | progress ] = list.add - promise[ tuple[ 1 ] ] = list.add; - - // Handle state - if ( stateString ) { - list.add( function() { - - // state = [ resolved | rejected ] - state = stateString; - - // [ reject_list | resolve_list ].disable; progress_list.lock - }, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock ); - } - - // deferred[ resolve | reject | notify ] - deferred[ tuple[ 0 ] ] = function() { - deferred[ tuple[ 0 ] + "With" ]( this === deferred ? promise : this, arguments ); - return this; - }; - deferred[ tuple[ 0 ] + "With" ] = list.fireWith; - } ); - - // Make the deferred a promise - promise.promise( deferred ); - - // Call given func if any - if ( func ) { - func.call( deferred, deferred ); - } - - // All done! - return deferred; - }, - - // Deferred helper - when: function( subordinate /* , ..., subordinateN */ ) { - var i = 0, - resolveValues = slice.call( arguments ), - length = resolveValues.length, - - // the count of uncompleted subordinates - remaining = length !== 1 || - ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0, - - // the master Deferred. - // If resolveValues consist of only a single Deferred, just use that. - deferred = remaining === 1 ? subordinate : jQuery.Deferred(), - - // Update function for both resolve and progress values - updateFunc = function( i, contexts, values ) { - return function( value ) { - contexts[ i ] = this; - values[ i ] = arguments.length > 1 ? slice.call( arguments ) : value; - if ( values === progressValues ) { - deferred.notifyWith( contexts, values ); - - } else if ( !( --remaining ) ) { - deferred.resolveWith( contexts, values ); - } - }; - }, - - progressValues, progressContexts, resolveContexts; - - // add listeners to Deferred subordinates; treat others as resolved - if ( length > 1 ) { - progressValues = new Array( length ); - progressContexts = new Array( length ); - resolveContexts = new Array( length ); - for ( ; i < length; i++ ) { - if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) { - resolveValues[ i ].promise() - .progress( updateFunc( i, progressContexts, progressValues ) ) - .done( updateFunc( i, resolveContexts, resolveValues ) ) - .fail( deferred.reject ); - } else { - --remaining; - } - } - } - - // if we're not waiting on anything, resolve the master - if ( !remaining ) { - deferred.resolveWith( resolveContexts, resolveValues ); - } - - return deferred.promise(); - } -} ); - - -// The deferred used on DOM ready -var readyList; - -jQuery.fn.ready = function( fn ) { - - // Add the callback - jQuery.ready.promise().done( fn ); - - return this; -}; - -jQuery.extend( { - - // Is the DOM ready to be used? Set to true once it occurs. - isReady: false, - - // A counter to track how many items to wait for before - // the ready event fires. See #6781 - readyWait: 1, - - // Hold (or release) the ready event - holdReady: function( hold ) { - if ( hold ) { - jQuery.readyWait++; - } else { - jQuery.ready( true ); - } - }, - - // Handle when the DOM is ready - ready: function( wait ) { - - // Abort if there are pending holds or we're already ready - if ( wait === true ? --jQuery.readyWait : jQuery.isReady ) { - return; - } - - // Remember that the DOM is ready - jQuery.isReady = true; - - // If a normal DOM Ready event fired, decrement, and wait if need be - if ( wait !== true && --jQuery.readyWait > 0 ) { - return; - } - - // If there are functions bound, to execute - readyList.resolveWith( document, [ jQuery ] ); - - // Trigger any bound ready events - if ( jQuery.fn.triggerHandler ) { - jQuery( document ).triggerHandler( "ready" ); - jQuery( document ).off( "ready" ); - } - } -} ); - -/** - * Clean-up method for dom ready events - */ -function detach() { - if ( document.addEventListener ) { - document.removeEventListener( "DOMContentLoaded", completed ); - window.removeEventListener( "load", completed ); - - } else { - document.detachEvent( "onreadystatechange", completed ); - window.detachEvent( "onload", completed ); - } -} - -/** - * The ready event handler and self cleanup method - */ -function completed() { - - // readyState === "complete" is good enough for us to call the dom ready in oldIE - if ( document.addEventListener || - window.event.type === "load" || - document.readyState === "complete" ) { - - detach(); - jQuery.ready(); - } -} - -jQuery.ready.promise = function( obj ) { - if ( !readyList ) { - - readyList = jQuery.Deferred(); - - // Catch cases where $(document).ready() is called - // after the browser event has already occurred. - // Support: IE6-10 - // Older IE sometimes signals "interactive" too soon - if ( document.readyState === "complete" || - ( document.readyState !== "loading" && !document.documentElement.doScroll ) ) { - - // Handle it asynchronously to allow scripts the opportunity to delay ready - window.setTimeout( jQuery.ready ); - - // Standards-based browsers support DOMContentLoaded - } else if ( document.addEventListener ) { - - // Use the handy event callback - document.addEventListener( "DOMContentLoaded", completed ); - - // A fallback to window.onload, that will always work - window.addEventListener( "load", completed ); - - // If IE event model is used - } else { - - // Ensure firing before onload, maybe late but safe also for iframes - document.attachEvent( "onreadystatechange", completed ); - - // A fallback to window.onload, that will always work - window.attachEvent( "onload", completed ); - - // If IE and not a frame - // continually check to see if the document is ready - var top = false; - - try { - top = window.frameElement == null && document.documentElement; - } catch ( e ) {} - - if ( top && top.doScroll ) { - ( function doScrollCheck() { - if ( !jQuery.isReady ) { - - try { - - // Use the trick by Diego Perini - // http://javascript.nwbox.com/IEContentLoaded/ - top.doScroll( "left" ); - } catch ( e ) { - return window.setTimeout( doScrollCheck, 50 ); - } - - // detach all dom ready events - detach(); - - // and execute any waiting functions - jQuery.ready(); - } - } )(); - } - } - } - return readyList.promise( obj ); -}; - -// Kick off the DOM ready check even if the user does not -jQuery.ready.promise(); - - - - -// Support: IE<9 -// Iteration over object's inherited properties before its own -var i; -for ( i in jQuery( support ) ) { - break; -} -support.ownFirst = i === "0"; - -// Note: most support tests are defined in their respective modules. -// false until the test is run -support.inlineBlockNeedsLayout = false; - -// Execute ASAP in case we need to set body.style.zoom -jQuery( function() { - - // Minified: var a,b,c,d - var val, div, body, container; - - body = document.getElementsByTagName( "body" )[ 0 ]; - if ( !body || !body.style ) { - - // Return for frameset docs that don't have a body - return; - } - - // Setup - div = document.createElement( "div" ); - container = document.createElement( "div" ); - container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; - body.appendChild( container ).appendChild( div ); - - if ( typeof div.style.zoom !== "undefined" ) { - - // Support: IE<8 - // Check if natively block-level elements act like inline-block - // elements when setting their display to 'inline' and giving - // them layout - div.style.cssText = "display:inline;margin:0;border:0;padding:1px;width:1px;zoom:1"; - - support.inlineBlockNeedsLayout = val = div.offsetWidth === 3; - if ( val ) { - - // Prevent IE 6 from affecting layout for positioned elements #11048 - // Prevent IE from shrinking the body in IE 7 mode #12869 - // Support: IE<8 - body.style.zoom = 1; - } - } - - body.removeChild( container ); -} ); - - -( function() { - var div = document.createElement( "div" ); - - // Support: IE<9 - support.deleteExpando = true; - try { - delete div.test; - } catch ( e ) { - support.deleteExpando = false; - } - - // Null elements to avoid leaks in IE. - div = null; -} )(); -var acceptData = function( elem ) { - var noData = jQuery.noData[ ( elem.nodeName + " " ).toLowerCase() ], - nodeType = +elem.nodeType || 1; - - // Do not set data on non-element DOM nodes because it will not be cleared (#8335). - return nodeType !== 1 && nodeType !== 9 ? - false : - - // Nodes accept data unless otherwise specified; rejection can be conditional - !noData || noData !== true && elem.getAttribute( "classid" ) === noData; -}; - - - - -var rbrace = /^(?:\{[\w\W]*\}|\[[\w\W]*\])$/, - rmultiDash = /([A-Z])/g; - -function dataAttr( elem, key, data ) { - - // If nothing was found internally, try to fetch any - // data from the HTML5 data-* attribute - if ( data === undefined && elem.nodeType === 1 ) { - - var name = "data-" + key.replace( rmultiDash, "-$1" ).toLowerCase(); - - data = elem.getAttribute( name ); - - if ( typeof data === "string" ) { - try { - data = data === "true" ? true : - data === "false" ? false : - data === "null" ? null : - - // Only convert to a number if it doesn't change the string - +data + "" === data ? +data : - rbrace.test( data ) ? jQuery.parseJSON( data ) : - data; - } catch ( e ) {} - - // Make sure we set the data so it isn't changed later - jQuery.data( elem, key, data ); - - } else { - data = undefined; - } - } - - return data; -} - -// checks a cache object for emptiness -function isEmptyDataObject( obj ) { - var name; - for ( name in obj ) { - - // if the public data object is empty, the private is still empty - if ( name === "data" && jQuery.isEmptyObject( obj[ name ] ) ) { - continue; - } - if ( name !== "toJSON" ) { - return false; - } - } - - return true; -} - -function internalData( elem, name, data, pvt /* Internal Use Only */ ) { - if ( !acceptData( elem ) ) { - return; - } - - var ret, thisCache, - internalKey = jQuery.expando, - - // We have to handle DOM nodes and JS objects differently because IE6-7 - // can't GC object references properly across the DOM-JS boundary - isNode = elem.nodeType, - - // Only DOM nodes need the global jQuery cache; JS object data is - // attached directly to the object so GC can occur automatically - cache = isNode ? jQuery.cache : elem, - - // Only defining an ID for JS objects if its cache already exists allows - // the code to shortcut on the same path as a DOM node with no cache - id = isNode ? elem[ internalKey ] : elem[ internalKey ] && internalKey; - - // Avoid doing any more work than we need to when trying to get data on an - // object that has no data at all - if ( ( !id || !cache[ id ] || ( !pvt && !cache[ id ].data ) ) && - data === undefined && typeof name === "string" ) { - return; - } - - if ( !id ) { - - // Only DOM nodes need a new unique ID for each element since their data - // ends up in the global cache - if ( isNode ) { - id = elem[ internalKey ] = deletedIds.pop() || jQuery.guid++; - } else { - id = internalKey; - } - } - - if ( !cache[ id ] ) { - - // Avoid exposing jQuery metadata on plain JS objects when the object - // is serialized using JSON.stringify - cache[ id ] = isNode ? {} : { toJSON: jQuery.noop }; - } - - // An object can be passed to jQuery.data instead of a key/value pair; this gets - // shallow copied over onto the existing cache - if ( typeof name === "object" || typeof name === "function" ) { - if ( pvt ) { - cache[ id ] = jQuery.extend( cache[ id ], name ); - } else { - cache[ id ].data = jQuery.extend( cache[ id ].data, name ); - } - } - - thisCache = cache[ id ]; - - // jQuery data() is stored in a separate object inside the object's internal data - // cache in order to avoid key collisions between internal data and user-defined - // data. - if ( !pvt ) { - if ( !thisCache.data ) { - thisCache.data = {}; - } - - thisCache = thisCache.data; - } - - if ( data !== undefined ) { - thisCache[ jQuery.camelCase( name ) ] = data; - } - - // Check for both converted-to-camel and non-converted data property names - // If a data property was specified - if ( typeof name === "string" ) { - - // First Try to find as-is property data - ret = thisCache[ name ]; - - // Test for null|undefined property data - if ( ret == null ) { - - // Try to find the camelCased property - ret = thisCache[ jQuery.camelCase( name ) ]; - } - } else { - ret = thisCache; - } - - return ret; -} - -function internalRemoveData( elem, name, pvt ) { - if ( !acceptData( elem ) ) { - return; - } - - var thisCache, i, - isNode = elem.nodeType, - - // See jQuery.data for more information - cache = isNode ? jQuery.cache : elem, - id = isNode ? elem[ jQuery.expando ] : jQuery.expando; - - // If there is already no cache entry for this object, there is no - // purpose in continuing - if ( !cache[ id ] ) { - return; - } - - if ( name ) { - - thisCache = pvt ? cache[ id ] : cache[ id ].data; - - if ( thisCache ) { - - // Support array or space separated string names for data keys - if ( !jQuery.isArray( name ) ) { - - // try the string as a key before any manipulation - if ( name in thisCache ) { - name = [ name ]; - } else { - - // split the camel cased version by spaces unless a key with the spaces exists - name = jQuery.camelCase( name ); - if ( name in thisCache ) { - name = [ name ]; - } else { - name = name.split( " " ); - } - } - } else { - - // If "name" is an array of keys... - // When data is initially created, via ("key", "val") signature, - // keys will be converted to camelCase. - // Since there is no way to tell _how_ a key was added, remove - // both plain key and camelCase key. #12786 - // This will only penalize the array argument path. - name = name.concat( jQuery.map( name, jQuery.camelCase ) ); - } - - i = name.length; - while ( i-- ) { - delete thisCache[ name[ i ] ]; - } - - // If there is no data left in the cache, we want to continue - // and let the cache object itself get destroyed - if ( pvt ? !isEmptyDataObject( thisCache ) : !jQuery.isEmptyObject( thisCache ) ) { - return; - } - } - } - - // See jQuery.data for more information - if ( !pvt ) { - delete cache[ id ].data; - - // Don't destroy the parent cache unless the internal data object - // had been the only thing left in it - if ( !isEmptyDataObject( cache[ id ] ) ) { - return; - } - } - - // Destroy the cache - if ( isNode ) { - jQuery.cleanData( [ elem ], true ); - - // Use delete when supported for expandos or `cache` is not a window per isWindow (#10080) - /* jshint eqeqeq: false */ - } else if ( support.deleteExpando || cache != cache.window ) { - /* jshint eqeqeq: true */ - delete cache[ id ]; - - // When all else fails, undefined - } else { - cache[ id ] = undefined; - } -} - -jQuery.extend( { - cache: {}, - - // The following elements (space-suffixed to avoid Object.prototype collisions) - // throw uncatchable exceptions if you attempt to set expando properties - noData: { - "applet ": true, - "embed ": true, - - // ...but Flash objects (which have this classid) *can* handle expandos - "object ": "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" - }, - - hasData: function( elem ) { - elem = elem.nodeType ? jQuery.cache[ elem[ jQuery.expando ] ] : elem[ jQuery.expando ]; - return !!elem && !isEmptyDataObject( elem ); - }, - - data: function( elem, name, data ) { - return internalData( elem, name, data ); - }, - - removeData: function( elem, name ) { - return internalRemoveData( elem, name ); - }, - - // For internal use only. - _data: function( elem, name, data ) { - return internalData( elem, name, data, true ); - }, - - _removeData: function( elem, name ) { - return internalRemoveData( elem, name, true ); - } -} ); - -jQuery.fn.extend( { - data: function( key, value ) { - var i, name, data, - elem = this[ 0 ], - attrs = elem && elem.attributes; - - // Special expections of .data basically thwart jQuery.access, - // so implement the relevant behavior ourselves - - // Gets all values - if ( key === undefined ) { - if ( this.length ) { - data = jQuery.data( elem ); - - if ( elem.nodeType === 1 && !jQuery._data( elem, "parsedAttrs" ) ) { - i = attrs.length; - while ( i-- ) { - - // Support: IE11+ - // The attrs elements can be null (#14894) - if ( attrs[ i ] ) { - name = attrs[ i ].name; - if ( name.indexOf( "data-" ) === 0 ) { - name = jQuery.camelCase( name.slice( 5 ) ); - dataAttr( elem, name, data[ name ] ); - } - } - } - jQuery._data( elem, "parsedAttrs", true ); - } - } - - return data; - } - - // Sets multiple values - if ( typeof key === "object" ) { - return this.each( function() { - jQuery.data( this, key ); - } ); - } - - return arguments.length > 1 ? - - // Sets one value - this.each( function() { - jQuery.data( this, key, value ); - } ) : - - // Gets one value - // Try to fetch any internally stored data first - elem ? dataAttr( elem, key, jQuery.data( elem, key ) ) : undefined; - }, - - removeData: function( key ) { - return this.each( function() { - jQuery.removeData( this, key ); - } ); - } -} ); - - -jQuery.extend( { - queue: function( elem, type, data ) { - var queue; - - if ( elem ) { - type = ( type || "fx" ) + "queue"; - queue = jQuery._data( elem, type ); - - // Speed up dequeue by getting out quickly if this is just a lookup - if ( data ) { - if ( !queue || jQuery.isArray( data ) ) { - queue = jQuery._data( elem, type, jQuery.makeArray( data ) ); - } else { - queue.push( data ); - } - } - return queue || []; - } - }, - - dequeue: function( elem, type ) { - type = type || "fx"; - - var queue = jQuery.queue( elem, type ), - startLength = queue.length, - fn = queue.shift(), - hooks = jQuery._queueHooks( elem, type ), - next = function() { - jQuery.dequeue( elem, type ); - }; - - // If the fx queue is dequeued, always remove the progress sentinel - if ( fn === "inprogress" ) { - fn = queue.shift(); - startLength--; - } - - if ( fn ) { - - // Add a progress sentinel to prevent the fx queue from being - // automatically dequeued - if ( type === "fx" ) { - queue.unshift( "inprogress" ); - } - - // clear up the last queue stop function - delete hooks.stop; - fn.call( elem, next, hooks ); - } - - if ( !startLength && hooks ) { - hooks.empty.fire(); - } - }, - - // not intended for public consumption - generates a queueHooks object, - // or returns the current one - _queueHooks: function( elem, type ) { - var key = type + "queueHooks"; - return jQuery._data( elem, key ) || jQuery._data( elem, key, { - empty: jQuery.Callbacks( "once memory" ).add( function() { - jQuery._removeData( elem, type + "queue" ); - jQuery._removeData( elem, key ); - } ) - } ); - } -} ); - -jQuery.fn.extend( { - queue: function( type, data ) { - var setter = 2; - - if ( typeof type !== "string" ) { - data = type; - type = "fx"; - setter--; - } - - if ( arguments.length < setter ) { - return jQuery.queue( this[ 0 ], type ); - } - - return data === undefined ? - this : - this.each( function() { - var queue = jQuery.queue( this, type, data ); - - // ensure a hooks for this queue - jQuery._queueHooks( this, type ); - - if ( type === "fx" && queue[ 0 ] !== "inprogress" ) { - jQuery.dequeue( this, type ); - } - } ); - }, - dequeue: function( type ) { - return this.each( function() { - jQuery.dequeue( this, type ); - } ); - }, - clearQueue: function( type ) { - return this.queue( type || "fx", [] ); - }, - - // Get a promise resolved when queues of a certain type - // are emptied (fx is the type by default) - promise: function( type, obj ) { - var tmp, - count = 1, - defer = jQuery.Deferred(), - elements = this, - i = this.length, - resolve = function() { - if ( !( --count ) ) { - defer.resolveWith( elements, [ elements ] ); - } - }; - - if ( typeof type !== "string" ) { - obj = type; - type = undefined; - } - type = type || "fx"; - - while ( i-- ) { - tmp = jQuery._data( elements[ i ], type + "queueHooks" ); - if ( tmp && tmp.empty ) { - count++; - tmp.empty.add( resolve ); - } - } - resolve(); - return defer.promise( obj ); - } -} ); - - -( function() { - var shrinkWrapBlocksVal; - - support.shrinkWrapBlocks = function() { - if ( shrinkWrapBlocksVal != null ) { - return shrinkWrapBlocksVal; - } - - // Will be changed later if needed. - shrinkWrapBlocksVal = false; - - // Minified: var b,c,d - var div, body, container; - - body = document.getElementsByTagName( "body" )[ 0 ]; - if ( !body || !body.style ) { - - // Test fired too early or in an unsupported environment, exit. - return; - } - - // Setup - div = document.createElement( "div" ); - container = document.createElement( "div" ); - container.style.cssText = "position:absolute;border:0;width:0;height:0;top:0;left:-9999px"; - body.appendChild( container ).appendChild( div ); - - // Support: IE6 - // Check if elements with layout shrink-wrap their children - if ( typeof div.style.zoom !== "undefined" ) { - - // Reset CSS: box-sizing; display; margin; border - div.style.cssText = - - // Support: Firefox<29, Android 2.3 - // Vendor-prefix box-sizing - "-webkit-box-sizing:content-box;-moz-box-sizing:content-box;" + - "box-sizing:content-box;display:block;margin:0;border:0;" + - "padding:1px;width:1px;zoom:1"; - div.appendChild( document.createElement( "div" ) ).style.width = "5px"; - shrinkWrapBlocksVal = div.offsetWidth !== 3; - } - - body.removeChild( container ); - - return shrinkWrapBlocksVal; - }; - -} )(); -var pnum = ( /[+-]?(?:\d*\.|)\d+(?:[eE][+-]?\d+|)/ ).source; - -var rcssNum = new RegExp( "^(?:([+-])=|)(" + pnum + ")([a-z%]*)$", "i" ); - - -var cssExpand = [ "Top", "Right", "Bottom", "Left" ]; - -var isHidden = function( elem, el ) { - - // isHidden might be called from jQuery#filter function; - // in that case, element will be second argument - elem = el || elem; - return jQuery.css( elem, "display" ) === "none" || - !jQuery.contains( elem.ownerDocument, elem ); - }; - - - -function adjustCSS( elem, prop, valueParts, tween ) { - var adjusted, - scale = 1, - maxIterations = 20, - currentValue = tween ? - function() { return tween.cur(); } : - function() { return jQuery.css( elem, prop, "" ); }, - initial = currentValue(), - unit = valueParts && valueParts[ 3 ] || ( jQuery.cssNumber[ prop ] ? "" : "px" ), - - // Starting value computation is required for potential unit mismatches - initialInUnit = ( jQuery.cssNumber[ prop ] || unit !== "px" && +initial ) && - rcssNum.exec( jQuery.css( elem, prop ) ); - - if ( initialInUnit && initialInUnit[ 3 ] !== unit ) { - - // Trust units reported by jQuery.css - unit = unit || initialInUnit[ 3 ]; - - // Make sure we update the tween properties later on - valueParts = valueParts || []; - - // Iteratively approximate from a nonzero starting point - initialInUnit = +initial || 1; - - do { - - // If previous iteration zeroed out, double until we get *something*. - // Use string for doubling so we don't accidentally see scale as unchanged below - scale = scale || ".5"; - - // Adjust and apply - initialInUnit = initialInUnit / scale; - jQuery.style( elem, prop, initialInUnit + unit ); - - // Update scale, tolerating zero or NaN from tween.cur() - // Break the loop if scale is unchanged or perfect, or if we've just had enough. - } while ( - scale !== ( scale = currentValue() / initial ) && scale !== 1 && --maxIterations - ); - } - - if ( valueParts ) { - initialInUnit = +initialInUnit || +initial || 0; - - // Apply relative offset (+=/-=) if specified - adjusted = valueParts[ 1 ] ? - initialInUnit + ( valueParts[ 1 ] + 1 ) * valueParts[ 2 ] : - +valueParts[ 2 ]; - if ( tween ) { - tween.unit = unit; - tween.start = initialInUnit; - tween.end = adjusted; - } - } - return adjusted; -} - - -// Multifunctional method to get and set values of a collection -// The value/s can optionally be executed if it's a function -var access = function( elems, fn, key, value, chainable, emptyGet, raw ) { - var i = 0, - length = elems.length, - bulk = key == null; - - // Sets many values - if ( jQuery.type( key ) === "object" ) { - chainable = true; - for ( i in key ) { - access( elems, fn, i, key[ i ], true, emptyGet, raw ); - } - - // Sets one value - } else if ( value !== undefined ) { - chainable = true; - - if ( !jQuery.isFunction( value ) ) { - raw = true; - } - - if ( bulk ) { - - // Bulk operations run against the entire set - if ( raw ) { - fn.call( elems, value ); - fn = null; - - // ...except when executing function values - } else { - bulk = fn; - fn = function( elem, key, value ) { - return bulk.call( jQuery( elem ), value ); - }; - } - } - - if ( fn ) { - for ( ; i < length; i++ ) { - fn( - elems[ i ], - key, - raw ? value : value.call( elems[ i ], i, fn( elems[ i ], key ) ) - ); - } - } - } - - return chainable ? - elems : - - // Gets - bulk ? - fn.call( elems ) : - length ? fn( elems[ 0 ], key ) : emptyGet; -}; -var rcheckableType = ( /^(?:checkbox|radio)$/i ); - -var rtagName = ( /<([\w:-]+)/ ); - -var rscriptType = ( /^$|\/(?:java|ecma)script/i ); - -var rleadingWhitespace = ( /^\s+/ ); - -var nodeNames = "abbr|article|aside|audio|bdi|canvas|data|datalist|" + - "details|dialog|figcaption|figure|footer|header|hgroup|main|" + - "mark|meter|nav|output|picture|progress|section|summary|template|time|video"; - - - -function createSafeFragment( document ) { - var list = nodeNames.split( "|" ), - safeFrag = document.createDocumentFragment(); - - if ( safeFrag.createElement ) { - while ( list.length ) { - safeFrag.createElement( - list.pop() - ); - } - } - return safeFrag; -} - - -( function() { - var div = document.createElement( "div" ), - fragment = document.createDocumentFragment(), - input = document.createElement( "input" ); - - // Setup - div.innerHTML = "
                                    a"; - - // IE strips leading whitespace when .innerHTML is used - support.leadingWhitespace = div.firstChild.nodeType === 3; - - // Make sure that tbody elements aren't automatically inserted - // IE will insert them into empty tables - support.tbody = !div.getElementsByTagName( "tbody" ).length; - - // Make sure that link elements get serialized correctly by innerHTML - // This requires a wrapper element in IE - support.htmlSerialize = !!div.getElementsByTagName( "link" ).length; - - // Makes sure cloning an html5 element does not cause problems - // Where outerHTML is undefined, this still works - support.html5Clone = - document.createElement( "nav" ).cloneNode( true ).outerHTML !== "<:nav>"; - - // Check if a disconnected checkbox will retain its checked - // value of true after appended to the DOM (IE6/7) - input.type = "checkbox"; - input.checked = true; - fragment.appendChild( input ); - support.appendChecked = input.checked; - - // Make sure textarea (and checkbox) defaultValue is properly cloned - // Support: IE6-IE11+ - div.innerHTML = ""; - support.noCloneChecked = !!div.cloneNode( true ).lastChild.defaultValue; - - // #11217 - WebKit loses check when the name is after the checked attribute - fragment.appendChild( div ); - - // Support: Windows Web Apps (WWA) - // `name` and `type` must use .setAttribute for WWA (#14901) - input = document.createElement( "input" ); - input.setAttribute( "type", "radio" ); - input.setAttribute( "checked", "checked" ); - input.setAttribute( "name", "t" ); - - div.appendChild( input ); - - // Support: Safari 5.1, iOS 5.1, Android 4.x, Android 2.3 - // old WebKit doesn't clone checked state correctly in fragments - support.checkClone = div.cloneNode( true ).cloneNode( true ).lastChild.checked; - - // Support: IE<9 - // Cloned elements keep attachEvent handlers, we use addEventListener on IE9+ - support.noCloneEvent = !!div.addEventListener; - - // Support: IE<9 - // Since attributes and properties are the same in IE, - // cleanData must set properties to undefined rather than use removeAttribute - div[ jQuery.expando ] = 1; - support.attributes = !div.getAttribute( jQuery.expando ); -} )(); - - -// We have to close these tags to support XHTML (#13200) -var wrapMap = { - option: [ 1, "" ], - legend: [ 1, "
                                    ", "
                                    " ], - area: [ 1, "", "" ], - - // Support: IE8 - param: [ 1, "", "" ], - thead: [ 1, "", "
                                    " ], - tr: [ 2, "", "
                                    " ], - col: [ 2, "", "
                                    " ], - td: [ 3, "", "
                                    " ], - - // IE6-8 can't serialize link, script, style, or any html5 (NoScope) tags, - // unless wrapped in a div with non-breaking characters in front of it. - _default: support.htmlSerialize ? [ 0, "", "" ] : [ 1, "X
                                    ", "
                                    " ] -}; - -// Support: IE8-IE9 -wrapMap.optgroup = wrapMap.option; - -wrapMap.tbody = wrapMap.tfoot = wrapMap.colgroup = wrapMap.caption = wrapMap.thead; -wrapMap.th = wrapMap.td; - - -function getAll( context, tag ) { - var elems, elem, - i = 0, - found = typeof context.getElementsByTagName !== "undefined" ? - context.getElementsByTagName( tag || "*" ) : - typeof context.querySelectorAll !== "undefined" ? - context.querySelectorAll( tag || "*" ) : - undefined; - - if ( !found ) { - for ( found = [], elems = context.childNodes || context; - ( elem = elems[ i ] ) != null; - i++ - ) { - if ( !tag || jQuery.nodeName( elem, tag ) ) { - found.push( elem ); - } else { - jQuery.merge( found, getAll( elem, tag ) ); - } - } - } - - return tag === undefined || tag && jQuery.nodeName( context, tag ) ? - jQuery.merge( [ context ], found ) : - found; -} - - -// Mark scripts as having already been evaluated -function setGlobalEval( elems, refElements ) { - var elem, - i = 0; - for ( ; ( elem = elems[ i ] ) != null; i++ ) { - jQuery._data( - elem, - "globalEval", - !refElements || jQuery._data( refElements[ i ], "globalEval" ) - ); - } -} - - -var rhtml = /<|&#?\w+;/, - rtbody = / from table fragments - if ( !support.tbody ) { - - // String was a , *may* have spurious - elem = tag === "table" && !rtbody.test( elem ) ? - tmp.firstChild : - - // String was a bare or - wrap[ 1 ] === "
                                    " && !rtbody.test( elem ) ? - tmp : - 0; - - j = elem && elem.childNodes.length; - while ( j-- ) { - if ( jQuery.nodeName( ( tbody = elem.childNodes[ j ] ), "tbody" ) && - !tbody.childNodes.length ) { - - elem.removeChild( tbody ); - } - } - } - - jQuery.merge( nodes, tmp.childNodes ); - - // Fix #12392 for WebKit and IE > 9 - tmp.textContent = ""; - - // Fix #12392 for oldIE - while ( tmp.firstChild ) { - tmp.removeChild( tmp.firstChild ); - } - - // Remember the top-level container for proper cleanup - tmp = safe.lastChild; - } - } - } - - // Fix #11356: Clear elements from fragment - if ( tmp ) { - safe.removeChild( tmp ); - } - - // Reset defaultChecked for any radios and checkboxes - // about to be appended to the DOM in IE 6/7 (#8060) - if ( !support.appendChecked ) { - jQuery.grep( getAll( nodes, "input" ), fixDefaultChecked ); - } - - i = 0; - while ( ( elem = nodes[ i++ ] ) ) { - - // Skip elements already in the context collection (trac-4087) - if ( selection && jQuery.inArray( elem, selection ) > -1 ) { - if ( ignored ) { - ignored.push( elem ); - } - - continue; - } - - contains = jQuery.contains( elem.ownerDocument, elem ); - - // Append to fragment - tmp = getAll( safe.appendChild( elem ), "script" ); - - // Preserve script evaluation history - if ( contains ) { - setGlobalEval( tmp ); - } - - // Capture executables - if ( scripts ) { - j = 0; - while ( ( elem = tmp[ j++ ] ) ) { - if ( rscriptType.test( elem.type || "" ) ) { - scripts.push( elem ); - } - } - } - } - - tmp = null; - - return safe; -} - - -( function() { - var i, eventName, - div = document.createElement( "div" ); - - // Support: IE<9 (lack submit/change bubble), Firefox (lack focus(in | out) events) - for ( i in { submit: true, change: true, focusin: true } ) { - eventName = "on" + i; - - if ( !( support[ i ] = eventName in window ) ) { - - // Beware of CSP restrictions (https://developer.mozilla.org/en/Security/CSP) - div.setAttribute( eventName, "t" ); - support[ i ] = div.attributes[ eventName ].expando === false; - } - } - - // Null elements to avoid leaks in IE. - div = null; -} )(); - - -var rformElems = /^(?:input|select|textarea)$/i, - rkeyEvent = /^key/, - rmouseEvent = /^(?:mouse|pointer|contextmenu|drag|drop)|click/, - rfocusMorph = /^(?:focusinfocus|focusoutblur)$/, - rtypenamespace = /^([^.]*)(?:\.(.+)|)/; - -function returnTrue() { - return true; -} - -function returnFalse() { - return false; -} - -// Support: IE9 -// See #13393 for more info -function safeActiveElement() { - try { - return document.activeElement; - } catch ( err ) { } -} - -function on( elem, types, selector, data, fn, one ) { - var origFn, type; - - // Types can be a map of types/handlers - if ( typeof types === "object" ) { - - // ( types-Object, selector, data ) - if ( typeof selector !== "string" ) { - - // ( types-Object, data ) - data = data || selector; - selector = undefined; - } - for ( type in types ) { - on( elem, type, selector, data, types[ type ], one ); - } - return elem; - } - - if ( data == null && fn == null ) { - - // ( types, fn ) - fn = selector; - data = selector = undefined; - } else if ( fn == null ) { - if ( typeof selector === "string" ) { - - // ( types, selector, fn ) - fn = data; - data = undefined; - } else { - - // ( types, data, fn ) - fn = data; - data = selector; - selector = undefined; - } - } - if ( fn === false ) { - fn = returnFalse; - } else if ( !fn ) { - return elem; - } - - if ( one === 1 ) { - origFn = fn; - fn = function( event ) { - - // Can use an empty set, since event contains the info - jQuery().off( event ); - return origFn.apply( this, arguments ); - }; - - // Use same guid so caller can remove using origFn - fn.guid = origFn.guid || ( origFn.guid = jQuery.guid++ ); - } - return elem.each( function() { - jQuery.event.add( this, types, fn, data, selector ); - } ); -} - -/* - * Helper functions for managing events -- not part of the public interface. - * Props to Dean Edwards' addEvent library for many of the ideas. - */ -jQuery.event = { - - global: {}, - - add: function( elem, types, handler, data, selector ) { - var tmp, events, t, handleObjIn, - special, eventHandle, handleObj, - handlers, type, namespaces, origType, - elemData = jQuery._data( elem ); - - // Don't attach events to noData or text/comment nodes (but allow plain objects) - if ( !elemData ) { - return; - } - - // Caller can pass in an object of custom data in lieu of the handler - if ( handler.handler ) { - handleObjIn = handler; - handler = handleObjIn.handler; - selector = handleObjIn.selector; - } - - // Make sure that the handler has a unique ID, used to find/remove it later - if ( !handler.guid ) { - handler.guid = jQuery.guid++; - } - - // Init the element's event structure and main handler, if this is the first - if ( !( events = elemData.events ) ) { - events = elemData.events = {}; - } - if ( !( eventHandle = elemData.handle ) ) { - eventHandle = elemData.handle = function( e ) { - - // Discard the second event of a jQuery.event.trigger() and - // when an event is called after a page has unloaded - return typeof jQuery !== "undefined" && - ( !e || jQuery.event.triggered !== e.type ) ? - jQuery.event.dispatch.apply( eventHandle.elem, arguments ) : - undefined; - }; - - // Add elem as a property of the handle fn to prevent a memory leak - // with IE non-native events - eventHandle.elem = elem; - } - - // Handle multiple events separated by a space - types = ( types || "" ).match( rnotwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // There *must* be a type, no attaching namespace-only handlers - if ( !type ) { - continue; - } - - // If event changes its type, use the special event handlers for the changed type - special = jQuery.event.special[ type ] || {}; - - // If selector defined, determine special event api type, otherwise given type - type = ( selector ? special.delegateType : special.bindType ) || type; - - // Update special based on newly reset type - special = jQuery.event.special[ type ] || {}; - - // handleObj is passed to all event handlers - handleObj = jQuery.extend( { - type: type, - origType: origType, - data: data, - handler: handler, - guid: handler.guid, - selector: selector, - needsContext: selector && jQuery.expr.match.needsContext.test( selector ), - namespace: namespaces.join( "." ) - }, handleObjIn ); - - // Init the event handler queue if we're the first - if ( !( handlers = events[ type ] ) ) { - handlers = events[ type ] = []; - handlers.delegateCount = 0; - - // Only use addEventListener/attachEvent if the special events handler returns false - if ( !special.setup || - special.setup.call( elem, data, namespaces, eventHandle ) === false ) { - - // Bind the global event handler to the element - if ( elem.addEventListener ) { - elem.addEventListener( type, eventHandle, false ); - - } else if ( elem.attachEvent ) { - elem.attachEvent( "on" + type, eventHandle ); - } - } - } - - if ( special.add ) { - special.add.call( elem, handleObj ); - - if ( !handleObj.handler.guid ) { - handleObj.handler.guid = handler.guid; - } - } - - // Add to the element's handler list, delegates in front - if ( selector ) { - handlers.splice( handlers.delegateCount++, 0, handleObj ); - } else { - handlers.push( handleObj ); - } - - // Keep track of which events have ever been used, for event optimization - jQuery.event.global[ type ] = true; - } - - // Nullify elem to prevent memory leaks in IE - elem = null; - }, - - // Detach an event or set of events from an element - remove: function( elem, types, handler, selector, mappedTypes ) { - var j, handleObj, tmp, - origCount, t, events, - special, handlers, type, - namespaces, origType, - elemData = jQuery.hasData( elem ) && jQuery._data( elem ); - - if ( !elemData || !( events = elemData.events ) ) { - return; - } - - // Once for each type.namespace in types; type may be omitted - types = ( types || "" ).match( rnotwhite ) || [ "" ]; - t = types.length; - while ( t-- ) { - tmp = rtypenamespace.exec( types[ t ] ) || []; - type = origType = tmp[ 1 ]; - namespaces = ( tmp[ 2 ] || "" ).split( "." ).sort(); - - // Unbind all events (on this namespace, if provided) for the element - if ( !type ) { - for ( type in events ) { - jQuery.event.remove( elem, type + types[ t ], handler, selector, true ); - } - continue; - } - - special = jQuery.event.special[ type ] || {}; - type = ( selector ? special.delegateType : special.bindType ) || type; - handlers = events[ type ] || []; - tmp = tmp[ 2 ] && - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ); - - // Remove matching events - origCount = j = handlers.length; - while ( j-- ) { - handleObj = handlers[ j ]; - - if ( ( mappedTypes || origType === handleObj.origType ) && - ( !handler || handler.guid === handleObj.guid ) && - ( !tmp || tmp.test( handleObj.namespace ) ) && - ( !selector || selector === handleObj.selector || - selector === "**" && handleObj.selector ) ) { - handlers.splice( j, 1 ); - - if ( handleObj.selector ) { - handlers.delegateCount--; - } - if ( special.remove ) { - special.remove.call( elem, handleObj ); - } - } - } - - // Remove generic event handler if we removed something and no more handlers exist - // (avoids potential for endless recursion during removal of special event handlers) - if ( origCount && !handlers.length ) { - if ( !special.teardown || - special.teardown.call( elem, namespaces, elemData.handle ) === false ) { - - jQuery.removeEvent( elem, type, elemData.handle ); - } - - delete events[ type ]; - } - } - - // Remove the expando if it's no longer used - if ( jQuery.isEmptyObject( events ) ) { - delete elemData.handle; - - // removeData also checks for emptiness and clears the expando if empty - // so use it instead of delete - jQuery._removeData( elem, "events" ); - } - }, - - trigger: function( event, data, elem, onlyHandlers ) { - var handle, ontype, cur, - bubbleType, special, tmp, i, - eventPath = [ elem || document ], - type = hasOwn.call( event, "type" ) ? event.type : event, - namespaces = hasOwn.call( event, "namespace" ) ? event.namespace.split( "." ) : []; - - cur = tmp = elem = elem || document; - - // Don't do events on text and comment nodes - if ( elem.nodeType === 3 || elem.nodeType === 8 ) { - return; - } - - // focus/blur morphs to focusin/out; ensure we're not firing them right now - if ( rfocusMorph.test( type + jQuery.event.triggered ) ) { - return; - } - - if ( type.indexOf( "." ) > -1 ) { - - // Namespaced trigger; create a regexp to match event type in handle() - namespaces = type.split( "." ); - type = namespaces.shift(); - namespaces.sort(); - } - ontype = type.indexOf( ":" ) < 0 && "on" + type; - - // Caller can pass in a jQuery.Event object, Object, or just an event type string - event = event[ jQuery.expando ] ? - event : - new jQuery.Event( type, typeof event === "object" && event ); - - // Trigger bitmask: & 1 for native handlers; & 2 for jQuery (always true) - event.isTrigger = onlyHandlers ? 2 : 3; - event.namespace = namespaces.join( "." ); - event.rnamespace = event.namespace ? - new RegExp( "(^|\\.)" + namespaces.join( "\\.(?:.*\\.|)" ) + "(\\.|$)" ) : - null; - - // Clean up the event in case it is being reused - event.result = undefined; - if ( !event.target ) { - event.target = elem; - } - - // Clone any incoming data and prepend the event, creating the handler arg list - data = data == null ? - [ event ] : - jQuery.makeArray( data, [ event ] ); - - // Allow special events to draw outside the lines - special = jQuery.event.special[ type ] || {}; - if ( !onlyHandlers && special.trigger && special.trigger.apply( elem, data ) === false ) { - return; - } - - // Determine event propagation path in advance, per W3C events spec (#9951) - // Bubble up to document, then to window; watch for a global ownerDocument var (#9724) - if ( !onlyHandlers && !special.noBubble && !jQuery.isWindow( elem ) ) { - - bubbleType = special.delegateType || type; - if ( !rfocusMorph.test( bubbleType + type ) ) { - cur = cur.parentNode; - } - for ( ; cur; cur = cur.parentNode ) { - eventPath.push( cur ); - tmp = cur; - } - - // Only add window if we got to document (e.g., not plain obj or detached DOM) - if ( tmp === ( elem.ownerDocument || document ) ) { - eventPath.push( tmp.defaultView || tmp.parentWindow || window ); - } - } - - // Fire handlers on the event path - i = 0; - while ( ( cur = eventPath[ i++ ] ) && !event.isPropagationStopped() ) { - - event.type = i > 1 ? - bubbleType : - special.bindType || type; - - // jQuery handler - handle = ( jQuery._data( cur, "events" ) || {} )[ event.type ] && - jQuery._data( cur, "handle" ); - - if ( handle ) { - handle.apply( cur, data ); - } - - // Native handler - handle = ontype && cur[ ontype ]; - if ( handle && handle.apply && acceptData( cur ) ) { - event.result = handle.apply( cur, data ); - if ( event.result === false ) { - event.preventDefault(); - } - } - } - event.type = type; - - // If nobody prevented the default action, do it now - if ( !onlyHandlers && !event.isDefaultPrevented() ) { - - if ( - ( !special._default || - special._default.apply( eventPath.pop(), data ) === false - ) && acceptData( elem ) - ) { - - // Call a native DOM method on the target with the same name name as the event. - // Can't use an .isFunction() check here because IE6/7 fails that test. - // Don't do default actions on window, that's where global variables be (#6170) - if ( ontype && elem[ type ] && !jQuery.isWindow( elem ) ) { - - // Don't re-trigger an onFOO event when we call its FOO() method - tmp = elem[ ontype ]; - - if ( tmp ) { - elem[ ontype ] = null; - } - - // Prevent re-triggering of the same event, since we already bubbled it above - jQuery.event.triggered = type; - try { - elem[ type ](); - } catch ( e ) { - - // IE<9 dies on focus/blur to hidden element (#1486,#12518) - // only reproducible on winXP IE8 native, not IE9 in IE8 mode - } - jQuery.event.triggered = undefined; - - if ( tmp ) { - elem[ ontype ] = tmp; - } - } - } - } - - return event.result; - }, - - dispatch: function( event ) { - - // Make a writable jQuery.Event from the native event object - event = jQuery.event.fix( event ); - - var i, j, ret, matched, handleObj, - handlerQueue = [], - args = slice.call( arguments ), - handlers = ( jQuery._data( this, "events" ) || {} )[ event.type ] || [], - special = jQuery.event.special[ event.type ] || {}; - - // Use the fix-ed jQuery.Event rather than the (read-only) native event - args[ 0 ] = event; - event.delegateTarget = this; - - // Call the preDispatch hook for the mapped type, and let it bail if desired - if ( special.preDispatch && special.preDispatch.call( this, event ) === false ) { - return; - } - - // Determine handlers - handlerQueue = jQuery.event.handlers.call( this, event, handlers ); - - // Run delegates first; they may want to stop propagation beneath us - i = 0; - while ( ( matched = handlerQueue[ i++ ] ) && !event.isPropagationStopped() ) { - event.currentTarget = matched.elem; - - j = 0; - while ( ( handleObj = matched.handlers[ j++ ] ) && - !event.isImmediatePropagationStopped() ) { - - // Triggered event must either 1) have no namespace, or 2) have namespace(s) - // a subset or equal to those in the bound event (both can have no namespace). - if ( !event.rnamespace || event.rnamespace.test( handleObj.namespace ) ) { - - event.handleObj = handleObj; - event.data = handleObj.data; - - ret = ( ( jQuery.event.special[ handleObj.origType ] || {} ).handle || - handleObj.handler ).apply( matched.elem, args ); - - if ( ret !== undefined ) { - if ( ( event.result = ret ) === false ) { - event.preventDefault(); - event.stopPropagation(); - } - } - } - } - } - - // Call the postDispatch hook for the mapped type - if ( special.postDispatch ) { - special.postDispatch.call( this, event ); - } - - return event.result; - }, - - handlers: function( event, handlers ) { - var i, matches, sel, handleObj, - handlerQueue = [], - delegateCount = handlers.delegateCount, - cur = event.target; - - // Support (at least): Chrome, IE9 - // Find delegate handlers - // Black-hole SVG instance trees (#13180) - // - // Support: Firefox<=42+ - // Avoid non-left-click in FF but don't block IE radio events (#3861, gh-2343) - if ( delegateCount && cur.nodeType && - ( event.type !== "click" || isNaN( event.button ) || event.button < 1 ) ) { - - /* jshint eqeqeq: false */ - for ( ; cur != this; cur = cur.parentNode || this ) { - /* jshint eqeqeq: true */ - - // Don't check non-elements (#13208) - // Don't process clicks on disabled elements (#6911, #8165, #11382, #11764) - if ( cur.nodeType === 1 && ( cur.disabled !== true || event.type !== "click" ) ) { - matches = []; - for ( i = 0; i < delegateCount; i++ ) { - handleObj = handlers[ i ]; - - // Don't conflict with Object.prototype properties (#13203) - sel = handleObj.selector + " "; - - if ( matches[ sel ] === undefined ) { - matches[ sel ] = handleObj.needsContext ? - jQuery( sel, this ).index( cur ) > -1 : - jQuery.find( sel, this, null, [ cur ] ).length; - } - if ( matches[ sel ] ) { - matches.push( handleObj ); - } - } - if ( matches.length ) { - handlerQueue.push( { elem: cur, handlers: matches } ); - } - } - } - } - - // Add the remaining (directly-bound) handlers - if ( delegateCount < handlers.length ) { - handlerQueue.push( { elem: this, handlers: handlers.slice( delegateCount ) } ); - } - - return handlerQueue; - }, - - fix: function( event ) { - if ( event[ jQuery.expando ] ) { - return event; - } - - // Create a writable copy of the event object and normalize some properties - var i, prop, copy, - type = event.type, - originalEvent = event, - fixHook = this.fixHooks[ type ]; - - if ( !fixHook ) { - this.fixHooks[ type ] = fixHook = - rmouseEvent.test( type ) ? this.mouseHooks : - rkeyEvent.test( type ) ? this.keyHooks : - {}; - } - copy = fixHook.props ? this.props.concat( fixHook.props ) : this.props; - - event = new jQuery.Event( originalEvent ); - - i = copy.length; - while ( i-- ) { - prop = copy[ i ]; - event[ prop ] = originalEvent[ prop ]; - } - - // Support: IE<9 - // Fix target property (#1925) - if ( !event.target ) { - event.target = originalEvent.srcElement || document; - } - - // Support: Safari 6-8+ - // Target should not be a text node (#504, #13143) - if ( event.target.nodeType === 3 ) { - event.target = event.target.parentNode; - } - - // Support: IE<9 - // For mouse/key events, metaKey==false if it's undefined (#3368, #11328) - event.metaKey = !!event.metaKey; - - return fixHook.filter ? fixHook.filter( event, originalEvent ) : event; - }, - - // Includes some event props shared by KeyEvent and MouseEvent - props: ( "altKey bubbles cancelable ctrlKey currentTarget detail eventPhase " + - "metaKey relatedTarget shiftKey target timeStamp view which" ).split( " " ), - - fixHooks: {}, - - keyHooks: { - props: "char charCode key keyCode".split( " " ), - filter: function( event, original ) { - - // Add which for key events - if ( event.which == null ) { - event.which = original.charCode != null ? original.charCode : original.keyCode; - } - - return event; - } - }, - - mouseHooks: { - props: ( "button buttons clientX clientY fromElement offsetX offsetY " + - "pageX pageY screenX screenY toElement" ).split( " " ), - filter: function( event, original ) { - var body, eventDoc, doc, - button = original.button, - fromElement = original.fromElement; - - // Calculate pageX/Y if missing and clientX/Y available - if ( event.pageX == null && original.clientX != null ) { - eventDoc = event.target.ownerDocument || document; - doc = eventDoc.documentElement; - body = eventDoc.body; - - event.pageX = original.clientX + - ( doc && doc.scrollLeft || body && body.scrollLeft || 0 ) - - ( doc && doc.clientLeft || body && body.clientLeft || 0 ); - event.pageY = original.clientY + - ( doc && doc.scrollTop || body && body.scrollTop || 0 ) - - ( doc && doc.clientTop || body && body.clientTop || 0 ); - } - - // Add relatedTarget, if necessary - if ( !event.relatedTarget && fromElement ) { - event.relatedTarget = fromElement === event.target ? - original.toElement : - fromElement; - } - - // Add which for click: 1 === left; 2 === middle; 3 === right - // Note: button is not normalized, so don't use it - if ( !event.which && button !== undefined ) { - event.which = ( button & 1 ? 1 : ( button & 2 ? 3 : ( button & 4 ? 2 : 0 ) ) ); - } - - return event; - } - }, - - special: { - load: { - - // Prevent triggered image.load events from bubbling to window.load - noBubble: true - }, - focus: { - - // Fire native event if possible so blur/focus sequence is correct - trigger: function() { - if ( this !== safeActiveElement() && this.focus ) { - try { - this.focus(); - return false; - } catch ( e ) { - - // Support: IE<9 - // If we error on focus to hidden element (#1486, #12518), - // let .trigger() run the handlers - } - } - }, - delegateType: "focusin" - }, - blur: { - trigger: function() { - if ( this === safeActiveElement() && this.blur ) { - this.blur(); - return false; - } - }, - delegateType: "focusout" - }, - click: { - - // For checkbox, fire native event so checked state will be right - trigger: function() { - if ( jQuery.nodeName( this, "input" ) && this.type === "checkbox" && this.click ) { - this.click(); - return false; - } - }, - - // For cross-browser consistency, don't fire native .click() on links - _default: function( event ) { - return jQuery.nodeName( event.target, "a" ); - } - }, - - beforeunload: { - postDispatch: function( event ) { - - // Support: Firefox 20+ - // Firefox doesn't alert if the returnValue field is not set. - if ( event.result !== undefined && event.originalEvent ) { - event.originalEvent.returnValue = event.result; - } - } - } - }, - - // Piggyback on a donor event to simulate a different one - simulate: function( type, elem, event ) { - var e = jQuery.extend( - new jQuery.Event(), - event, - { - type: type, - isSimulated: true - - // Previously, `originalEvent: {}` was set here, so stopPropagation call - // would not be triggered on donor event, since in our own - // jQuery.event.stopPropagation function we had a check for existence of - // originalEvent.stopPropagation method, so, consequently it would be a noop. - // - // Guard for simulated events was moved to jQuery.event.stopPropagation function - // since `originalEvent` should point to the original event for the - // constancy with other events and for more focused logic - } - ); - - jQuery.event.trigger( e, null, elem ); - - if ( e.isDefaultPrevented() ) { - event.preventDefault(); - } - } -}; - -jQuery.removeEvent = document.removeEventListener ? - function( elem, type, handle ) { - - // This "if" is needed for plain objects - if ( elem.removeEventListener ) { - elem.removeEventListener( type, handle ); - } - } : - function( elem, type, handle ) { - var name = "on" + type; - - if ( elem.detachEvent ) { - - // #8545, #7054, preventing memory leaks for custom events in IE6-8 - // detachEvent needed property on element, by name of that event, - // to properly expose it to GC - if ( typeof elem[ name ] === "undefined" ) { - elem[ name ] = null; - } - - elem.detachEvent( name, handle ); - } - }; - -jQuery.Event = function( src, props ) { - - // Allow instantiation without the 'new' keyword - if ( !( this instanceof jQuery.Event ) ) { - return new jQuery.Event( src, props ); - } - - // Event object - if ( src && src.type ) { - this.originalEvent = src; - this.type = src.type; - - // Events bubbling up the document may have been marked as prevented - // by a handler lower down the tree; reflect the correct value. - this.isDefaultPrevented = src.defaultPrevented || - src.defaultPrevented === undefined && - - // Support: IE < 9, Android < 4.0 - src.returnValue === false ? - returnTrue : - returnFalse; - - // Event type - } else { - this.type = src; - } - - // Put explicitly provided properties onto the event object - if ( props ) { - jQuery.extend( this, props ); - } - - // Create a timestamp if incoming event doesn't have one - this.timeStamp = src && src.timeStamp || jQuery.now(); - - // Mark it as fixed - this[ jQuery.expando ] = true; -}; - -// jQuery.Event is based on DOM3 Events as specified by the ECMAScript Language Binding -// http://www.w3.org/TR/2003/WD-DOM-Level-3-Events-20030331/ecma-script-binding.html -jQuery.Event.prototype = { - constructor: jQuery.Event, - isDefaultPrevented: returnFalse, - isPropagationStopped: returnFalse, - isImmediatePropagationStopped: returnFalse, - - preventDefault: function() { - var e = this.originalEvent; - - this.isDefaultPrevented = returnTrue; - if ( !e ) { - return; - } - - // If preventDefault exists, run it on the original event - if ( e.preventDefault ) { - e.preventDefault(); - - // Support: IE - // Otherwise set the returnValue property of the original event to false - } else { - e.returnValue = false; - } - }, - stopPropagation: function() { - var e = this.originalEvent; - - this.isPropagationStopped = returnTrue; - - if ( !e || this.isSimulated ) { - return; - } - - // If stopPropagation exists, run it on the original event - if ( e.stopPropagation ) { - e.stopPropagation(); - } - - // Support: IE - // Set the cancelBubble property of the original event to true - e.cancelBubble = true; - }, - stopImmediatePropagation: function() { - var e = this.originalEvent; - - this.isImmediatePropagationStopped = returnTrue; - - if ( e && e.stopImmediatePropagation ) { - e.stopImmediatePropagation(); - } - - this.stopPropagation(); - } -}; - -// Create mouseenter/leave events using mouseover/out and event-time checks -// so that event delegation works in jQuery. -// Do the same for pointerenter/pointerleave and pointerover/pointerout -// -// Support: Safari 7 only -// Safari sends mouseenter too often; see: -// https://code.google.com/p/chromium/issues/detail?id=470258 -// for the description of the bug (it existed in older Chrome versions as well). -jQuery.each( { - mouseenter: "mouseover", - mouseleave: "mouseout", - pointerenter: "pointerover", - pointerleave: "pointerout" -}, function( orig, fix ) { - jQuery.event.special[ orig ] = { - delegateType: fix, - bindType: fix, - - handle: function( event ) { - var ret, - target = this, - related = event.relatedTarget, - handleObj = event.handleObj; - - // For mouseenter/leave call the handler if related is outside the target. - // NB: No relatedTarget if the mouse left/entered the browser window - if ( !related || ( related !== target && !jQuery.contains( target, related ) ) ) { - event.type = handleObj.origType; - ret = handleObj.handler.apply( this, arguments ); - event.type = fix; - } - return ret; - } - }; -} ); - -// IE submit delegation -if ( !support.submit ) { - - jQuery.event.special.submit = { - setup: function() { - - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Lazy-add a submit handler when a descendant form may potentially be submitted - jQuery.event.add( this, "click._submit keypress._submit", function( e ) { - - // Node name check avoids a VML-related crash in IE (#9807) - var elem = e.target, - form = jQuery.nodeName( elem, "input" ) || jQuery.nodeName( elem, "button" ) ? - - // Support: IE <=8 - // We use jQuery.prop instead of elem.form - // to allow fixing the IE8 delegated submit issue (gh-2332) - // by 3rd party polyfills/workarounds. - jQuery.prop( elem, "form" ) : - undefined; - - if ( form && !jQuery._data( form, "submit" ) ) { - jQuery.event.add( form, "submit._submit", function( event ) { - event._submitBubble = true; - } ); - jQuery._data( form, "submit", true ); - } - } ); - - // return undefined since we don't need an event listener - }, - - postDispatch: function( event ) { - - // If form was submitted by the user, bubble the event up the tree - if ( event._submitBubble ) { - delete event._submitBubble; - if ( this.parentNode && !event.isTrigger ) { - jQuery.event.simulate( "submit", this.parentNode, event ); - } - } - }, - - teardown: function() { - - // Only need this for delegated form submit events - if ( jQuery.nodeName( this, "form" ) ) { - return false; - } - - // Remove delegated handlers; cleanData eventually reaps submit handlers attached above - jQuery.event.remove( this, "._submit" ); - } - }; -} - -// IE change delegation and checkbox/radio fix -if ( !support.change ) { - - jQuery.event.special.change = { - - setup: function() { - - if ( rformElems.test( this.nodeName ) ) { - - // IE doesn't fire change on a check/radio until blur; trigger it on click - // after a propertychange. Eat the blur-change in special.change.handle. - // This still fires onchange a second time for check/radio after blur. - if ( this.type === "checkbox" || this.type === "radio" ) { - jQuery.event.add( this, "propertychange._change", function( event ) { - if ( event.originalEvent.propertyName === "checked" ) { - this._justChanged = true; - } - } ); - jQuery.event.add( this, "click._change", function( event ) { - if ( this._justChanged && !event.isTrigger ) { - this._justChanged = false; - } - - // Allow triggered, simulated change events (#11500) - jQuery.event.simulate( "change", this, event ); - } ); - } - return false; - } - - // Delegated event; lazy-add a change handler on descendant inputs - jQuery.event.add( this, "beforeactivate._change", function( e ) { - var elem = e.target; - - if ( rformElems.test( elem.nodeName ) && !jQuery._data( elem, "change" ) ) { - jQuery.event.add( elem, "change._change", function( event ) { - if ( this.parentNode && !event.isSimulated && !event.isTrigger ) { - jQuery.event.simulate( "change", this.parentNode, event ); - } - } ); - jQuery._data( elem, "change", true ); - } - } ); - }, - - handle: function( event ) { - var elem = event.target; - - // Swallow native change events from checkbox/radio, we already triggered them above - if ( this !== elem || event.isSimulated || event.isTrigger || - ( elem.type !== "radio" && elem.type !== "checkbox" ) ) { - - return event.handleObj.handler.apply( this, arguments ); - } - }, - - teardown: function() { - jQuery.event.remove( this, "._change" ); - - return !rformElems.test( this.nodeName ); - } - }; -} - -// Support: Firefox -// Firefox doesn't have focus(in | out) events -// Related ticket - https://bugzilla.mozilla.org/show_bug.cgi?id=687787 -// -// Support: Chrome, Safari -// focus(in | out) events fire after focus & blur events, -// which is spec violation - http://www.w3.org/TR/DOM-Level-3-Events/#events-focusevent-event-order -// Related ticket - https://code.google.com/p/chromium/issues/detail?id=449857 -if ( !support.focusin ) { - jQuery.each( { focus: "focusin", blur: "focusout" }, function( orig, fix ) { - - // Attach a single capturing handler on the document while someone wants focusin/focusout - var handler = function( event ) { - jQuery.event.simulate( fix, event.target, jQuery.event.fix( event ) ); - }; - - jQuery.event.special[ fix ] = { - setup: function() { - var doc = this.ownerDocument || this, - attaches = jQuery._data( doc, fix ); - - if ( !attaches ) { - doc.addEventListener( orig, handler, true ); - } - jQuery._data( doc, fix, ( attaches || 0 ) + 1 ); - }, - teardown: function() { - var doc = this.ownerDocument || this, - attaches = jQuery._data( doc, fix ) - 1; - - if ( !attaches ) { - doc.removeEventListener( orig, handler, true ); - jQuery._removeData( doc, fix ); - } else { - jQuery._data( doc, fix, attaches ); - } - } - }; - } ); -} - -jQuery.fn.extend( { - - on: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn ); - }, - one: function( types, selector, data, fn ) { - return on( this, types, selector, data, fn, 1 ); - }, - off: function( types, selector, fn ) { - var handleObj, type; - if ( types && types.preventDefault && types.handleObj ) { - - // ( event ) dispatched jQuery.Event - handleObj = types.handleObj; - jQuery( types.delegateTarget ).off( - handleObj.namespace ? - handleObj.origType + "." + handleObj.namespace : - handleObj.origType, - handleObj.selector, - handleObj.handler - ); - return this; - } - if ( typeof types === "object" ) { - - // ( types-object [, selector] ) - for ( type in types ) { - this.off( type, selector, types[ type ] ); - } - return this; - } - if ( selector === false || typeof selector === "function" ) { - - // ( types [, fn] ) - fn = selector; - selector = undefined; - } - if ( fn === false ) { - fn = returnFalse; - } - return this.each( function() { - jQuery.event.remove( this, types, fn, selector ); - } ); - }, - - trigger: function( type, data ) { - return this.each( function() { - jQuery.event.trigger( type, data, this ); - } ); - }, - triggerHandler: function( type, data ) { - var elem = this[ 0 ]; - if ( elem ) { - return jQuery.event.trigger( type, data, elem, true ); - } - } -} ); - - -var rinlinejQuery = / jQuery\d+="(?:null|\d+)"/g, - rnoshimcache = new RegExp( "<(?:" + nodeNames + ")[\\s/>]", "i" ), - rxhtmlTag = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:-]+)[^>]*)\/>/gi, - - // Support: IE 10-11, Edge 10240+ - // In IE/Edge using regex groups here causes severe slowdowns. - // See https://connect.microsoft.com/IE/feedback/details/1736512/ - rnoInnerhtml = /\s*$/g, - safeFragment = createSafeFragment( document ), - fragmentDiv = safeFragment.appendChild( document.createElement( "div" ) ); - -// Support: IE<8 -// Manipulating tables requires a tbody -function manipulationTarget( elem, content ) { - return jQuery.nodeName( elem, "table" ) && - jQuery.nodeName( content.nodeType !== 11 ? content : content.firstChild, "tr" ) ? - - elem.getElementsByTagName( "tbody" )[ 0 ] || - elem.appendChild( elem.ownerDocument.createElement( "tbody" ) ) : - elem; -} - -// Replace/restore the type attribute of script elements for safe DOM manipulation -function disableScript( elem ) { - elem.type = ( jQuery.find.attr( elem, "type" ) !== null ) + "/" + elem.type; - return elem; -} -function restoreScript( elem ) { - var match = rscriptTypeMasked.exec( elem.type ); - if ( match ) { - elem.type = match[ 1 ]; - } else { - elem.removeAttribute( "type" ); - } - return elem; -} - -function cloneCopyEvent( src, dest ) { - if ( dest.nodeType !== 1 || !jQuery.hasData( src ) ) { - return; - } - - var type, i, l, - oldData = jQuery._data( src ), - curData = jQuery._data( dest, oldData ), - events = oldData.events; - - if ( events ) { - delete curData.handle; - curData.events = {}; - - for ( type in events ) { - for ( i = 0, l = events[ type ].length; i < l; i++ ) { - jQuery.event.add( dest, type, events[ type ][ i ] ); - } - } - } - - // make the cloned public data object a copy from the original - if ( curData.data ) { - curData.data = jQuery.extend( {}, curData.data ); - } -} - -function fixCloneNodeIssues( src, dest ) { - var nodeName, e, data; - - // We do not need to do anything for non-Elements - if ( dest.nodeType !== 1 ) { - return; - } - - nodeName = dest.nodeName.toLowerCase(); - - // IE6-8 copies events bound via attachEvent when using cloneNode. - if ( !support.noCloneEvent && dest[ jQuery.expando ] ) { - data = jQuery._data( dest ); - - for ( e in data.events ) { - jQuery.removeEvent( dest, e, data.handle ); - } - - // Event data gets referenced instead of copied if the expando gets copied too - dest.removeAttribute( jQuery.expando ); - } - - // IE blanks contents when cloning scripts, and tries to evaluate newly-set text - if ( nodeName === "script" && dest.text !== src.text ) { - disableScript( dest ).text = src.text; - restoreScript( dest ); - - // IE6-10 improperly clones children of object elements using classid. - // IE10 throws NoModificationAllowedError if parent is null, #12132. - } else if ( nodeName === "object" ) { - if ( dest.parentNode ) { - dest.outerHTML = src.outerHTML; - } - - // This path appears unavoidable for IE9. When cloning an object - // element in IE9, the outerHTML strategy above is not sufficient. - // If the src has innerHTML and the destination does not, - // copy the src.innerHTML into the dest.innerHTML. #10324 - if ( support.html5Clone && ( src.innerHTML && !jQuery.trim( dest.innerHTML ) ) ) { - dest.innerHTML = src.innerHTML; - } - - } else if ( nodeName === "input" && rcheckableType.test( src.type ) ) { - - // IE6-8 fails to persist the checked state of a cloned checkbox - // or radio button. Worse, IE6-7 fail to give the cloned element - // a checked appearance if the defaultChecked value isn't also set - - dest.defaultChecked = dest.checked = src.checked; - - // IE6-7 get confused and end up setting the value of a cloned - // checkbox/radio button to an empty string instead of "on" - if ( dest.value !== src.value ) { - dest.value = src.value; - } - - // IE6-8 fails to return the selected option to the default selected - // state when cloning options - } else if ( nodeName === "option" ) { - dest.defaultSelected = dest.selected = src.defaultSelected; - - // IE6-8 fails to set the defaultValue to the correct value when - // cloning other types of input fields - } else if ( nodeName === "input" || nodeName === "textarea" ) { - dest.defaultValue = src.defaultValue; - } -} - -function domManip( collection, args, callback, ignored ) { - - // Flatten any nested arrays - args = concat.apply( [], args ); - - var first, node, hasScripts, - scripts, doc, fragment, - i = 0, - l = collection.length, - iNoClone = l - 1, - value = args[ 0 ], - isFunction = jQuery.isFunction( value ); - - // We can't cloneNode fragments that contain checked, in WebKit - if ( isFunction || - ( l > 1 && typeof value === "string" && - !support.checkClone && rchecked.test( value ) ) ) { - return collection.each( function( index ) { - var self = collection.eq( index ); - if ( isFunction ) { - args[ 0 ] = value.call( this, index, self.html() ); - } - domManip( self, args, callback, ignored ); - } ); - } - - if ( l ) { - fragment = buildFragment( args, collection[ 0 ].ownerDocument, false, collection, ignored ); - first = fragment.firstChild; - - if ( fragment.childNodes.length === 1 ) { - fragment = first; - } - - // Require either new content or an interest in ignored elements to invoke the callback - if ( first || ignored ) { - scripts = jQuery.map( getAll( fragment, "script" ), disableScript ); - hasScripts = scripts.length; - - // Use the original fragment for the last item - // instead of the first because it can end up - // being emptied incorrectly in certain situations (#8070). - for ( ; i < l; i++ ) { - node = fragment; - - if ( i !== iNoClone ) { - node = jQuery.clone( node, true, true ); - - // Keep references to cloned scripts for later restoration - if ( hasScripts ) { - - // Support: Android<4.1, PhantomJS<2 - // push.apply(_, arraylike) throws on ancient WebKit - jQuery.merge( scripts, getAll( node, "script" ) ); - } - } - - callback.call( collection[ i ], node, i ); - } - - if ( hasScripts ) { - doc = scripts[ scripts.length - 1 ].ownerDocument; - - // Reenable scripts - jQuery.map( scripts, restoreScript ); - - // Evaluate executable scripts on first document insertion - for ( i = 0; i < hasScripts; i++ ) { - node = scripts[ i ]; - if ( rscriptType.test( node.type || "" ) && - !jQuery._data( node, "globalEval" ) && - jQuery.contains( doc, node ) ) { - - if ( node.src ) { - - // Optional AJAX dependency, but won't run scripts if not present - if ( jQuery._evalUrl ) { - jQuery._evalUrl( node.src ); - } - } else { - jQuery.globalEval( - ( node.text || node.textContent || node.innerHTML || "" ) - .replace( rcleanScript, "" ) - ); - } - } - } - } - - // Fix #11809: Avoid leaking memory - fragment = first = null; - } - } - - return collection; -} - -function remove( elem, selector, keepData ) { - var node, - elems = selector ? jQuery.filter( selector, elem ) : elem, - i = 0; - - for ( ; ( node = elems[ i ] ) != null; i++ ) { - - if ( !keepData && node.nodeType === 1 ) { - jQuery.cleanData( getAll( node ) ); - } - - if ( node.parentNode ) { - if ( keepData && jQuery.contains( node.ownerDocument, node ) ) { - setGlobalEval( getAll( node, "script" ) ); - } - node.parentNode.removeChild( node ); - } - } - - return elem; -} - -jQuery.extend( { - htmlPrefilter: function( html ) { - return html.replace( rxhtmlTag, "<$1>" ); - }, - - clone: function( elem, dataAndEvents, deepDataAndEvents ) { - var destElements, node, clone, i, srcElements, - inPage = jQuery.contains( elem.ownerDocument, elem ); - - if ( support.html5Clone || jQuery.isXMLDoc( elem ) || - !rnoshimcache.test( "<" + elem.nodeName + ">" ) ) { - - clone = elem.cloneNode( true ); - - // IE<=8 does not properly clone detached, unknown element nodes - } else { - fragmentDiv.innerHTML = elem.outerHTML; - fragmentDiv.removeChild( clone = fragmentDiv.firstChild ); - } - - if ( ( !support.noCloneEvent || !support.noCloneChecked ) && - ( elem.nodeType === 1 || elem.nodeType === 11 ) && !jQuery.isXMLDoc( elem ) ) { - - // We eschew Sizzle here for performance reasons: http://jsperf.com/getall-vs-sizzle/2 - destElements = getAll( clone ); - srcElements = getAll( elem ); - - // Fix all IE cloning issues - for ( i = 0; ( node = srcElements[ i ] ) != null; ++i ) { - - // Ensure that the destination node is not null; Fixes #9587 - if ( destElements[ i ] ) { - fixCloneNodeIssues( node, destElements[ i ] ); - } - } - } - - // Copy the events from the original to the clone - if ( dataAndEvents ) { - if ( deepDataAndEvents ) { - srcElements = srcElements || getAll( elem ); - destElements = destElements || getAll( clone ); - - for ( i = 0; ( node = srcElements[ i ] ) != null; i++ ) { - cloneCopyEvent( node, destElements[ i ] ); - } - } else { - cloneCopyEvent( elem, clone ); - } - } - - // Preserve script evaluation history - destElements = getAll( clone, "script" ); - if ( destElements.length > 0 ) { - setGlobalEval( destElements, !inPage && getAll( elem, "script" ) ); - } - - destElements = srcElements = node = null; - - // Return the cloned set - return clone; - }, - - cleanData: function( elems, /* internal */ forceAcceptData ) { - var elem, type, id, data, - i = 0, - internalKey = jQuery.expando, - cache = jQuery.cache, - attributes = support.attributes, - special = jQuery.event.special; - - for ( ; ( elem = elems[ i ] ) != null; i++ ) { - if ( forceAcceptData || acceptData( elem ) ) { - - id = elem[ internalKey ]; - data = id && cache[ id ]; - - if ( data ) { - if ( data.events ) { - for ( type in data.events ) { - if ( special[ type ] ) { - jQuery.event.remove( elem, type ); - - // This is a shortcut to avoid jQuery.event.remove's overhead - } else { - jQuery.removeEvent( elem, type, data.handle ); - } - } - } - - // Remove cache only if it was not already removed by jQuery.event.remove - if ( cache[ id ] ) { - - delete cache[ id ]; - - // Support: IE<9 - // IE does not allow us to delete expando properties from nodes - // IE creates expando attributes along with the property - // IE does not have a removeAttribute function on Document nodes - if ( !attributes && typeof elem.removeAttribute !== "undefined" ) { - elem.removeAttribute( internalKey ); - - // Webkit & Blink performance suffers when deleting properties - // from DOM nodes, so set to undefined instead - // https://code.google.com/p/chromium/issues/detail?id=378607 - } else { - elem[ internalKey ] = undefined; - } - - deletedIds.push( id ); - } - } - } - } - } -} ); - -jQuery.fn.extend( { - - // Keep domManip exposed until 3.0 (gh-2225) - domManip: domManip, - - detach: function( selector ) { - return remove( this, selector, true ); - }, - - remove: function( selector ) { - return remove( this, selector ); - }, - - text: function( value ) { - return access( this, function( value ) { - return value === undefined ? - jQuery.text( this ) : - this.empty().append( - ( this[ 0 ] && this[ 0 ].ownerDocument || document ).createTextNode( value ) - ); - }, null, value, arguments.length ); - }, - - append: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.appendChild( elem ); - } - } ); - }, - - prepend: function() { - return domManip( this, arguments, function( elem ) { - if ( this.nodeType === 1 || this.nodeType === 11 || this.nodeType === 9 ) { - var target = manipulationTarget( this, elem ); - target.insertBefore( elem, target.firstChild ); - } - } ); - }, - - before: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this ); - } - } ); - }, - - after: function() { - return domManip( this, arguments, function( elem ) { - if ( this.parentNode ) { - this.parentNode.insertBefore( elem, this.nextSibling ); - } - } ); - }, - - empty: function() { - var elem, - i = 0; - - for ( ; ( elem = this[ i ] ) != null; i++ ) { - - // Remove element nodes and prevent memory leaks - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - } - - // Remove any remaining nodes - while ( elem.firstChild ) { - elem.removeChild( elem.firstChild ); - } - - // If this is a select, ensure that it displays empty (#12336) - // Support: IE<9 - if ( elem.options && jQuery.nodeName( elem, "select" ) ) { - elem.options.length = 0; - } - } - - return this; - }, - - clone: function( dataAndEvents, deepDataAndEvents ) { - dataAndEvents = dataAndEvents == null ? false : dataAndEvents; - deepDataAndEvents = deepDataAndEvents == null ? dataAndEvents : deepDataAndEvents; - - return this.map( function() { - return jQuery.clone( this, dataAndEvents, deepDataAndEvents ); - } ); - }, - - html: function( value ) { - return access( this, function( value ) { - var elem = this[ 0 ] || {}, - i = 0, - l = this.length; - - if ( value === undefined ) { - return elem.nodeType === 1 ? - elem.innerHTML.replace( rinlinejQuery, "" ) : - undefined; - } - - // See if we can take a shortcut and just use innerHTML - if ( typeof value === "string" && !rnoInnerhtml.test( value ) && - ( support.htmlSerialize || !rnoshimcache.test( value ) ) && - ( support.leadingWhitespace || !rleadingWhitespace.test( value ) ) && - !wrapMap[ ( rtagName.exec( value ) || [ "", "" ] )[ 1 ].toLowerCase() ] ) { - - value = jQuery.htmlPrefilter( value ); - - try { - for ( ; i < l; i++ ) { - - // Remove element nodes and prevent memory leaks - elem = this[ i ] || {}; - if ( elem.nodeType === 1 ) { - jQuery.cleanData( getAll( elem, false ) ); - elem.innerHTML = value; - } - } - - elem = 0; - - // If using innerHTML throws an exception, use the fallback method - } catch ( e ) {} - } - - if ( elem ) { - this.empty().append( value ); - } - }, null, value, arguments.length ); - }, - - replaceWith: function() { - var ignored = []; - - // Make the changes, replacing each non-ignored context element with the new content - return domManip( this, arguments, function( elem ) { - var parent = this.parentNode; - - if ( jQuery.inArray( this, ignored ) < 0 ) { - jQuery.cleanData( getAll( this ) ); - if ( parent ) { - parent.replaceChild( elem, this ); - } - } - - // Force callback invocation - }, ignored ); - } -} ); - -jQuery.each( { - appendTo: "append", - prependTo: "prepend", - insertBefore: "before", - insertAfter: "after", - replaceAll: "replaceWith" -}, function( name, original ) { - jQuery.fn[ name ] = function( selector ) { - var elems, - i = 0, - ret = [], - insert = jQuery( selector ), - last = insert.length - 1; - - for ( ; i <= last; i++ ) { - elems = i === last ? this : this.clone( true ); - jQuery( insert[ i ] )[ original ]( elems ); - - // Modern browsers can apply jQuery collections as arrays, but oldIE needs a .get() - push.apply( ret, elems.get() ); - } - - return this.pushStack( ret ); - }; -} ); - - -var iframe, - elemdisplay = { - - // Support: Firefox - // We have to pre-define these values for FF (#10227) - HTML: "block", - BODY: "block" - }; - -/** - * Retrieve the actual display of a element - * @param {String} name nodeName of the element - * @param {Object} doc Document object - */ - -// Called only from within defaultDisplay -function actualDisplay( name, doc ) { - var elem = jQuery( doc.createElement( name ) ).appendTo( doc.body ), - - display = jQuery.css( elem[ 0 ], "display" ); - - // We don't have any data stored on the element, - // so use "detach" method as fast way to get rid of the element - elem.detach(); - - return display; -} - -/** - * Try to determine the default display value of an element - * @param {String} nodeName - */ -function defaultDisplay( nodeName ) { - var doc = document, - display = elemdisplay[ nodeName ]; - - if ( !display ) { - display = actualDisplay( nodeName, doc ); - - // If the simple way fails, read from inside an iframe - if ( display === "none" || !display ) { - - // Use the already-created iframe if possible - iframe = ( iframe || jQuery( "' - ,'' - ,''].join('')) - - //编辑器不兼容ie8以下 - if(device.ie && device.ie < 8){ - return textArea.removeClass('layui-hide').addClass(SHOW); - } - - haveBuild[0] && (haveBuild.remove()); - - setIframe.call(that, editor, textArea[0], set) - textArea.addClass('layui-hide').after(editor); - - return that.index; - }; - - //获得编辑器中内容 - Edit.prototype.getContent = function(index){ - var iframeWin = getWin(index); - if(!iframeWin[0]) return; - return toLower(iframeWin[0].document.body.innerHTML); - }; - - //获得编辑器中纯文本内容 - Edit.prototype.getText = function(index){ - var iframeWin = getWin(index); - if(!iframeWin[0]) return; - return $(iframeWin[0].document.body).text(); - }; - /** - * 设置编辑器内容 - * @param {[type]} index 编辑器索引 - * @param {[type]} content 要设置的内容 - * @param {[type]} flag 是否追加模式 - */ - Edit.prototype.setContent = function(index, content, flag){ - var iframeWin = getWin(index); - if(!iframeWin[0]) return; - if(flag){ - $(iframeWin[0].document.body).append(content) - }else{ - $(iframeWin[0].document.body).html(content) - }; - layedit.sync(index) - }; - //将编辑器内容同步到textarea(一般用于异步提交时) - Edit.prototype.sync = function(index){ - var iframeWin = getWin(index); - if(!iframeWin[0]) return; - var textarea = $('#'+iframeWin[1].attr('textarea')); - textarea.val(toLower(iframeWin[0].document.body.innerHTML)); - }; - - //获取编辑器选中内容 - Edit.prototype.getSelection = function(index){ - var iframeWin = getWin(index); - if(!iframeWin[0]) return; - var range = Range(iframeWin[0].document); - return document.selection ? range.text : range.toString(); - }; - - //iframe初始化 - var setIframe = function(editor, textArea, set){ - var that = this, iframe = editor.find('iframe'); - - iframe.css({ - height: set.height - }).on('load', function(){ - var conts = iframe.contents() - ,iframeWin = iframe.prop('contentWindow') - ,head = conts.find('head') - ,style = $([''].join('')) - ,body = conts.find('body'); - - head.append(style); - body.attr('contenteditable', 'true').css({ - 'min-height': set.height - }).html(textArea.value||''); - - hotkey.apply(that, [iframeWin, iframe, textArea, set]); //快捷键处理 - toolActive.call(that, iframeWin, editor, set); //触发工具 - - }); - } - - //获得iframe窗口对象 - ,getWin = function(index){ - var iframe = $('#LAY_layedit_'+ index) - ,iframeWin = iframe.prop('contentWindow'); - return [iframeWin, iframe]; - } - - //IE8下将标签处理成小写 - ,toLower = function(html){ - if(device.ie == 8){ - html = html.replace(/<.+>/g, function(str){ - return str.toLowerCase(); - }); - } - return html; - } - - //快捷键处理 - ,hotkey = function(iframeWin, iframe, textArea, set){ - var iframeDOM = iframeWin.document, body = $(iframeDOM.body); - body.on('keydown', function(e){ - var keycode = e.keyCode; - //处理回车 - if(keycode === 13){ - var range = Range(iframeDOM); - var container = getContainer(range) - ,parentNode = container.parentNode; - - if(parentNode.tagName.toLowerCase() === 'pre'){ - if(e.shiftKey) return - layer.msg('请暂时用shift+enter'); - return false; - } - iframeDOM.execCommand('formatBlock', false, '

                                    '); - } - }); - - //给textarea同步内容 - $(textArea).parents('form').on('submit', function(){ - var html = body.html(); - //IE8下将标签处理成小写 - if(device.ie == 8){ - html = html.replace(/<.+>/g, function(str){ - return str.toLowerCase(); - }); - } - textArea.value = html; - }); - - //处理粘贴 - body.on('paste', function(e){ - iframeDOM.execCommand('formatBlock', false, '

                                    '); - setTimeout(function(){ - filter.call(iframeWin, body); - textArea.value = body.html(); - }, 100); - }); - } - - //标签过滤 - ,filter = function(body){ - var iframeWin = this - ,iframeDOM = iframeWin.document; - - //清除影响版面的css属性 - body.find('*[style]').each(function(){ - var textAlign = this.style.textAlign; - this.removeAttribute('style'); - $(this).css({ - 'text-align': textAlign || '' - }) - }); - - //修饰表格 - body.find('table').addClass('layui-table'); - - //移除不安全的标签 - body.find('script,link').remove(); - } - - //Range对象兼容性处理 - ,Range = function(iframeDOM){ - return iframeDOM.selection - ? iframeDOM.selection.createRange() - : iframeDOM.getSelection().getRangeAt(0); - } - - //当前Range对象的endContainer兼容性处理 - ,getContainer = function(range){ - return range.endContainer || range.parentElement().childNodes[0] - } - - //在选区插入内联元素 - ,insertInline = function(tagName, attr, range){ - var iframeDOM = this.document - ,elem = document.createElement(tagName) - for(var key in attr){ - elem.setAttribute(key, attr[key]); - } - elem.removeAttribute('text'); - - if(iframeDOM.selection){ //IE - var text = range.text || attr.text; - if(tagName === 'a' && !text) return; - if(text){ - elem.innerHTML = text; - } - range.pasteHTML($(elem).prop('outerHTML')); - range.select(); - } else { //非IE - var text = range.toString() || attr.text; - if(tagName === 'a' && !text) return; - if(text){ - elem.innerHTML = text; - } - range.deleteContents(); - range.insertNode(elem); - } - } - - //工具选中 - ,toolCheck = function(tools, othis){ - var iframeDOM = this.document - ,CHECK = 'layedit-tool-active' - ,container = getContainer(Range(iframeDOM)) - ,item = function(type){ - return tools.find('.layedit-tool-'+type) - } - - if(othis){ - othis[othis.hasClass(CHECK) ? 'removeClass' : 'addClass'](CHECK); - } - - tools.find('>i').removeClass(CHECK); - item('unlink').addClass(ABLED); - - $(container).parents().each(function(){ - var tagName = this.tagName.toLowerCase() - ,textAlign = this.style.textAlign; - - //文字 - if(tagName === 'b' || tagName === 'strong'){ - item('b').addClass(CHECK) - } - if(tagName === 'i' || tagName === 'em'){ - item('i').addClass(CHECK) - } - if(tagName === 'u'){ - item('u').addClass(CHECK) - } - if(tagName === 'strike'){ - item('d').addClass(CHECK) - } - - //对齐 - if(tagName === 'p'){ - if(textAlign === 'center'){ - item('center').addClass(CHECK); - } else if(textAlign === 'right'){ - item('right').addClass(CHECK); - } else { - item('left').addClass(CHECK); - } - } - - //超链接 - if(tagName === 'a'){ - item('link').addClass(CHECK); - item('unlink').removeClass(ABLED); - } - }); - } - - //触发工具 - ,toolActive = function(iframeWin, editor, set){ - var iframeDOM = iframeWin.document - ,body = $(iframeDOM.body) - ,toolEvent = { - //超链接 - link: function(range){ - var container = getContainer(range) - ,parentNode = $(container).parent(); - - link.call(body, { - href: parentNode.attr('href') - ,target: parentNode.attr('target') - }, function(field){ - var parent = parentNode[0]; - if(parent.tagName === 'A'){ - parent.href = field.url; - } else { - insertInline.call(iframeWin, 'a', { - target: field.target - ,href: field.url - ,text: field.url - }, range); - } - }); - } - //清除超链接 - ,unlink: function(range){ - iframeDOM.execCommand('unlink'); - } - //表情 - ,face: function(range){ - face.call(this, function(img){ - insertInline.call(iframeWin, 'img', { - src: img.src - ,alt: img.alt - }, range); - }); - } - //图片 - ,image: function(range){ - var that = this; - layui.use('upload', function(upload){ - var uploadImage = set.uploadImage || {}; - upload({ - url: uploadImage.url - ,method: uploadImage.type - ,elem: $(that).find('input')[0] - ,unwrap: true - ,success: function(res){ - if(res.code == 0){ - res.data = res.data || {}; - insertInline.call(iframeWin, 'img', { - src: res.data.src - ,alt: res.data.title - }, range); - } else { - layer.msg(res.msg||'上传失败'); - } - } - }); - }); - } - //插入代码 - ,code: function(range){ - code.call(body, function(pre){ - insertInline.call(iframeWin, 'pre', { - text: pre.code - ,'lay-lang': pre.lang - }, range); - }); - } - //帮助 - ,help: function(){ - layer.open({ - type: 2 - ,title: '帮助' - ,area: ['600px', '380px'] - ,shadeClose: true - ,shade: 0.1 - ,skin: 'layui-layer-msg' - ,content: ['http://www.layui.com/about/layedit/help.html', 'no'] - }); - } - } - ,tools = editor.find('.layui-layedit-tool') - - ,click = function(){ - var othis = $(this) - ,events = othis.attr('layedit-event') - ,command = othis.attr('lay-command'); - - if(othis.hasClass(ABLED)) return; - - body.focus(); - - var range = Range(iframeDOM) - ,container = range.commonAncestorContainer - - if(command){ - iframeDOM.execCommand(command); - if(/justifyLeft|justifyCenter|justifyRight/.test(command)){ - iframeDOM.execCommand('formatBlock', false, '

                                    '); - } - setTimeout(function(){ - body.focus(); - }, 10); - } else { - toolEvent[events] && toolEvent[events].call(this, range); - } - toolCheck.call(iframeWin, tools, othis); - } - - ,isClick = /image/ - - tools.find('>i').on('mousedown', function(){ - var othis = $(this) - ,events = othis.attr('layedit-event'); - if(isClick.test(events)) return; - click.call(this) - }).on('click', function(){ - var othis = $(this) - ,events = othis.attr('layedit-event'); - if(!isClick.test(events)) return; - click.call(this) - }); - - //触发内容区域 - body.on('click', function(){ - toolCheck.call(iframeWin, tools); - layer.close(face.index); - }); - } - - //超链接面板 - ,link = function(options, callback){ - var body = this, index = layer.open({ - type: 1 - ,id: 'LAY_layedit_link' - ,area: '350px' - ,shade: 0.05 - ,shadeClose: true - ,moveType: 1 - ,title: '超链接' - ,skin: 'layui-layer-msg' - ,content: ['

                                      ' - ,'
                                    • ' - ,'' - ,'
                                      ' - ,'' - ,'
                                      ' - ,'
                                    • ' - ,'
                                    • ' - ,'' - ,'
                                      ' - ,'' - ,'' - ,'
                                      ' - ,'
                                    • ' - ,'
                                    • ' - ,'' - ,'' - ,'
                                    • ' - ,'
                                    '].join('') - ,success: function(layero, index){ - var eventFilter = 'submit(layedit-link-yes)'; - form.render('radio'); - layero.find('.layui-btn-primary').on('click', function(){ - layer.close(index); - body.focus(); - }); - form.on(eventFilter, function(data){ - layer.close(link.index); - callback && callback(data.field); - }); - } - }); - link.index = index; - } - - //表情面板 - ,face = function(callback){ - //表情库 - var faces = function(){ - var alt = ["[微笑]", "[嘻嘻]", "[哈哈]", "[可爱]", "[可怜]", "[挖鼻]", "[吃惊]", "[害羞]", "[挤眼]", "[闭嘴]", "[鄙视]", "[爱你]", "[泪]", "[偷笑]", "[亲亲]", "[生病]", "[太开心]", "[白眼]", "[右哼哼]", "[左哼哼]", "[嘘]", "[衰]", "[委屈]", "[吐]", "[哈欠]", "[抱抱]", "[怒]", "[疑问]", "[馋嘴]", "[拜拜]", "[思考]", "[汗]", "[困]", "[睡]", "[钱]", "[失望]", "[酷]", "[色]", "[哼]", "[鼓掌]", "[晕]", "[悲伤]", "[抓狂]", "[黑线]", "[阴险]", "[怒骂]", "[互粉]", "[心]", "[伤心]", "[猪头]", "[熊猫]", "[兔子]", "[ok]", "[耶]", "[good]", "[NO]", "[赞]", "[来]", "[弱]", "[草泥马]", "[神马]", "[囧]", "[浮云]", "[给力]", "[围观]", "[威武]", "[奥特曼]", "[礼物]", "[钟]", "[话筒]", "[蜡烛]", "[蛋糕]"], arr = {}; - layui.each(alt, function(index, item){ - arr[item] = layui.cache.dir + 'images/face/'+ index + '.gif'; - }); - return arr; - }(); - face.hide = face.hide || function(e){ - if($(e.target).attr('layedit-event') !== 'face'){ - layer.close(face.index); - } - } - return face.index = layer.tips(function(){ - var content = []; - layui.each(faces, function(key, item){ - content.push('
                                  • '+ key +'
                                  • '); - }); - return '
                                      ' + content.join('') + '
                                    '; - }(), this, { - tips: 1 - ,time: 0 - ,skin: 'layui-box layui-util-face' - ,maxWidth: 500 - ,success: function(layero, index){ - layero.css({ - marginTop: -4 - ,marginLeft: -10 - }).find('.layui-clear>li').on('click', function(){ - callback && callback({ - src: faces[this.title] - ,alt: this.title - }); - layer.close(index); - }); - $(document).off('click', face.hide).on('click', face.hide); - } - }); - } - - //插入代码面板 - ,code = function(callback){ - var body = this, index = layer.open({ - type: 1 - ,id: 'LAY_layedit_code' - ,area: '550px' - ,shade: 0.05 - ,shadeClose: true - ,moveType: 1 - ,title: '插入代码' - ,skin: 'layui-layer-msg' - ,content: ['
                                      ' - ,'
                                    • ' - ,'' - ,'
                                      ' - ,'' - ,'
                                      ' - ,'
                                    • ' - ,'
                                    • ' - ,'' - ,'
                                      ' - ,'' - ,'
                                      ' - ,'
                                    • ' - ,'
                                    • ' - ,'' - ,'' - ,'
                                    • ' - ,'
                                    '].join('') - ,success: function(layero, index){ - var eventFilter = 'submit(layedit-code-yes)'; - form.render('select'); - layero.find('.layui-btn-primary').on('click', function(){ - layer.close(index); - body.focus(); - }); - form.on(eventFilter, function(data){ - layer.close(code.index); - callback && callback(data.field); - }); - } - }); - code.index = index; - } - - //全部工具 - ,tools = { - html: '' - ,strong: '' - ,italic: '' - ,underline: '' - ,del: '' - - ,'|': '' - - ,left: '' - ,center: '' - ,right: '' - ,link: '' - ,unlink: '' - ,face: '' - ,image: '' - ,code: '' - - ,help: '' - } - - ,edit = new Edit(); - - exports(MOD_NAME, edit); -}); diff --git a/src/lay/modules/layer.js b/src/lay/modules/layer.js deleted file mode 100644 index b4f6f4db9..000000000 --- a/src/lay/modules/layer.js +++ /dev/null @@ -1,1270 +0,0 @@ -/** - - @Name:layer v3.0.3 Web弹层组件 - @Author:贤心 - @Site:http://layer.layui.com - @License:MIT - - */ - -;!function(window, undefined){ -"use strict"; - -var isLayui = window.layui && layui.define, $, win, ready = { - getPath: function(){ - var js = document.scripts, script = js[js.length - 1], jsPath = script.src; - if(script.getAttribute('merge')) return; - return jsPath.substring(0, jsPath.lastIndexOf("/") + 1); - }(), - - config: {}, end: {}, minIndex: 0, minLeft: [], - btn: ['确定', '取消'], - - //五种原始层模式 - type: ['dialog', 'page', 'iframe', 'loading', 'tips'] -}; - -//默认内置方法。 -var layer = { - v: '3.0.3', - ie: function(){ //ie版本 - var agent = navigator.userAgent.toLowerCase(); - return (!!window.ActiveXObject || "ActiveXObject" in window) ? ( - (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于ie11并没有msie的标识 - ) : false; - }(), - index: (window.layer && window.layer.v) ? 100000 : 0, - path: ready.getPath, - config: function(options, fn){ - options = options || {}; - layer.cache = ready.config = $.extend({}, ready.config, options); - layer.path = ready.config.path || layer.path; - typeof options.extend === 'string' && (options.extend = [options.extend]); - - if(ready.config.path) layer.ready(); - - if(!options.extend) return this; - - isLayui - ? layui.addcss('modules/layer/' + options.extend) - : layer.link('skin/' + options.extend); - - return this; - }, - - //载入CSS配件 - link: function(href, fn, cssname){ - - //未设置路径,则不主动加载css - if(!layer.path) return; - - var head = $('head')[0], link = document.createElement('link'); - if(typeof fn === 'string') cssname = fn; - var app = (cssname || href).replace(/\.|\//g, ''); - var id = 'layuicss-'+app, timeout = 0; - - link.rel = 'stylesheet'; - link.href = layer.path + href; - link.id = id; - - if(!$('#'+ id)[0]){ - head.appendChild(link); - } - - if(typeof fn !== 'function') return; - - //轮询css是否加载完毕 - (function poll() { - if(++timeout > 8 * 1000 / 100){ - return window.console && console.error('layer.css: Invalid'); - }; - parseInt($('#'+id).css('width')) === 1989 ? fn() : setTimeout(poll, 100); - }()); - }, - - ready: function(callback){ - var cssname = 'skinlayercss', ver = '303'; - isLayui ? layui.addcss('modules/layer/default/layer.css?v='+layer.v+ver, callback, cssname) - : layer.link('skin/default/layer.css?v='+layer.v+ver, callback, cssname); - return this; - }, - - //各种快捷引用 - alert: function(content, options, yes){ - var type = typeof options === 'function'; - if(type) yes = options; - return layer.open($.extend({ - content: content, - yes: yes - }, type ? {} : options)); - }, - - confirm: function(content, options, yes, cancel){ - var type = typeof options === 'function'; - if(type){ - cancel = yes; - yes = options; - } - return layer.open($.extend({ - content: content, - btn: ready.btn, - yes: yes, - btn2: cancel - }, type ? {} : options)); - }, - - msg: function(content, options, end){ //最常用提示层 - var type = typeof options === 'function', rskin = ready.config.skin; - var skin = (rskin ? rskin + ' ' + rskin + '-msg' : '')||'layui-layer-msg'; - var anim = doms.anim.length - 1; - if(type) end = options; - return layer.open($.extend({ - content: content, - time: 3000, - shade: false, - skin: skin, - title: false, - closeBtn: false, - btn: false, - resize: false, - end: end - }, (type && !ready.config.skin) ? { - skin: skin + ' layui-layer-hui', - anim: anim - } : function(){ - options = options || {}; - if(options.icon === -1 || options.icon === undefined && !ready.config.skin){ - options.skin = skin + ' ' + (options.skin||'layui-layer-hui'); - } - return options; - }())); - }, - - load: function(icon, options){ - return layer.open($.extend({ - type: 3, - icon: icon || 0, - resize: false, - shade: 0.01 - }, options)); - }, - - tips: function(content, follow, options){ - return layer.open($.extend({ - type: 4, - content: [content, follow], - closeBtn: false, - time: 3000, - shade: false, - resize: false, - fixed: false, - maxWidth: 210 - }, options)); - } -}; - -var Class = function(setings){ - var that = this; - that.index = ++layer.index; - that.config = $.extend({}, that.config, ready.config, setings); - document.body ? that.creat() : setTimeout(function(){ - that.creat(); - }, 30); -}; - -Class.pt = Class.prototype; - -//缓存常用字符 -var doms = ['layui-layer', '.layui-layer-title', '.layui-layer-main', '.layui-layer-dialog', 'layui-layer-iframe', 'layui-layer-content', 'layui-layer-btn', 'layui-layer-close']; -doms.anim = ['layer-anim', 'layer-anim-01', 'layer-anim-02', 'layer-anim-03', 'layer-anim-04', 'layer-anim-05', 'layer-anim-06']; - -//默认配置 -Class.pt.config = { - type: 0, - shade: 0.3, - fixed: true, - move: doms[1], - title: '信息', - offset: 'auto', - area: 'auto', - closeBtn: 1, - time: 0, //0表示不自动关闭 - zIndex: 19891014, - maxWidth: 360, - anim: 0, - isOutAnim: true, - icon: -1, - moveType: 1, - resize: true, - scrollbar: true, //是否允许浏览器滚动条 - tips: 2 -}; - -//容器 -Class.pt.vessel = function(conType, callback){ - var that = this, times = that.index, config = that.config; - var zIndex = config.zIndex + times, titype = typeof config.title === 'object'; - var ismax = config.maxmin && (config.type === 1 || config.type === 2); - var titleHTML = (config.title ? '
                                    ' - + (titype ? config.title[0] : config.title) - + '
                                    ' : ''); - - config.zIndex = zIndex; - callback([ - //遮罩 - config.shade ? ('
                                    ') : '', - - //主体 - '
                                    ' - + (conType && config.type != 2 ? '' : titleHTML) - + '
                                    ' - + (config.type == 0 && config.icon !== -1 ? '' : '') - + (config.type == 1 && conType ? '' : (config.content||'')) - + '
                                    ' - + ''+ function(){ - var closebtn = ismax ? '' : ''; - config.closeBtn && (closebtn += ''); - return closebtn; - }() + '' - + (config.btn ? function(){ - var button = ''; - typeof config.btn === 'string' && (config.btn = [config.btn]); - for(var i = 0, len = config.btn.length; i < len; i++){ - button += ''+ config.btn[i] +'' - } - return '
                                    '+ button +'
                                    ' - }() : '') - + (config.resize ? '' : '') - + '
                                    ' - ], titleHTML, $('
                                    ')); - return that; -}; - -//创建骨架 -Class.pt.creat = function(){ - var that = this - ,config = that.config - ,times = that.index, nodeIndex - ,content = config.content - ,conType = typeof content === 'object' - ,body = $('body'); - - if(config.id && $('#'+config.id)[0]) return; - - if(typeof config.area === 'string'){ - config.area = config.area === 'auto' ? ['', ''] : [config.area, '']; - } - - //anim兼容旧版shift - if(config.shift){ - config.anim = config.shift; - } - - if(layer.ie == 6){ - config.fixed = false; - } - - switch(config.type){ - case 0: - config.btn = ('btn' in config) ? config.btn : ready.btn[0]; - layer.closeAll('dialog'); - break; - case 2: - var content = config.content = conType ? config.content : [config.content||'http://layer.layui.com', 'auto']; - config.content = ''; - break; - case 3: - delete config.title; - delete config.closeBtn; - config.icon === -1 && (config.icon === 0); - layer.closeAll('loading'); - break; - case 4: - conType || (config.content = [config.content, 'body']); - config.follow = config.content[1]; - config.content = config.content[0] + ''; - delete config.title; - config.tips = typeof config.tips === 'object' ? config.tips : [config.tips, true]; - config.tipsMore || layer.closeAll('tips'); - break; - } - - //建立容器 - that.vessel(conType, function(html, titleHTML, moveElem){ - body.append(html[0]); - conType ? function(){ - (config.type == 2 || config.type == 4) ? function(){ - $('body').append(html[1]); - }() : function(){ - if(!content.parents('.'+doms[0])[0]){ - content.data('display', content.css('display')).show().addClass('layui-layer-wrap').wrap(html[1]); - $('#'+ doms[0] + times).find('.'+doms[5]).before(titleHTML); - } - }(); - }() : body.append(html[1]); - $('.layui-layer-move')[0] || body.append(ready.moveElem = moveElem); - that.layero = $('#'+ doms[0] + times); - config.scrollbar || doms.html.css('overflow', 'hidden').attr('layer-full', times); - }).auto(times); - - config.type == 2 && layer.ie == 6 && that.layero.find('iframe').attr('src', content[0]); - - //坐标自适应浏览器窗口尺寸 - config.type == 4 ? that.tips() : that.offset(); - if(config.fixed){ - win.on('resize', function(){ - that.offset(); - (/^\d+%$/.test(config.area[0]) || /^\d+%$/.test(config.area[1])) && that.auto(times); - config.type == 4 && that.tips(); - }); - } - - config.time <= 0 || setTimeout(function(){ - layer.close(that.index) - }, config.time); - that.move().callback(); - - //为兼容jQuery3.0的css动画影响元素尺寸计算 - if(doms.anim[config.anim]){ - that.layero.addClass(doms.anim[config.anim]); - }; - - //记录关闭动画 - if(config.isOutAnim){ - that.layero.data('isOutAnim', true); - } -}; - -//自适应 -Class.pt.auto = function(index){ - var that = this, config = that.config, layero = $('#'+ doms[0] + index); - if(config.area[0] === '' && config.maxWidth > 0){ - //为了修复IE7下一个让人难以理解的bug - if(layer.ie && layer.ie < 8 && config.btn){ - layero.width(layero.innerWidth()); - } - layero.outerWidth() > config.maxWidth && layero.width(config.maxWidth); - } - var area = [layero.innerWidth(), layero.innerHeight()]; - var titHeight = layero.find(doms[1]).outerHeight() || 0; - var btnHeight = layero.find('.'+doms[6]).outerHeight() || 0; - function setHeight(elem){ - elem = layero.find(elem); - elem.height(area[1] - titHeight - btnHeight - 2*(parseFloat(elem.css('padding-top'))|0)); - } - switch(config.type){ - case 2: - setHeight('iframe'); - break; - default: - if(config.area[1] === ''){ - if(config.fixed && area[1] >= win.height()){ - area[1] = win.height(); - setHeight('.'+doms[5]); - } - } else { - setHeight('.'+doms[5]); - } - break; - } - return that; -}; - -//计算坐标 -Class.pt.offset = function(){ - var that = this, config = that.config, layero = that.layero; - var area = [layero.outerWidth(), layero.outerHeight()]; - var type = typeof config.offset === 'object'; - that.offsetTop = (win.height() - area[1])/2; - that.offsetLeft = (win.width() - area[0])/2; - - if(type){ - that.offsetTop = config.offset[0]; - that.offsetLeft = config.offset[1]||that.offsetLeft; - } else if(config.offset !== 'auto'){ - - if(config.offset === 't'){ //上 - that.offsetTop = 0; - } else if(config.offset === 'r'){ //右 - that.offsetLeft = win.width() - area[0]; - } else if(config.offset === 'b'){ //下 - that.offsetTop = win.height() - area[1]; - } else if(config.offset === 'l'){ //左 - that.offsetLeft = 0; - } else if(config.offset === 'lt'){ //左上角 - that.offsetTop = 0; - that.offsetLeft = 0; - } else if(config.offset === 'lb'){ //左下角 - that.offsetTop = win.height() - area[1]; - that.offsetLeft = 0; - } else if(config.offset === 'rt'){ //右上角 - that.offsetTop = 0; - that.offsetLeft = win.width() - area[0]; - } else if(config.offset === 'rb'){ //右下角 - that.offsetTop = win.height() - area[1]; - that.offsetLeft = win.width() - area[0]; - } else { - that.offsetTop = config.offset; - } - - } - - if(!config.fixed){ - that.offsetTop = /%$/.test(that.offsetTop) ? - win.height()*parseFloat(that.offsetTop)/100 - : parseFloat(that.offsetTop); - that.offsetLeft = /%$/.test(that.offsetLeft) ? - win.width()*parseFloat(that.offsetLeft)/100 - : parseFloat(that.offsetLeft); - that.offsetTop += win.scrollTop(); - that.offsetLeft += win.scrollLeft(); - } - - if(layero.attr('minLeft')){ - that.offsetTop = win.height() - (layero.find(doms[1]).outerHeight() || 0); - that.offsetLeft = layero.css('left'); - } - - layero.css({top: that.offsetTop, left: that.offsetLeft}); -}; - -//Tips -Class.pt.tips = function(){ - var that = this, config = that.config, layero = that.layero; - var layArea = [layero.outerWidth(), layero.outerHeight()], follow = $(config.follow); - if(!follow[0]) follow = $('body'); - var goal = { - width: follow.outerWidth(), - height: follow.outerHeight(), - top: follow.offset().top, - left: follow.offset().left - }, tipsG = layero.find('.layui-layer-TipsG'); - - var guide = config.tips[0]; - config.tips[1] || tipsG.remove(); - - goal.autoLeft = function(){ - if(goal.left + layArea[0] - win.width() > 0){ - goal.tipLeft = goal.left + goal.width - layArea[0]; - tipsG.css({right: 12, left: 'auto'}); - } else { - goal.tipLeft = goal.left; - }; - }; - - //辨别tips的方位 - goal.where = [function(){ //上 - goal.autoLeft(); - goal.tipTop = goal.top - layArea[1] - 10; - tipsG.removeClass('layui-layer-TipsB').addClass('layui-layer-TipsT').css('border-right-color', config.tips[1]); - }, function(){ //右 - goal.tipLeft = goal.left + goal.width + 10; - goal.tipTop = goal.top; - tipsG.removeClass('layui-layer-TipsL').addClass('layui-layer-TipsR').css('border-bottom-color', config.tips[1]); - }, function(){ //下 - goal.autoLeft(); - goal.tipTop = goal.top + goal.height + 10; - tipsG.removeClass('layui-layer-TipsT').addClass('layui-layer-TipsB').css('border-right-color', config.tips[1]); - }, function(){ //左 - goal.tipLeft = goal.left - layArea[0] - 10; - goal.tipTop = goal.top; - tipsG.removeClass('layui-layer-TipsR').addClass('layui-layer-TipsL').css('border-bottom-color', config.tips[1]); - }]; - goal.where[guide-1](); - - /* 8*2为小三角形占据的空间 */ - if(guide === 1){ - goal.top - (win.scrollTop() + layArea[1] + 8*2) < 0 && goal.where[2](); - } else if(guide === 2){ - win.width() - (goal.left + goal.width + layArea[0] + 8*2) > 0 || goal.where[3]() - } else if(guide === 3){ - (goal.top - win.scrollTop() + goal.height + layArea[1] + 8*2) - win.height() > 0 && goal.where[0](); - } else if(guide === 4){ - layArea[0] + 8*2 - goal.left > 0 && goal.where[1]() - } - - layero.find('.'+doms[5]).css({ - 'background-color': config.tips[1], - 'padding-right': (config.closeBtn ? '30px' : '') - }); - layero.css({ - left: goal.tipLeft - (config.fixed ? win.scrollLeft() : 0), - top: goal.tipTop - (config.fixed ? win.scrollTop() : 0) - }); -} - -//拖拽层 -Class.pt.move = function(){ - var that = this - ,config = that.config - ,_DOC = $(document) - ,layero = that.layero - ,moveElem = layero.find(config.move) - ,resizeElem = layero.find('.layui-layer-resize') - ,dict = {}; - - if(config.move){ - moveElem.css('cursor', 'move'); - } - - moveElem.on('mousedown', function(e){ - e.preventDefault(); - if(config.move){ - dict.moveStart = true; - dict.offset = [ - e.clientX - parseFloat(layero.css('left')) - ,e.clientY - parseFloat(layero.css('top')) - ]; - ready.moveElem.css('cursor', 'move').show(); - } - }); - - resizeElem.on('mousedown', function(e){ - e.preventDefault(); - dict.resizeStart = true; - dict.offset = [e.clientX, e.clientY]; - dict.area = [ - layero.outerWidth() - ,layero.outerHeight() - ]; - ready.moveElem.css('cursor', 'se-resize').show(); - }); - - _DOC.on('mousemove', function(e){ - - //拖拽移动 - if(dict.moveStart){ - var X = e.clientX - dict.offset[0] - ,Y = e.clientY - dict.offset[1] - ,fixed = layero.css('position') === 'fixed'; - - e.preventDefault(); - - dict.stX = fixed ? 0 : win.scrollLeft(); - dict.stY = fixed ? 0 : win.scrollTop(); - - //控制元素不被拖出窗口外 - if(!config.moveOut){ - var setRig = win.width() - layero.outerWidth() + dict.stX - ,setBot = win.height() - layero.outerHeight() + dict.stY; - X < dict.stX && (X = dict.stX); - X > setRig && (X = setRig); - Y < dict.stY && (Y = dict.stY); - Y > setBot && (Y = setBot); - } - - layero.css({ - left: X - ,top: Y - }); - } - - //Resize - if(config.resize && dict.resizeStart){ - var X = e.clientX - dict.offset[0] - ,Y = e.clientY - dict.offset[1]; - - e.preventDefault(); - - layer.style(that.index, { - width: dict.area[0] + X - ,height: dict.area[1] + Y - }) - dict.isResize = true; - config.resizing && config.resizing(layero); - } - }).on('mouseup', function(e){ - if(dict.moveStart){ - delete dict.moveStart; - ready.moveElem.hide(); - config.moveEnd && config.moveEnd(layero); - } - if(dict.resizeStart){ - delete dict.resizeStart; - ready.moveElem.hide(); - } - }); - - return that; -}; - -Class.pt.callback = function(){ - var that = this, layero = that.layero, config = that.config; - that.openLayer(); - if(config.success){ - if(config.type == 2){ - layero.find('iframe').on('load', function(){ - config.success(layero, that.index); - }); - } else { - config.success(layero, that.index); - } - } - layer.ie == 6 && that.IE6(layero); - - //按钮 - layero.find('.'+ doms[6]).children('a').on('click', function(){ - var index = $(this).index(); - if(index === 0){ - if(config.yes){ - config.yes(that.index, layero) - } else if(config['btn1']){ - config['btn1'](that.index, layero) - } else { - layer.close(that.index); - } - } else { - var close = config['btn'+(index+1)] && config['btn'+(index+1)](that.index, layero); - close === false || layer.close(that.index); - } - }); - - //取消 - function cancel(){ - var close = config.cancel && config.cancel(that.index, layero); - close === false || layer.close(that.index); - } - - //右上角关闭回调 - layero.find('.'+ doms[7]).on('click', cancel); - - //点遮罩关闭 - if(config.shadeClose){ - $('#layui-layer-shade'+ that.index).on('click', function(){ - layer.close(that.index); - }); - } - - //最小化 - layero.find('.layui-layer-min').on('click', function(){ - var min = config.min && config.min(layero); - min === false || layer.min(that.index, config); - }); - - //全屏/还原 - layero.find('.layui-layer-max').on('click', function(){ - if($(this).hasClass('layui-layer-maxmin')){ - layer.restore(that.index); - config.restore && config.restore(layero); - } else { - layer.full(that.index, config); - setTimeout(function(){ - config.full && config.full(layero); - }, 100); - } - }); - - config.end && (ready.end[that.index] = config.end); -}; - -//for ie6 恢复select -ready.reselect = function(){ - $.each($('select'), function(index , value){ - var sthis = $(this); - if(!sthis.parents('.'+doms[0])[0]){ - (sthis.attr('layer') == 1 && $('.'+doms[0]).length < 1) && sthis.removeAttr('layer').show(); - } - sthis = null; - }); -}; - -Class.pt.IE6 = function(layero){ - //隐藏select - $('select').each(function(index , value){ - var sthis = $(this); - if(!sthis.parents('.'+doms[0])[0]){ - sthis.css('display') === 'none' || sthis.attr({'layer' : '1'}).hide(); - } - sthis = null; - }); -}; - -//需依赖原型的对外方法 -Class.pt.openLayer = function(){ - var that = this; - - //置顶当前窗口 - layer.zIndex = that.config.zIndex; - layer.setTop = function(layero){ - var setZindex = function(){ - layer.zIndex++; - layero.css('z-index', layer.zIndex + 1); - }; - layer.zIndex = parseInt(layero[0].style.zIndex); - layero.on('mousedown', setZindex); - return layer.zIndex; - }; -}; - -ready.record = function(layero){ - var area = [ - layero.width(), - layero.height(), - layero.position().top, - layero.position().left + parseFloat(layero.css('margin-left')) - ]; - layero.find('.layui-layer-max').addClass('layui-layer-maxmin'); - layero.attr({area: area}); -}; - -ready.rescollbar = function(index){ - if(doms.html.attr('layer-full') == index){ - if(doms.html[0].style.removeProperty){ - doms.html[0].style.removeProperty('overflow'); - } else { - doms.html[0].style.removeAttribute('overflow'); - } - doms.html.removeAttr('layer-full'); - } -}; - -/** 内置成员 */ - -window.layer = layer; - -//获取子iframe的DOM -layer.getChildFrame = function(selector, index){ - index = index || $('.'+doms[4]).attr('times'); - return $('#'+ doms[0] + index).find('iframe').contents().find(selector); -}; - -//得到当前iframe层的索引,子iframe时使用 -layer.getFrameIndex = function(name){ - return $('#'+ name).parents('.'+doms[4]).attr('times'); -}; - -//iframe层自适应宽高 -layer.iframeAuto = function(index){ - if(!index) return; - var heg = layer.getChildFrame('html', index).outerHeight(); - var layero = $('#'+ doms[0] + index); - var titHeight = layero.find(doms[1]).outerHeight() || 0; - var btnHeight = layero.find('.'+doms[6]).outerHeight() || 0; - layero.css({height: heg + titHeight + btnHeight}); - layero.find('iframe').css({height: heg}); -}; - -//重置iframe url -layer.iframeSrc = function(index, url){ - $('#'+ doms[0] + index).find('iframe').attr('src', url); -}; - -//设定层的样式 -layer.style = function(index, options, limit){ - var layero = $('#'+ doms[0] + index) - ,contElem = layero.find('.layui-layer-content') - ,type = layero.attr('type') - ,titHeight = layero.find(doms[1]).outerHeight() || 0 - ,btnHeight = layero.find('.'+doms[6]).outerHeight() || 0 - ,minLeft = layero.attr('minLeft'); - - if(type === ready.type[3] || type === ready.type[4]){ - return; - } - - if(!limit){ - if(parseFloat(options.width) <= 260){ - options.width = 260; - }; - - if(parseFloat(options.height) - titHeight - btnHeight <= 64){ - options.height = 64 + titHeight + btnHeight; - }; - } - - layero.css(options); - btnHeight = layero.find('.'+doms[6]).outerHeight(); - - if(type === ready.type[2]){ - layero.find('iframe').css({ - height: parseFloat(options.height) - titHeight - btnHeight - }); - } else { - contElem.css({ - height: parseFloat(options.height) - titHeight - btnHeight - - parseFloat(contElem.css('padding-top')) - - parseFloat(contElem.css('padding-bottom')) - }) - } -}; - -//最小化 -layer.min = function(index, options){ - var layero = $('#'+ doms[0] + index) - ,titHeight = layero.find(doms[1]).outerHeight() || 0 - ,left = layero.attr('minLeft') || (181*ready.minIndex)+'px' - ,position = layero.css('position'); - - ready.record(layero); - - if(ready.minLeft[0]){ - left = ready.minLeft[0]; - ready.minLeft.shift(); - } - - layero.attr('position', position); - - layer.style(index, { - width: 180 - ,height: titHeight - ,left: left - ,top: win.height() - titHeight - ,position: 'fixed' - ,overflow: 'hidden' - }, true); - - layero.find('.layui-layer-min').hide(); - layero.attr('type') === 'page' && layero.find(doms[4]).hide(); - ready.rescollbar(index); - - if(!layero.attr('minLeft')){ - ready.minIndex++; - } - layero.attr('minLeft', left); -}; - -//还原 -layer.restore = function(index){ - var layero = $('#'+ doms[0] + index), area = layero.attr('area').split(','); - var type = layero.attr('type'); - layer.style(index, { - width: parseFloat(area[0]), - height: parseFloat(area[1]), - top: parseFloat(area[2]), - left: parseFloat(area[3]), - position: layero.attr('position'), - overflow: 'visible' - }, true); - layero.find('.layui-layer-max').removeClass('layui-layer-maxmin'); - layero.find('.layui-layer-min').show(); - layero.attr('type') === 'page' && layero.find(doms[4]).show(); - ready.rescollbar(index); -}; - -//全屏 -layer.full = function(index){ - var layero = $('#'+ doms[0] + index), timer; - ready.record(layero); - if(!doms.html.attr('layer-full')){ - doms.html.css('overflow','hidden').attr('layer-full', index); - } - clearTimeout(timer); - timer = setTimeout(function(){ - var isfix = layero.css('position') === 'fixed'; - layer.style(index, { - top: isfix ? 0 : win.scrollTop(), - left: isfix ? 0 : win.scrollLeft(), - width: win.width(), - height: win.height() - }, true); - layero.find('.layui-layer-min').hide(); - }, 100); -}; - -//改变title -layer.title = function(name, index){ - var title = $('#'+ doms[0] + (index||layer.index)).find(doms[1]); - title.html(name); -}; - -//关闭layer总方法 -layer.close = function(index){ - var layero = $('#'+ doms[0] + index), type = layero.attr('type'), closeAnim = 'layer-anim-close'; - if(!layero[0]) return; - var WRAP = 'layui-layer-wrap', remove = function(){ - if(type === ready.type[1] && layero.attr('conType') === 'object'){ - layero.children(':not(.'+ doms[5] +')').remove(); - var wrap = layero.find('.'+WRAP); - for(var i = 0; i < 2; i++){ - wrap.unwrap(); - } - wrap.css('display', wrap.data('display')).removeClass(WRAP); - } else { - //低版本IE 回收 iframe - if(type === ready.type[2]){ - try { - var iframe = $('#'+doms[4]+index)[0]; - iframe.contentWindow.document.write(''); - iframe.contentWindow.close(); - layero.find('.'+doms[5])[0].removeChild(iframe); - } catch(e){} - } - layero[0].innerHTML = ''; - layero.remove(); - } - typeof ready.end[index] === 'function' && ready.end[index](); - delete ready.end[index]; - }; - - if(layero.data('isOutAnim')){ - layero.addClass(closeAnim); - } - - $('#layui-layer-moves, #layui-layer-shade' + index).remove(); - layer.ie == 6 && ready.reselect(); - ready.rescollbar(index); - if(layero.attr('minLeft')){ - ready.minIndex--; - ready.minLeft.push(layero.attr('minLeft')); - } - - if((layer.ie && layer.ie < 10) || !layero.data('isOutAnim')){ - remove() - } else { - setTimeout(function(){ - remove(); - }, 200); - } -}; - -//关闭所有层 -layer.closeAll = function(type){ - $.each($('.'+doms[0]), function(){ - var othis = $(this); - var is = type ? (othis.attr('type') === type) : 1; - is && layer.close(othis.attr('times')); - is = null; - }); -}; - -/** - - 拓展模块,layui开始合并在一起 - - */ - -var cache = layer.cache||{}, skin = function(type){ - return (cache.skin ? (' ' + cache.skin + ' ' + cache.skin + '-'+type) : ''); -}; - -//仿系统prompt -layer.prompt = function(options, yes){ - var style = ''; - options = options || {}; - - if(typeof options === 'function') yes = options; - - if(options.area){ - var area = options.area; - style = 'style="width: '+ area[0] +'; height: '+ area[1] + ';"'; - delete options.area; - } - var prompt, content = options.formType == 2 ? '' : function(){ - return ''; - }(); - - var success = options.success; - delete options.success; - - return layer.open($.extend({ - type: 1 - ,btn: ['确定','取消'] - ,content: content - ,skin: 'layui-layer-prompt' + skin('prompt') - ,maxWidth: win.width() - ,success: function(layero){ - prompt = layero.find('.layui-layer-input'); - prompt.focus(); - typeof success === 'function' && success(layero); - } - ,resize: false - ,yes: function(index){ - var value = prompt.val(); - if(value === ''){ - prompt.focus(); - } else if(value.length > (options.maxlength||500)) { - layer.tips('最多输入'+ (options.maxlength || 500) +'个字数', prompt, {tips: 1}); - } else { - yes && yes(value, index, prompt); - } - } - }, options)); -}; - -//tab层 -layer.tab = function(options){ - options = options || {}; - - var tab = options.tab || {} - ,success = options.success; - - delete options.success; - - return layer.open($.extend({ - type: 1, - skin: 'layui-layer-tab' + skin('tab'), - resize: false, - title: function(){ - var len = tab.length, ii = 1, str = ''; - if(len > 0){ - str = ''+ tab[0].title +''; - for(; ii < len; ii++){ - str += ''+ tab[ii].title +''; - } - } - return str; - }(), - content: '
                                      '+ function(){ - var len = tab.length, ii = 1, str = ''; - if(len > 0){ - str = '
                                    • '+ (tab[0].content || 'no content') +'
                                    • '; - for(; ii < len; ii++){ - str += '
                                    • '+ (tab[ii].content || 'no content') +'
                                    • '; - } - } - return str; - }() +'
                                    ', - success: function(layero){ - var btn = layero.find('.layui-layer-title').children(); - var main = layero.find('.layui-layer-tabmain').children(); - btn.on('mousedown', function(e){ - e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; - var othis = $(this), index = othis.index(); - othis.addClass('layui-layer-tabnow').siblings().removeClass('layui-layer-tabnow'); - main.eq(index).show().siblings().hide(); - typeof options.change === 'function' && options.change(index); - }); - typeof success === 'function' && success(layero); - } - }, options)); -}; - -//相册层 -layer.photos = function(options, loop, key){ - var dict = {}; - options = options || {}; - if(!options.photos) return; - var type = options.photos.constructor === Object; - var photos = type ? options.photos : {}, data = photos.data || []; - var start = photos.start || 0; - dict.imgIndex = (start|0) + 1; - - options.img = options.img || 'img'; - - var success = options.success; - delete options.success; - - if(!type){ //页面直接获取 - var parent = $(options.photos), pushData = function(){ - data = []; - parent.find(options.img).each(function(index){ - var othis = $(this); - othis.attr('layer-index', index); - data.push({ - alt: othis.attr('alt'), - pid: othis.attr('layer-pid'), - src: othis.attr('layer-src') || othis.attr('src'), - thumb: othis.attr('src') - }); - }) - }; - - pushData(); - - if (data.length === 0) return; - - loop || parent.on('click', options.img, function(){ - var othis = $(this), index = othis.attr('layer-index'); - layer.photos($.extend(options, { - photos: { - start: index, - data: data, - tab: options.tab - }, - full: options.full - }), true); - pushData(); - }) - - //不直接弹出 - if(!loop) return; - - } else if (data.length === 0){ - return layer.msg('没有图片'); - } - - //上一张 - dict.imgprev = function(key){ - dict.imgIndex--; - if(dict.imgIndex < 1){ - dict.imgIndex = data.length; - } - dict.tabimg(key); - }; - - //下一张 - dict.imgnext = function(key,errorMsg){ - dict.imgIndex++; - if(dict.imgIndex > data.length){ - dict.imgIndex = 1; - if (errorMsg) {return}; - } - dict.tabimg(key) - }; - - //方向键 - dict.keyup = function(event){ - if(!dict.end){ - var code = event.keyCode; - event.preventDefault(); - if(code === 37){ - dict.imgprev(true); - } else if(code === 39) { - dict.imgnext(true); - } else if(code === 27) { - layer.close(dict.index); - } - } - } - - //切换 - dict.tabimg = function(key){ - if(data.length <= 1) return; - photos.start = dict.imgIndex - 1; - layer.close(dict.index); - return layer.photos(options, true, key); - setTimeout(function(){ - layer.photos(options, true, key); - }, 200); - } - - //一些动作 - dict.event = function(){ - dict.bigimg.hover(function(){ - dict.imgsee.show(); - }, function(){ - dict.imgsee.hide(); - }); - - dict.bigimg.find('.layui-layer-imgprev').on('click', function(event){ - event.preventDefault(); - dict.imgprev(); - }); - - dict.bigimg.find('.layui-layer-imgnext').on('click', function(event){ - event.preventDefault(); - dict.imgnext(); - }); - - $(document).on('keyup', dict.keyup); - }; - - //图片预加载 - function loadImage(url, callback, error) { - var img = new Image(); - img.src = url; - if(img.complete){ - return callback(img); - } - img.onload = function(){ - img.onload = null; - callback(img); - }; - img.onerror = function(e){ - img.onerror = null; - error(e); - }; - }; - - dict.loadi = layer.load(1, { - shade: 'shade' in options ? false : 0.9, - scrollbar: false - }); - - loadImage(data[start].src, function(img){ - layer.close(dict.loadi); - dict.index = layer.open($.extend({ - type: 1, - id: 'layui-layer-photos', - area: function(){ - var imgarea = [img.width, img.height]; - var winarea = [$(window).width() - 100, $(window).height() - 100]; - - //如果 实际图片的宽或者高比 屏幕大(那么进行缩放) - if(!options.full && (imgarea[0]>winarea[0]||imgarea[1]>winarea[1])){ - var wh = [imgarea[0]/winarea[0],imgarea[1]/winarea[1]];//取宽度缩放比例、高度缩放比例 - if(wh[0] > wh[1]){//取缩放比例最大的进行缩放 - imgarea[0] = imgarea[0]/wh[0]; - imgarea[1] = imgarea[1]/wh[0]; - } else if(wh[0] < wh[1]){ - imgarea[0] = imgarea[0]/wh[1]; - imgarea[1] = imgarea[1]/wh[1]; - } - } - - return [imgarea[0]+'px', imgarea[1]+'px']; - }(), - title: false, - shade: 0.9, - shadeClose: true, - closeBtn: false, - move: '.layui-layer-phimg img', - moveType: 1, - scrollbar: false, - moveOut: true, - //anim: Math.random()*5|0, - isOutAnim: false, - skin: 'layui-layer-photos' + skin('photos'), - content: '
                                    ' - +''+ (data[start].alt||'') +'' - +'
                                    ' - +(data.length > 1 ? '' : '') - +'
                                    '+ (data[start].alt||'') +''+ dict.imgIndex +'/'+ data.length +'
                                    ' - +'
                                    ' - +'
                                    ', - success: function(layero, index){ - dict.bigimg = layero.find('.layui-layer-phimg'); - dict.imgsee = layero.find('.layui-layer-imguide,.layui-layer-imgbar'); - dict.event(layero); - options.tab && options.tab(data[start], layero); - typeof success === 'function' && success(layero); - }, end: function(){ - dict.end = true; - $(document).off('keyup', dict.keyup); - } - }, options)); - }, function(){ - layer.close(dict.loadi); - layer.msg('当前图片地址异常
                                    是否继续查看下一张?', { - time: 30000, - btn: ['下一张', '不看了'], - yes: function(){ - data.length > 1 && dict.imgnext(true,true); - } - }); - }); -}; - -//主入口 -ready.run = function(_$){ - $ = _$; - win = $(window); - doms.html = $('html'); - layer.open = function(deliver){ - var o = new Class(deliver); - return o.index; - }; -}; - -//加载方式 -window.layui && layui.define ? ( - layer.ready() - ,layui.define('jquery', function(exports){ //layui加载 - layer.path = layui.cache.dir; - ready.run(layui.jquery); - - //暴露模块 - window.layer = layer; - exports('layer', layer); - }) -) : ( - (typeof define === 'function' && define.amd) ? define(['jquery'], function(){ //requirejs加载 - ready.run(window.jQuery); - return layer; - }) : function(){ //普通script标签加载 - ready.run(window.jQuery); - layer.ready(); - }() -); - -}(window); diff --git a/src/lay/modules/laypage.js b/src/lay/modules/laypage.js deleted file mode 100644 index 55041501a..000000000 --- a/src/lay/modules/laypage.js +++ /dev/null @@ -1,162 +0,0 @@ -/** - - @Name : layui.laypage 分页组件 - @Author:贤心 - @License:MIT - - */ - -layui.define(function(exports){ - "use strict"; - - function laypage(options){ - var skin = 'laypagecss'; - new Page(options); - } - - var doc = document, id = 'getElementById', tag = 'getElementsByTagName'; - var index = 0, Page = function(options){ - var that = this; - var conf = that.config = options || {}; - conf.item = index++; - that.render(true); - }; - - Page.on = function(elem, even, fn){ - elem.attachEvent ? elem.attachEvent('on'+ even, function(){ - fn.call(elem, window.even); //for ie, this指向为当前dom元素 - }) : elem.addEventListener(even, fn, false); - return Page; - }; - - //判断传入的容器类型 - Page.prototype.type = function(){ - var conf = this.config; - if(typeof conf.cont === 'object'){ - return conf.cont.length === undefined ? 2 : 3; - } - }; - - //分页视图 - Page.prototype.view = function(){ - var that = this, conf = that.config, view = [], dict = {}; - conf.pages = conf.pages|0; - conf.curr = (conf.curr|0) || 1; - conf.groups = 'groups' in conf ? (conf.groups|0) : 5; - conf.first = 'first' in conf ? conf.first : '首页'; - conf.last = 'last' in conf ? conf.last : '末页'; - conf.prev = 'prev' in conf ? conf.prev : '上一页'; - conf.next = 'next' in conf ? conf.next : '下一页'; - - if(conf.pages <= 1){ - return ''; - } - - if(conf.groups > conf.pages){ - conf.groups = conf.pages; - } - - //计算当前组 - dict.index = Math.ceil((conf.curr + ((conf.groups > 1 && conf.groups !== conf.pages) ? 1 : 0))/(conf.groups === 0 ? 1 : conf.groups)); - - //当前页非首页,则输出上一页 - if(conf.curr > 1 && conf.prev){ - view.push(''+ conf.prev +''); - } - - //当前组非首组,则输出首页 - if(dict.index > 1 && conf.first && conf.groups !== 0){ - view.push(''+ conf.first +''); - } - - //输出当前页组 - dict.poor = Math.floor((conf.groups-1)/2); - dict.start = dict.index > 1 ? conf.curr - dict.poor : 1; - dict.end = dict.index > 1 ? (function(){ - var max = conf.curr + (conf.groups - dict.poor - 1); - return max > conf.pages ? conf.pages : max; - }()) : conf.groups; - if(dict.end - dict.start < conf.groups - 1){ //最后一组状态 - dict.start = dict.end - conf.groups + 1; - } - for(; dict.start <= dict.end; dict.start++){ - if(dict.start === conf.curr){ - view.push(''+ dict.start +''); - } else { - view.push(''+ dict.start +''); - } - } - - //总页数大于连续分页数,且当前组最大页小于总页,输出尾页 - if(conf.pages > conf.groups && dict.end < conf.pages && conf.last && conf.groups !== 0){ - view.push(''+ conf.last +''); - } - - //当前页不为尾页时,输出下一页 - dict.flow = !conf.prev && conf.groups === 0; - if(conf.curr !== conf.pages && conf.next || dict.flow){ - view.push((function(){ - return (dict.flow && conf.curr === conf.pages) - ? ''+ conf.next +'' - : ''+ conf.next +''; - }())); - } - - return '
                                    '+ view.join('') + function(){ - return conf.skip - ? '到第 页 ' - + '' - : ''; - }() +'
                                    '; - }; - - //跳页 - Page.prototype.jump = function(elem){ - if(!elem) return; - var that = this, conf = that.config, childs = elem.children; - var btn = elem[tag]('button')[0]; - var input = elem[tag]('input')[0]; - for(var i = 0, len = childs.length; i < len; i++){ - if(childs[i].nodeName.toLowerCase() === 'a'){ - Page.on(childs[i], 'click', function(){ - var curr = this.getAttribute('data-page')|0; - conf.curr = curr; - that.render(); - - }); - } - } - if(btn){ - Page.on(btn, 'click', function(){ - var curr = input.value.replace(/\s|\D/g, '')|0; - if(curr && curr <= conf.pages){ - conf.curr = curr; - that.render(); - } - }); - } - }; - - //渲染分页 - Page.prototype.render = function(load){ - var that = this, conf = that.config, type = that.type(); - var view = that.view(); - if(type === 2){ - conf.cont.innerHTML = view; - } else if(type === 3){ - conf.cont.html(view); - } else { - doc[id](conf.cont).innerHTML = view; - } - conf.jump && conf.jump(conf, load); - that.jump(doc[id]('layui-laypage-' + conf.item)); - if(conf.hash && !load){ - location.hash = '!'+ conf.hash +'='+ conf.curr; - } - }; - - exports('laypage', laypage); - -}); \ No newline at end of file diff --git a/src/lay/modules/laytpl.js b/src/lay/modules/laytpl.js deleted file mode 100644 index e800196cc..000000000 --- a/src/lay/modules/laytpl.js +++ /dev/null @@ -1,111 +0,0 @@ -/** - - @Name : layui.laytpl 模板引擎 - @Author:贤心 - @License:MIT - - */ - -layui.define(function(exports){ - - "use strict"; - - var config = { - open: '{{', - close: '}}' - }; - - var tool = { - exp: function(str){ - return new RegExp(str, 'g'); - }, - //匹配满足规则内容 - query: function(type, _, __){ - var types = [ - '#([\\s\\S])+?', //js语句 - '([^{#}])*?' //普通字段 - ][type || 0]; - return exp((_||'') + config.open + types + config.close + (__||'')); - }, - escape: function(html){ - return String(html||'').replace(/&(?!#?[a-zA-Z0-9]+;)/g, '&') - .replace(//g, '>').replace(/'/g, ''').replace(/"/g, '"'); - }, - error: function(e, tplog){ - var error = 'Laytpl Error:'; - typeof console === 'object' && console.error(error + e + '\n'+ (tplog || '')); - return error + e; - } - }; - - var exp = tool.exp, Tpl = function(tpl){ - this.tpl = tpl; - }; - - Tpl.pt = Tpl.prototype; - - window.errors = 0; - - //编译模版 - Tpl.pt.parse = function(tpl, data){ - var that = this, tplog = tpl; - var jss = exp('^'+config.open+'#', ''), jsse = exp(config.close+'$', ''); - - tpl = tpl.replace(/\s+|\r|\t|\n/g, ' ').replace(exp(config.open+'#'), config.open+'# ') - - .replace(exp(config.close+'}'), '} '+config.close).replace(/\\/g, '\\\\') - - .replace(/(?="|')/g, '\\').replace(tool.query(), function(str){ - str = str.replace(jss, '').replace(jsse, ''); - return '";' + str.replace(/\\/g, '') + ';view+="'; - }) - - .replace(tool.query(1), function(str){ - var start = '"+('; - if(str.replace(/\s/g, '') === config.open+config.close){ - return ''; - } - str = str.replace(exp(config.open+'|'+config.close), ''); - if(/^=/.test(str)){ - str = str.replace(/^=/, ''); - start = '"+_escape_('; - } - return start + str.replace(/\\/g, '') + ')+"'; - }); - - tpl = '"use strict";var view = "' + tpl + '";return view;'; - - try{ - that.cache = tpl = new Function('d, _escape_', tpl); - return tpl(data, tool.escape); - } catch(e){ - delete that.cache; - return tool.error(e, tplog); - } - }; - - Tpl.pt.render = function(data, callback){ - var that = this, tpl; - if(!data) return tool.error('no data'); - tpl = that.cache ? that.cache(data, tool.escape) : that.parse(that.tpl, data); - if(!callback) return tpl; - callback(tpl); - }; - - var laytpl = function(tpl){ - if(typeof tpl !== 'string') return tool.error('Template not found'); - return new Tpl(tpl); - }; - - laytpl.config = function(options){ - options = options || {}; - for(var i in options){ - config[i] = options[i]; - } - }; - - laytpl.v = '1.2.0'; - - exports('laytpl', laytpl); - -}); \ No newline at end of file diff --git a/src/lay/modules/mobile.js b/src/lay/modules/mobile.js deleted file mode 100644 index e6f00164d..000000000 --- a/src/lay/modules/mobile.js +++ /dev/null @@ -1,30 +0,0 @@ -/** - - @Name:layui 移动模块入口 | 构建后则为移动模块集合 - @Author:贤心 - @License:MIT - - */ - - -if(!layui['layui.mobile']){ - layui.config({ - base: layui.cache.dir + 'lay/modules/mobile/' - }).extend({ - 'layer-mobile': 'layer-mobile' - ,'zepto': 'zepto' - ,'upload-mobile': 'upload-mobile' - ,'layim-mobile': 'layim-mobile' - }); -} - -layui.define([ - 'layer-mobile' - ,'zepto' - ,'layim-mobile' -], function(exports){ - exports('mobile', { - layer: layui['layer-mobile'] //弹层 - ,layim: layui['layim-mobile'] //WebIM - }); -}); \ No newline at end of file diff --git a/src/lay/modules/mobile/layer-mobile.js b/src/lay/modules/mobile/layer-mobile.js deleted file mode 100644 index 1b9ff1f37..000000000 --- a/src/lay/modules/mobile/layer-mobile.js +++ /dev/null @@ -1,189 +0,0 @@ -/*! - - @Name:layer mobile v2.0.0 弹层组件移动版 - @Author:贤心 - @Site:http://layer.layui.com/mobie/ - @License:MIT - - */ - -layui.define(function(exports){ - - "use strict"; - - var win = window, doc = document, query = 'querySelectorAll', claname = 'getElementsByClassName', S = function(s){ - return doc[query](s); - }; - - //默认配置 - var config = { - type: 0 - ,shade: true - ,shadeClose: true - ,fixed: true - ,anim: 'scale' //默认动画类型 - }; - - var ready = { - extend: function(obj){ - var newobj = JSON.parse(JSON.stringify(config)); - for(var i in obj){ - newobj[i] = obj[i]; - } - return newobj; - }, - timer: {}, end: {} - }; - - //点触事件 - ready.touch = function(elem, fn){ - elem.addEventListener('click', function(e){ - fn.call(this, e); - }, false); - }; - - var index = 0, classs = ['layui-m-layer'], Layer = function(options){ - var that = this; - that.config = ready.extend(options); - that.view(); - }; - - Layer.prototype.view = function(){ - var that = this, config = that.config, layerbox = doc.createElement('div'); - - that.id = layerbox.id = classs[0] + index; - layerbox.setAttribute('class', classs[0] + ' ' + classs[0]+(config.type || 0)); - layerbox.setAttribute('index', index); - - //标题区域 - var title = (function(){ - var titype = typeof config.title === 'object'; - return config.title - ? '

                                    '+ (titype ? config.title[0] : config.title) +'

                                    ' - : ''; - }()); - - //按钮区域 - var button = (function(){ - typeof config.btn === 'string' && (config.btn = [config.btn]); - var btns = (config.btn || []).length, btndom; - if(btns === 0 || !config.btn){ - return ''; - } - btndom = ''+ config.btn[0] +'' - if(btns === 2){ - btndom = ''+ config.btn[1] +'' + btndom; - } - return '
                                    '+ btndom + '
                                    '; - }()); - - if(!config.fixed){ - config.top = config.hasOwnProperty('top') ? config.top : 100; - config.style = config.style || ''; - config.style += ' top:'+ ( doc.body.scrollTop + config.top) + 'px'; - } - - if(config.type === 2){ - config.content = '

                                    '+ (config.content||'') +'

                                    '; - } - - if(config.skin) config.anim = 'up'; - if(config.skin === 'msg') config.shade = false; - - layerbox.innerHTML = (config.shade ? '
                                    ' : '') - +'
                                    ' - +'
                                    ' - +'
                                    ' - + title - +'
                                    '+ config.content +'
                                    ' - + button - +'
                                    ' - +'
                                    ' - +'
                                    '; - - if(!config.type || config.type === 2){ - var dialogs = doc[claname](classs[0] + config.type), dialen = dialogs.length; - if(dialen >= 1){ - layer.close(dialogs[0].getAttribute('index')) - } - } - - document.body.appendChild(layerbox); - var elem = that.elem = S('#'+that.id)[0]; - config.success && config.success(elem); - - that.index = index++; - that.action(config, elem); - }; - - Layer.prototype.action = function(config, elem){ - var that = this; - - //自动关闭 - if(config.time){ - ready.timer[that.index] = setTimeout(function(){ - layer.close(that.index); - }, config.time*1000); - } - - //确认取消 - var btn = function(){ - var type = this.getAttribute('type'); - if(type == 0){ - config.no && config.no(); - layer.close(that.index); - } else { - config.yes ? config.yes(that.index) : layer.close(that.index); - } - }; - if(config.btn){ - var btns = elem[claname]('layui-m-layerbtn')[0].children, btnlen = btns.length; - for(var ii = 0; ii < btnlen; ii++){ - ready.touch(btns[ii], btn); - } - } - - //点遮罩关闭 - if(config.shade && config.shadeClose){ - var shade = elem[claname]('layui-m-layershade')[0]; - ready.touch(shade, function(){ - layer.close(that.index, config.end); - }); - } - - config.end && (ready.end[that.index] = config.end); - }; - - var layer = { - v: '2.0 m', - index: index, - - //核心方法 - open: function(options){ - var o = new Layer(options || {}); - return o.index; - }, - - close: function(index){ - var ibox = S('#'+classs[0]+index)[0]; - if(!ibox) return; - ibox.innerHTML = ''; - doc.body.removeChild(ibox); - clearTimeout(ready.timer[index]); - delete ready.timer[index]; - typeof ready.end[index] === 'function' && ready.end[index](); - delete ready.end[index]; - }, - - //关闭所有layer层 - closeAll: function(){ - var boxs = doc[claname](classs[0]); - for(var i = 0, len = boxs.length; i < len; i++){ - layer.close((boxs[0].getAttribute('index')|0)); - } - } - }; - - exports('layer-mobile', layer); - -}); \ No newline at end of file diff --git a/src/lay/modules/mobile/layim-mobile-open.js b/src/lay/modules/mobile/layim-mobile-open.js deleted file mode 100644 index bd623c548..000000000 --- a/src/lay/modules/mobile/layim-mobile-open.js +++ /dev/null @@ -1,11 +0,0 @@ -/** - - @Name:layim mobile 开源包 - @Author:贤心 - @License:MIT - - */ - -layui.define(function(exports){ - exports('layim-mobile', layui.v); -}); \ No newline at end of file diff --git a/src/lay/modules/mobile/upload-mobile.js b/src/lay/modules/mobile/upload-mobile.js deleted file mode 100644 index 4f4ac7abe..000000000 --- a/src/lay/modules/mobile/upload-mobile.js +++ /dev/null @@ -1,166 +0,0 @@ -/*! - - @Title: layui.upload 单文件上传 - 全浏览器兼容版 - @Author: 贤心 - @License:MIT - - */ - -layui.define(['layer-mobile', 'zepto'] , function(exports){ - "use strict"; - - var $ = layui.zepto; - var layer = layui['layer-mobile']; - var device = layui.device(); - - var elemDragEnter = 'layui-upload-enter'; - var elemIframe = 'layui-upload-iframe'; - - var msgConf = { - icon: 2 - ,shift: 6 - }, fileType = { - file: '文件' - ,video: '视频' - ,audio: '音频' - }; - - layer.msg = function(content){ - return layer.open({ - content: content || '' - ,skin: 'msg' - ,time: 2 //2秒后自动关闭 - }); - }; - - var Upload = function(options){ - this.options = options; - }; - - //初始化渲染 - Upload.prototype.init = function(){ - var that = this, options = that.options; - var body = $('body'), elem = $(options.elem || '.layui-upload-file'); - var iframe = $(''); - - //插入iframe - $('#'+elemIframe)[0] || body.append(iframe); - - return elem.each(function(index, item){ - item = $(item); - var form = '
                                    '; - - var type = item.attr('lay-type') || options.type; //获取文件类型 - - //包裹ui元素 - if(!options.unwrap){ - form = '
                                    ' + form + ''+ ( - item.attr('lay-title') || options.title|| ('上传'+ (fileType[type]||'图片') ) - ) +'
                                    '; - } - - form = $(form); - - //拖拽支持 - if(!options.unwrap){ - form.on('dragover', function(e){ - e.preventDefault(); - $(this).addClass(elemDragEnter); - }).on('dragleave', function(){ - $(this).removeClass(elemDragEnter); - }).on('drop', function(){ - $(this).removeClass(elemDragEnter); - }); - } - - //如果已经实例化,则移除包裹元素 - if(item.parent('form').attr('target') === elemIframe){ - if(options.unwrap){ - item.unwrap(); - } else { - item.parent().next().remove(); - item.unwrap().unwrap(); - } - }; - - //包裹元素 - item.wrap(form); - - //触发上传 - item.off('change').on('change', function(){ - that.action(this, type); - }); - }); - }; - - //提交上传 - Upload.prototype.action = function(input, type){ - var that = this, options = that.options, val = input.value; - var item = $(input), ext = item.attr('lay-ext') || options.ext || ''; //获取支持上传的文件扩展名; - - if(!val){ - return; - }; - - //校验文件 - switch(type){ - case 'file': //一般文件 - if(ext && !RegExp('\\w\\.('+ ext +')$', 'i').test(escape(val))){ - layer.msg('不支持该文件格式', msgConf); - return input.value = ''; - } - break; - case 'video': //视频文件 - if(!RegExp('\\w\\.('+ (ext||'avi|mp4|wma|rmvb|rm|flash|3gp|flv') +')$', 'i').test(escape(val))){ - layer.msg('不支持该视频格式', msgConf); - return input.value = ''; - } - break; - case 'audio': //音频文件 - if(!RegExp('\\w\\.('+ (ext||'mp3|wav|mid') +')$', 'i').test(escape(val))){ - layer.msg('不支持该音频格式', msgConf); - return input.value = ''; - } - break; - default: //图片文件 - if(!RegExp('\\w\\.('+ (ext||'jpg|png|gif|bmp|jpeg') +')$', 'i').test(escape(val))){ - layer.msg('不支持该图片格式', msgConf); - return input.value = ''; - } - break; - } - - options.before && options.before(input); - item.parent().submit(); - - var iframe = $('#'+elemIframe), timer = setInterval(function() { - var res; - try { - res = iframe.contents().find('body').text(); - } catch(e) { - layer.msg('上传接口存在跨域', msgConf); - clearInterval(timer); - } - if(res){ - clearInterval(timer); - iframe.contents().find('body').html(''); - try { - res = JSON.parse(res); - } catch(e){ - res = {}; - return layer.msg('请对上传接口返回JSON字符', msgConf); - } - typeof options.success === 'function' && options.success(res, input); - } - }, 30); - - input.value = ''; - }; - - //暴露接口 - exports('upload-mobile', function(options){ - var upload = new Upload(options = options || {}); - upload.init(); - }); -}); - diff --git a/src/lay/modules/mobile/zepto.js b/src/lay/modules/mobile/zepto.js deleted file mode 100644 index 404ec0b8c..000000000 --- a/src/lay/modules/mobile/zepto.js +++ /dev/null @@ -1,1646 +0,0 @@ -/* Zepto v1.2.0 - zepto event ajax form ie - zeptojs.com/license */ - -layui.define(function(exports){ - - var Zepto = (function() { - var undefined, key, $, classList, emptyArray = [], concat = emptyArray.concat, filter = emptyArray.filter, slice = emptyArray.slice, - document = window.document, - elementDisplay = {}, classCache = {}, - cssNumber = { 'column-count': 1, 'columns': 1, 'font-weight': 1, 'line-height': 1,'opacity': 1, 'z-index': 1, 'zoom': 1 }, - fragmentRE = /^\s*<(\w+|!)[^>]*>/, - singleTagRE = /^<(\w+)\s*\/?>(?:<\/\1>|)$/, - tagExpanderRE = /<(?!area|br|col|embed|hr|img|input|link|meta|param)(([\w:]+)[^>]*)\/>/ig, - rootNodeRE = /^(?:body|html)$/i, - capitalRE = /([A-Z])/g, - - // special attributes that should be get/set via method calls - methodAttributes = ['val', 'css', 'html', 'text', 'data', 'width', 'height', 'offset'], - - adjacencyOperators = [ 'after', 'prepend', 'before', 'append' ], - table = document.createElement('table'), - tableRow = document.createElement('tr'), - containers = { - 'tr': document.createElement('tbody'), - 'tbody': table, 'thead': table, 'tfoot': table, - 'td': tableRow, 'th': tableRow, - '*': document.createElement('div') - }, - readyRE = /complete|loaded|interactive/, - simpleSelectorRE = /^[\w-]*$/, - class2type = {}, - toString = class2type.toString, - zepto = {}, - camelize, uniq, - tempParent = document.createElement('div'), - propMap = { - 'tabindex': 'tabIndex', - 'readonly': 'readOnly', - 'for': 'htmlFor', - 'class': 'className', - 'maxlength': 'maxLength', - 'cellspacing': 'cellSpacing', - 'cellpadding': 'cellPadding', - 'rowspan': 'rowSpan', - 'colspan': 'colSpan', - 'usemap': 'useMap', - 'frameborder': 'frameBorder', - 'contenteditable': 'contentEditable' - }, - isArray = Array.isArray || - function(object){ return object instanceof Array } - - zepto.matches = function(element, selector) { - if (!selector || !element || element.nodeType !== 1) return false - var matchesSelector = element.matches || element.webkitMatchesSelector || - element.mozMatchesSelector || element.oMatchesSelector || - element.matchesSelector - if (matchesSelector) return matchesSelector.call(element, selector) - // fall back to performing a selector: - var match, parent = element.parentNode, temp = !parent - if (temp) (parent = tempParent).appendChild(element) - match = ~zepto.qsa(parent, selector).indexOf(element) - temp && tempParent.removeChild(element) - return match - } - - function type(obj) { - return obj == null ? String(obj) : - class2type[toString.call(obj)] || "object" - } - - function isFunction(value) { return type(value) == "function" } - function isWindow(obj) { return obj != null && obj == obj.window } - function isDocument(obj) { return obj != null && obj.nodeType == obj.DOCUMENT_NODE } - function isObject(obj) { return type(obj) == "object" } - function isPlainObject(obj) { - return isObject(obj) && !isWindow(obj) && Object.getPrototypeOf(obj) == Object.prototype - } - - function likeArray(obj) { - var length = !!obj && 'length' in obj && obj.length, - type = $.type(obj) - - return 'function' != type && !isWindow(obj) && ( - 'array' == type || length === 0 || - (typeof length == 'number' && length > 0 && (length - 1) in obj) - ) - } - - function compact(array) { return filter.call(array, function(item){ return item != null }) } - function flatten(array) { return array.length > 0 ? $.fn.concat.apply([], array) : array } - camelize = function(str){ return str.replace(/-+(.)?/g, function(match, chr){ return chr ? chr.toUpperCase() : '' }) } - function dasherize(str) { - return str.replace(/::/g, '/') - .replace(/([A-Z]+)([A-Z][a-z])/g, '$1_$2') - .replace(/([a-z\d])([A-Z])/g, '$1_$2') - .replace(/_/g, '-') - .toLowerCase() - } - uniq = function(array){ return filter.call(array, function(item, idx){ return array.indexOf(item) == idx }) } - - function classRE(name) { - return name in classCache ? - classCache[name] : (classCache[name] = new RegExp('(^|\\s)' + name + '(\\s|$)')) - } - - function maybeAddPx(name, value) { - return (typeof value == "number" && !cssNumber[dasherize(name)]) ? value + "px" : value - } - - function defaultDisplay(nodeName) { - var element, display - if (!elementDisplay[nodeName]) { - element = document.createElement(nodeName) - document.body.appendChild(element) - display = getComputedStyle(element, '').getPropertyValue("display") - element.parentNode.removeChild(element) - display == "none" && (display = "block") - elementDisplay[nodeName] = display - } - return elementDisplay[nodeName] - } - - function children(element) { - return 'children' in element ? - slice.call(element.children) : - $.map(element.childNodes, function(node){ if (node.nodeType == 1) return node }) - } - - function Z(dom, selector) { - var i, len = dom ? dom.length : 0 - for (i = 0; i < len; i++) this[i] = dom[i] - this.length = len - this.selector = selector || '' - } - - // `$.zepto.fragment` takes a html string and an optional tag name - // to generate DOM nodes from the given html string. - // The generated DOM nodes are returned as an array. - // This function can be overridden in plugins for example to make - // it compatible with browsers that don't support the DOM fully. - zepto.fragment = function(html, name, properties) { - var dom, nodes, container - - // A special case optimization for a single tag - if (singleTagRE.test(html)) dom = $(document.createElement(RegExp.$1)) - - if (!dom) { - if (html.replace) html = html.replace(tagExpanderRE, "<$1>") - if (name === undefined) name = fragmentRE.test(html) && RegExp.$1 - if (!(name in containers)) name = '*' - - container = containers[name] - container.innerHTML = '' + html - dom = $.each(slice.call(container.childNodes), function(){ - container.removeChild(this) - }) - } - - if (isPlainObject(properties)) { - nodes = $(dom) - $.each(properties, function(key, value) { - if (methodAttributes.indexOf(key) > -1) nodes[key](value) - else nodes.attr(key, value) - }) - } - - return dom - } - - // `$.zepto.Z` swaps out the prototype of the given `dom` array - // of nodes with `$.fn` and thus supplying all the Zepto functions - // to the array. This method can be overridden in plugins. - zepto.Z = function(dom, selector) { - return new Z(dom, selector) - } - - // `$.zepto.isZ` should return `true` if the given object is a Zepto - // collection. This method can be overridden in plugins. - zepto.isZ = function(object) { - return object instanceof zepto.Z - } - - // `$.zepto.init` is Zepto's counterpart to jQuery's `$.fn.init` and - // takes a CSS selector and an optional context (and handles various - // special cases). - // This method can be overridden in plugins. - zepto.init = function(selector, context) { - var dom - // If nothing given, return an empty Zepto collection - if (!selector) return zepto.Z() - // Optimize for string selectors - else if (typeof selector == 'string') { - selector = selector.trim() - // If it's a html fragment, create nodes from it - // Note: In both Chrome 21 and Firefox 15, DOM error 12 - // is thrown if the fragment doesn't begin with < - if (selector[0] == '<' && fragmentRE.test(selector)) - dom = zepto.fragment(selector, RegExp.$1, context), selector = null - // If there's a context, create a collection on that context first, and select - // nodes from there - else if (context !== undefined) return $(context).find(selector) - // If it's a CSS selector, use it to select nodes. - else dom = zepto.qsa(document, selector) - } - // If a function is given, call it when the DOM is ready - else if (isFunction(selector)) return $(document).ready(selector) - // If a Zepto collection is given, just return it - else if (zepto.isZ(selector)) return selector - else { - // normalize array if an array of nodes is given - if (isArray(selector)) dom = compact(selector) - // Wrap DOM nodes. - else if (isObject(selector)) - dom = [selector], selector = null - // If it's a html fragment, create nodes from it - else if (fragmentRE.test(selector)) - dom = zepto.fragment(selector.trim(), RegExp.$1, context), selector = null - // If there's a context, create a collection on that context first, and select - // nodes from there - else if (context !== undefined) return $(context).find(selector) - // And last but no least, if it's a CSS selector, use it to select nodes. - else dom = zepto.qsa(document, selector) - } - // create a new Zepto collection from the nodes found - return zepto.Z(dom, selector) - } - - // `$` will be the base `Zepto` object. When calling this - // function just call `$.zepto.init, which makes the implementation - // details of selecting nodes and creating Zepto collections - // patchable in plugins. - $ = function(selector, context){ - return zepto.init(selector, context) - } - - function extend(target, source, deep) { - for (key in source) - if (deep && (isPlainObject(source[key]) || isArray(source[key]))) { - if (isPlainObject(source[key]) && !isPlainObject(target[key])) - target[key] = {} - if (isArray(source[key]) && !isArray(target[key])) - target[key] = [] - extend(target[key], source[key], deep) - } - else if (source[key] !== undefined) target[key] = source[key] - } - - // Copy all but undefined properties from one or more - // objects to the `target` object. - $.extend = function(target){ - var deep, args = slice.call(arguments, 1) - if (typeof target == 'boolean') { - deep = target - target = args.shift() - } - args.forEach(function(arg){ extend(target, arg, deep) }) - return target - } - - // `$.zepto.qsa` is Zepto's CSS selector implementation which - // uses `document.querySelectorAll` and optimizes for some special cases, like `#id`. - // This method can be overridden in plugins. - zepto.qsa = function(element, selector){ - var found, - maybeID = selector[0] == '#', - maybeClass = !maybeID && selector[0] == '.', - nameOnly = maybeID || maybeClass ? selector.slice(1) : selector, // Ensure that a 1 char tag name still gets checked - isSimple = simpleSelectorRE.test(nameOnly) - return (element.getElementById && isSimple && maybeID) ? // Safari DocumentFragment doesn't have getElementById - ( (found = element.getElementById(nameOnly)) ? [found] : [] ) : - (element.nodeType !== 1 && element.nodeType !== 9 && element.nodeType !== 11) ? [] : - slice.call( - isSimple && !maybeID && element.getElementsByClassName ? // DocumentFragment doesn't have getElementsByClassName/TagName - maybeClass ? element.getElementsByClassName(nameOnly) : // If it's simple, it could be a class - element.getElementsByTagName(selector) : // Or a tag - element.querySelectorAll(selector) // Or it's not simple, and we need to query all - ) - } - - function filtered(nodes, selector) { - return selector == null ? $(nodes) : $(nodes).filter(selector) - } - - $.contains = document.documentElement.contains ? - function(parent, node) { - return parent !== node && parent.contains(node) - } : - function(parent, node) { - while (node && (node = node.parentNode)) - if (node === parent) return true - return false - } - - function funcArg(context, arg, idx, payload) { - return isFunction(arg) ? arg.call(context, idx, payload) : arg - } - - function setAttribute(node, name, value) { - value == null ? node.removeAttribute(name) : node.setAttribute(name, value) - } - - // access className property while respecting SVGAnimatedString - function className(node, value){ - var klass = node.className || '', - svg = klass && klass.baseVal !== undefined - - if (value === undefined) return svg ? klass.baseVal : klass - svg ? (klass.baseVal = value) : (node.className = value) - } - - // "true" => true - // "false" => false - // "null" => null - // "42" => 42 - // "42.5" => 42.5 - // "08" => "08" - // JSON => parse if valid - // String => self - function deserializeValue(value) { - try { - return value ? - value == "true" || - ( value == "false" ? false : - value == "null" ? null : - +value + "" == value ? +value : - /^[\[\{]/.test(value) ? $.parseJSON(value) : - value ) - : value - } catch(e) { - return value - } - } - - $.type = type - $.isFunction = isFunction - $.isWindow = isWindow - $.isArray = isArray - $.isPlainObject = isPlainObject - - $.isEmptyObject = function(obj) { - var name - for (name in obj) return false - return true - } - - $.isNumeric = function(val) { - var num = Number(val), type = typeof val - return val != null && type != 'boolean' && - (type != 'string' || val.length) && - !isNaN(num) && isFinite(num) || false - } - - $.inArray = function(elem, array, i){ - return emptyArray.indexOf.call(array, elem, i) - } - - $.camelCase = camelize - $.trim = function(str) { - return str == null ? "" : String.prototype.trim.call(str) - } - - // plugin compatibility - $.uuid = 0 - $.support = { } - $.expr = { } - $.noop = function() {} - - $.map = function(elements, callback){ - var value, values = [], i, key - if (likeArray(elements)) - for (i = 0; i < elements.length; i++) { - value = callback(elements[i], i) - if (value != null) values.push(value) - } - else - for (key in elements) { - value = callback(elements[key], key) - if (value != null) values.push(value) - } - return flatten(values) - } - - $.each = function(elements, callback){ - var i, key - if (likeArray(elements)) { - for (i = 0; i < elements.length; i++) - if (callback.call(elements[i], i, elements[i]) === false) return elements - } else { - for (key in elements) - if (callback.call(elements[key], key, elements[key]) === false) return elements - } - - return elements - } - - $.grep = function(elements, callback){ - return filter.call(elements, callback) - } - - if (window.JSON) $.parseJSON = JSON.parse - - // Populate the class2type map - $.each("Boolean Number String Function Array Date RegExp Object Error".split(" "), function(i, name) { - class2type[ "[object " + name + "]" ] = name.toLowerCase() - }) - - // Define methods that will be available on all - // Zepto collections - $.fn = { - constructor: zepto.Z, - length: 0, - - // Because a collection acts like an array - // copy over these useful array functions. - forEach: emptyArray.forEach, - reduce: emptyArray.reduce, - push: emptyArray.push, - sort: emptyArray.sort, - splice: emptyArray.splice, - indexOf: emptyArray.indexOf, - concat: function(){ - var i, value, args = [] - for (i = 0; i < arguments.length; i++) { - value = arguments[i] - args[i] = zepto.isZ(value) ? value.toArray() : value - } - return concat.apply(zepto.isZ(this) ? this.toArray() : this, args) - }, - - // `map` and `slice` in the jQuery API work differently - // from their array counterparts - map: function(fn){ - return $($.map(this, function(el, i){ return fn.call(el, i, el) })) - }, - slice: function(){ - return $(slice.apply(this, arguments)) - }, - - ready: function(callback){ - // need to check if document.body exists for IE as that browser reports - // document ready when it hasn't yet created the body element - if (readyRE.test(document.readyState) && document.body) callback($) - else document.addEventListener('DOMContentLoaded', function(){ callback($) }, false) - return this - }, - get: function(idx){ - return idx === undefined ? slice.call(this) : this[idx >= 0 ? idx : idx + this.length] - }, - toArray: function(){ return this.get() }, - size: function(){ - return this.length - }, - remove: function(){ - return this.each(function(){ - if (this.parentNode != null) - this.parentNode.removeChild(this) - }) - }, - each: function(callback){ - emptyArray.every.call(this, function(el, idx){ - return callback.call(el, idx, el) !== false - }) - return this - }, - filter: function(selector){ - if (isFunction(selector)) return this.not(this.not(selector)) - return $(filter.call(this, function(element){ - return zepto.matches(element, selector) - })) - }, - add: function(selector,context){ - return $(uniq(this.concat($(selector,context)))) - }, - is: function(selector){ - return this.length > 0 && zepto.matches(this[0], selector) - }, - not: function(selector){ - var nodes=[] - if (isFunction(selector) && selector.call !== undefined) - this.each(function(idx){ - if (!selector.call(this,idx)) nodes.push(this) - }) - else { - var excludes = typeof selector == 'string' ? this.filter(selector) : - (likeArray(selector) && isFunction(selector.item)) ? slice.call(selector) : $(selector) - this.forEach(function(el){ - if (excludes.indexOf(el) < 0) nodes.push(el) - }) - } - return $(nodes) - }, - has: function(selector){ - return this.filter(function(){ - return isObject(selector) ? - $.contains(this, selector) : - $(this).find(selector).size() - }) - }, - eq: function(idx){ - return idx === -1 ? this.slice(idx) : this.slice(idx, + idx + 1) - }, - first: function(){ - var el = this[0] - return el && !isObject(el) ? el : $(el) - }, - last: function(){ - var el = this[this.length - 1] - return el && !isObject(el) ? el : $(el) - }, - find: function(selector){ - var result, $this = this - if (!selector) result = $() - else if (typeof selector == 'object') - result = $(selector).filter(function(){ - var node = this - return emptyArray.some.call($this, function(parent){ - return $.contains(parent, node) - }) - }) - else if (this.length == 1) result = $(zepto.qsa(this[0], selector)) - else result = this.map(function(){ return zepto.qsa(this, selector) }) - return result - }, - closest: function(selector, context){ - var nodes = [], collection = typeof selector == 'object' && $(selector) - this.each(function(_, node){ - while (node && !(collection ? collection.indexOf(node) >= 0 : zepto.matches(node, selector))) - node = node !== context && !isDocument(node) && node.parentNode - if (node && nodes.indexOf(node) < 0) nodes.push(node) - }) - return $(nodes) - }, - parents: function(selector){ - var ancestors = [], nodes = this - while (nodes.length > 0) - nodes = $.map(nodes, function(node){ - if ((node = node.parentNode) && !isDocument(node) && ancestors.indexOf(node) < 0) { - ancestors.push(node) - return node - } - }) - return filtered(ancestors, selector) - }, - parent: function(selector){ - return filtered(uniq(this.pluck('parentNode')), selector) - }, - children: function(selector){ - return filtered(this.map(function(){ return children(this) }), selector) - }, - contents: function() { - return this.map(function() { return this.contentDocument || slice.call(this.childNodes) }) - }, - siblings: function(selector){ - return filtered(this.map(function(i, el){ - return filter.call(children(el.parentNode), function(child){ return child!==el }) - }), selector) - }, - empty: function(){ - return this.each(function(){ this.innerHTML = '' }) - }, - // `pluck` is borrowed from Prototype.js - pluck: function(property){ - return $.map(this, function(el){ return el[property] }) - }, - show: function(){ - return this.each(function(){ - this.style.display == "none" && (this.style.display = '') - if (getComputedStyle(this, '').getPropertyValue("display") == "none") - this.style.display = defaultDisplay(this.nodeName) - }) - }, - replaceWith: function(newContent){ - return this.before(newContent).remove() - }, - wrap: function(structure){ - var func = isFunction(structure) - if (this[0] && !func) - var dom = $(structure).get(0), - clone = dom.parentNode || this.length > 1 - - return this.each(function(index){ - $(this).wrapAll( - func ? structure.call(this, index) : - clone ? dom.cloneNode(true) : dom - ) - }) - }, - wrapAll: function(structure){ - if (this[0]) { - $(this[0]).before(structure = $(structure)) - var children - // drill down to the inmost element - while ((children = structure.children()).length) structure = children.first() - $(structure).append(this) - } - return this - }, - wrapInner: function(structure){ - var func = isFunction(structure) - return this.each(function(index){ - var self = $(this), contents = self.contents(), - dom = func ? structure.call(this, index) : structure - contents.length ? contents.wrapAll(dom) : self.append(dom) - }) - }, - unwrap: function(){ - this.parent().each(function(){ - $(this).replaceWith($(this).children()) - }) - return this - }, - clone: function(){ - return this.map(function(){ return this.cloneNode(true) }) - }, - hide: function(){ - return this.css("display", "none") - }, - toggle: function(setting){ - return this.each(function(){ - var el = $(this) - ;(setting === undefined ? el.css("display") == "none" : setting) ? el.show() : el.hide() - }) - }, - prev: function(selector){ return $(this.pluck('previousElementSibling')).filter(selector || '*') }, - next: function(selector){ return $(this.pluck('nextElementSibling')).filter(selector || '*') }, - html: function(html){ - return 0 in arguments ? - this.each(function(idx){ - var originHtml = this.innerHTML - $(this).empty().append( funcArg(this, html, idx, originHtml) ) - }) : - (0 in this ? this[0].innerHTML : null) - }, - text: function(text){ - return 0 in arguments ? - this.each(function(idx){ - var newText = funcArg(this, text, idx, this.textContent) - this.textContent = newText == null ? '' : ''+newText - }) : - (0 in this ? this.pluck('textContent').join("") : null) - }, - attr: function(name, value){ - var result - return (typeof name == 'string' && !(1 in arguments)) ? - (0 in this && this[0].nodeType == 1 && (result = this[0].getAttribute(name)) != null ? result : undefined) : - this.each(function(idx){ - if (this.nodeType !== 1) return - if (isObject(name)) for (key in name) setAttribute(this, key, name[key]) - else setAttribute(this, name, funcArg(this, value, idx, this.getAttribute(name))) - }) - }, - removeAttr: function(name){ - return this.each(function(){ this.nodeType === 1 && name.split(' ').forEach(function(attribute){ - setAttribute(this, attribute) - }, this)}) - }, - prop: function(name, value){ - name = propMap[name] || name - return (1 in arguments) ? - this.each(function(idx){ - this[name] = funcArg(this, value, idx, this[name]) - }) : - (this[0] && this[0][name]) - }, - removeProp: function(name){ - name = propMap[name] || name - return this.each(function(){ delete this[name] }) - }, - data: function(name, value){ - var attrName = 'data-' + name.replace(capitalRE, '-$1').toLowerCase() - - var data = (1 in arguments) ? - this.attr(attrName, value) : - this.attr(attrName) - - return data !== null ? deserializeValue(data) : undefined - }, - val: function(value){ - if (0 in arguments) { - if (value == null) value = "" - return this.each(function(idx){ - this.value = funcArg(this, value, idx, this.value) - }) - } else { - return this[0] && (this[0].multiple ? - $(this[0]).find('option').filter(function(){ return this.selected }).pluck('value') : - this[0].value) - } - }, - offset: function(coordinates){ - if (coordinates) return this.each(function(index){ - var $this = $(this), - coords = funcArg(this, coordinates, index, $this.offset()), - parentOffset = $this.offsetParent().offset(), - props = { - top: coords.top - parentOffset.top, - left: coords.left - parentOffset.left - } - - if ($this.css('position') == 'static') props['position'] = 'relative' - $this.css(props) - }) - if (!this.length) return null - if (document.documentElement !== this[0] && !$.contains(document.documentElement, this[0])) - return {top: 0, left: 0} - var obj = this[0].getBoundingClientRect() - return { - left: obj.left + window.pageXOffset, - top: obj.top + window.pageYOffset, - width: Math.round(obj.width), - height: Math.round(obj.height) - } - }, - css: function(property, value){ - if (arguments.length < 2) { - var element = this[0] - if (typeof property == 'string') { - if (!element) return - return element.style[camelize(property)] || getComputedStyle(element, '').getPropertyValue(property) - } else if (isArray(property)) { - if (!element) return - var props = {} - var computedStyle = getComputedStyle(element, '') - $.each(property, function(_, prop){ - props[prop] = (element.style[camelize(prop)] || computedStyle.getPropertyValue(prop)) - }) - return props - } - } - - var css = '' - if (type(property) == 'string') { - if (!value && value !== 0) - this.each(function(){ this.style.removeProperty(dasherize(property)) }) - else - css = dasherize(property) + ":" + maybeAddPx(property, value) - } else { - for (key in property) - if (!property[key] && property[key] !== 0) - this.each(function(){ this.style.removeProperty(dasherize(key)) }) - else - css += dasherize(key) + ':' + maybeAddPx(key, property[key]) + ';' - } - - return this.each(function(){ this.style.cssText += ';' + css }) - }, - index: function(element){ - return element ? this.indexOf($(element)[0]) : this.parent().children().indexOf(this[0]) - }, - hasClass: function(name){ - if (!name) return false - return emptyArray.some.call(this, function(el){ - return this.test(className(el)) - }, classRE(name)) - }, - addClass: function(name){ - if (!name) return this - return this.each(function(idx){ - if (!('className' in this)) return - classList = [] - var cls = className(this), newName = funcArg(this, name, idx, cls) - newName.split(/\s+/g).forEach(function(klass){ - if (!$(this).hasClass(klass)) classList.push(klass) - }, this) - classList.length && className(this, cls + (cls ? " " : "") + classList.join(" ")) - }) - }, - removeClass: function(name){ - return this.each(function(idx){ - if (!('className' in this)) return - if (name === undefined) return className(this, '') - classList = className(this) - funcArg(this, name, idx, classList).split(/\s+/g).forEach(function(klass){ - classList = classList.replace(classRE(klass), " ") - }) - className(this, classList.trim()) - }) - }, - toggleClass: function(name, when){ - if (!name) return this - return this.each(function(idx){ - var $this = $(this), names = funcArg(this, name, idx, className(this)) - names.split(/\s+/g).forEach(function(klass){ - (when === undefined ? !$this.hasClass(klass) : when) ? - $this.addClass(klass) : $this.removeClass(klass) - }) - }) - }, - scrollTop: function(value){ - if (!this.length) return - var hasScrollTop = 'scrollTop' in this[0] - if (value === undefined) return hasScrollTop ? this[0].scrollTop : this[0].pageYOffset - return this.each(hasScrollTop ? - function(){ this.scrollTop = value } : - function(){ this.scrollTo(this.scrollX, value) }) - }, - scrollLeft: function(value){ - if (!this.length) return - var hasScrollLeft = 'scrollLeft' in this[0] - if (value === undefined) return hasScrollLeft ? this[0].scrollLeft : this[0].pageXOffset - return this.each(hasScrollLeft ? - function(){ this.scrollLeft = value } : - function(){ this.scrollTo(value, this.scrollY) }) - }, - position: function() { - if (!this.length) return - - var elem = this[0], - // Get *real* offsetParent - offsetParent = this.offsetParent(), - // Get correct offsets - offset = this.offset(), - parentOffset = rootNodeRE.test(offsetParent[0].nodeName) ? { top: 0, left: 0 } : offsetParent.offset() - - // Subtract element margins - // note: when an element has margin: auto the offsetLeft and marginLeft - // are the same in Safari causing offset.left to incorrectly be 0 - offset.top -= parseFloat( $(elem).css('margin-top') ) || 0 - offset.left -= parseFloat( $(elem).css('margin-left') ) || 0 - - // Add offsetParent borders - parentOffset.top += parseFloat( $(offsetParent[0]).css('border-top-width') ) || 0 - parentOffset.left += parseFloat( $(offsetParent[0]).css('border-left-width') ) || 0 - - // Subtract the two offsets - return { - top: offset.top - parentOffset.top, - left: offset.left - parentOffset.left - } - }, - offsetParent: function() { - return this.map(function(){ - var parent = this.offsetParent || document.body - while (parent && !rootNodeRE.test(parent.nodeName) && $(parent).css("position") == "static") - parent = parent.offsetParent - return parent - }) - } - } - - // for now - $.fn.detach = $.fn.remove - - // Generate the `width` and `height` functions - ;['width', 'height'].forEach(function(dimension){ - var dimensionProperty = - dimension.replace(/./, function(m){ return m[0].toUpperCase() }) - - $.fn[dimension] = function(value){ - var offset, el = this[0] - if (value === undefined) return isWindow(el) ? el['inner' + dimensionProperty] : - isDocument(el) ? el.documentElement['scroll' + dimensionProperty] : - (offset = this.offset()) && offset[dimension] - else return this.each(function(idx){ - el = $(this) - el.css(dimension, funcArg(this, value, idx, el[dimension]())) - }) - } - }) - - function traverseNode(node, fun) { - fun(node) - for (var i = 0, len = node.childNodes.length; i < len; i++) - traverseNode(node.childNodes[i], fun) - } - - // Generate the `after`, `prepend`, `before`, `append`, - // `insertAfter`, `insertBefore`, `appendTo`, and `prependTo` methods. - adjacencyOperators.forEach(function(operator, operatorIndex) { - var inside = operatorIndex % 2 //=> prepend, append - - $.fn[operator] = function(){ - // arguments can be nodes, arrays of nodes, Zepto objects and HTML strings - var argType, nodes = $.map(arguments, function(arg) { - var arr = [] - argType = type(arg) - if (argType == "array") { - arg.forEach(function(el) { - if (el.nodeType !== undefined) return arr.push(el) - else if ($.zepto.isZ(el)) return arr = arr.concat(el.get()) - arr = arr.concat(zepto.fragment(el)) - }) - return arr - } - return argType == "object" || arg == null ? - arg : zepto.fragment(arg) - }), - parent, copyByClone = this.length > 1 - if (nodes.length < 1) return this - - return this.each(function(_, target){ - parent = inside ? target : target.parentNode - - // convert all methods to a "before" operation - target = operatorIndex == 0 ? target.nextSibling : - operatorIndex == 1 ? target.firstChild : - operatorIndex == 2 ? target : - null - - var parentInDocument = $.contains(document.documentElement, parent) - - nodes.forEach(function(node){ - if (copyByClone) node = node.cloneNode(true) - else if (!parent) return $(node).remove() - - parent.insertBefore(node, target) - if (parentInDocument) traverseNode(node, function(el){ - if (el.nodeName != null && el.nodeName.toUpperCase() === 'SCRIPT' && - (!el.type || el.type === 'text/javascript') && !el.src){ - var target = el.ownerDocument ? el.ownerDocument.defaultView : window - target['eval'].call(target, el.innerHTML) - } - }) - }) - }) - } - - // after => insertAfter - // prepend => prependTo - // before => insertBefore - // append => appendTo - $.fn[inside ? operator+'To' : 'insert'+(operatorIndex ? 'Before' : 'After')] = function(html){ - $(html)[operator](this) - return this - } - }) - - zepto.Z.prototype = Z.prototype = $.fn - - // Export internal API functions in the `$.zepto` namespace - zepto.uniq = uniq - zepto.deserializeValue = deserializeValue - $.zepto = zepto - - return $ -})() - -;(function($){ - var _zid = 1, undefined, - slice = Array.prototype.slice, - isFunction = $.isFunction, - isString = function(obj){ return typeof obj == 'string' }, - handlers = {}, - specialEvents={}, - focusinSupported = 'onfocusin' in window, - focus = { focus: 'focusin', blur: 'focusout' }, - hover = { mouseenter: 'mouseover', mouseleave: 'mouseout' } - - specialEvents.click = specialEvents.mousedown = specialEvents.mouseup = specialEvents.mousemove = 'MouseEvents' - - function zid(element) { - return element._zid || (element._zid = _zid++) - } - function findHandlers(element, event, fn, selector) { - event = parse(event) - if (event.ns) var matcher = matcherFor(event.ns) - return (handlers[zid(element)] || []).filter(function(handler) { - return handler - && (!event.e || handler.e == event.e) - && (!event.ns || matcher.test(handler.ns)) - && (!fn || zid(handler.fn) === zid(fn)) - && (!selector || handler.sel == selector) - }) - } - function parse(event) { - var parts = ('' + event).split('.') - return {e: parts[0], ns: parts.slice(1).sort().join(' ')} - } - function matcherFor(ns) { - return new RegExp('(?:^| )' + ns.replace(' ', ' .* ?') + '(?: |$)') - } - - function eventCapture(handler, captureSetting) { - return handler.del && - (!focusinSupported && (handler.e in focus)) || - !!captureSetting - } - - function realEvent(type) { - return hover[type] || (focusinSupported && focus[type]) || type - } - - function add(element, events, fn, data, selector, delegator, capture){ - var id = zid(element), set = (handlers[id] || (handlers[id] = [])) - events.split(/\s/).forEach(function(event){ - if (event == 'ready') return $(document).ready(fn) - var handler = parse(event) - handler.fn = fn - handler.sel = selector - // emulate mouseenter, mouseleave - if (handler.e in hover) fn = function(e){ - var related = e.relatedTarget - if (!related || (related !== this && !$.contains(this, related))) - return handler.fn.apply(this, arguments) - } - handler.del = delegator - var callback = delegator || fn - handler.proxy = function(e){ - e = compatible(e) - if (e.isImmediatePropagationStopped()) return - e.data = data - var result = callback.apply(element, e._args == undefined ? [e] : [e].concat(e._args)) - if (result === false) e.preventDefault(), e.stopPropagation() - return result - } - handler.i = set.length - set.push(handler) - if ('addEventListener' in element) - element.addEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) - }) - } - function remove(element, events, fn, selector, capture){ - var id = zid(element) - ;(events || '').split(/\s/).forEach(function(event){ - findHandlers(element, event, fn, selector).forEach(function(handler){ - delete handlers[id][handler.i] - if ('removeEventListener' in element) - element.removeEventListener(realEvent(handler.e), handler.proxy, eventCapture(handler, capture)) - }) - }) - } - - $.event = { add: add, remove: remove } - - $.proxy = function(fn, context) { - var args = (2 in arguments) && slice.call(arguments, 2) - if (isFunction(fn)) { - var proxyFn = function(){ return fn.apply(context, args ? args.concat(slice.call(arguments)) : arguments) } - proxyFn._zid = zid(fn) - return proxyFn - } else if (isString(context)) { - if (args) { - args.unshift(fn[context], fn) - return $.proxy.apply(null, args) - } else { - return $.proxy(fn[context], fn) - } - } else { - throw new TypeError("expected function") - } - } - - $.fn.bind = function(event, data, callback){ - return this.on(event, data, callback) - } - $.fn.unbind = function(event, callback){ - return this.off(event, callback) - } - $.fn.one = function(event, selector, data, callback){ - return this.on(event, selector, data, callback, 1) - } - - var returnTrue = function(){return true}, - returnFalse = function(){return false}, - ignoreProperties = /^([A-Z]|returnValue$|layer[XY]$|webkitMovement[XY]$)/, - eventMethods = { - preventDefault: 'isDefaultPrevented', - stopImmediatePropagation: 'isImmediatePropagationStopped', - stopPropagation: 'isPropagationStopped' - } - - function compatible(event, source) { - if (source || !event.isDefaultPrevented) { - source || (source = event) - - $.each(eventMethods, function(name, predicate) { - var sourceMethod = source[name] - event[name] = function(){ - this[predicate] = returnTrue - return sourceMethod && sourceMethod.apply(source, arguments) - } - event[predicate] = returnFalse - }) - - event.timeStamp || (event.timeStamp = Date.now()) - - if (source.defaultPrevented !== undefined ? source.defaultPrevented : - 'returnValue' in source ? source.returnValue === false : - source.getPreventDefault && source.getPreventDefault()) - event.isDefaultPrevented = returnTrue - } - return event - } - - function createProxy(event) { - var key, proxy = { originalEvent: event } - for (key in event) - if (!ignoreProperties.test(key) && event[key] !== undefined) proxy[key] = event[key] - - return compatible(proxy, event) - } - - $.fn.delegate = function(selector, event, callback){ - return this.on(event, selector, callback) - } - $.fn.undelegate = function(selector, event, callback){ - return this.off(event, selector, callback) - } - - $.fn.live = function(event, callback){ - $(document.body).delegate(this.selector, event, callback) - return this - } - $.fn.die = function(event, callback){ - $(document.body).undelegate(this.selector, event, callback) - return this - } - - $.fn.on = function(event, selector, data, callback, one){ - var autoRemove, delegator, $this = this - if (event && !isString(event)) { - $.each(event, function(type, fn){ - $this.on(type, selector, data, fn, one) - }) - return $this - } - - if (!isString(selector) && !isFunction(callback) && callback !== false) - callback = data, data = selector, selector = undefined - if (callback === undefined || data === false) - callback = data, data = undefined - - if (callback === false) callback = returnFalse - - return $this.each(function(_, element){ - if (one) autoRemove = function(e){ - remove(element, e.type, callback) - return callback.apply(this, arguments) - } - - if (selector) delegator = function(e){ - var evt, match = $(e.target).closest(selector, element).get(0) - if (match && match !== element) { - evt = $.extend(createProxy(e), {currentTarget: match, liveFired: element}) - return (autoRemove || callback).apply(match, [evt].concat(slice.call(arguments, 1))) - } - } - - add(element, event, callback, data, selector, delegator || autoRemove) - }) - } - $.fn.off = function(event, selector, callback){ - var $this = this - if (event && !isString(event)) { - $.each(event, function(type, fn){ - $this.off(type, selector, fn) - }) - return $this - } - - if (!isString(selector) && !isFunction(callback) && callback !== false) - callback = selector, selector = undefined - - if (callback === false) callback = returnFalse - - return $this.each(function(){ - remove(this, event, callback, selector) - }) - } - - $.fn.trigger = function(event, args){ - event = (isString(event) || $.isPlainObject(event)) ? $.Event(event) : compatible(event) - event._args = args - return this.each(function(){ - // handle focus(), blur() by calling them directly - if (event.type in focus && typeof this[event.type] == "function") this[event.type]() - // items in the collection might not be DOM elements - else if ('dispatchEvent' in this) this.dispatchEvent(event) - else $(this).triggerHandler(event, args) - }) - } - - // triggers event handlers on current element just as if an event occurred, - // doesn't trigger an actual event, doesn't bubble - $.fn.triggerHandler = function(event, args){ - var e, result - this.each(function(i, element){ - e = createProxy(isString(event) ? $.Event(event) : event) - e._args = args - e.target = element - $.each(findHandlers(element, event.type || event), function(i, handler){ - result = handler.proxy(e) - if (e.isImmediatePropagationStopped()) return false - }) - }) - return result - } - - // shortcut methods for `.bind(event, fn)` for each event type - ;('focusin focusout focus blur load resize scroll unload click dblclick '+ - 'mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave '+ - 'change select keydown keypress keyup error').split(' ').forEach(function(event) { - $.fn[event] = function(callback) { - return (0 in arguments) ? - this.bind(event, callback) : - this.trigger(event) - } - }) - - $.Event = function(type, props) { - if (!isString(type)) props = type, type = props.type - var event = document.createEvent(specialEvents[type] || 'Events'), bubbles = true - if (props) for (var name in props) (name == 'bubbles') ? (bubbles = !!props[name]) : (event[name] = props[name]) - event.initEvent(type, bubbles, true) - return compatible(event) - } - -})(Zepto) - -;(function($){ - var jsonpID = +new Date(), - document = window.document, - key, - name, - rscript = /)<[^<]*)*<\/script>/gi, - scriptTypeRE = /^(?:text|application)\/javascript/i, - xmlTypeRE = /^(?:text|application)\/xml/i, - jsonType = 'application/json', - htmlType = 'text/html', - blankRE = /^\s*$/, - originAnchor = document.createElement('a') - - originAnchor.href = window.location.href - - // trigger a custom event and return false if it was cancelled - function triggerAndReturn(context, eventName, data) { - var event = $.Event(eventName) - $(context).trigger(event, data) - return !event.isDefaultPrevented() - } - - // trigger an Ajax "global" event - function triggerGlobal(settings, context, eventName, data) { - if (settings.global) return triggerAndReturn(context || document, eventName, data) - } - - // Number of active Ajax requests - $.active = 0 - - function ajaxStart(settings) { - if (settings.global && $.active++ === 0) triggerGlobal(settings, null, 'ajaxStart') - } - function ajaxStop(settings) { - if (settings.global && !(--$.active)) triggerGlobal(settings, null, 'ajaxStop') - } - - // triggers an extra global event "ajaxBeforeSend" that's like "ajaxSend" but cancelable - function ajaxBeforeSend(xhr, settings) { - var context = settings.context - if (settings.beforeSend.call(context, xhr, settings) === false || - triggerGlobal(settings, context, 'ajaxBeforeSend', [xhr, settings]) === false) - return false - - triggerGlobal(settings, context, 'ajaxSend', [xhr, settings]) - } - function ajaxSuccess(data, xhr, settings, deferred) { - var context = settings.context, status = 'success' - settings.success.call(context, data, status, xhr) - if (deferred) deferred.resolveWith(context, [data, status, xhr]) - triggerGlobal(settings, context, 'ajaxSuccess', [xhr, settings, data]) - ajaxComplete(status, xhr, settings) - } - // type: "timeout", "error", "abort", "parsererror" - function ajaxError(error, type, xhr, settings, deferred) { - var context = settings.context - settings.error.call(context, xhr, type, error) - if (deferred) deferred.rejectWith(context, [xhr, type, error]) - triggerGlobal(settings, context, 'ajaxError', [xhr, settings, error || type]) - ajaxComplete(type, xhr, settings) - } - // status: "success", "notmodified", "error", "timeout", "abort", "parsererror" - function ajaxComplete(status, xhr, settings) { - var context = settings.context - settings.complete.call(context, xhr, status) - triggerGlobal(settings, context, 'ajaxComplete', [xhr, settings]) - ajaxStop(settings) - } - - function ajaxDataFilter(data, type, settings) { - if (settings.dataFilter == empty) return data - var context = settings.context - return settings.dataFilter.call(context, data, type) - } - - // Empty function, used as default callback - function empty() {} - - $.ajaxJSONP = function(options, deferred){ - if (!('type' in options)) return $.ajax(options) - - var _callbackName = options.jsonpCallback, - callbackName = ($.isFunction(_callbackName) ? - _callbackName() : _callbackName) || ('Zepto' + (jsonpID++)), - script = document.createElement('script'), - originalCallback = window[callbackName], - responseData, - abort = function(errorType) { - $(script).triggerHandler('error', errorType || 'abort') - }, - xhr = { abort: abort }, abortTimeout - - if (deferred) deferred.promise(xhr) - - $(script).on('load error', function(e, errorType){ - clearTimeout(abortTimeout) - $(script).off().remove() - - if (e.type == 'error' || !responseData) { - ajaxError(null, errorType || 'error', xhr, options, deferred) - } else { - ajaxSuccess(responseData[0], xhr, options, deferred) - } - - window[callbackName] = originalCallback - if (responseData && $.isFunction(originalCallback)) - originalCallback(responseData[0]) - - originalCallback = responseData = undefined - }) - - if (ajaxBeforeSend(xhr, options) === false) { - abort('abort') - return xhr - } - - window[callbackName] = function(){ - responseData = arguments - } - - script.src = options.url.replace(/\?(.+)=\?/, '?$1=' + callbackName) - document.head.appendChild(script) - - if (options.timeout > 0) abortTimeout = setTimeout(function(){ - abort('timeout') - }, options.timeout) - - return xhr - } - - $.ajaxSettings = { - // Default type of request - type: 'GET', - // Callback that is executed before request - beforeSend: empty, - // Callback that is executed if the request succeeds - success: empty, - // Callback that is executed the the server drops error - error: empty, - // Callback that is executed on request complete (both: error and success) - complete: empty, - // The context for the callbacks - context: null, - // Whether to trigger "global" Ajax events - global: true, - // Transport - xhr: function () { - return new window.XMLHttpRequest() - }, - // MIME types mapping - // IIS returns Javascript as "application/x-javascript" - accepts: { - script: 'text/javascript, application/javascript, application/x-javascript', - json: jsonType, - xml: 'application/xml, text/xml', - html: htmlType, - text: 'text/plain' - }, - // Whether the request is to another domain - crossDomain: false, - // Default timeout - timeout: 0, - // Whether data should be serialized to string - processData: true, - // Whether the browser should be allowed to cache GET responses - cache: true, - //Used to handle the raw response data of XMLHttpRequest. - //This is a pre-filtering function to sanitize the response. - //The sanitized response should be returned - dataFilter: empty - } - - function mimeToDataType(mime) { - if (mime) mime = mime.split(';', 2)[0] - return mime && ( mime == htmlType ? 'html' : - mime == jsonType ? 'json' : - scriptTypeRE.test(mime) ? 'script' : - xmlTypeRE.test(mime) && 'xml' ) || 'text' - } - - function appendQuery(url, query) { - if (query == '') return url - return (url + '&' + query).replace(/[&?]{1,2}/, '?') - } - - // serialize payload and append it to the URL for GET requests - function serializeData(options) { - if (options.processData && options.data && $.type(options.data) != "string") - options.data = $.param(options.data, options.traditional) - if (options.data && (!options.type || options.type.toUpperCase() == 'GET' || 'jsonp' == options.dataType)) - options.url = appendQuery(options.url, options.data), options.data = undefined - } - - $.ajax = function(options){ - var settings = $.extend({}, options || {}), - deferred = $.Deferred && $.Deferred(), - urlAnchor, hashIndex - for (key in $.ajaxSettings) if (settings[key] === undefined) settings[key] = $.ajaxSettings[key] - - ajaxStart(settings) - - if (!settings.crossDomain) { - urlAnchor = document.createElement('a') - urlAnchor.href = settings.url - // cleans up URL for .href (IE only), see https://github.com/madrobby/zepto/pull/1049 - urlAnchor.href = urlAnchor.href - settings.crossDomain = (originAnchor.protocol + '//' + originAnchor.host) !== (urlAnchor.protocol + '//' + urlAnchor.host) - } - - if (!settings.url) settings.url = window.location.toString() - if ((hashIndex = settings.url.indexOf('#')) > -1) settings.url = settings.url.slice(0, hashIndex) - serializeData(settings) - - var dataType = settings.dataType, hasPlaceholder = /\?.+=\?/.test(settings.url) - if (hasPlaceholder) dataType = 'jsonp' - - if (settings.cache === false || ( - (!options || options.cache !== true) && - ('script' == dataType || 'jsonp' == dataType) - )) - settings.url = appendQuery(settings.url, '_=' + Date.now()) - - if ('jsonp' == dataType) { - if (!hasPlaceholder) - settings.url = appendQuery(settings.url, - settings.jsonp ? (settings.jsonp + '=?') : settings.jsonp === false ? '' : 'callback=?') - return $.ajaxJSONP(settings, deferred) - } - - var mime = settings.accepts[dataType], - headers = { }, - setHeader = function(name, value) { headers[name.toLowerCase()] = [name, value] }, - protocol = /^([\w-]+:)\/\//.test(settings.url) ? RegExp.$1 : window.location.protocol, - xhr = settings.xhr(), - nativeSetHeader = xhr.setRequestHeader, - abortTimeout - - if (deferred) deferred.promise(xhr) - - if (!settings.crossDomain) setHeader('X-Requested-With', 'XMLHttpRequest') - setHeader('Accept', mime || '*/*') - if (mime = settings.mimeType || mime) { - if (mime.indexOf(',') > -1) mime = mime.split(',', 2)[0] - xhr.overrideMimeType && xhr.overrideMimeType(mime) - } - if (settings.contentType || (settings.contentType !== false && settings.data && settings.type.toUpperCase() != 'GET')) - setHeader('Content-Type', settings.contentType || 'application/x-www-form-urlencoded') - - if (settings.headers) for (name in settings.headers) setHeader(name, settings.headers[name]) - xhr.setRequestHeader = setHeader - - xhr.onreadystatechange = function(){ - if (xhr.readyState == 4) { - xhr.onreadystatechange = empty - clearTimeout(abortTimeout) - var result, error = false - if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304 || (xhr.status == 0 && protocol == 'file:')) { - dataType = dataType || mimeToDataType(settings.mimeType || xhr.getResponseHeader('content-type')) - - if (xhr.responseType == 'arraybuffer' || xhr.responseType == 'blob') - result = xhr.response - else { - result = xhr.responseText - - try { - // http://perfectionkills.com/global-eval-what-are-the-options/ - // sanitize response accordingly if data filter callback provided - result = ajaxDataFilter(result, dataType, settings) - if (dataType == 'script') (1,eval)(result) - else if (dataType == 'xml') result = xhr.responseXML - else if (dataType == 'json') result = blankRE.test(result) ? null : $.parseJSON(result) - } catch (e) { error = e } - - if (error) return ajaxError(error, 'parsererror', xhr, settings, deferred) - } - - ajaxSuccess(result, xhr, settings, deferred) - } else { - ajaxError(xhr.statusText || null, xhr.status ? 'error' : 'abort', xhr, settings, deferred) - } - } - } - - if (ajaxBeforeSend(xhr, settings) === false) { - xhr.abort() - ajaxError(null, 'abort', xhr, settings, deferred) - return xhr - } - - var async = 'async' in settings ? settings.async : true - xhr.open(settings.type, settings.url, async, settings.username, settings.password) - - if (settings.xhrFields) for (name in settings.xhrFields) xhr[name] = settings.xhrFields[name] - - for (name in headers) nativeSetHeader.apply(xhr, headers[name]) - - if (settings.timeout > 0) abortTimeout = setTimeout(function(){ - xhr.onreadystatechange = empty - xhr.abort() - ajaxError(null, 'timeout', xhr, settings, deferred) - }, settings.timeout) - - // avoid sending empty string (#319) - xhr.send(settings.data ? settings.data : null) - return xhr - } - - // handle optional data/success arguments - function parseArguments(url, data, success, dataType) { - if ($.isFunction(data)) dataType = success, success = data, data = undefined - if (!$.isFunction(success)) dataType = success, success = undefined - return { - url: url - , data: data - , success: success - , dataType: dataType - } - } - - $.get = function(/* url, data, success, dataType */){ - return $.ajax(parseArguments.apply(null, arguments)) - } - - $.post = function(/* url, data, success, dataType */){ - var options = parseArguments.apply(null, arguments) - options.type = 'POST' - return $.ajax(options) - } - - $.getJSON = function(/* url, data, success */){ - var options = parseArguments.apply(null, arguments) - options.dataType = 'json' - return $.ajax(options) - } - - $.fn.load = function(url, data, success){ - if (!this.length) return this - var self = this, parts = url.split(/\s/), selector, - options = parseArguments(url, data, success), - callback = options.success - if (parts.length > 1) options.url = parts[0], selector = parts[1] - options.success = function(response){ - self.html(selector ? - $('
                                    ').html(response.replace(rscript, "")).find(selector) - : response) - callback && callback.apply(self, arguments) - } - $.ajax(options) - return this - } - - var escape = encodeURIComponent - - function serialize(params, obj, traditional, scope){ - var type, array = $.isArray(obj), hash = $.isPlainObject(obj) - $.each(obj, function(key, value) { - type = $.type(value) - if (scope) key = traditional ? scope : - scope + '[' + (hash || type == 'object' || type == 'array' ? key : '') + ']' - // handle data in serializeArray() format - if (!scope && array) params.add(value.name, value.value) - // recurse into nested objects - else if (type == "array" || (!traditional && type == "object")) - serialize(params, value, traditional, key) - else params.add(key, value) - }) - } - - $.param = function(obj, traditional){ - var params = [] - params.add = function(key, value) { - if ($.isFunction(value)) value = value() - if (value == null) value = "" - this.push(escape(key) + '=' + escape(value)) - } - serialize(params, obj, traditional) - return params.join('&').replace(/%20/g, '+') - } -})(Zepto) - -;(function($){ - $.fn.serializeArray = function() { - var name, type, result = [], - add = function(value) { - if (value.forEach) return value.forEach(add) - result.push({ name: name, value: value }) - } - if (this[0]) $.each(this[0].elements, function(_, field){ - type = field.type, name = field.name - if (name && field.nodeName.toLowerCase() != 'fieldset' && - !field.disabled && type != 'submit' && type != 'reset' && type != 'button' && type != 'file' && - ((type != 'radio' && type != 'checkbox') || field.checked)) - add($(field).val()) - }) - return result - } - - $.fn.serialize = function(){ - var result = [] - this.serializeArray().forEach(function(elm){ - result.push(encodeURIComponent(elm.name) + '=' + encodeURIComponent(elm.value)) - }) - return result.join('&') - } - - $.fn.submit = function(callback) { - if (0 in arguments) this.bind('submit', callback) - else if (this.length) { - var event = $.Event('submit') - this.eq(0).trigger(event) - if (!event.isDefaultPrevented()) this.get(0).submit() - } - return this - } - -})(Zepto) - -;(function(){ - // getComputedStyle shouldn't freak out when called - // without a valid element as argument - try { - getComputedStyle(undefined) - } catch(e) { - var nativeGetComputedStyle = getComputedStyle - window.getComputedStyle = function(element, pseudoElement){ - try { - return nativeGetComputedStyle(element, pseudoElement) - } catch(e) { - return null - } - } - } -})() - - - exports('zepto', Zepto) -}); \ No newline at end of file diff --git a/src/lay/modules/tree.js b/src/lay/modules/tree.js deleted file mode 100644 index 6a47a5ded..000000000 --- a/src/lay/modules/tree.js +++ /dev/null @@ -1,215 +0,0 @@ -/** - - @Name:layui.tree 树组件 - @Author:贤心 - @License:MIT - - */ - - -layui.define('jquery', function(exports){ - "use strict"; - - var $ = layui.jquery; - var hint = layui.hint(); - - var enterSkin = 'layui-tree-enter', Tree = function(options){ - this.options = options; - }; - - //图标 - var icon = { - arrow: ['', ''] //箭头 - ,checkbox: ['', ''] //复选框 - ,radio: ['', ''] //单选框 - ,branch: ['', ''] //父节点 - ,leaf: '' //叶节点 - }; - - //初始化 - Tree.prototype.init = function(elem){ - var that = this; - elem.addClass('layui-box layui-tree'); //添加tree样式 - if(that.options.skin){ - elem.addClass('layui-tree-skin-'+ that.options.skin); - } - that.tree(elem); - that.on(elem); - }; - - //树节点解析 - Tree.prototype.tree = function(elem, children){ - var that = this, options = that.options - var nodes = children || options.nodes; - - layui.each(nodes, function(index, item){ - var hasChild = item.children && item.children.length > 0; - var ul = $('
                                      '); - var li = $(['
                                    • ' - //展开箭头 - ,function(){ - return hasChild ? ''+ ( - item.spread ? icon.arrow[1] : icon.arrow[0] - ) +'' : ''; - }() - - //复选框/单选框 - ,function(){ - return options.check ? ( - ''+ ( - options.check === 'checkbox' ? icon.checkbox[0] : ( - options.check === 'radio' ? icon.radio[0] : '' - ) - ) +'' - ) : ''; - }() - - //节点 - ,function(){ - return '' - + (''+ ( - hasChild ? ( - item.spread ? icon.branch[1] : icon.branch[0] - ) : icon.leaf - ) +'') //节点图标 - + (''+ (item.name||'未命名') +''); - }() - - ,'
                                    • '].join('')); - - //如果有子节点,则递归继续生成树 - if(hasChild){ - li.append(ul); - that.tree(ul, item.children); - } - - elem.append(li); - - //触发点击节点回调 - typeof options.click === 'function' && that.click(li, item); - - //伸展节点 - that.spread(li, item); - - //拖拽节点 - options.drag && that.drag(li, item); - }); - }; - - //点击节点回调 - Tree.prototype.click = function(elem, item){ - var that = this, options = that.options; - elem.children('a').on('click', function(e){ - layui.stope(e); - options.click(item) - }); - }; - - //伸展节点 - Tree.prototype.spread = function(elem, item){ - var that = this, options = that.options; - var arrow = elem.children('.layui-tree-spread') - var ul = elem.children('ul'), a = elem.children('a'); - - //执行伸展 - var open = function(){ - if(elem.data('spread')){ - elem.data('spread', null) - ul.removeClass('layui-show'); - arrow.html(icon.arrow[0]); - a.find('.layui-icon').html(icon.branch[0]); - } else { - elem.data('spread', true); - ul.addClass('layui-show'); - arrow.html(icon.arrow[1]); - a.find('.layui-icon').html(icon.branch[1]); - } - }; - - //如果没有子节点,则不执行 - if(!ul[0]) return; - - arrow.on('click', open); - a.on('dblclick', open); - } - - //通用事件 - Tree.prototype.on = function(elem){ - var that = this, options = that.options; - var dragStr = 'layui-tree-drag'; - - //屏蔽选中文字 - elem.find('i').on('selectstart', function(e){ - return false - }); - - //拖拽 - if(options.drag){ - $(document).on('mousemove', function(e){ - var move = that.move; - if(move.from){ - var to = move.to, treeMove = $('
                                      '); - e.preventDefault(); - $('.' + dragStr)[0] || $('body').append(treeMove); - var dragElem = $('.' + dragStr)[0] ? $('.' + dragStr) : treeMove; - (dragElem).addClass('layui-show').html(move.from.elem.children('a').html()); - dragElem.css({ - left: e.pageX + 10 - ,top: e.pageY + 10 - }) - } - }).on('mouseup', function(){ - var move = that.move; - if(move.from){ - move.from.elem.children('a').removeClass(enterSkin); - move.to && move.to.elem.children('a').removeClass(enterSkin); - that.move = {}; - $('.' + dragStr).remove(); - } - }); - } - }; - - //拖拽节点 - Tree.prototype.move = {}; - Tree.prototype.drag = function(elem, item){ - var that = this, options = that.options; - var a = elem.children('a'), mouseenter = function(){ - var othis = $(this), move = that.move; - if(move.from){ - move.to = { - item: item - ,elem: elem - }; - othis.addClass(enterSkin); - } - }; - a.on('mousedown', function(){ - var move = that.move - move.from = { - item: item - ,elem: elem - }; - }); - a.on('mouseenter', mouseenter).on('mousemove', mouseenter) - .on('mouseleave', function(){ - var othis = $(this), move = that.move; - if(move.from){ - delete move.to; - othis.removeClass(enterSkin); - } - }); - }; - - //暴露接口 - exports('tree', function(options){ - var tree = new Tree(options = options || {}); - var elem = $(options.elem); - if(!elem[0]){ - return hint.error('layui.tree 没有找到'+ options.elem +'元素'); - } - tree.init(elem); - }); -}); diff --git a/src/lay/modules/upload.js b/src/lay/modules/upload.js deleted file mode 100644 index 13dd51ca7..000000000 --- a/src/lay/modules/upload.js +++ /dev/null @@ -1,158 +0,0 @@ -/*! - - @Title: layui.upload 单文件上传 - 全浏览器兼容版 - @Author: 贤心 - @License:MIT - - */ - -layui.define('layer' , function(exports){ - "use strict"; - - var $ = layui.jquery; - var layer = layui.layer; - var device = layui.device(); - - var elemDragEnter = 'layui-upload-enter'; - var elemIframe = 'layui-upload-iframe'; - - var msgConf = { - icon: 2 - ,shift: 6 - }, fileType = { - file: '文件' - ,video: '视频' - ,audio: '音频' - }; - - var Upload = function(options){ - this.options = options; - }; - - //初始化渲染 - Upload.prototype.init = function(){ - var that = this, options = that.options; - var body = $('body'), elem = $(options.elem || '.layui-upload-file'); - var iframe = $(''); - - //插入iframe - $('#'+elemIframe)[0] || body.append(iframe); - - return elem.each(function(index, item){ - item = $(item); - var form = '
                                      '; - - var type = item.attr('lay-type') || options.type; //获取文件类型 - - //包裹ui元素 - if(!options.unwrap){ - form = '
                                      ' + form + ''+ ( - item.attr('lay-title') || options.title|| ('上传'+ (fileType[type]||'图片') ) - ) +'
                                      '; - } - - form = $(form); - - //拖拽支持 - if(!options.unwrap){ - form.on('dragover', function(e){ - e.preventDefault(); - $(this).addClass(elemDragEnter); - }).on('dragleave', function(){ - $(this).removeClass(elemDragEnter); - }).on('drop', function(){ - $(this).removeClass(elemDragEnter); - }); - } - - //如果已经实例化,则移除包裹元素 - if(item.parent('form').attr('target') === elemIframe){ - if(options.unwrap){ - item.unwrap(); - } else { - item.parent().next().remove(); - item.unwrap().unwrap(); - } - }; - - //包裹元素 - item.wrap(form); - - //触发上传 - item.off('change').on('change', function(){ - that.action(this, type); - }); - }); - }; - - //提交上传 - Upload.prototype.action = function(input, type){ - var that = this, options = that.options, val = input.value; - var item = $(input), ext = item.attr('lay-ext') || options.ext || ''; //获取支持上传的文件扩展名; - - if(!val){ - return; - }; - - //校验文件 - switch(type){ - case 'file': //一般文件 - if(ext && !RegExp('\\w\\.('+ ext +')$', 'i').test(escape(val))){ - layer.msg('不支持该文件格式', msgConf); - return input.value = ''; - } - break; - case 'video': //视频文件 - if(!RegExp('\\w\\.('+ (ext||'avi|mp4|wma|rmvb|rm|flash|3gp|flv') +')$', 'i').test(escape(val))){ - layer.msg('不支持该视频格式', msgConf); - return input.value = ''; - } - break; - case 'audio': //音频文件 - if(!RegExp('\\w\\.('+ (ext||'mp3|wav|mid') +')$', 'i').test(escape(val))){ - layer.msg('不支持该音频格式', msgConf); - return input.value = ''; - } - break; - default: //图片文件 - if(!RegExp('\\w\\.('+ (ext||'jpg|png|gif|bmp|jpeg') +')$', 'i').test(escape(val))){ - layer.msg('不支持该图片格式', msgConf); - return input.value = ''; - } - break; - } - - options.before && options.before(input); - item.parent().submit(); - - var iframe = $('#'+elemIframe), timer = setInterval(function() { - var res; - try { - res = iframe.contents().find('body').text(); - } catch(e) { - layer.msg('上传接口存在跨域', msgConf); - clearInterval(timer); - } - if(res){ - clearInterval(timer); - iframe.contents().find('body').html(''); - try { - res = JSON.parse(res); - } catch(e){ - res = {}; - return layer.msg('请对上传接口返回JSON字符', msgConf); - } - typeof options.success === 'function' && options.success(res, input); - } - }, 30); - - input.value = ''; - }; - - //暴露接口 - exports('upload', function(options){ - var upload = new Upload(options = options || {}); - upload.init(); - }); -}); - diff --git a/src/lay/modules/util.js b/src/lay/modules/util.js deleted file mode 100644 index b88f31729..000000000 --- a/src/lay/modules/util.js +++ /dev/null @@ -1,69 +0,0 @@ -/** - - @Name:layui.util 工具集 - @Author:贤心 - @License:MIT - -*/ - -layui.define('jquery', function(exports){ - "use strict"; - - var $ = layui.jquery - - ,util = { - //固定块 - fixbar: function(options){ - options = options || {}; - options.bgcolor = options.bgcolor ? ('background-color:' + options.bgcolor) : ''; - - var TOP_BAR = 'layui-fixbar-top', timer, is, icon = [ - options.bar1 === true ? '' : options.bar1 //bar1 - 信息图标 - ,options.bar2 === true ? '' : options.bar2 //bar2 - 问号图标 - ,'' //置顶 - ] - - ,dom = $(['
                                        ' - ,options.bar1 ? '
                                      • '+ icon[0] +'
                                      • ' : '' - ,options.bar2 ? '
                                      • '+ icon[1] +'
                                      • ' : '' - ,'
                                      • '+ icon[2] +'
                                      • ' - ,'
                                      '].join('')) - - ,topbar = dom.find('.'+TOP_BAR) - - ,scroll = function(){ - var stop = $(document).scrollTop(); - if(stop >= (options.showHeight || 200)){ - is || (topbar.show(), is = 1); - } else { - is && (topbar.hide(), is = 0); - } - }; - - if($('.layui-fixbar')[0]) return; - typeof options.css === 'object' && (dom.css(options.css)); - $('body').append(dom), scroll(); - - //bar点击事件 - dom.find('li').on('click', function(){ - var othis = $(this), type = othis.attr('lay-type'); - if(type === 'top'){ - $('html,body').animate({ - scrollTop : 0 - }, 200);; - } - options.click && options.click.call(this, type); - }); - - //Top显示控制 - $(document).on('scroll', function(){ - if(timer) clearTimeout(timer); - timer = setTimeout(function(){ - scroll(); - }, 100); - }); - } - }; - - exports('util', util); -}); \ No newline at end of file diff --git a/src/layui.js b/src/layui.js deleted file mode 100644 index 3185a2cf6..000000000 --- a/src/layui.js +++ /dev/null @@ -1,433 +0,0 @@ -/*! - - @Title: Layui - @Description:经典模块化前端框架 - @Site: www.layui.com - @Author: 贤心 - @License:MIT - - */ - -;!function(win){ - -"use strict"; - -var Lay = function(){ - this.v = '1.0.9_rls'; //版本号 -}; - -Lay.fn = Lay.prototype; - -var doc = document, config = Lay.fn.cache = {}, - -//获取layui所在目录 -getPath = function(){ - var js = doc.scripts, jsPath = js[js.length - 1].src; - return jsPath.substring(0, jsPath.lastIndexOf('/') + 1); -}(), - -//异常提示 -error = function(msg){ - win.console && console.error && console.error('Layui hint: ' + msg); -}, - -isOpera = typeof opera !== 'undefined' && opera.toString() === '[object Opera]', - -//内置模块 -modules = { - layer: 'modules/layer' //弹层 - ,laydate: 'modules/laydate' //日期 - ,laypage: 'modules/laypage' //分页 - ,laytpl: 'modules/laytpl' //模板引擎 - ,layim: 'modules/layim' //web通讯 - ,layedit: 'modules/layedit' //富文本编辑器 - ,form: 'modules/form' //表单集 - ,upload: 'modules/upload' //上传 - ,tree: 'modules/tree' //树结构 - ,table: 'modules/table' //富表格 - ,element: 'modules/element' //常用元素操作 - ,util: 'modules/util' //工具块 - ,flow: 'modules/flow' //流加载 - ,carousel: 'modules/carousel' //轮播 - ,code: 'modules/code' //代码修饰器 - ,jquery: 'modules/jquery' //DOM库(第三方) - - ,mobile: 'modules/mobile' //移动大模块 | 若当前为开发目录,则为移动模块入口,否则为移动模块集合 - ,'layui.all': 'dest/layui.all' //PC模块合并版 -}; - -config.modules = {}; //记录模块物理路径 -config.status = {}; //记录模块加载状态 -config.timeout = 10; //符合规范的模块请求最长等待秒数 -config.event = {}; //记录模块自定义事件 - -//定义模块 -Lay.fn.define = function(deps, callback){ - var that = this - ,type = typeof deps === 'function' - ,mods = function(){ - typeof callback === 'function' && callback(function(app, exports){ - layui[app] = exports; - config.status[app] = true; - }); - return this; - }; - - type && ( - callback = deps, - deps = [] - ); - - if(layui['layui.all'] || (!layui['layui.all'] && layui['layui.mobile'])){ - return mods.call(that); - } - - that.use(deps, mods); - return that; -}; - -//使用特定模块 -Lay.fn.use = function(apps, callback, exports){ - var that = this, dir = config.dir = config.dir ? config.dir : getPath; - var head = doc.getElementsByTagName('head')[0]; - - apps = typeof apps === 'string' ? [apps] : apps; - - //如果页面已经存在jQuery1.7+库且所定义的模块依赖jQuery,则不加载内部jquery模块 - if(window.jQuery && jQuery.fn.on){ - that.each(apps, function(index, item){ - if(item === 'jquery'){ - apps.splice(index, 1); - } - }); - layui.jquery = jQuery; - } - - var item = apps[0], timeout = 0; - exports = exports || []; - - //静态资源host - config.host = config.host || (dir.match(/\/\/([\s\S]+?)\//)||['//'+ location.host +'/'])[0]; - - if(apps.length === 0 - || (layui['layui.all'] && modules[item]) - || (!layui['layui.all'] && layui['layui.mobile'] && modules[item]) - ){ - return onCallback(), that; - } - - //加载完毕 - function onScriptLoad(e, url){ - var readyRegExp = navigator.platform === 'PLaySTATION 3' ? /^complete$/ : /^(complete|loaded)$/ - if (e.type === 'load' || (readyRegExp.test((e.currentTarget || e.srcElement).readyState))) { - config.modules[item] = url; - head.removeChild(node); - (function poll() { - if(++timeout > config.timeout * 1000 / 4){ - return error(item + ' is not a valid module'); - }; - config.status[item] ? onCallback() : setTimeout(poll, 4); - }()); - } - } - - //加载模块 - var node = doc.createElement('script'), url = ( - modules[item] ? (dir + 'lay/') : (config.base || '') - ) + (that.modules[item] || item) + '.js'; - node.async = true; - node.charset = 'utf-8'; - node.src = url + function(){ - var version = config.version === true - ? (config.v || (new Date()).getTime()) - : (config.version||''); - return version ? ('?v=' + version) : ''; - }(); - - //首次加载 - if(!config.modules[item]){ - head.appendChild(node); - if(node.attachEvent && !(node.attachEvent.toString && node.attachEvent.toString().indexOf('[native code') < 0) && !isOpera){ - node.attachEvent('onreadystatechange', function(e){ - onScriptLoad(e, url); - }); - } else { - node.addEventListener('load', function(e){ - onScriptLoad(e, url); - }, false); - } - } else { - (function poll() { - if(++timeout > config.timeout * 1000 / 4){ - return error(item + ' is not a valid module'); - }; - (typeof config.modules[item] === 'string' && config.status[item]) - ? onCallback() - : setTimeout(poll, 4); - }()); - } - - config.modules[item] = url; - - //回调 - function onCallback(){ - exports.push(layui[item]); - apps.length > 1 ? - that.use(apps.slice(1), callback, exports) - : ( typeof callback === 'function' && callback.apply(layui, exports) ); - } - - return that; - -}; - -//获取节点的style属性值 -Lay.fn.getStyle = function(node, name){ - var style = node.currentStyle ? node.currentStyle : win.getComputedStyle(node, null); - return style[style.getPropertyValue ? 'getPropertyValue' : 'getAttribute'](name); -}; - -//css外部加载器 -Lay.fn.link = function(href, fn, cssname){ - var that = this, link = doc.createElement('link'); - var head = doc.getElementsByTagName('head')[0]; - if(typeof fn === 'string') cssname = fn; - var app = (cssname || href).replace(/\.|\//g, ''); - var id = link.id = 'layuicss-'+app, timeout = 0; - - link.rel = 'stylesheet'; - link.href = href + (config.debug ? '?v='+new Date().getTime() : ''); - link.media = 'all'; - - if(!doc.getElementById(id)){ - head.appendChild(link); - } - - if(typeof fn !== 'function') return that; - - //轮询css是否加载完毕 - (function poll() { - if(++timeout > config.timeout * 1000 / 100){ - return error(href + ' timeout'); - }; - parseInt(that.getStyle(doc.getElementById(id), 'width')) === 1989 ? function(){ - fn(); - }() : setTimeout(poll, 100); - }()); - - return that; -}; - -//css内部加载器 -Lay.fn.addcss = function(firename, fn, cssname){ - return layui.link(config.dir + 'css/' + firename, fn, cssname); -}; - -//图片预加载 -Lay.fn.img = function(url, callback, error) { - var img = new Image(); - img.src = url; - if(img.complete){ - return callback(img); - } - img.onload = function(){ - img.onload = null; - callback(img); - }; - img.onerror = function(e){ - img.onerror = null; - error(e); - }; -}; - -//全局配置 -Lay.fn.config = function(options){ - options = options || {}; - for(var key in options){ - config[key] = options[key]; - } - return this; -}; - -//记录全部模块 -Lay.fn.modules = function(){ - var clone = {}; - for(var o in modules){ - clone[o] = modules[o]; - } - return clone; -}(); - -//拓展模块 -Lay.fn.extend = function(options){ - var that = this; - - //验证模块是否被占用 - options = options || {}; - for(var o in options){ - if(that[o] || that.modules[o]){ - error('\u6A21\u5757\u540D '+ o +' \u5DF2\u88AB\u5360\u7528'); - } else { - that.modules[o] = options[o]; - } - } - - return that; -}; - -//路由解析 -Lay.fn.router = function(hash){ - var that = this, hash = hash || location.hash, data = { - path: [] - ,search: {} - ,hash: (hash.match(/[^#](#.*$)/) || [])[1] || '' - }; - - if(!/^#\//.test(hash)) return data; //禁止非路由规范 - hash = hash.replace(/^#\//, '').replace(/([^#])(#.*$)/, '$1').split('/') || []; - - //提取Hash结构 - that.each(hash, function(index, item){ - /^\w+=/.test(item) ? function(){ - item = item.split('='); - data.search[item[0]] = item[1]; - }() : data.path.push(item); - }); - - return data; -}; - -//本地存储 -Lay.fn.data = function(table, settings){ - table = table || 'layui'; - - if(!win.JSON || !win.JSON.parse) return; - - //如果settings为null,则删除表 - if(settings === null){ - return delete localStorage[table]; - } - - settings = typeof settings === 'object' - ? settings - : {key: settings}; - - try{ - var data = JSON.parse(localStorage[table]); - } catch(e){ - var data = {}; - } - - if(settings.value) data[settings.key] = settings.value; - if(settings.remove) delete data[settings.key]; - localStorage[table] = JSON.stringify(data); - - return settings.key ? data[settings.key] : data; -}; - -//设备信息 -Lay.fn.device = function(key){ - var agent = navigator.userAgent.toLowerCase(); - - //获取版本号 - var getVersion = function(label){ - var exp = new RegExp(label + '/([^\\s\\_\\-]+)'); - label = (agent.match(exp)||[])[1]; - return label || false; - }; - - var result = { - os: function(){ //底层操作系统 - if(/windows/.test(agent)){ - return 'windows'; - } else if(/linux/.test(agent)){ - return 'linux'; - } else if(/mac/.test(agent)){ - return 'mac'; - } else if(/iphone|ipod|ipad|ios/.test(agent)){ - return 'ios'; - } - }() - ,ie: function(){ //ie版本 - return (!!win.ActiveXObject || "ActiveXObject" in win) ? ( - (agent.match(/msie\s(\d+)/) || [])[1] || '11' //由于ie11并没有msie的标识 - ) : false; - }() - ,weixin: getVersion('micromessenger') //是否微信 - }; - - //任意的key - if(key && !result[key]){ - result[key] = getVersion(key); - } - - //移动设备 - result.android = /android/.test(agent); - result.ios = result.os === 'ios'; - - return result; -}; - -//提示 -Lay.fn.hint = function(){ - return { - error: error - } -}; - -//遍历 -Lay.fn.each = function(obj, fn){ - var that = this, key; - if(typeof fn !== 'function') return that; - obj = obj || []; - if(obj.constructor === Object){ - for(key in obj){ - if(fn.call(obj[key], key, obj[key])) break; - } - } else { - for(key = 0; key < obj.length; key++){ - if(fn.call(obj[key], key, obj[key])) break; - } - } - return that; -}; - -//阻止事件冒泡 -Lay.fn.stope = function(e){ - e = e || win.event; - e.stopPropagation ? e.stopPropagation() : e.cancelBubble = true; -}; - -//自定义模块事件 -Lay.fn.onevent = function(modName, events, callback){ - if(typeof modName !== 'string' - || typeof callback !== 'function') return this; - config.event[modName + '.' + events] = [callback]; - - //不再对多次事件监听做支持 - /* - config.event[modName + '.' + events] - ? config.event[modName + '.' + events].push(callback) - : config.event[modName + '.' + events] = [callback]; - */ - - return this; -}; - -//执行自定义模块事件 -Lay.fn.event = function(modName, events, params){ - var that = this, result = null, filter = events.match(/\(.*\)$/)||[]; //提取事件过滤器 - var set = (events = modName + '.'+ events).replace(filter, ''); //获取事件本体名 - var callback = function(_, item){ - var res = item && item.call(that, params); - res === false && result === null && (result = false); - }; - layui.each(config.event[set], callback); - filter[0] && layui.each(config.event[events], callback); //执行过滤器中的事件 - return result; -}; - -win.layui = new Lay(); - -}(window); - diff --git a/src/utils/browser.js b/src/utils/browser.js new file mode 100644 index 000000000..cf27cad67 --- /dev/null +++ b/src/utils/browser.js @@ -0,0 +1,28 @@ +/** + * browser utils + */ + +/** + * 打开新窗口 + * @param {Object} options + * @param {string} [options.url] - 目标 URL 地址 + * @param {string} [options.target] - 目标窗口名称 + * @param {string} [options.specs] - 目标窗口特征字符串 + * @param {string} [options.content] - 目标窗口内容 + * @param {Window} [options.window] - 目标窗口对象 + * @return {Window|null} + */ +export function openWindow(options = {}) { + const win = + options.window || + window.open(options.url || '', options.target, options.specs); + + if (!win) return null; + if (options.url) return win; + + win.document.open('text/html', 'replace'); + win.document.write(options.content || ''); + win.document.close(); + + return win; +} diff --git a/src/utils/date.js b/src/utils/date.js new file mode 100644 index 000000000..0e0beeec2 --- /dev/null +++ b/src/utils/date.js @@ -0,0 +1,266 @@ +/** + * date + * 日期时间工具 + */ + +import { lay } from '../core/lay.js'; +import { i18n } from '../core/i18n.js'; +import { log } from '../core/logger.js'; +import { $ } from 'jquery'; + +// 正则引用自 dayjs +// https://github.com/iamkun/dayjs/blob/v1.11.9/src/constant.js#L30 +const REGEX_FORMAT = + /\[([^\]]+)]|y{1,4}|M{1,2}|d{1,2}|H{1,2}|h{1,2}|a|A|m{1,2}|s{1,2}|SSS/g; +const REGEX_PARSE = + /^(\d{4})[-/]?(\d{1,2})?[-/]?(\d{0,2})[T\s]*(\d{1,2})?:?(\d{1,2})?:?(\d{1,2})?[.:]?(\d+)?$/i; + +/** + * 转化为指定格式的日期字符串 + * @param {number|string|Date} time - 毫秒级时间戳或日期对象 + * @param {string} format - 日期格式 + * @param {Object} options - 选项 + * @param {Function} options.customMeridiem - 自定义 meridiem 格式 + * @returns {string} + */ +export function toDateString(time, format, options) { + // 若 null 或空字符,则返回空字符 + if (time === null || time === '') { + return ''; + } + + // 标准化 time 参数值 + var normalizeDate = function (date) { + if (typeof date === 'undefined') { + return new Date(); + } + if (!isNaN(date)) { + return new Date(typeof date === 'string' ? parseInt(date) : date); + } + if (typeof date === 'string' && !/Z$/i.test(date)) { + var d = date.match(REGEX_PARSE); + if (d) { + var m = d[2] - 1 || 0; + var ms = (d[7] || '0').substring(0, 3); + return new Date( + d[1], + m, + d[3] || 1, + d[4] || 0, + d[5] || 0, + d[6] || 0, + ms, + ); + } + } + + return new Date(date); + }; + var date = normalizeDate(time); + + if (!date.getDate()) { + return ( + log('Invalid millisecond for "utils.toDateString(millisecond)"'), + '' + ); + } + + var years = date.getFullYear(); + var month = date.getMonth(); + var days = date.getDate(); + var hours = date.getHours(); + var minutes = date.getMinutes(); + var seconds = date.getSeconds(); + var milliseconds = date.getMilliseconds(); + + var defaultMeridiem = i18n.$t('utils.toDateString.meridiem'); + + var meridiem = (options && options.customMeridiem) || defaultMeridiem; + + var matches = { + yy: function () { + return String(years).slice(-2); + }, + yyyy: function () { + return lay.digit(years, 4); + }, + M: function () { + return String(month + 1); + }, + MM: function () { + return lay.digit(month + 1); + }, + d: function () { + return String(days); + }, + dd: function () { + return lay.digit(days); + }, + H: function () { + return String(hours); + }, + HH: function () { + return lay.digit(hours); + }, + h: function () { + return String(hours % 12 || 12); + }, + hh: function () { + return lay.digit(hours % 12 || 12); + }, + A: function () { + return meridiem(hours, minutes); + }, + m: function () { + return String(minutes); + }, + mm: function () { + return lay.digit(minutes); + }, + s: function () { + return String(seconds); + }, + ss: function () { + return lay.digit(seconds); + }, + SSS: function () { + return lay.digit(milliseconds, 3); + }, + }; + + format = format || 'yyyy-MM-dd HH:mm:ss'; + + return format.replace(REGEX_FORMAT, function (match, $1) { + return $1 || (matches[match] && matches[match]()) || match; + }); +} + +/** + * 倒计时 + * @param {Object} options + * @param {number|string|Date} options.date - 目标时间值 + * @param {number|string|Date} options.now - 当前时间值,一般取当前服务器时间 + * @param {Function} [options.ready] - 倒计时准备就绪的回调函数 + * @param {Function} options.clock - 计时中的回调函数 + * @param {Function} [options.done] - 计时完成后的回调函数 + * @returns {Object} inst - 倒计时实例对象 + * @returns {Function} inst.clear - 清除计时器 + * @returns {Function} inst.reload - 重置倒计时 + */ +export function countdown(options) { + // 默认可选项 + options = $.extend( + true, + { + date: new Date(), + now: new Date(), + }, + options, + ); + + // 实例对象 + var inst = { + options: options, + // 清除计时器 + clear: function () { + clearTimeout(inst.timer); + }, + // 重置倒计时 + reload: function (opts) { + this.clear(); + $.extend( + true, + this.options, + { + now: new Date(), + }, + opts, + ); + count(); + }, + }; + + typeof options.ready === 'function' && options.ready(); + + // 计算倒计时 + var count = (function fn() { + var date = new Date(options.date); + var now = new Date(options.now); + var countTime = (function (time) { + return time > 0 ? time : 0; + })(date.getTime() - now.getTime()); + var result = { + d: Math.floor(countTime / (1000 * 60 * 60 * 24)), // 天 + h: Math.floor(countTime / (1000 * 60 * 60)) % 24, // 时 + m: Math.floor(countTime / (1000 * 60)) % 60, // 分 + s: Math.floor(countTime / 1000) % 60, // 秒 + }; + var next = function () { + now.setTime(now.getTime() + 1000); + options.now = now; + count(); + }; + + // 计时 - 以秒间隔 + inst.timer = setTimeout(next, 1000); + typeof options.clock === 'function' && options.clock(result, inst); + + // 计时完成 + if (countTime <= 0) { + clearTimeout(inst.timer); + typeof options.done === 'function' && options.done(result, inst); + } + + return fn; + })(); + + return inst; +} + +/** + * 某个时间在多久前 + * @param {number|string|Date} time - 某个时间的毫秒数或日期对象 + * @param {boolean} onlyDate - 是否在超过 30 天后,只返回日期字符串 + * @returns {string} 返回时间描述字符串 + */ +export function timeAgo(time, onlyDate) { + var arr = [[], []]; + var stamp = new Date().getTime() - new Date(time).getTime(); + + // 返回具体日期 + if (stamp > 1000 * 60 * 60 * 24 * 31) { + stamp = new Date(time); + arr[0][0] = lay.digit(stamp.getFullYear(), 4); + arr[0][1] = lay.digit(stamp.getMonth() + 1); + arr[0][2] = lay.digit(stamp.getDate()); + + // 是否输出时间 + if (!onlyDate) { + arr[1][0] = lay.digit(stamp.getHours()); + arr[1][1] = lay.digit(stamp.getMinutes()); + arr[1][2] = lay.digit(stamp.getSeconds()); + } + + return arr[0].join('-') + (arr[1].length ? ` ${arr[1].join(':')}` : ''); + } + + // 30 天以内,返回「多久前」 + if (stamp >= 1000 * 60 * 60 * 24) { + return i18n.$t('utils.timeAgo.days', { + days: (stamp / 1000 / 60 / 60 / 24) | 0, + }); + } else if (stamp >= 1000 * 60 * 60) { + return i18n.$t('utils.timeAgo.hours', { + hours: (stamp / 1000 / 60 / 60) | 0, + }); + } else if (stamp >= 1000 * 60 * 3) { + // 3 分钟以内为:刚刚 + return i18n.$t('utils.timeAgo.minutes', { + minutes: (stamp / 1000 / 60) | 0, + }); + } else if (stamp < 0) { + return i18n.$t('utils.timeAgo.future'); + } else { + return i18n.$t('utils.timeAgo.justNow'); + } +} diff --git a/src/utils/events.js b/src/utils/events.js new file mode 100644 index 000000000..7b3af18cb --- /dev/null +++ b/src/utils/events.js @@ -0,0 +1,76 @@ +/** + * events utils + */ + +import { $ } from 'jquery'; + +/** + * 批量绑定事件 + * @param {string} [attr="lay-on"] - 触发事件的元素属性名 + * @param {Object.} events - 事件集合 + * @param {Object} [options] - 参数的更多选项 + * @param {(string|HTMLElement|JQuery)} [options.elem="body"] - 触发事件的委托元素 + * @param {string} [options.trigger="click"] - 事件触发的方式 + * @returns {Object} 返回当前 events 参数设置的事件集合 + */ +export function on(attr, events, options) { + // 若参数一为 object 类型,则为事件集,且省略 attr + if (typeof attr === 'object') { + options = events || {}; + events = attr; + attr = options.attr || 'lay-on'; // 默认属性名 + } + + // 更多选项 + options = $.extend( + { + elem: 'body', + trigger: 'click', + }, + typeof options === 'object' + ? options + : { + trigger: options, // 兼容旧版 + }, + ); + + var elem = (options.elem = $(options.elem)); + var attrSelector = '[' + attr + ']'; + var DATANAME = 'UTIL_ON_DATA'; // 缓存在委托元素上的 data-* 属性名 + + if (!elem[0]) return; // 若委托元素不存在 + + // 初始化 data 默认值,以委托元素为存储单元 + if (!elem.data(DATANAME)) { + elem.data(DATANAME, { + events: {}, + }); + } + + // 读取 data 缓存 + var dataCache = elem.data(DATANAME); + + // 根据 attr 和 trigger 的组合作为 key + var key = attr + '_' + options.trigger; + + // 根据 key 记录事件集合 + events = dataCache.events[key] = $.extend( + true, + dataCache.events[key], + events, + ); + + // 清除事件委托,避免重复绑定 + var trigger = options.trigger + '.lay_util_on'; + elem.off(trigger, attrSelector); + + // 绑定事件委托 + elem.on(trigger, attrSelector, function (e) { + var othis = $(this); + var attrValue = othis.attr(attr); + typeof events[attrValue] === 'function' && + events[attrValue].call(this, othis, e); + }); + + return events; +} diff --git a/src/utils/index.js b/src/utils/index.js new file mode 100644 index 000000000..a8281e463 --- /dev/null +++ b/src/utils/index.js @@ -0,0 +1,8 @@ +/** + * utils + * 工具集 + */ + +export * from './events.js'; +export * from './date.js'; +export * from './browser.js'; diff --git a/test/all.html b/test/all.html deleted file mode 100644 index f0c261730..000000000 --- a/test/all.html +++ /dev/null @@ -1,76 +0,0 @@ - - - - - -合并版使用 - layui - - - - - - - -
                                      - - - - - - - diff --git a/test/button.html b/test/button.html deleted file mode 100644 index b16ffdc09..000000000 --- a/test/button.html +++ /dev/null @@ -1,108 +0,0 @@ - - - - - 按钮 - layui - - - - - - - - - - - - - -按钮色系: - -原始按钮 -默认按钮 - - - - - -

                                      - -按钮图标: - - - - - - - - - -

                                      - -按钮尺寸: - - - - - - - - - - - -

                                      - -按钮圆角: - - - - - - - - -

                                      - -按钮图文: - - - - - -

                                      - -按钮组: - -
                                      - - - -
                                      - -
                                      - - - - -
                                      - -
                                      - - - - -
                                      - -


                                      - - - - - - - diff --git a/test/carousel.html b/test/carousel.html deleted file mode 100644 index d8d4988d7..000000000 --- a/test/carousel.html +++ /dev/null @@ -1,28 +0,0 @@ - - - - - -轮播组件 - layui - - - - - - - -

                                      轮播图

                                      -
                                        -
                                      • -
                                      - - - - - - diff --git a/test/code.html b/test/code.html deleted file mode 100644 index 5084112c6..000000000 --- a/test/code.html +++ /dev/null @@ -1,129 +0,0 @@ - - - - - -代码修饰器 - layui - - - - - - - -
                                      -//路由
                                      -LAY.fn.router = function(hash){
                                      -  var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -  var item, param = {
                                      -    dir: []
                                      -  };
                                      -  for(var i = 0; i < hashs.length; i++){
                                      -    item = hashs[i].split('=');
                                      -    /^\w+=/.test(hashs[i]) ? function(){
                                      -      if(item[0] !== 'dir'){
                                      -        param[item[0]] = item[1];
                                      -      }
                                      -    }() : param.dir.push(hashs[i]);
                                      -    item = null;
                                      -  }
                                      -  return param;
                                      -};
                                      -
                                      - -
                                      -//路由
                                      -LAY.fn.router = function(hash){
                                      -  var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -  var item, param = {
                                      -    dir: []
                                      -  };
                                      -  for(var i = 0; i < hashs.length; i++){
                                      -    item = hashs[i].split('=');
                                      -    /^\w+=/.test(hashs[i]) ? function(){
                                      -      if(item[0] !== 'dir'){
                                      -        param[item[0]] = item[1];
                                      -      }
                                      -    }() : param.dir.push(hashs[i]);
                                      -    item = null;
                                      -  }
                                      -  return param;
                                      -};
                                      -
                                      - -
                                      -var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -var item, param = {
                                      -  dir: []
                                      -};
                                      -
                                      -//代码中的代码
                                      -var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -var item, param = {
                                      -  dir: []
                                      -};
                                      -
                                      -
                                      - -
                                      -//路由
                                      -LAY.fn.router = function(hash){
                                      -  var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -  var item, param = {
                                      -    dir: []
                                      -  };
                                      -  for(var i = 0; i < hashs.length; i++){
                                      -    item = hashs[i].split('=');
                                      -    /^\w+=/.test(hashs[i]) ? function(){
                                      -      if(item[0] !== 'dir'){
                                      -        param[item[0]] = item[1];
                                      -      }
                                      -    }() : param.dir.push(hashs[i]);
                                      -    item = null;
                                      -  }
                                      -  return param;
                                      -};
                                      -
                                      -//代码中的代码
                                      -var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -var item, param = {
                                      -  dir: []
                                      -};
                                      -
                                      -//代码中的代码
                                      -var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -var item, param = {
                                      -  dir: []
                                      -};
                                      -
                                      -//代码中的代码
                                      -var hashs = (hash || location.hash).replace(/^#/, '').split('/') || [];
                                      -var item, param = {
                                      -  dir: []
                                      -};
                                      -
                                      -
                                      -
                                      -
                                      - - -
                                      -  
                                      - 123 -
                                      -
                                      - - - - - - diff --git a/test/element.html b/test/element.html deleted file mode 100644 index ca6a63ce9..000000000 --- a/test/element.html +++ /dev/null @@ -1,258 +0,0 @@ - - - - - -常用元素 - layui - - - - - - - - -
                                      -
                                      -

                                      杜甫

                                      -
                                      -

                                      杜甫的思想核心是儒家的仁政思想,他有“致君尧舜上,再使风俗淳”的宏伟抱负。杜甫虽然在世时名声并不显赫,但后来声名远播,对中国文学和日本文学都产生了深远的影响。杜甫共有约1500首诗歌被保留了下来,大多集于《杜工部集》。

                                      -
                                      -
                                      -
                                      -

                                      李清照

                                      -
                                      -

                                      李清照出生于书香门第,早期生活优裕,其父李格非藏书甚富,她小时候就在良好的家庭环境中打下文学基础。出嫁后与夫赵明诚共同致力于书画金石的搜集整理。金兵入据中原时,流寓南方,境遇孤苦。所作词,前期多写其悠闲生活,后期多悲叹身世,情调感伤。形式上善用白描手法,自辟途径,语言清丽。

                                      -
                                      -
                                      -
                                      -

                                      鲁迅

                                      -
                                      -

                                      鲁迅一生在文学创作、文学批评、思想研究、文学史研究、翻译、美术理论引进、基础科学介绍和古籍校勘与研究等多个领域具有重大贡献。他对于五四运动以后的中国社会思想文化发展具有重大影响,蜚声世界文坛,尤其在韩国、日本思想文化领域有极其重要的地位和影响,被誉为“二十世纪东亚文化地图上占最大领土的作家”。

                                      -
                                      -
                                      -
                                      - -

                                      - -
                                      -
                                      -
                                      - -
                                      - -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      -
                                      - -
                                      -
                                      -
                                      - -

                                      - -
                                      Layui正是你苦苦寻找的前端UI框架
                                      -
                                      Layui正是你苦苦寻找的前端UI框架Layui正是你苦苦寻找的前端UI框架Layui正是你苦苦寻找的前端UI框架Layui正是你苦苦寻找的前端UI框架Layui正是你苦苦寻找的前端UI框架
                                      - -
                                      - 字段集区块 - 默认风格 -
                                      - 内容区域 -
                                      -
                                      - -横线上文 -
                                      -横线下文 - -

                                      - - - -

                                      - - - - -

                                      - - - 首页 - 国际新闻 - 亚太地区 - 正文 - - -

                                      - - - 娱乐 - 八卦 - 体育 - 搞笑 - 视频 - 游戏 - 综艺 - - -

                                      - -
                                      -
                                        -
                                      • 标题1
                                      • -
                                      • 标题2
                                      • -
                                      • 标题3
                                      • -
                                      • 标题4
                                      • -
                                      • 标题5
                                      • -
                                      -
                                      -
                                      1
                                      -
                                      2
                                      -
                                      3
                                      -
                                      4
                                      -
                                      5
                                      -
                                      -
                                      - - - - - -
                                      -
                                        -
                                      • 标题1
                                      • -
                                      • 标题2
                                      • -
                                      • 标题3
                                      • -
                                      • 标题4
                                      • -
                                      • 标题5
                                      • -
                                      • 标题6
                                      • -
                                      -
                                      - -
                                      -
                                      -
                                        -
                                      • 标题一
                                      • -
                                      • 标题2
                                      • -
                                      • 标题3
                                      • -
                                      • 标题4
                                      • -
                                      • 标题5
                                      • -
                                      • 标题6
                                      • -
                                      -
                                      -
                                      -
                                      - -
                                      -
                                      -
                                      2
                                      -
                                      3
                                      -
                                      4
                                      -
                                      5
                                      -
                                      6
                                      -
                                      -
                                      -
                                      - -
                                      -
                                        -
                                      • 标题1
                                      • -
                                      • 标题2
                                      • -
                                      • 标题3
                                      • -
                                      • 标题4
                                      • -
                                      • 标题5
                                      • -
                                      • 标题6
                                      • -
                                      • 标题7
                                      • -
                                      • 标题8
                                      • -
                                      -
                                      - - - - - - - diff --git a/test/extend.html b/test/extend.html deleted file mode 100644 index 6669b84fc..000000000 --- a/test/extend.html +++ /dev/null @@ -1,30 +0,0 @@ - - - - - -自定义模块 - layui - - - - - - - - - - - - - diff --git a/test/flow.html b/test/flow.html deleted file mode 100644 index c867a57a0..000000000 --- a/test/flow.html +++ /dev/null @@ -1,70 +0,0 @@ - - - - - -流加载 - layui - - - - - - - - -
                                        - - -
                                        - - - - - - - - - -
                                        - - - - - - - diff --git a/test/form.html b/test/form.html deleted file mode 100644 index 8709b35be..000000000 --- a/test/form.html +++ /dev/null @@ -1,255 +0,0 @@ - - - - - 表单模块 - layui - - - - - - - - - - - - - -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        请务必填写用户名
                                        -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        - -
                                        -
                                        - -
                                        - -
                                        - -
                                        -
                                        - -
                                        - -
                                        - - - -
                                        -
                                        -
                                        - -
                                        - - - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        - -
                                        - - - -
                                        -
                                        -
                                        - -
                                        - - - -
                                        -
                                        -
                                        - -
                                        - -
                                        -
                                        -
                                        -
                                        - - -
                                        -
                                        - - -


                                        - - - - - - - - -
                                        - - - - - - - - - - diff --git a/test/js/child/test.js b/test/js/child/test.js deleted file mode 100644 index 560835207..000000000 --- a/test/js/child/test.js +++ /dev/null @@ -1,8 +0,0 @@ - - -layui.define(function(exports){ - - exports('test', { - title: '子目录模块加载' - }) -}); \ No newline at end of file diff --git a/test/js/index.js b/test/js/index.js deleted file mode 100644 index e4eca313c..000000000 --- a/test/js/index.js +++ /dev/null @@ -1,8 +0,0 @@ - - -layui.define(function(exports){ - - exports('index', { - title: '模块入口' - }); -}); \ No newline at end of file diff --git a/test/json/layim/getList.json b/test/json/layim/getList.json deleted file mode 100644 index 37947e066..000000000 --- a/test/json/layim/getList.json +++ /dev/null @@ -1,99 +0,0 @@ -{ - "code": 0 - ,"msg": "" - ,"data": { - "mine": { - "username": "纸飞机" - ,"id": "100000" - ,"status": "online" - ,"sign": "在深邃的编码世界,做一枚轻盈的纸飞机" - ,"avatar": "http://cdn.firstlinkapp.com/upload/2016_6/1465575923433_33812.jpg" - } - ,"friend": [{ - "groupname": "前端码屌" - ,"id": 1 - ,"online": 2 - ,"list": [{ - "username": "贤心" - ,"id": "100001" - ,"avatar": "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" - ,"sign": "这些都是测试数据,实际使用请严格按照该格式返回" - },{ - "username": "Z_子晴" - ,"id": "108101" - ,"avatar": "http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg" - ,"sign": "微电商达人" - },{ - "username": "Lemon_CC" - ,"id": "102101" - ,"avatar": "http://tp2.sinaimg.cn/1833062053/180/5643591594/0" - ,"sign": "" - },{ - "username": "马小云" - ,"id": "168168" - ,"avatar": "http://tp4.sinaimg.cn/2145291155/180/5601307179/1" - ,"sign": "让天下没有难写的代码" - ,"status": "offline" - },{ - "username": "徐小峥" - ,"id": "666666" - ,"avatar": "http://tp2.sinaimg.cn/1783286485/180/5677568891/1" - ,"sign": "代码在囧途,也要写到底" - }] - },{ - "groupname": "网红" - ,"id": 2 - ,"online": 3 - ,"list": [{ - "username": "罗玉凤" - ,"id": "121286" - ,"avatar": "http://tp1.sinaimg.cn/1241679004/180/5743814375/0" - ,"sign": "在自己实力不济的时候,不要去相信什么媒体和记者。他们不是善良的人,有时候候他们的采访对当事人而言就是陷阱" - },{ - "username": "长泽梓Azusa" - ,"id": "100001222" - ,"sign": "我是日本女艺人长泽あずさ" - ,"avatar": "http://tva1.sinaimg.cn/crop.0.0.180.180.180/86b15b6cjw1e8qgp5bmzyj2050050aa8.jpg" - },{ - "username": "大鱼_MsYuyu" - ,"id": "12123454" - ,"avatar": "http://tp1.sinaimg.cn/5286730964/50/5745125631/0" - ,"sign": "我瘋了!這也太準了吧 超級笑點低" - },{ - "username": "谢楠" - ,"id": "10034001" - ,"avatar": "http://tp4.sinaimg.cn/1665074831/180/5617130952/0" - ,"sign": "" - },{ - "username": "柏雪近在它香" - ,"id": "3435343" - ,"avatar": "http://tp2.sinaimg.cn/2518326245/180/5636099025/0" - ,"sign": "" - }] - },{ - "groupname": "我心中的女神" - ,"id": 3 - ,"online": 1 - ,"list": [{ - "username": "林心如" - ,"id": "76543" - ,"avatar": "http://tp3.sinaimg.cn/1223762662/180/5741707953/0" - ,"sign": "我爱贤心" - },{ - "username": "佟丽娅" - ,"id": "4803920" - ,"avatar": "http://tp4.sinaimg.cn/1345566427/180/5730976522/0" - ,"sign": "我也爱贤心吖吖啊" - }] - }] - ,"group": [{ - "groupname": "前端群" - ,"id": "101" - ,"avatar": "http://tp2.sinaimg.cn/2211874245/180/40050524279/0" - },{ - "groupname": "Fly社区官方群" - ,"id": "102" - ,"avatar": "http://tp2.sinaimg.cn/5488749285/50/5719808192/1" - }] - } -} \ No newline at end of file diff --git a/test/json/layim/getMembers.json b/test/json/layim/getMembers.json deleted file mode 100644 index d3577b236..000000000 --- a/test/json/layim/getMembers.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "code": 0 - ,"msg": "" - ,"data": { - "owner": { - "username": "贤心" - ,"id": "100001" - ,"avatar": "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" - ,"sign": "这些都是测试数据,实际使用请严格按照该格式返回" - } - ,"members": 12 - ,"list": [{ - "username": "贤心" - ,"id": "100001" - ,"avatar": "http://tp1.sinaimg.cn/1571889140/180/40030060651/1" - ,"sign": "这些都是测试数据,实际使用请严格按照该格式返回" - },{ - "username": "Z_子晴" - ,"id": "108101" - ,"avatar": "http://tva3.sinaimg.cn/crop.0.0.512.512.180/8693225ajw8f2rt20ptykj20e80e8weu.jpg" - ,"sign": "微电商达人" - },{ - "username": "Lemon_CC" - ,"id": "102101" - ,"avatar": "http://tp2.sinaimg.cn/1833062053/180/5643591594/0" - ,"sign": "" - },{ - "username": "马小云" - ,"id": "168168" - ,"avatar": "http://tp4.sinaimg.cn/2145291155/180/5601307179/1" - ,"sign": "让天下没有难写的代码" - },{ - "username": "徐小峥" - ,"id": "666666" - ,"avatar": "http://tp2.sinaimg.cn/1783286485/180/5677568891/1" - ,"sign": "代码在囧途,也要写到底" - },{ - "username": "罗玉凤" - ,"id": "121286" - ,"avatar": "http://tp1.sinaimg.cn/1241679004/180/5743814375/0" - ,"sign": "在自己实力不济的时候,不要去相信什么媒体和记者。他们不是善良的人,有时候候他们的采访对当事人而言就是陷阱" - },{ - "username": "长泽梓Azusa" - ,"id": "100001222" - ,"avatar": "http://tva1.sinaimg.cn/crop.0.0.180.180.180/86b15b6cjw1e8qgp5bmzyj2050050aa8.jpg" - ,"sign": "我是日本女艺人长泽あずさ" - },{ - "username": "大鱼_MsYuyu" - ,"id": "12123454" - ,"avatar": "http://tp1.sinaimg.cn/5286730964/50/5745125631/0" - ,"sign": "我瘋了!這也太準了吧 超級笑點低" - },{ - "username": "谢楠" - ,"id": "10034001" - ,"avatar": "http://tp4.sinaimg.cn/1665074831/180/5617130952/0" - ,"sign": "" - },{ - "username": "柏雪近在它香" - ,"id": "3435343" - ,"avatar": "http://tp2.sinaimg.cn/2518326245/180/5636099025/0" - ,"sign": "" - },{ - "username": "林心如" - ,"id": "76543" - ,"avatar": "http://tp3.sinaimg.cn/1223762662/180/5741707953/0" - ,"sign": "我爱贤心" - },{ - "username": "佟丽娅" - ,"id": "4803920" - ,"avatar": "http://tp4.sinaimg.cn/1345566427/180/5730976522/0" - ,"sign": "我也爱贤心吖吖啊" - }] - } -} \ No newline at end of file diff --git a/test/laydate.html b/test/laydate.html deleted file mode 100644 index 8f00a70ff..000000000 --- a/test/laydate.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - - - -表单模块 - layui - - - - - - - -
                                          -
                                        • - -
                                          - -
                                          -
                                        • -
                                        - - - - - diff --git a/test/layedit.html b/test/layedit.html deleted file mode 100644 index d2046bdc3..000000000 --- a/test/layedit.html +++ /dev/null @@ -1,51 +0,0 @@ - - - - - -富文本编辑器 - layui - - - - - - - -
                                        -
                                        -
                                        - -
                                        - - 获取选中内容 - -
                                        - - - - - - \ No newline at end of file diff --git a/test/layer.html b/test/layer.html deleted file mode 100644 index b7145a391..000000000 --- a/test/layer.html +++ /dev/null @@ -1,111 +0,0 @@ - - - - - - - -layer弹层 - layui - - - - - - - - - - - - - - - - - - diff --git a/test/layout.html b/test/layout.html deleted file mode 100644 index 39d016f67..000000000 --- a/test/layout.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - - - -layout 后台大框架布局 - Layui - - - -
                                        -
                                        - -
                                        -
                                        -
                                        - -
                                        -
                                        -
                                        - -
                                        - -
                                        - - - - diff --git a/test/laypage.html b/test/laypage.html deleted file mode 100644 index ab4376610..000000000 --- a/test/laypage.html +++ /dev/null @@ -1,89 +0,0 @@ - - - - - -分页 - layui - - - - - - - -
                                        -
                                        -
                                        -
                                        -
                                        -
                                        -
                                        - - - - - - diff --git a/test/slider.html b/test/slider.html deleted file mode 100644 index 997b54500..000000000 --- a/test/slider.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - 滑块 - layui - - - - - - - - - - - - - - - - - - - - - - - diff --git a/test/table.html b/test/table.html deleted file mode 100644 index 8f6abb992..000000000 --- a/test/table.html +++ /dev/null @@ -1,153 +0,0 @@ - - - - - -常用元素 - layui - - - - - - - - -
                                        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                        昵称加入时间签名
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                        昵称加入时间签名
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                        昵称加入时间签名
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
                                        昵称加入时间签名
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        贤心2016-11-29人生就像是一场修行
                                        - - - - - - diff --git a/test/tree.html b/test/tree.html deleted file mode 100644 index 49449c33e..000000000 --- a/test/tree.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - -树模块 - layui - - - - - - - -
                                          - -
                                            - - - - -
                                            -# layui.tree-v2 备忘
                                            -* check参数 - checkbox、radio的支持
                                            -* 拖拽的支持
                                            -
                                            - - - diff --git a/test/upload.html b/test/upload.html deleted file mode 100644 index 36f91e8db..000000000 --- a/test/upload.html +++ /dev/null @@ -1,49 +0,0 @@ - - - - - -文件上传模块 - layui - - - - - - - - -

                                            -保留原格式: -

                                            - -

                                            - -

                                            - - - - - - diff --git a/test/util.html b/test/util.html deleted file mode 100644 index af7c29bf9..000000000 --- a/test/util.html +++ /dev/null @@ -1,36 +0,0 @@ - - - - - -工具集 - layui - - - - - - - -1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            1
                                            - - - - - diff --git a/test/xingzuo.html b/test/xingzuo.html deleted file mode 100644 index 5fd2783ef..000000000 --- a/test/xingzuo.html +++ /dev/null @@ -1,104 +0,0 @@ - - - - - -星座配对 - - - - - - - - - - -
                                            - -
                                              -
                                            • 天秤座
                                            • -
                                            • 处女座
                                            • -
                                            • 水瓶座
                                            • -
                                            • 双子座
                                            • -
                                            • 双鱼座
                                            • -
                                            • 白羊座
                                            • -
                                            -
                                            - - - - - \ No newline at end of file diff --git a/tests/unit/core.test.js b/tests/unit/core.test.js new file mode 100644 index 000000000..f41490739 --- /dev/null +++ b/tests/unit/core.test.js @@ -0,0 +1,12 @@ +/** + * Core Unit Tests + */ + +// 单元测试将在 Layui 3 开发接近完成阶段完善 +describe('Test Demo', () => { + test('Hello, Layui!', () => { + const greet = (name) => `Hello, ${name}!`; + expect(greet('Layui')).toBe('Hello, Layui!'); + expect(greet('World')).toBe('Hello, World!'); + }); +}); diff --git a/tests/visual/assets/i18n/en.js b/tests/visual/assets/i18n/en.js new file mode 100644 index 000000000..57293269b --- /dev/null +++ b/tests/visual/assets/i18n/en.js @@ -0,0 +1,179 @@ +/** + * English (en) + */ + +// Common English internationalization message object +export default { + code: { + copy: 'Copy Code', + copied: 'Copied', + copyError: 'Copy Failed', + maximize: 'Maximize', + restore: 'Restore', + preview: 'Preview in New Window', + }, + colorpicker: { + clear: 'Clear', + confirm: 'OK', + }, + dropdown: { + noData: 'No Data', + }, + flow: { + loadMore: 'Load More', + noMore: 'No More Data', + }, + form: { + select: { + noData: 'No Data', + noMatch: 'No Matching Data', + placeholder: 'Please Select', + }, + validateMessages: { + required: 'This field is required', + phone: 'Invalid phone number format', + email: 'Invalid email format', + url: 'Invalid URL format', + number: 'Numbers only', + date: 'Invalid date format', + identity: 'Invalid ID number format', + }, + verifyErrorPromptTitle: 'Notice', + }, + laydate: { + months: [ + 'Jan', + 'Feb', + 'Mar', + 'Apr', + 'May', + 'Jun', + 'Jul', + 'Aug', + 'Sep', + 'Oct', + 'Nov', + 'Dec', + ], + weeks: ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'], + time: ['Hour', 'Minute', 'Second'], + literal: { + year: '', + }, + selectDate: 'Select Date', + selectTime: 'Select Time', + startTime: 'Start Time', + endTime: 'End Time', + tools: { + confirm: 'Confirm', + clear: 'Clear', + now: 'Now', + reset: 'Reset', + }, + rangeOrderPrompt: + 'End time cannot be less than start Time\nPlease re-select', + invalidDatePrompt: 'Invalid date\n', + formatErrorPrompt: + 'Date format is invalid\nMust follow the format:\n{format}\n', + autoResetPrompt: 'It has been reset', + preview: 'The selected result', + }, + layer: { + confirm: 'OK', + cancel: 'Cancel', + defaultTitle: 'Info', + prompt: { + inputLengthPrompt: 'Maximum {length} characters', + }, + photos: { + noData: 'No Image', + tools: { + rotate: 'Rotate', + scaleX: 'Flip Horizontally', + zoomIn: 'Zoom In', + zoomOut: 'Zoom Out', + reset: 'Reset', + close: 'Close', + }, + viewPicture: 'View Original', + urlError: { + prompt: 'Image URL is invalid, \nContinue to next one?', + confirm: 'Next', + cancel: 'Cancel', + }, + }, + }, + laypage: { + prev: 'Prev', + next: 'Next', + first: 'First', + last: 'Last', + total: 'Total {total} items', + pagesize: 'items/page', + goto: 'Go to', + page: 'page', + confirm: 'Confirm', + }, + table: { + sort: { + asc: 'Ascending', + desc: 'Descending', + }, + noData: 'No Data', + tools: { + filter: { + title: 'Filter Columns', + }, + export: { + title: 'Export', + noDataPrompt: 'No data in the table', + csvText: 'Export CSV File', + }, + print: { + title: 'Print', + noDataPrompt: 'No data in the table', + }, + }, + dataFormatError: + 'Returned data is invalid. The correct success status code should be: "{statusName}": {statusCode}', + xhrError: 'Request Error: {msg}', + }, + transfer: { + noData: 'No Data', + noMatch: 'No Match', + title: ['List One', 'List Two'], + searchPlaceholder: 'Search by Keyword', + }, + tree: { + defaultNodeName: 'Unnamed', + noData: 'No Data', + deleteNodePrompt: 'Are you sure you want to delete the node "{name}"?', + }, + upload: { + fileType: { + file: 'File', + image: 'Image', + video: 'Video', + audio: 'Audio', + }, + validateMessages: { + fileExtensionError: 'Unsupported format in selected {fileType}', + filesOverLengthLimit: 'Maximum {length} files allowed at once', + currentFilesLength: 'You have selected {length} files', + fileOverSizeLimit: 'File size must not exceed {size}', + }, + chooseText: '{length} files', + }, + utils: { + timeAgo: { + days: '{days} days ago', + hours: '{hours} hours ago', + minutes: '{minutes} minutes ago', + future: 'In the future', + justNow: 'Just now', + }, + toDateString: { + meridiem: (hours, minutes) => (hours < 12 ? 'AM' : 'PM'), + }, + }, +}; diff --git a/tests/visual/assets/i18n/fr.js b/tests/visual/assets/i18n/fr.js new file mode 100644 index 000000000..f7a9582be --- /dev/null +++ b/tests/visual/assets/i18n/fr.js @@ -0,0 +1,181 @@ +/** + * Français (fr) + */ + +export default { + code: { + copy: 'Copier le code', + copied: 'Copié', + copyError: 'Échec de la copie', + maximize: 'Afficher en plein écran', + restore: 'Restaurer l’affichage', + preview: 'Aperçu dans une nouvelle fenêtre', + }, + colorpicker: { + clear: 'Effacer', + confirm: 'OK', + }, + dropdown: { + noData: 'Aucune donnée disponible', + }, + flow: { + loadMore: 'Charger plus', + noMore: 'Plus de données', + }, + form: { + select: { + noData: 'Aucune donnée disponible', + noMatch: 'Aucune correspondance', + placeholder: 'Veuillez sélectionner', + }, + validateMessages: { + required: 'Ce champ est obligatoire', + phone: 'Numéro de téléphone invalide', + email: 'Adresse e-mail invalide', + url: 'URL invalide', + number: 'Uniquement des chiffres', + date: 'Format de date invalide', + identity: 'Numéro d’identification invalide', + }, + verifyErrorPromptTitle: 'Avertissement', + }, + laydate: { + months: [ + 'Janv', + 'Févr', + 'Mars', + 'Avr', + 'Mai', + 'Juin', + 'Juil', + 'Août', + 'Sept', + 'Oct', + 'Nov', + 'Déc', + ], + weeks: ['Di', 'Lu', 'Ma', 'Me', 'Je', 'Ve', 'Sa'], + time: ['Heure', 'Minute', 'Seconde'], + literal: { + year: '', + }, + selectDate: 'Sélec. date', + selectTime: 'Sélec. heure', + startTime: 'Heure de début', + endTime: 'Heure de fin', + // Recommandé en version abrégée en raison de l’espace limité du composant + tools: { + confirm: 'OK', + clear: 'Eff.', + now: 'Ajd.', + reset: 'Réinit.', + }, + rangeOrderPrompt: + 'L’heure de fin ne peut pas être antérieure à l’heure de début\nVeuillez recommencer', + invalidDatePrompt: 'Date ou heure hors plage valide\n', + formatErrorPrompt: + 'Format de date invalide\nLe format attendu est :\n{format}\n', + autoResetPrompt: 'Il a été réinitialisé pour vous', + preview: 'Résultat sélectionné actuel', + }, + layer: { + confirm: 'Confirmer', + cancel: 'Annuler', + defaultTitle: 'Information', + prompt: { + inputLengthPrompt: 'Maximum {length} caractères', + }, + photos: { + noData: 'Aucune image', + tools: { + rotate: 'Faire pivoter', + scaleX: 'Inverser horizontalement', + zoomIn: 'Agrandir', + zoomOut: 'Réduire', + reset: 'Réinitialiser', + close: 'Fermer', + }, + viewPicture: 'Voir l’image originale', + urlError: { + prompt: + 'L’adresse de l’image est invalide,\nContinuer avec la suivante ?', + confirm: 'Suivante', + cancel: 'Annuler', + }, + }, + }, + laypage: { + prev: 'Page précédente', + next: 'Page suivante', + first: 'Première', + last: 'Dernière', + total: 'Total {total} éléments', + pagesize: 'éléments/page', + goto: 'Aller à', + page: 'page', + confirm: 'Confirmer', + }, + table: { + sort: { + asc: 'Croissant', + desc: 'Décroissant', + }, + noData: 'Aucune donnée', + tools: { + filter: { + title: 'Filtrer les colonnes', + }, + export: { + title: 'Exporter', + noDataPrompt: 'Aucune donnée à exporter', + csvText: 'Exporter au format CSV', + }, + print: { + title: 'Imprimer', + noDataPrompt: 'Aucune donnée à imprimer', + }, + }, + dataFormatError: + 'Les données retournées sont invalides. Le code de réussite attendu est : "{statusName}": {statusCode}', + xhrError: 'Erreur de requête : {msg}', + }, + transfer: { + noData: 'Aucune donnée', + noMatch: 'Aucune correspondance', + title: ['Liste 1', 'Liste 2'], + searchPlaceholder: 'Recherche par mot-clé', + }, + tree: { + defaultNodeName: 'Sans nom', + noData: 'Aucune donnée', + deleteNodePrompt: 'Confirmer la suppression du nœud "{name}" ?', + }, + upload: { + fileType: { + file: 'Fichier', + image: 'Image', + video: 'Vidéo', + audio: 'Audio', + }, + validateMessages: { + fileExtensionError: + 'Le {fileType} sélectionné contient un format non supporté', + filesOverLengthLimit: 'Nombre maximum de fichiers : {length}', + currentFilesLength: 'Vous avez sélectionné {length} fichiers', + fileOverSizeLimit: 'La taille du fichier ne doit pas dépasser {size}', + }, + chooseText: '{length} fichiers', + }, + utils: { + timeAgo: { + days: 'il y a {days} jours', + hours: 'il y a {hours} heures', + minutes: 'il y a {minutes} minutes', + future: 'Futur', + justNow: 'À l’instant', + }, + toDateString: { + meridiem: (hours, minutes) => (hours < 12 ? 'AM' : 'PM'), + }, + }, +}; diff --git a/tests/visual/assets/i18n/zh-HK.js b/tests/visual/assets/i18n/zh-HK.js new file mode 100644 index 000000000..dda67285c --- /dev/null +++ b/tests/visual/assets/i18n/zh-HK.js @@ -0,0 +1,190 @@ +/** + * 繁體中文 (zh-HK) + */ + +export default { + code: { + copy: '複製代碼', + copied: '已複製', + copyError: '複製失敗', + maximize: '最大化顯示', + restore: '還原顯示', + preview: '在新視窗預覽', + }, + colorpicker: { + clear: '清除', + confirm: '確定', + }, + dropdown: { + noData: '暫無資料', + }, + flow: { + loadMore: '載入更多', + noMore: '沒有更多了', + }, + form: { + select: { + noData: '暫無資料', + noMatch: '無匹配資料', + placeholder: '請選擇', + }, + validateMessages: { + required: '必填項不能為空', + phone: '手機號碼格式不正確', + email: '電郵格式不正確', + url: '連結格式不正確', + number: '只能填寫數字', + date: '日期格式不正確', + identity: '身份證號碼格式不正確', + }, + verifyErrorPromptTitle: '提示', + }, + laydate: { + months: [ + '1月', + '2月', + '3月', + '4月', + '5月', + '6月', + '7月', + '8月', + '9月', + '10月', + '11月', + '12月', + ], + weeks: ['日', '一', '二', '三', '四', '五', '六'], + time: ['時', '分', '秒'], + literal: { + year: '年', + }, + selectDate: '選擇日期', + selectTime: '選擇時間', + startTime: '開始時間', + endTime: '結束時間', + tools: { + confirm: '確定', + clear: '清除', + now: '現在', + reset: '重設', + }, + rangeOrderPrompt: '結束時間不能早於開始時間\n請重新選擇', + invalidDatePrompt: '不在有效日期或時間範圍內\n', + formatErrorPrompt: '日期格式不合法\n必須遵循:\n{format}\n', + autoResetPrompt: '已自動重設', + preview: '當前選中的結果', + }, + layer: { + confirm: '確定', + cancel: '取消', + defaultTitle: '資訊', + prompt: { + inputLengthPrompt: '最多輸入 {length} 個字符', + }, + photos: { + noData: '沒有圖片', + tools: { + rotate: '旋轉', + scaleX: '水平變換', + zoomIn: '放大', + zoomOut: '縮小', + reset: '還原', + close: '關閉', + }, + viewPicture: '查看原圖', + urlError: { + prompt: '當前圖片地址異常,\n是否繼續查看下一張?', + confirm: '下一張', + cancel: '不看了', + }, + }, + }, + laypage: { + prev: '上一頁', + next: '下一頁', + first: '首頁', + last: '尾頁', + total: '共 {total} 條', + pagesize: '條/頁', + goto: '到第', + page: '頁', + confirm: '確定', + }, + table: { + sort: { + asc: '升序', + desc: '降序', + }, + noData: '無資料', + tools: { + filter: { + title: '篩選列', + }, + export: { + title: '匯出', + noDataPrompt: '當前表格無資料', + csvText: '匯出 CSV 檔案', + }, + print: { + title: '列印', + noDataPrompt: '當前表格無資料', + }, + }, + dataFormatError: + '返回的資料不符合規範,正確的成功狀態碼應為:"{statusName}": {statusCode}', + xhrError: '請求異常,錯誤提示:{msg}', + }, + transfer: { + noData: '無資料', + noMatch: '無匹配資料', + title: ['列表一', '列表二'], + searchPlaceholder: '關鍵詞搜尋', + }, + tree: { + defaultNodeName: '未命名', + noData: '無資料', + deleteNodePrompt: '確認刪除"{name}"節點嗎?', + }, + upload: { + fileType: { + file: '檔案', + image: '圖片', + video: '影片', + audio: '音訊', + }, + validateMessages: { + fileExtensionError: '選擇的{fileType}中包含不支援的格式', + filesOverLengthLimit: '同時最多只能上傳: {length} 個檔案', + currentFilesLength: '您當前已經選擇了: {length} 個檔案', + fileOverSizeLimit: '檔案大小不能超過 {size}', + }, + chooseText: '{length} 個檔案', + }, + utils: { + timeAgo: { + days: '{days} 天前', + hours: '{hours} 小時前', + minutes: '{minutes} 分鐘前', + future: '未來', + justNow: '剛剛', + }, + toDateString: { + meridiem: (hours, minutes) => { + var hm = hours * 100 + minutes; + if (hm < 500) { + return '凌晨'; + } else if (hm < 800) { + return '早上'; + } else if (hm < 1200) { + return '上午'; + } else if (hm < 1300) { + return '中午'; + } else if (hm < 1900) { + return '下午'; + } + return '晚上'; + }, + }, + }, +}; diff --git a/tests/visual/assets/json/table/demo1.json b/tests/visual/assets/json/table/demo1.json new file mode 100644 index 000000000..1deddc84b --- /dev/null +++ b/tests/visual/assets/json/table/demo1.json @@ -0,0 +1,145 @@ +{ + "code": 0, + "msg": "", + "count": 3000000, + "totalRow": { + "checkin": "777" + }, + "data1": [], + "data": [ + { + "id": "10001", + "username": "杜甫123", + "email": "test1@email.com", + "sex": "", + "city": "浙江杭州", + "sign": "舍南舍北皆春水,但见群鸥日日来。花径不曾缘客扫,蓬门今始为君开。盘飧市远无兼味,樽酒家贫只旧醅。肯与邻翁相对饮,隔篱呼取尽余杯。", + "experience": 7, + "ip": "192.168.0.8", + "checkin": 0, + "joinTime": "2016-10-14", + "LAY_DISABLED": true + }, + { + "id": "10002", + "username": "李白", + "email": "test2@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "君不见,黄河之水天上来,奔流到海不复回。 君不见,高堂明镜悲白发,朝如青丝暮成雪。 人生得意须尽欢,莫使金樽空对月。 天生我材必有用,千金散尽还复来。 烹羊宰牛且为乐,会须一饮三百杯。 岑夫子,丹丘生,将进酒,杯莫停。 与君歌一曲,请君为我倾耳听。(倾耳听 一作:侧耳听) 钟鼓馔玉不足贵,但愿长醉不复醒。(不足贵 一作:何足贵;不复醒 一作:不愿醒/不用醒) 古来圣贤皆寂寞,惟有饮者留其名。(古来 一作:自古;惟 通:唯) 陈王昔时宴平乐,斗酒十千恣欢谑。 主人何为言少钱,径须沽取对君酌。 五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。", + "experience": 9, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14", + "LAY_CHECKED": true + }, + { + "id": "10003", + "username": "苏轼", + "email": "test3@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "大江东去,浪淘尽,千古风流人物。故垒西边,人道是,三国周郎赤壁。乱石穿空,惊涛拍岸,卷起千堆雪。江山如画,一时多少豪杰。遥想公瑾当年,小乔初嫁了,雄姿英发。羽扇纶巾,谈笑间,樯橹灰飞烟灭。故国神游,多情应笑我,早生华发。人生如梦,一尊还酹江月。", + "experience": 8, + "ip": "192.168.0.8", + "checkin": null, + "joinTime": "2016-10-14" + }, + { + "id": "10004", + "username": "李清照", + "email": "test4@email.com", + "sex": "女", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 6, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10005", + "username": "冰心", + "email": "test5@email.com", + "sex": "女", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 64, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10006", + "username": "张三", + "email": "test6@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 65, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10007", + "username": "张三7", + "email": "test7@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 49, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10008", + "username": "张三8", + "email": "test8@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 5, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10009", + "username": "张三9", + "email": "test9@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 5, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10010", + "username": "张三10", + "email": "test10@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 5, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10011", + "username": "张三11", + "email": "test11@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": 5, + "ip": "192.168.0.8", + "checkin": "106", + "joinTime": "2016-10-14" + } + ] +} diff --git a/tests/visual/assets/json/table/demo2.json b/tests/visual/assets/json/table/demo2.json new file mode 100644 index 000000000..62e45bf9f --- /dev/null +++ b/tests/visual/assets/json/table/demo2.json @@ -0,0 +1,67 @@ +{ + "code": 0, + "msg": "", + "count": 66, + "data": [ + { + "username": "张小三", + "amount": 18, + "province": "浙江", + "city": "杭州", + "zone": "西湖区", + "street": "西溪街道", + "address": "西溪花园", + "house": "30栋1单元" + }, + { + "username": "李小四", + "amount": 39, + "province": "江苏", + "city": "苏州", + "zone": "姑苏区", + "street": "丝绸路", + "address": "天墅之城", + "house": "9幢2单元" + }, + { + "username": "王小四", + "amount": 8, + "province": "江西", + "city": "南昌", + "zone": "青山湖区", + "street": "艾溪湖办事处", + "address": "中兴和园", + "house": "1幢3单元" + }, + { + "username": "赵小六", + "amount": 16, + "province": "福建", + "city": "泉州", + "zone": "丰泽区", + "street": "南洋街道", + "address": "南洋村", + "house": "6幢1单元" + }, + { + "username": "孙小七", + "amount": 12, + "province": "湖北", + "city": "武汉", + "zone": "武昌区", + "street": "武昌大道", + "address": "两湖花园", + "house": "16幢2单元" + }, + { + "username": "周小八", + "amount": 11, + "province": "安徽", + "city": "黄山", + "zone": "黄山区", + "street": "汤口镇", + "address": "温泉村", + "house": "21号" + } + ] +} diff --git a/tests/visual/assets/json/table/demo3.json b/tests/visual/assets/json/table/demo3.json new file mode 100644 index 000000000..ae47d0d44 --- /dev/null +++ b/tests/visual/assets/json/table/demo3.json @@ -0,0 +1,82 @@ +{ + "status": 200, + "message": "", + "total": 333333, + "data": { + "list": [ + { + "id": "10001", + "username": "杜甫3", + "email": "test@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "鼠标移动到此处,可以通过点击单元格右侧的下拉图标,查看到被隐藏的全部内容。", + "experience": "7", + "ip": "192.168.0.8", + "logins": 0, + "joinTime": "2016-10-14" + }, + { + "id": "10002", + "username": "李白3", + "email": "test@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "君不见,黄河之水天上来,奔流到海不复回。 君不见,高堂明镜悲白发,朝如青丝暮成雪。 人生得意须尽欢,莫使金樽空对月。 天生我材必有用,千金散尽还复来。 烹羊宰牛且为乐,会须一饮三百杯。 岑夫子,丹丘生,将进酒,杯莫停。 与君歌一曲,请君为我倾耳听。(倾耳听 一作:侧耳听) 钟鼓馔玉不足贵,但愿长醉不复醒。(不足贵 一作:何足贵;不复醒 一作:不愿醒/不用醒) 古来圣贤皆寂寞,惟有饮者留其名。(古来 一作:自古;惟 通:唯) 陈王昔时宴平乐,斗酒十千恣欢谑。 主人何为言少钱,径须沽取对君酌。 五花马,千金裘,呼儿将出换美酒,与尔同销万古愁。", + "experience": "9", + "ip": "192.168.0.8", + "logins": "106", + "joinTime": "2016-10-14", + "LAY_CHECKED": true + }, + { + "id": "10003", + "username": "王勃", + "email": "test@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": "8", + "ip": "192.168.0.8", + "logins": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10004", + "username": "李清照", + "email": "test@email.com", + "sex": "女", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": "6", + "ip": "192.168.0.8", + "logins": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10005", + "username": "冰心", + "email": "test@email.com", + "sex": "女", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": "64", + "ip": "192.168.0.8", + "logins": "106", + "joinTime": "2016-10-14" + }, + { + "id": "10006", + "username": "贤心", + "email": "test@email.com", + "sex": "男", + "city": "浙江杭州", + "sign": "人生恰似一场修行", + "experience": "65", + "ip": "192.168.0.8", + "logins": "106", + "joinTime": "2016-10-14" + } + ] + } +} diff --git a/tests/visual/assets/json/treeTable/demo-1.json b/tests/visual/assets/json/treeTable/demo-1.json new file mode 100644 index 000000000..f9915f8fb --- /dev/null +++ b/tests/visual/assets/json/treeTable/demo-1.json @@ -0,0 +1,5078 @@ +{ + "code": 0, + "count": 1000, + "data": [ + { + "id": 1, + "name": "User-1", + "type": 4, + "status": 2, + "score": 28, + "experience": 54981, + "sex": "男", + "city": "丽江市", + "description": "-", + "createTime": "2014-06-04 12:29:55", + "parentId": null, + "children": [ + { + "id": 2, + "name": "User-2", + "type": 2, + "status": 3, + "score": 75, + "experience": 43884, + "sex": "女", + "city": "大理白族自治州", + "description": "-", + "createTime": "1971-11-03 19:15:43", + "parentId": null, + "children": [ + { + "id": 3, + "name": "User-3", + "type": 2, + "status": 3, + "score": 72, + "experience": 75912, + "sex": "女", + "city": "渭南市", + "description": "-", + "createTime": "2022-01-17 01:48:02", + "parentId": null, + "children": [ + { + "id": 4, + "name": "User-4", + "type": 3, + "status": 3, + "score": 21, + "experience": 23198, + "sex": "男", + "city": "海外", + "description": "-", + "createTime": "1986-11-06 23:56:45", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 5, + "name": "User-5", + "type": 3, + "status": 3, + "score": 89, + "experience": 25710, + "sex": "女", + "city": "盐城市", + "description": "-", + "createTime": "2007-10-03 21:44:59", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 6, + "name": "User-6", + "type": 2, + "status": 4, + "score": 70, + "experience": 51144, + "sex": "男", + "city": "益阳市", + "description": "-", + "createTime": "2017-02-21 00:26:02", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 7, + "name": "User-7", + "type": 5, + "status": 3, + "score": 24, + "experience": 64919, + "sex": "男", + "city": "贵港市", + "description": "-", + "createTime": "1981-05-14 17:52:03", + "parentId": null, + "children": [ + { + "id": 8, + "name": "User-8", + "type": 6, + "status": 2, + "score": 2, + "experience": 80656, + "sex": "男", + "city": "宿迁市", + "description": "-", + "createTime": "1984-05-24 20:44:26", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 9, + "name": "User-9", + "type": 6, + "status": 2, + "score": 58, + "experience": 2414, + "sex": "女", + "city": "宿州市", + "description": "-", + "createTime": "2015-05-06 00:39:19", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 10, + "name": "User-10", + "type": 4, + "status": 2, + "score": 89, + "experience": 97592, + "sex": "女", + "city": "钦州市", + "description": "-", + "createTime": "1985-05-26 03:50:09", + "parentId": null, + "children": [ + { + "id": 11, + "name": "User-11", + "type": 2, + "status": 2, + "score": 85, + "experience": 37406, + "sex": "女", + "city": "黄南藏族自治州", + "description": "-", + "createTime": "2022-10-09 11:51:44", + "parentId": null, + "children": [ + { + "id": 12, + "name": "User-12", + "type": 4, + "status": 3, + "score": 40, + "experience": 13714, + "sex": "女", + "city": "黔东南苗族侗族自治州", + "description": "-", + "createTime": "1991-09-01 09:19:11", + "parentId": null, + "children": [ + { + "id": 13, + "name": "User-13", + "type": 5, + "status": 4, + "score": 47, + "experience": 89189, + "sex": "男", + "city": "金昌市", + "description": "-", + "createTime": "1978-12-03 09:59:56", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 14, + "name": "User-14", + "type": 2, + "status": 3, + "score": 53, + "experience": 10739, + "sex": "女", + "city": "上海市", + "description": "-", + "createTime": "1989-03-31 19:08:12", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 15, + "name": "User-15", + "type": 5, + "status": 2, + "score": 76, + "experience": 40019, + "sex": "男", + "city": "遵义市", + "description": "-", + "createTime": "1996-12-12 16:34:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 16, + "name": "User-16", + "type": 3, + "status": 1, + "score": 81, + "experience": 30559, + "sex": "男", + "city": "开封市", + "description": "-", + "createTime": "1979-09-24 03:53:59", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 17, + "name": "User-17", + "type": 6, + "status": 4, + "score": 16, + "experience": 56549, + "sex": "女", + "city": "宁波市", + "description": "-", + "createTime": "1994-06-30 15:07:08", + "parentId": null, + "children": [ + { + "id": 18, + "name": "User-18", + "type": 2, + "status": 2, + "score": 22, + "experience": 31311, + "sex": "男", + "city": "黔东南苗族侗族自治州", + "description": "-", + "createTime": "1995-10-07 06:13:07", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 19, + "name": "User-19", + "type": 3, + "status": 1, + "score": 23, + "experience": 63334, + "sex": "女", + "city": "离岛", + "description": "-", + "createTime": "2002-09-25 11:36:07", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 20, + "name": "User-20", + "type": 2, + "status": 2, + "score": 30, + "experience": 5650, + "sex": "男", + "city": "许昌市", + "description": "-", + "createTime": "2001-08-08 14:25:42", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 21, + "name": "User-21", + "type": 2, + "status": 1, + "score": 74, + "experience": 71912, + "sex": "女", + "city": "海北藏族自治州", + "description": "-", + "createTime": "2016-10-18 15:54:30", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 22, + "name": "User-22", + "type": 2, + "status": 3, + "score": 87, + "experience": 65197, + "sex": "女", + "city": "定西市", + "description": "-", + "createTime": "1991-01-09 18:26:58", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 23, + "name": "User-23", + "type": 2, + "status": 4, + "score": 73, + "experience": 27868, + "sex": "男", + "city": "威海市", + "description": "-", + "createTime": "1981-10-13 18:52:11", + "parentId": null, + "children": [ + { + "id": 24, + "name": "User-24", + "type": 4, + "status": 2, + "score": 99, + "experience": 69882, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "1990-09-26 19:08:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 25, + "name": "User-25", + "type": 3, + "status": 2, + "score": 82, + "experience": 25619, + "sex": "女", + "city": "澳门半岛", + "description": "-", + "createTime": "1991-02-16 04:19:14", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 26, + "name": "User-26", + "type": 4, + "status": 2, + "score": 2, + "experience": 8058, + "sex": "男", + "city": "阿里地区", + "description": "-", + "createTime": "2002-10-19 09:44:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 27, + "name": "User-27", + "type": 4, + "status": 4, + "score": 95, + "experience": 68763, + "sex": "男", + "city": "天津市", + "description": "-", + "createTime": "2002-12-24 23:10:26", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 28, + "name": "User-28", + "type": 2, + "status": 4, + "score": 91, + "experience": 33513, + "sex": "女", + "city": "临沂市", + "description": "-", + "createTime": "2003-02-04 13:35:09", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 29, + "name": "User-29", + "type": 1, + "status": 1, + "score": 23, + "experience": 71620, + "sex": "男", + "city": "拉萨市", + "description": "-", + "createTime": "2020-12-22 10:11:11", + "parentId": null, + "children": [ + { + "id": 30, + "name": "User-30", + "type": 3, + "status": 3, + "score": 13, + "experience": 32398, + "sex": "女", + "city": "武威市", + "description": "-", + "createTime": "1982-10-26 11:27:06", + "parentId": null, + "children": [ + { + "id": 31, + "name": "User-31", + "type": 4, + "status": 1, + "score": 93, + "experience": 89245, + "sex": "男", + "city": "楚雄彝族自治州", + "description": "-", + "createTime": "1979-10-05 12:28:39", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 32, + "name": "User-32", + "type": 6, + "status": 4, + "score": 31, + "experience": 73504, + "sex": "女", + "city": "上海市", + "description": "-", + "createTime": "1991-01-11 06:55:04", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 33, + "name": "User-33", + "type": 5, + "status": 4, + "score": 27, + "experience": 95824, + "sex": "女", + "city": "鹰潭市", + "description": "-", + "createTime": "2009-06-17 04:15:06", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 34, + "name": "User-34", + "type": 4, + "status": 1, + "score": 37, + "experience": 63563, + "sex": "男", + "city": "红河哈尼族彝族自治州", + "description": "-", + "createTime": "1979-01-12 13:19:02", + "parentId": null, + "children": [ + { + "id": 35, + "name": "User-35", + "type": 4, + "status": 2, + "score": 81, + "experience": 46868, + "sex": "男", + "city": "德宏傣族景颇族自治州", + "description": "-", + "createTime": "1981-10-24 01:48:43", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 36, + "name": "User-36", + "type": 2, + "status": 1, + "score": 92, + "experience": 70256, + "sex": "女", + "city": "厦门市", + "description": "-", + "createTime": "1998-05-23 22:54:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 37, + "name": "User-37", + "type": 6, + "status": 2, + "score": 25, + "experience": 24689, + "sex": "女", + "city": "铁岭市", + "description": "-", + "createTime": "1980-05-03 04:42:32", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 38, + "name": "User-38", + "type": 4, + "status": 4, + "score": 83, + "experience": 96973, + "sex": "男", + "city": "武汉市", + "description": "-", + "createTime": "1979-11-04 03:18:53", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 39, + "name": "User-39", + "type": 4, + "status": 2, + "score": 37, + "experience": 23248, + "sex": "女", + "city": "黔东南苗族侗族自治州", + "description": "-", + "createTime": "2017-03-03 14:54:05", + "parentId": null, + "children": [ + { + "id": 40, + "name": "User-40", + "type": 5, + "status": 3, + "score": 53, + "experience": 89498, + "sex": "女", + "city": "吐鲁番地区", + "description": "-", + "createTime": "2005-01-14 16:36:11", + "parentId": null, + "children": [ + { + "id": 41, + "name": "User-41", + "type": 4, + "status": 3, + "score": 13, + "experience": 47225, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "1994-07-14 23:17:37", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 42, + "name": "User-42", + "type": 2, + "status": 2, + "score": 54, + "experience": 67027, + "sex": "男", + "city": "丽水市", + "description": "-", + "createTime": "2019-04-06 23:40:35", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 43, + "name": "User-43", + "type": 2, + "status": 2, + "score": 59, + "experience": 16009, + "sex": "男", + "city": "新界", + "description": "-", + "createTime": "1972-11-10 06:24:19", + "parentId": null, + "children": [ + { + "id": 44, + "name": "User-44", + "type": 6, + "status": 3, + "score": 26, + "experience": 48609, + "sex": "女", + "city": "东莞市", + "description": "-", + "createTime": "1993-04-21 21:27:36", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 45, + "name": "User-45", + "type": 1, + "status": 2, + "score": 28, + "experience": 13681, + "sex": "女", + "city": "常德市", + "description": "-", + "createTime": "2016-01-19 16:21:48", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 46, + "name": "User-46", + "type": 1, + "status": 2, + "score": 77, + "experience": 50932, + "sex": "男", + "city": "武汉市", + "description": "-", + "createTime": "1977-11-26 05:13:27", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 47, + "name": "User-47", + "type": 3, + "status": 1, + "score": 10, + "experience": 19599, + "sex": "男", + "city": "长治市", + "description": "-", + "createTime": "1980-10-28 04:42:20", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 48, + "name": "User-48", + "type": 6, + "status": 3, + "score": 50, + "experience": 63403, + "sex": "男", + "city": "香港岛", + "description": "-", + "createTime": "1974-05-23 17:23:13", + "parentId": null, + "children": [ + { + "id": 49, + "name": "User-49", + "type": 2, + "status": 1, + "score": 7, + "experience": 21161, + "sex": "男", + "city": "梅州市", + "description": "-", + "createTime": "1977-05-01 15:25:24", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 50, + "name": "User-50", + "type": 5, + "status": 2, + "score": 34, + "experience": 93741, + "sex": "男", + "city": "鸡西市", + "description": "-", + "createTime": "2018-04-14 23:13:38", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 51, + "name": "User-51", + "type": 2, + "status": 2, + "score": 92, + "experience": 36687, + "sex": "女", + "city": "温州市", + "description": "-", + "createTime": "1993-06-04 04:00:14", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 52, + "name": "User-52", + "type": 6, + "status": 2, + "score": 14, + "experience": 47342, + "sex": "男", + "city": "重庆市", + "description": "-", + "createTime": "1972-02-26 22:46:51", + "parentId": null, + "children": [ + { + "id": 53, + "name": "User-53", + "type": 1, + "status": 3, + "score": 97, + "experience": 40784, + "sex": "男", + "city": "邵阳市", + "description": "-", + "createTime": "1976-12-27 01:00:37", + "parentId": null, + "children": [ + { + "id": 54, + "name": "User-54", + "type": 4, + "status": 3, + "score": 93, + "experience": 10865, + "sex": "男", + "city": "龙岩市", + "description": "-", + "createTime": "2001-09-03 02:08:42", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 55, + "name": "User-55", + "type": 1, + "status": 2, + "score": 56, + "experience": 68232, + "sex": "男", + "city": "赣州市", + "description": "-", + "createTime": "1995-12-13 08:29:10", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 56, + "name": "User-56", + "type": 1, + "status": 2, + "score": 46, + "experience": 68897, + "sex": "女", + "city": "哈密地区", + "description": "-", + "createTime": "2007-08-05 00:54:06", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 57, + "name": "User-57", + "type": 4, + "status": 3, + "score": 68, + "experience": 58983, + "sex": "女", + "city": "北京市", + "description": "-", + "createTime": "1979-03-14 13:21:33", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 58, + "name": "User-58", + "type": 5, + "status": 1, + "score": 6, + "experience": 17343, + "sex": "男", + "city": "苗栗县", + "description": "-", + "createTime": "1996-01-21 18:43:11", + "parentId": null, + "children": [ + { + "id": 59, + "name": "User-59", + "type": 5, + "status": 2, + "score": 98, + "experience": 75262, + "sex": "女", + "city": "怀化市", + "description": "-", + "createTime": "2022-06-28 12:25:50", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 60, + "name": "User-60", + "type": 3, + "status": 3, + "score": 3, + "experience": 5817, + "sex": "女", + "city": "三亚市", + "description": "-", + "createTime": "1993-10-13 21:54:57", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 61, + "name": "User-61", + "type": 2, + "status": 3, + "score": 3, + "experience": 65548, + "sex": "男", + "city": "台州市", + "description": "-", + "createTime": "2017-11-06 13:16:14", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 62, + "name": "User-62", + "type": 5, + "status": 3, + "score": 37, + "experience": 33679, + "sex": "女", + "city": "辽源市", + "description": "-", + "createTime": "2002-10-19 22:53:23", + "parentId": null, + "children": [ + { + "id": 63, + "name": "User-63", + "type": 5, + "status": 3, + "score": 12, + "experience": 91033, + "sex": "女", + "city": "银川市", + "description": "-", + "createTime": "1973-04-17 07:33:35", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 64, + "name": "User-64", + "type": 3, + "status": 2, + "score": 87, + "experience": 30560, + "sex": "男", + "city": "昌都地区", + "description": "-", + "createTime": "1992-06-13 23:04:16", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 65, + "name": "User-65", + "type": 5, + "status": 2, + "score": 27, + "experience": 17982, + "sex": "女", + "city": "商洛市", + "description": "-", + "createTime": "2008-08-22 09:14:10", + "parentId": null, + "children": [ + { + "id": 66, + "name": "User-66", + "type": 3, + "status": 3, + "score": 91, + "experience": 47135, + "sex": "女", + "city": "离岛", + "description": "-", + "createTime": "1971-01-27 18:29:48", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 67, + "name": "User-67", + "type": 2, + "status": 1, + "score": 19, + "experience": 31440, + "sex": "女", + "city": "随州市", + "description": "-", + "createTime": "1979-10-14 10:30:22", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 68, + "name": "User-68", + "type": 5, + "status": 1, + "score": 88, + "experience": 48196, + "sex": "男", + "city": "承德市", + "description": "-", + "createTime": "1996-02-07 03:52:51", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 69, + "name": "User-69", + "type": 5, + "status": 1, + "score": 46, + "experience": 45341, + "sex": "女", + "city": "黔东南苗族侗族自治州", + "description": "-", + "createTime": "1995-05-08 20:53:45", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 70, + "name": "User-70", + "type": 3, + "status": 3, + "score": 19, + "experience": 66961, + "sex": "女", + "city": "固原市", + "description": "-", + "createTime": "1992-04-11 09:13:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 71, + "name": "User-71", + "type": 1, + "status": 3, + "score": 4, + "experience": 95553, + "sex": "女", + "city": "那曲地区", + "description": "-", + "createTime": "2019-07-31 00:30:49", + "parentId": null, + "children": [ + { + "id": 72, + "name": "User-72", + "type": 4, + "status": 4, + "score": 89, + "experience": 27410, + "sex": "男", + "city": "贺州市", + "description": "-", + "createTime": "1990-09-07 03:02:32", + "parentId": null, + "children": [ + { + "id": 73, + "name": "User-73", + "type": 6, + "status": 4, + "score": 93, + "experience": 84018, + "sex": "男", + "city": "雅安市", + "description": "-", + "createTime": "1972-01-18 02:00:25", + "parentId": null, + "children": [ + { + "id": 74, + "name": "User-74", + "type": 1, + "status": 4, + "score": 22, + "experience": 23025, + "sex": "女", + "city": "济南市", + "description": "-", + "createTime": "1991-12-18 23:27:07", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 75, + "name": "User-75", + "type": 5, + "status": 2, + "score": 75, + "experience": 58006, + "sex": "男", + "city": "新界", + "description": "-", + "createTime": "2004-03-03 09:28:00", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 76, + "name": "User-76", + "type": 2, + "status": 1, + "score": 79, + "experience": 86538, + "sex": "男", + "city": "果洛藏族自治州", + "description": "-", + "createTime": "2000-02-09 12:26:36", + "parentId": null, + "children": [ + { + "id": 77, + "name": "User-77", + "type": 2, + "status": 3, + "score": 60, + "experience": 61903, + "sex": "女", + "city": "呼伦贝尔市", + "description": "-", + "createTime": "1991-04-19 19:31:38", + "parentId": null, + "children": [ + { + "id": 78, + "name": "User-78", + "type": 4, + "status": 2, + "score": 67, + "experience": 10844, + "sex": "女", + "city": "鞍山市", + "description": "-", + "createTime": "2017-03-26 15:43:27", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 79, + "name": "User-79", + "type": 4, + "status": 2, + "score": 46, + "experience": 25354, + "sex": "男", + "city": "鸡西市", + "description": "-", + "createTime": "2018-01-30 03:43:56", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 80, + "name": "User-80", + "type": 5, + "status": 3, + "score": 13, + "experience": 30626, + "sex": "女", + "city": "玉溪市", + "description": "-", + "createTime": "1984-03-18 11:35:15", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 81, + "name": "User-81", + "type": 4, + "status": 3, + "score": 34, + "experience": 97578, + "sex": "女", + "city": "信阳市", + "description": "-", + "createTime": "2004-08-20 12:21:16", + "parentId": null, + "children": [ + { + "id": 82, + "name": "User-82", + "type": 6, + "status": 3, + "score": 38, + "experience": 7285, + "sex": "男", + "city": "舟山市", + "description": "-", + "createTime": "2001-03-16 07:04:17", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 83, + "name": "User-83", + "type": 3, + "status": 1, + "score": 51, + "experience": 41380, + "sex": "女", + "city": "佛山市", + "description": "-", + "createTime": "1998-06-01 18:21:57", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 84, + "name": "User-84", + "type": 2, + "status": 3, + "score": 37, + "experience": 19153, + "sex": "女", + "city": "宜宾市", + "description": "-", + "createTime": "1985-10-30 09:16:58", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 85, + "name": "User-85", + "type": 1, + "status": 1, + "score": 94, + "experience": 63371, + "sex": "男", + "city": "淮南市", + "description": "-", + "createTime": "2019-02-28 22:24:25", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 86, + "name": "User-86", + "type": 2, + "status": 4, + "score": 67, + "experience": 25315, + "sex": "男", + "city": "黔西南布依族苗族自治州", + "description": "-", + "createTime": "2011-11-29 07:06:26", + "parentId": null, + "children": [ + { + "id": 87, + "name": "User-87", + "type": 4, + "status": 4, + "score": 52, + "experience": 10751, + "sex": "女", + "city": "离岛", + "description": "-", + "createTime": "2022-08-05 23:21:27", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 88, + "name": "User-88", + "type": 4, + "status": 2, + "score": 65, + "experience": 38077, + "sex": "女", + "city": "黄石市", + "description": "-", + "createTime": "2007-12-12 15:47:51", + "parentId": null, + "children": [ + { + "id": 89, + "name": "User-89", + "type": 6, + "status": 2, + "score": 78, + "experience": 78006, + "sex": "男", + "city": "海口市", + "description": "-", + "createTime": "2007-10-20 18:46:39", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 90, + "name": "User-90", + "type": 3, + "status": 3, + "score": 66, + "experience": 91901, + "sex": "女", + "city": "上海市", + "description": "-", + "createTime": "1993-08-25 20:32:32", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 91, + "name": "User-91", + "type": 3, + "status": 3, + "score": 61, + "experience": 26129, + "sex": "女", + "city": "白山市", + "description": "-", + "createTime": "2002-01-04 16:12:16", + "parentId": null, + "children": [ + { + "id": 92, + "name": "User-92", + "type": 5, + "status": 3, + "score": 19, + "experience": 34580, + "sex": "男", + "city": "庆阳市", + "description": "-", + "createTime": "1987-02-28 01:36:59", + "parentId": null, + "children": [ + { + "id": 93, + "name": "User-93", + "type": 4, + "status": 4, + "score": 7, + "experience": 40805, + "sex": "女", + "city": "广州市", + "description": "-", + "createTime": "1986-02-23 02:19:01", + "parentId": null, + "children": [ + { + "id": 94, + "name": "User-94", + "type": 4, + "status": 2, + "score": 28, + "experience": 85777, + "sex": "男", + "city": "昌吉回族自治州", + "description": "-", + "createTime": "1987-02-21 18:49:17", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 95, + "name": "User-95", + "type": 3, + "status": 3, + "score": 33, + "experience": 50551, + "sex": "女", + "city": "三明市", + "description": "-", + "createTime": "2013-04-24 20:49:56", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 96, + "name": "User-96", + "type": 2, + "status": 2, + "score": 21, + "experience": 19915, + "sex": "女", + "city": "黄石市", + "description": "-", + "createTime": "2017-05-09 12:17:42", + "parentId": null, + "children": [ + { + "id": 97, + "name": "User-97", + "type": 3, + "status": 3, + "score": 25, + "experience": 22618, + "sex": "女", + "city": "汕尾市", + "description": "-", + "createTime": "1977-03-13 12:50:50", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 98, + "name": "User-98", + "type": 6, + "status": 2, + "score": 14, + "experience": 43979, + "sex": "女", + "city": "温州市", + "description": "-", + "createTime": "1991-04-10 20:49:11", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 99, + "name": "User-99", + "type": 3, + "status": 2, + "score": 82, + "experience": 24670, + "sex": "男", + "city": "贵港市", + "description": "-", + "createTime": "2012-12-19 08:28:58", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 100, + "name": "User-100", + "type": 4, + "status": 3, + "score": 64, + "experience": 84287, + "sex": "女", + "city": "张家界市", + "description": "-", + "createTime": "2000-09-28 06:14:34", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 101, + "name": "User-101", + "type": 3, + "status": 4, + "score": 68, + "experience": 39312, + "sex": "男", + "city": "玉树藏族自治州", + "description": "-", + "createTime": "2020-09-20 05:35:35", + "parentId": null, + "children": [ + { + "id": 102, + "name": "User-102", + "type": 3, + "status": 1, + "score": 74, + "experience": 16276, + "sex": "女", + "city": "延安市", + "description": "-", + "createTime": "1980-10-04 17:59:56", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 103, + "name": "User-103", + "type": 5, + "status": 2, + "score": 91, + "experience": 67473, + "sex": "男", + "city": "桃园县", + "description": "-", + "createTime": "2007-01-04 07:46:21", + "parentId": null, + "children": [ + { + "id": 104, + "name": "User-104", + "type": 1, + "status": 3, + "score": 3, + "experience": 91897, + "sex": "男", + "city": "营口市", + "description": "-", + "createTime": "2012-07-04 00:39:19", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 105, + "name": "User-105", + "type": 5, + "status": 2, + "score": 36, + "experience": 12972, + "sex": "男", + "city": "德州市", + "description": "-", + "createTime": "1993-06-04 03:52:48", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 106, + "name": "User-106", + "type": 2, + "status": 3, + "score": 60, + "experience": 58793, + "sex": "女", + "city": "开封市", + "description": "-", + "createTime": "2003-10-28 05:15:25", + "parentId": null, + "children": [ + { + "id": 107, + "name": "User-107", + "type": 6, + "status": 3, + "score": 70, + "experience": 88564, + "sex": "女", + "city": "大理白族自治州", + "description": "-", + "createTime": "1991-03-19 01:51:41", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 108, + "name": "User-108", + "type": 2, + "status": 2, + "score": 85, + "experience": 47918, + "sex": "男", + "city": "金门县", + "description": "-", + "createTime": "2015-06-18 04:18:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 109, + "name": "User-109", + "type": 2, + "status": 2, + "score": 15, + "experience": 72530, + "sex": "女", + "city": "上海市", + "description": "-", + "createTime": "1997-10-10 20:26:03", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 110, + "name": "User-110", + "type": 2, + "status": 2, + "score": 83, + "experience": 26538, + "sex": "男", + "city": "新竹市", + "description": "-", + "createTime": "2007-07-26 23:09:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 111, + "name": "User-111", + "type": 4, + "status": 2, + "score": 43, + "experience": 42129, + "sex": "男", + "city": "赤峰市", + "description": "-", + "createTime": "2015-12-17 09:23:18", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 112, + "name": "User-112", + "type": 4, + "status": 1, + "score": 74, + "experience": 61862, + "sex": "女", + "city": "潍坊市", + "description": "-", + "createTime": "2018-02-12 13:13:10", + "parentId": null, + "children": [ + { + "id": 113, + "name": "User-113", + "type": 1, + "status": 2, + "score": 65, + "experience": 52650, + "sex": "男", + "city": "德宏傣族景颇族自治州", + "description": "-", + "createTime": "2011-04-13 09:19:21", + "parentId": null, + "children": [ + { + "id": 114, + "name": "User-114", + "type": 3, + "status": 1, + "score": 82, + "experience": 53304, + "sex": "男", + "city": "益阳市", + "description": "-", + "createTime": "2021-09-25 03:56:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 115, + "name": "User-115", + "type": 3, + "status": 3, + "score": 32, + "experience": 1231, + "sex": "男", + "city": "娄底市", + "description": "-", + "createTime": "1984-10-28 18:20:13", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 116, + "name": "User-116", + "type": 3, + "status": 3, + "score": 89, + "experience": 65939, + "sex": "女", + "city": "昌都地区", + "description": "-", + "createTime": "1982-10-31 15:16:26", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 117, + "name": "User-117", + "type": 2, + "status": 4, + "score": 15, + "experience": 19416, + "sex": "女", + "city": "长治市", + "description": "-", + "createTime": "1990-04-09 13:29:32", + "parentId": null, + "children": [ + { + "id": 118, + "name": "User-118", + "type": 5, + "status": 2, + "score": 97, + "experience": 49212, + "sex": "女", + "city": "那曲地区", + "description": "-", + "createTime": "2018-12-15 15:50:57", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 119, + "name": "User-119", + "type": 2, + "status": 3, + "score": 82, + "experience": 19392, + "sex": "男", + "city": "海外", + "description": "-", + "createTime": "2016-03-01 20:52:25", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 120, + "name": "User-120", + "type": 5, + "status": 4, + "score": 51, + "experience": 78906, + "sex": "女", + "city": "九龙", + "description": "-", + "createTime": "1970-01-23 05:58:55", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 121, + "name": "User-121", + "type": 1, + "status": 2, + "score": 62, + "experience": 67953, + "sex": "女", + "city": "中山市", + "description": "-", + "createTime": "1980-03-31 19:15:07", + "parentId": null, + "children": [ + { + "id": 122, + "name": "User-122", + "type": 3, + "status": 2, + "score": 42, + "experience": 75027, + "sex": "男", + "city": "香港岛", + "description": "-", + "createTime": "1991-11-08 11:29:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 123, + "name": "User-123", + "type": 4, + "status": 1, + "score": 27, + "experience": 50832, + "sex": "男", + "city": "牡丹江市", + "description": "-", + "createTime": "1987-10-23 04:08:04", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 124, + "name": "User-124", + "type": 4, + "status": 3, + "score": 20, + "experience": 43261, + "sex": "男", + "city": "沧州市", + "description": "-", + "createTime": "2008-06-13 20:20:22", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 125, + "name": "User-125", + "type": 5, + "status": 2, + "score": 61, + "experience": 50399, + "sex": "女", + "city": "山南地区", + "description": "-", + "createTime": "2015-12-14 21:59:46", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 126, + "name": "User-126", + "type": 5, + "status": 2, + "score": 88, + "experience": 26933, + "sex": "女", + "city": "扬州市", + "description": "-", + "createTime": "1971-07-16 11:58:22", + "parentId": null, + "children": [ + { + "id": 127, + "name": "User-127", + "type": 1, + "status": 3, + "score": 86, + "experience": 15913, + "sex": "女", + "city": "宁波市", + "description": "-", + "createTime": "1979-06-01 23:52:36", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 128, + "name": "User-128", + "type": 5, + "status": 2, + "score": 61, + "experience": 74072, + "sex": "男", + "city": "乌兰察布市", + "description": "-", + "createTime": "1997-09-24 16:31:03", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 129, + "name": "User-129", + "type": 1, + "status": 3, + "score": 39, + "experience": 94200, + "sex": "男", + "city": "香港岛", + "description": "-", + "createTime": "1990-04-22 15:12:45", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 130, + "name": "User-130", + "type": 3, + "status": 3, + "score": 78, + "experience": 59502, + "sex": "男", + "city": "天津市", + "description": "-", + "createTime": "2011-01-03 07:20:25", + "parentId": null, + "children": [ + { + "id": 131, + "name": "User-131", + "type": 2, + "status": 3, + "score": 29, + "experience": 16545, + "sex": "男", + "city": "德阳市", + "description": "-", + "createTime": "2001-05-07 05:02:42", + "parentId": null, + "children": [ + { + "id": 132, + "name": "User-132", + "type": 3, + "status": 3, + "score": 53, + "experience": 8310, + "sex": "男", + "city": "襄阳市", + "description": "-", + "createTime": "1996-05-12 11:23:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 133, + "name": "User-133", + "type": 2, + "status": 3, + "score": 6, + "experience": 10610, + "sex": "男", + "city": "海口市", + "description": "-", + "createTime": "2013-05-11 17:50:19", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 134, + "name": "User-134", + "type": 4, + "status": 2, + "score": 67, + "experience": 70882, + "sex": "男", + "city": "遵义市", + "description": "-", + "createTime": "2014-03-04 22:55:14", + "parentId": null, + "children": [ + { + "id": 135, + "name": "User-135", + "type": 4, + "status": 3, + "score": 34, + "experience": 87799, + "sex": "女", + "city": "苗栗县", + "description": "-", + "createTime": "1990-04-13 14:44:06", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 136, + "name": "User-136", + "type": 6, + "status": 1, + "score": 66, + "experience": 58817, + "sex": "男", + "city": "大连市", + "description": "-", + "createTime": "1990-04-28 21:04:33", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 137, + "name": "User-137", + "type": 6, + "status": 2, + "score": 74, + "experience": 95991, + "sex": "男", + "city": "那曲地区", + "description": "-", + "createTime": "1994-06-04 16:01:44", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 138, + "name": "User-138", + "type": 1, + "status": 2, + "score": 99, + "experience": 71832, + "sex": "男", + "city": "阿里地区", + "description": "-", + "createTime": "1988-03-10 13:17:59", + "parentId": null, + "children": [ + { + "id": 139, + "name": "User-139", + "type": 6, + "status": 4, + "score": 36, + "experience": 86381, + "sex": "女", + "city": "菏泽市", + "description": "-", + "createTime": "2021-04-22 22:27:06", + "parentId": null, + "children": [ + { + "id": 140, + "name": "User-140", + "type": 6, + "status": 3, + "score": 36, + "experience": 43655, + "sex": "女", + "city": "通辽市", + "description": "-", + "createTime": "2001-12-20 09:14:52", + "parentId": null, + "children": [ + { + "id": 141, + "name": "User-141", + "type": 3, + "status": 2, + "score": 10, + "experience": 65976, + "sex": "女", + "city": "雅安市", + "description": "-", + "createTime": "1996-08-28 19:08:53", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 142, + "name": "User-142", + "type": 6, + "status": 4, + "score": 89, + "experience": 9828, + "sex": "男", + "city": "白山市", + "description": "-", + "createTime": "1985-09-21 14:58:12", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 143, + "name": "User-143", + "type": 6, + "status": 2, + "score": 1, + "experience": 84064, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "1973-11-04 08:28:54", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 144, + "name": "User-144", + "type": 5, + "status": 2, + "score": 46, + "experience": 51038, + "sex": "女", + "city": "南昌市", + "description": "-", + "createTime": "2010-01-27 02:05:48", + "parentId": null, + "children": [ + { + "id": 145, + "name": "User-145", + "type": 1, + "status": 3, + "score": 82, + "experience": 53656, + "sex": "女", + "city": "玉林市", + "description": "-", + "createTime": "1996-05-21 10:13:12", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 146, + "name": "User-146", + "type": 6, + "status": 4, + "score": 24, + "experience": 10700, + "sex": "男", + "city": "赤峰市", + "description": "-", + "createTime": "1998-03-08 12:08:46", + "parentId": null, + "children": [ + { + "id": 147, + "name": "User-147", + "type": 3, + "status": 1, + "score": 94, + "experience": 85060, + "sex": "女", + "city": "自贡市", + "description": "-", + "createTime": "2002-07-29 08:02:19", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 148, + "name": "User-148", + "type": 5, + "status": 2, + "score": 93, + "experience": 24255, + "sex": "男", + "city": "盐城市", + "description": "-", + "createTime": "2020-02-01 14:30:19", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 149, + "name": "User-149", + "type": 2, + "status": 4, + "score": 18, + "experience": 78062, + "sex": "女", + "city": "内江市", + "description": "-", + "createTime": "2003-02-26 08:59:31", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 150, + "name": "User-150", + "type": 4, + "status": 2, + "score": 13, + "experience": 48858, + "sex": "女", + "city": "上海市", + "description": "-", + "createTime": "1985-05-14 18:47:46", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 151, + "name": "User-151", + "type": 2, + "status": 3, + "score": 36, + "experience": 12807, + "sex": "男", + "city": "舟山市", + "description": "-", + "createTime": "2004-12-04 23:49:41", + "parentId": null, + "children": [ + { + "id": 152, + "name": "User-152", + "type": 2, + "status": 1, + "score": 60, + "experience": 38168, + "sex": "女", + "city": "喀什地区", + "description": "-", + "createTime": "1985-09-17 01:12:06", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 153, + "name": "User-153", + "type": 6, + "status": 1, + "score": 77, + "experience": 74590, + "sex": "男", + "city": "天津市", + "description": "-", + "createTime": "1970-02-02 10:02:55", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 154, + "name": "User-154", + "type": 5, + "status": 2, + "score": 92, + "experience": 76944, + "sex": "女", + "city": "临沧市", + "description": "-", + "createTime": "2013-12-06 17:42:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 155, + "name": "User-155", + "type": 3, + "status": 2, + "score": 29, + "experience": 78692, + "sex": "男", + "city": "秦皇岛市", + "description": "-", + "createTime": "2016-07-16 14:25:28", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 156, + "name": "User-156", + "type": 4, + "status": 2, + "score": 79, + "experience": 99919, + "sex": "女", + "city": "凉山彝族自治州", + "description": "-", + "createTime": "2010-07-15 10:21:19", + "parentId": null, + "children": [ + { + "id": 157, + "name": "User-157", + "type": 5, + "status": 3, + "score": 91, + "experience": 52354, + "sex": "男", + "city": "铜仁市", + "description": "-", + "createTime": "1977-03-20 09:15:54", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 158, + "name": "User-158", + "type": 5, + "status": 2, + "score": 22, + "experience": 51977, + "sex": "女", + "city": "宿州市", + "description": "-", + "createTime": "2016-11-17 20:01:17", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 159, + "name": "User-159", + "type": 1, + "status": 2, + "score": 43, + "experience": 46650, + "sex": "女", + "city": "沧州市", + "description": "-", + "createTime": "1987-09-05 06:14:08", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 160, + "name": "User-160", + "type": 6, + "status": 2, + "score": 57, + "experience": 7416, + "sex": "男", + "city": "澎湖县", + "description": "-", + "createTime": "1974-08-10 20:09:38", + "parentId": null, + "children": [ + { + "id": 161, + "name": "User-161", + "type": 5, + "status": 1, + "score": 53, + "experience": 12421, + "sex": "男", + "city": "阿克苏地区", + "description": "-", + "createTime": "1998-02-07 11:52:05", + "parentId": null, + "children": [ + { + "id": 162, + "name": "User-162", + "type": 3, + "status": 2, + "score": 100, + "experience": 19507, + "sex": "女", + "city": "随州市", + "description": "-", + "createTime": "2014-01-31 07:58:18", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 163, + "name": "User-163", + "type": 2, + "status": 2, + "score": 12, + "experience": 35637, + "sex": "男", + "city": "拉萨市", + "description": "-", + "createTime": "1983-10-02 10:31:23", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 164, + "name": "User-164", + "type": 6, + "status": 3, + "score": 65, + "experience": 42198, + "sex": "男", + "city": "香港岛", + "description": "-", + "createTime": "1987-12-22 14:34:32", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 165, + "name": "User-165", + "type": 2, + "status": 2, + "score": 73, + "experience": 40495, + "sex": "女", + "city": "天津市", + "description": "-", + "createTime": "1992-11-29 08:54:58", + "parentId": null, + "children": [ + { + "id": 166, + "name": "User-166", + "type": 3, + "status": 3, + "score": 83, + "experience": 62007, + "sex": "男", + "city": "重庆市", + "description": "-", + "createTime": "1992-10-01 19:14:47", + "parentId": null, + "children": [ + { + "id": 167, + "name": "User-167", + "type": 5, + "status": 4, + "score": 75, + "experience": 18137, + "sex": "女", + "city": "安顺市", + "description": "-", + "createTime": "2011-10-10 19:40:42", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 168, + "name": "User-168", + "type": 4, + "status": 3, + "score": 80, + "experience": 95421, + "sex": "男", + "city": "吴忠市", + "description": "-", + "createTime": "1972-10-27 14:58:59", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 169, + "name": "User-169", + "type": 6, + "status": 3, + "score": 10, + "experience": 2784, + "sex": "男", + "city": "伊春市", + "description": "-", + "createTime": "1992-07-06 23:16:42", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 170, + "name": "User-170", + "type": 5, + "status": 3, + "score": 68, + "experience": 54101, + "sex": "男", + "city": "贺州市", + "description": "-", + "createTime": "1970-01-21 21:50:15", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 171, + "name": "User-171", + "type": 5, + "status": 3, + "score": 38, + "experience": 51261, + "sex": "男", + "city": "上海市", + "description": "-", + "createTime": "1982-11-14 19:25:51", + "parentId": null, + "children": [ + { + "id": 172, + "name": "User-172", + "type": 3, + "status": 2, + "score": 4, + "experience": 73963, + "sex": "男", + "city": "徐州市", + "description": "-", + "createTime": "1993-04-15 02:08:57", + "parentId": null, + "children": [ + { + "id": 173, + "name": "User-173", + "type": 3, + "status": 1, + "score": 51, + "experience": 68723, + "sex": "女", + "city": "青岛市", + "description": "-", + "createTime": "2015-10-21 10:53:20", + "parentId": null, + "children": [ + { + "id": 174, + "name": "User-174", + "type": 3, + "status": 3, + "score": 68, + "experience": 62848, + "sex": "女", + "city": "周口市", + "description": "-", + "createTime": "2015-12-19 01:15:13", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 175, + "name": "User-175", + "type": 2, + "status": 3, + "score": 87, + "experience": 30871, + "sex": "女", + "city": "汕头市", + "description": "-", + "createTime": "1982-12-29 02:15:08", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 176, + "name": "User-176", + "type": 6, + "status": 2, + "score": 7, + "experience": 80089, + "sex": "男", + "city": "吉林市", + "description": "-", + "createTime": "2003-02-25 18:41:27", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 177, + "name": "User-177", + "type": 5, + "status": 4, + "score": 11, + "experience": 21782, + "sex": "女", + "city": "乌兰察布市", + "description": "-", + "createTime": "2014-10-10 20:45:07", + "parentId": null, + "children": [ + { + "id": 178, + "name": "User-178", + "type": 2, + "status": 2, + "score": 85, + "experience": 87330, + "sex": "女", + "city": "三亚市", + "description": "-", + "createTime": "1990-12-25 14:48:30", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 179, + "name": "User-179", + "type": 1, + "status": 1, + "score": 28, + "experience": 58951, + "sex": "男", + "city": "天津市", + "description": "-", + "createTime": "2007-09-14 00:42:03", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 180, + "name": "User-180", + "type": 5, + "status": 3, + "score": 74, + "experience": 83136, + "sex": "男", + "city": "抚州市", + "description": "-", + "createTime": "1990-08-17 16:49:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 181, + "name": "User-181", + "type": 1, + "status": 1, + "score": 37, + "experience": 40840, + "sex": "女", + "city": "三亚市", + "description": "-", + "createTime": "2000-05-12 08:01:46", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 182, + "name": "User-182", + "type": 1, + "status": 3, + "score": 40, + "experience": 86857, + "sex": "女", + "city": "三亚市", + "description": "-", + "createTime": "1981-03-30 01:02:44", + "parentId": null, + "children": [ + { + "id": 183, + "name": "User-183", + "type": 3, + "status": 1, + "score": 26, + "experience": 50377, + "sex": "男", + "city": "崇左市", + "description": "-", + "createTime": "1998-03-18 08:42:14", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 184, + "name": "User-184", + "type": 5, + "status": 3, + "score": 25, + "experience": 54099, + "sex": "女", + "city": "海口市", + "description": "-", + "createTime": "1980-01-26 12:11:04", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 185, + "name": "User-185", + "type": 6, + "status": 3, + "score": 87, + "experience": 80569, + "sex": "女", + "city": "运城市", + "description": "-", + "createTime": "2006-06-17 02:03:31", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 186, + "name": "User-186", + "type": 6, + "status": 3, + "score": 36, + "experience": 98204, + "sex": "男", + "city": "毕节市", + "description": "-", + "createTime": "1973-12-17 13:58:14", + "parentId": null, + "children": [ + { + "id": 187, + "name": "User-187", + "type": 2, + "status": 2, + "score": 50, + "experience": 6656, + "sex": "女", + "city": "常德市", + "description": "-", + "createTime": "1977-05-19 04:12:32", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 188, + "name": "User-188", + "type": 5, + "status": 2, + "score": 51, + "experience": 70421, + "sex": "男", + "city": "雅安市", + "description": "-", + "createTime": "1992-05-19 11:41:49", + "parentId": null, + "children": [ + { + "id": 189, + "name": "User-189", + "type": 3, + "status": 3, + "score": 86, + "experience": 10970, + "sex": "女", + "city": "陇南市", + "description": "-", + "createTime": "1986-07-20 03:40:31", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 190, + "name": "User-190", + "type": 6, + "status": 2, + "score": 81, + "experience": 35296, + "sex": "男", + "city": "重庆市", + "description": "-", + "createTime": "1994-08-03 11:42:24", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 191, + "name": "User-191", + "type": 2, + "status": 3, + "score": 36, + "experience": 60289, + "sex": "女", + "city": "滨州市", + "description": "-", + "createTime": "1981-11-09 18:18:23", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 192, + "name": "User-192", + "type": 1, + "status": 3, + "score": 80, + "experience": 84656, + "sex": "女", + "city": "果洛藏族自治州", + "description": "-", + "createTime": "1986-02-13 13:31:38", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 193, + "name": "User-193", + "type": 5, + "status": 2, + "score": 1, + "experience": 14433, + "sex": "男", + "city": "临汾市", + "description": "-", + "createTime": "2006-03-03 20:42:43", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 194, + "name": "User-194", + "type": 3, + "status": 4, + "score": 53, + "experience": 22962, + "sex": "女", + "city": "赣州市", + "description": "-", + "createTime": "2003-09-23 05:57:47", + "parentId": null, + "children": [ + { + "id": 195, + "name": "User-195", + "type": 3, + "status": 4, + "score": 78, + "experience": 80409, + "sex": "男", + "city": "晋城市", + "description": "-", + "createTime": "2022-04-16 13:45:56", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 196, + "name": "User-196", + "type": 3, + "status": 2, + "score": 83, + "experience": 35535, + "sex": "女", + "city": "庆阳市", + "description": "-", + "createTime": "2012-12-04 08:46:54", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 197, + "name": "User-197", + "type": 3, + "status": 2, + "score": 77, + "experience": 83542, + "sex": "女", + "city": "锦州市", + "description": "-", + "createTime": "2000-04-28 15:35:04", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 198, + "name": "User-198", + "type": 3, + "status": 4, + "score": 83, + "experience": 62489, + "sex": "女", + "city": "温州市", + "description": "-", + "createTime": "1989-12-11 18:50:29", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 199, + "name": "User-199", + "type": 2, + "status": 3, + "score": 81, + "experience": 74602, + "sex": "男", + "city": "自贡市", + "description": "-", + "createTime": "1996-10-30 22:16:31", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 200, + "name": "User-200", + "type": 6, + "status": 2, + "score": 31, + "experience": 28502, + "sex": "男", + "city": "宜兰县", + "description": "-", + "createTime": "1991-03-29 10:56:11", + "parentId": null, + "children": [ + { + "id": 201, + "name": "User-201", + "type": 5, + "status": 3, + "score": 23, + "experience": 45619, + "sex": "男", + "city": "商洛市", + "description": "-", + "createTime": "1997-11-04 08:13:06", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 202, + "name": "User-202", + "type": 5, + "status": 3, + "score": 7, + "experience": 7566, + "sex": "女", + "city": "随州市", + "description": "-", + "createTime": "1981-08-19 01:15:48", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 203, + "name": "User-203", + "type": 1, + "status": 3, + "score": 63, + "experience": 94626, + "sex": "男", + "city": "西宁市", + "description": "-", + "createTime": "1986-04-30 06:19:17", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 204, + "name": "User-204", + "type": 3, + "status": 3, + "score": 33, + "experience": 85619, + "sex": "女", + "city": "哈密地区", + "description": "-", + "createTime": "1977-09-15 16:53:05", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 205, + "name": "User-205", + "type": 3, + "status": 2, + "score": 95, + "experience": 66286, + "sex": "男", + "city": "安康市", + "description": "-", + "createTime": "1994-09-09 20:34:24", + "parentId": null, + "children": [ + { + "id": 206, + "name": "User-206", + "type": 5, + "status": 3, + "score": 48, + "experience": 93916, + "sex": "男", + "city": "攀枝花市", + "description": "-", + "createTime": "1996-05-16 00:14:46", + "parentId": null, + "children": [ + { + "id": 207, + "name": "User-207", + "type": 5, + "status": 3, + "score": 97, + "experience": 37124, + "sex": "女", + "city": "呼伦贝尔市", + "description": "-", + "createTime": "2009-06-18 14:55:19", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 208, + "name": "User-208", + "type": 2, + "status": 3, + "score": 77, + "experience": 37342, + "sex": "女", + "city": "九龙", + "description": "-", + "createTime": "2007-07-30 00:07:45", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 209, + "name": "User-209", + "type": 4, + "status": 1, + "score": 77, + "experience": 82846, + "sex": "男", + "city": "扬州市", + "description": "-", + "createTime": "1984-05-17 17:37:13", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 210, + "name": "User-210", + "type": 3, + "status": 1, + "score": 5, + "experience": 32873, + "sex": "女", + "city": "海外", + "description": "-", + "createTime": "1971-05-24 11:38:48", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 211, + "name": "User-211", + "type": 5, + "status": 2, + "score": 74, + "experience": 85519, + "sex": "男", + "city": "秦皇岛市", + "description": "-", + "createTime": "1970-01-17 07:29:46", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 212, + "name": "User-212", + "type": 4, + "status": 1, + "score": 33, + "experience": 80395, + "sex": "男", + "city": "白山市", + "description": "-", + "createTime": "2005-01-01 03:15:22", + "parentId": null, + "children": [ + { + "id": 213, + "name": "User-213", + "type": 4, + "status": 2, + "score": 55, + "experience": 17077, + "sex": "女", + "city": "毕节市", + "description": "-", + "createTime": "2020-01-13 21:32:59", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 214, + "name": "User-214", + "type": 3, + "status": 2, + "score": 38, + "experience": 57625, + "sex": "女", + "city": "海口市", + "description": "-", + "createTime": "2006-09-06 16:58:42", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 215, + "name": "User-215", + "type": 6, + "status": 2, + "score": 99, + "experience": 64592, + "sex": "女", + "city": "果洛藏族自治州", + "description": "-", + "createTime": "1987-07-29 17:20:38", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 216, + "name": "User-216", + "type": 5, + "status": 2, + "score": 44, + "experience": 69081, + "sex": "男", + "city": "天津市", + "description": "-", + "createTime": "1978-08-01 12:58:10", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 217, + "name": "User-217", + "type": 4, + "status": 2, + "score": 57, + "experience": 58398, + "sex": "男", + "city": "丹东市", + "description": "-", + "createTime": "1997-07-14 13:37:19", + "parentId": null, + "children": [ + { + "id": 218, + "name": "User-218", + "type": 3, + "status": 2, + "score": 11, + "experience": 65346, + "sex": "男", + "city": "百色市", + "description": "-", + "createTime": "1977-12-01 15:05:38", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 219, + "name": "User-219", + "type": 3, + "status": 2, + "score": 49, + "experience": 62808, + "sex": "女", + "city": "桃园县", + "description": "-", + "createTime": "1987-03-29 01:00:57", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 220, + "name": "User-220", + "type": 5, + "status": 2, + "score": 49, + "experience": 57282, + "sex": "女", + "city": "普洱市", + "description": "-", + "createTime": "2017-09-27 13:21:02", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 221, + "name": "User-221", + "type": 4, + "status": 2, + "score": 10, + "experience": 3034, + "sex": "男", + "city": "三沙市", + "description": "-", + "createTime": "1974-11-04 11:57:29", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 222, + "name": "User-222", + "type": 2, + "status": 4, + "score": 93, + "experience": 12235, + "sex": "男", + "city": "海南藏族自治州", + "description": "-", + "createTime": "1975-11-26 14:47:08", + "parentId": null, + "children": [ + { + "id": 223, + "name": "User-223", + "type": 1, + "status": 3, + "score": 61, + "experience": 49467, + "sex": "男", + "city": "澳门半岛", + "description": "-", + "createTime": "2023-04-09 00:28:41", + "parentId": null, + "children": [ + { + "id": 224, + "name": "User-224", + "type": 6, + "status": 3, + "score": 26, + "experience": 65118, + "sex": "女", + "city": "攀枝花市", + "description": "-", + "createTime": "2013-03-04 09:08:30", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 225, + "name": "User-225", + "type": 4, + "status": 1, + "score": 38, + "experience": 86342, + "sex": "男", + "city": "临夏回族自治州", + "description": "-", + "createTime": "1992-06-15 02:13:04", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 226, + "name": "User-226", + "type": 3, + "status": 2, + "score": 3, + "experience": 32179, + "sex": "女", + "city": "九龙", + "description": "-", + "createTime": "2009-03-13 06:48:47", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 227, + "name": "User-227", + "type": 1, + "status": 3, + "score": 96, + "experience": 38847, + "sex": "男", + "city": "梅州市", + "description": "-", + "createTime": "2020-04-16 09:43:04", + "parentId": null, + "children": [ + { + "id": 228, + "name": "User-228", + "type": 4, + "status": 4, + "score": 33, + "experience": 93101, + "sex": "女", + "city": "澳门半岛", + "description": "-", + "createTime": "1995-04-06 14:46:40", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 229, + "name": "User-229", + "type": 3, + "status": 1, + "score": 5, + "experience": 12628, + "sex": "男", + "city": "博尔塔拉蒙古自治州", + "description": "-", + "createTime": "2000-08-07 19:23:07", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 230, + "name": "User-230", + "type": 3, + "status": 3, + "score": 67, + "experience": 7013, + "sex": "女", + "city": "长治市", + "description": "-", + "createTime": "2002-12-14 10:11:11", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 231, + "name": "User-231", + "type": 4, + "status": 2, + "score": 37, + "experience": 61813, + "sex": "女", + "city": "博尔塔拉蒙古自治州", + "description": "-", + "createTime": "1970-06-27 23:24:44", + "parentId": null, + "children": [ + { + "id": 232, + "name": "User-232", + "type": 5, + "status": 2, + "score": 43, + "experience": 20578, + "sex": "男", + "city": "贵港市", + "description": "-", + "createTime": "1976-02-18 15:40:16", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 233, + "name": "User-233", + "type": 1, + "status": 2, + "score": 4, + "experience": 19621, + "sex": "女", + "city": "澳门半岛", + "description": "-", + "createTime": "2020-02-28 08:36:12", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 234, + "name": "User-234", + "type": 5, + "status": 2, + "score": 57, + "experience": 15400, + "sex": "男", + "city": "海东市", + "description": "-", + "createTime": "1976-11-22 23:04:12", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 235, + "name": "User-235", + "type": 4, + "status": 4, + "score": 18, + "experience": 36190, + "sex": "男", + "city": "海北藏族自治州", + "description": "-", + "createTime": "1978-01-30 19:43:36", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 236, + "name": "User-236", + "type": 5, + "status": 4, + "score": 69, + "experience": 51254, + "sex": "女", + "city": "北京市", + "description": "-", + "createTime": "2014-02-15 04:54:05", + "parentId": null, + "children": [ + { + "id": 237, + "name": "User-237", + "type": 2, + "status": 2, + "score": 99, + "experience": 34620, + "sex": "女", + "city": "河池市", + "description": "-", + "createTime": "2011-02-22 01:43:24", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 238, + "name": "User-238", + "type": 5, + "status": 3, + "score": 94, + "experience": 56612, + "sex": "女", + "city": "阿拉善盟", + "description": "-", + "createTime": "1996-04-13 12:44:00", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 239, + "name": "User-239", + "type": 2, + "status": 4, + "score": 27, + "experience": 1648, + "sex": "女", + "city": "长沙市", + "description": "-", + "createTime": "1989-06-01 07:38:48", + "parentId": null, + "children": [ + { + "id": 240, + "name": "User-240", + "type": 4, + "status": 2, + "score": 35, + "experience": 97895, + "sex": "男", + "city": "上海市", + "description": "-", + "createTime": "2002-04-19 15:07:58", + "parentId": null, + "children": [ + { + "id": 241, + "name": "User-241", + "type": 3, + "status": 1, + "score": 15, + "experience": 48229, + "sex": "女", + "city": "廊坊市", + "description": "-", + "createTime": "1997-04-12 20:09:02", + "parentId": null, + "children": [ + { + "id": 242, + "name": "User-242", + "type": 4, + "status": 4, + "score": 3, + "experience": 95377, + "sex": "女", + "city": "鹤壁市", + "description": "-", + "createTime": "1994-10-20 05:40:00", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 243, + "name": "User-243", + "type": 4, + "status": 1, + "score": 5, + "experience": 52728, + "sex": "男", + "city": "泉州市", + "description": "-", + "createTime": "2014-07-16 01:39:38", + "parentId": null, + "children": [ + { + "id": 244, + "name": "User-244", + "type": 5, + "status": 4, + "score": 80, + "experience": 51006, + "sex": "女", + "city": "离岛", + "description": "-", + "createTime": "1998-04-08 03:47:48", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 245, + "name": "User-245", + "type": 2, + "status": 4, + "score": 88, + "experience": 19853, + "sex": "男", + "city": "四平市", + "description": "-", + "createTime": "1998-08-15 16:27:36", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 246, + "name": "User-246", + "type": 6, + "status": 4, + "score": 52, + "experience": 63371, + "sex": "女", + "city": "肇庆市", + "description": "-", + "createTime": "2010-12-14 06:37:33", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 247, + "name": "User-247", + "type": 4, + "status": 2, + "score": 40, + "experience": 65183, + "sex": "男", + "city": "潍坊市", + "description": "-", + "createTime": "1975-07-09 23:34:16", + "parentId": null, + "children": [ + { + "id": 248, + "name": "User-248", + "type": 1, + "status": 3, + "score": 65, + "experience": 19079, + "sex": "男", + "city": "宜宾市", + "description": "-", + "createTime": "2013-03-01 13:33:15", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 249, + "name": "User-249", + "type": 6, + "status": 2, + "score": 80, + "experience": 37432, + "sex": "男", + "city": "临汾市", + "description": "-", + "createTime": "2003-02-04 13:42:18", + "parentId": null, + "children": [ + { + "id": 250, + "name": "User-250", + "type": 3, + "status": 3, + "score": 76, + "experience": 91326, + "sex": "女", + "city": "太原市", + "description": "-", + "createTime": "1997-03-04 20:12:43", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 251, + "name": "User-251", + "type": 1, + "status": 1, + "score": 29, + "experience": 93151, + "sex": "女", + "city": "营口市", + "description": "-", + "createTime": "1972-08-25 03:17:26", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 252, + "name": "User-252", + "type": 2, + "status": 2, + "score": 93, + "experience": 1882, + "sex": "女", + "city": "海外", + "description": "-", + "createTime": "2021-08-31 04:19:35", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 253, + "name": "User-253", + "type": 2, + "status": 4, + "score": 14, + "experience": 97501, + "sex": "女", + "city": "四平市", + "description": "-", + "createTime": "1991-03-16 04:18:45", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 254, + "name": "User-254", + "type": 3, + "status": 2, + "score": 43, + "experience": 77813, + "sex": "女", + "city": "那曲地区", + "description": "-", + "createTime": "2015-12-11 17:36:46", + "parentId": null, + "children": [ + { + "id": 255, + "name": "User-255", + "type": 4, + "status": 3, + "score": 7, + "experience": 88376, + "sex": "男", + "city": "贵阳市", + "description": "-", + "createTime": "1991-12-09 10:31:04", + "parentId": null, + "children": [ + { + "id": 256, + "name": "User-256", + "type": 5, + "status": 3, + "score": 24, + "experience": 66923, + "sex": "男", + "city": "海东市", + "description": "-", + "createTime": "2007-10-09 21:30:27", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 257, + "name": "User-257", + "type": 1, + "status": 2, + "score": 56, + "experience": 16966, + "sex": "女", + "city": "澳门半岛", + "description": "-", + "createTime": "1971-08-07 14:04:06", + "parentId": null, + "children": [ + { + "id": 258, + "name": "User-258", + "type": 3, + "status": 3, + "score": 43, + "experience": 68317, + "sex": "男", + "city": "杭州市", + "description": "-", + "createTime": "2000-06-23 23:43:22", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 259, + "name": "User-259", + "type": 3, + "status": 2, + "score": 19, + "experience": 65900, + "sex": "男", + "city": "杭州市", + "description": "-", + "createTime": "1972-11-02 03:14:29", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 260, + "name": "User-260", + "type": 2, + "status": 2, + "score": 33, + "experience": 26268, + "sex": "女", + "city": "包头市", + "description": "-", + "createTime": "1997-09-19 07:05:41", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 261, + "name": "User-261", + "type": 5, + "status": 1, + "score": 38, + "experience": 60653, + "sex": "女", + "city": "舟山市", + "description": "-", + "createTime": "1993-02-09 22:11:03", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 262, + "name": "User-262", + "type": 1, + "status": 2, + "score": 14, + "experience": 22944, + "sex": "男", + "city": "四平市", + "description": "-", + "createTime": "1979-09-12 21:59:09", + "parentId": null, + "children": [ + { + "id": 263, + "name": "User-263", + "type": 2, + "status": 2, + "score": 95, + "experience": 42730, + "sex": "男", + "city": "咸宁市", + "description": "-", + "createTime": "1971-07-06 13:35:24", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 264, + "name": "User-264", + "type": 3, + "status": 2, + "score": 8, + "experience": 81923, + "sex": "女", + "city": "铜陵市", + "description": "-", + "createTime": "2017-10-06 07:55:26", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 265, + "name": "User-265", + "type": 5, + "status": 2, + "score": 45, + "experience": 34796, + "sex": "男", + "city": "吉林市", + "description": "-", + "createTime": "1978-04-13 03:09:01", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 266, + "name": "User-266", + "type": 1, + "status": 2, + "score": 33, + "experience": 36888, + "sex": "女", + "city": "邵阳市", + "description": "-", + "createTime": "1986-08-10 22:38:19", + "parentId": null, + "children": [ + { + "id": 267, + "name": "User-267", + "type": 4, + "status": 3, + "score": 68, + "experience": 86617, + "sex": "女", + "city": "日照市", + "description": "-", + "createTime": "1988-09-20 23:59:03", + "parentId": null, + "children": [ + { + "id": 268, + "name": "User-268", + "type": 5, + "status": 2, + "score": 87, + "experience": 38669, + "sex": "男", + "city": "锦州市", + "description": "-", + "createTime": "2003-01-29 15:05:06", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 269, + "name": "User-269", + "type": 2, + "status": 4, + "score": 94, + "experience": 55962, + "sex": "女", + "city": "咸阳市", + "description": "-", + "createTime": "1999-05-31 06:27:39", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 270, + "name": "User-270", + "type": 4, + "status": 1, + "score": 67, + "experience": 37707, + "sex": "男", + "city": "吴忠市", + "description": "-", + "createTime": "1984-02-08 15:38:35", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 271, + "name": "User-271", + "type": 4, + "status": 2, + "score": 24, + "experience": 42013, + "sex": "女", + "city": "宝鸡市", + "description": "-", + "createTime": "2013-10-19 09:10:48", + "parentId": null, + "children": [ + { + "id": 272, + "name": "User-272", + "type": 5, + "status": 4, + "score": 7, + "experience": 86631, + "sex": "男", + "city": "黄石市", + "description": "-", + "createTime": "1983-02-15 19:44:19", + "parentId": null, + "children": [ + { + "id": 273, + "name": "User-273", + "type": 5, + "status": 1, + "score": 5, + "experience": 90121, + "sex": "女", + "city": "淮安市", + "description": "-", + "createTime": "1986-05-10 21:35:11", + "parentId": null, + "children": [ + { + "id": 274, + "name": "User-274", + "type": 1, + "status": 3, + "score": 97, + "experience": 74832, + "sex": "男", + "city": "四平市", + "description": "-", + "createTime": "1996-08-04 00:38:03", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 275, + "name": "User-275", + "type": 2, + "status": 2, + "score": 42, + "experience": 45129, + "sex": "男", + "city": "昌都地区", + "description": "-", + "createTime": "1983-01-14 21:58:01", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 276, + "name": "User-276", + "type": 4, + "status": 3, + "score": 2, + "experience": 40565, + "sex": "女", + "city": "普洱市", + "description": "-", + "createTime": "1998-03-28 19:05:33", + "parentId": null, + "children": [ + { + "id": 277, + "name": "User-277", + "type": 2, + "status": 1, + "score": 6, + "experience": 27426, + "sex": "男", + "city": "安顺市", + "description": "-", + "createTime": "2023-01-17 10:34:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 278, + "name": "User-278", + "type": 4, + "status": 2, + "score": 36, + "experience": 22014, + "sex": "男", + "city": "榆林市", + "description": "-", + "createTime": "1993-01-12 09:41:01", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 279, + "name": "User-279", + "type": 4, + "status": 1, + "score": 43, + "experience": 35756, + "sex": "女", + "city": "天津市", + "description": "-", + "createTime": "2002-03-20 11:28:25", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 280, + "name": "User-280", + "type": 2, + "status": 3, + "score": 94, + "experience": 59280, + "sex": "女", + "city": "松原市", + "description": "-", + "createTime": "2008-09-28 10:43:16", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 281, + "name": "User-281", + "type": 5, + "status": 3, + "score": 77, + "experience": 83642, + "sex": "男", + "city": "汕头市", + "description": "-", + "createTime": "2016-07-11 13:48:25", + "parentId": null, + "children": [ + { + "id": 282, + "name": "User-282", + "type": 2, + "status": 3, + "score": 16, + "experience": 75399, + "sex": "男", + "city": "南平市", + "description": "-", + "createTime": "2020-04-11 16:46:07", + "parentId": null, + "children": [ + { + "id": 283, + "name": "User-283", + "type": 2, + "status": 2, + "score": 53, + "experience": 57226, + "sex": "男", + "city": "北京市", + "description": "-", + "createTime": "1995-03-17 00:42:50", + "parentId": null, + "children": [ + { + "id": 284, + "name": "User-284", + "type": 3, + "status": 2, + "score": 19, + "experience": 84763, + "sex": "男", + "city": "澳门半岛", + "description": "-", + "createTime": "2017-08-15 18:16:29", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 285, + "name": "User-285", + "type": 3, + "status": 3, + "score": 39, + "experience": 67178, + "sex": "女", + "city": "南昌市", + "description": "-", + "createTime": "1992-07-26 05:30:51", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 286, + "name": "User-286", + "type": 2, + "status": 1, + "score": 90, + "experience": 92236, + "sex": "女", + "city": "茂名市", + "description": "-", + "createTime": "1987-09-26 10:59:31", + "parentId": null, + "children": [ + { + "id": 287, + "name": "User-287", + "type": 1, + "status": 1, + "score": 53, + "experience": 52079, + "sex": "男", + "city": "固原市", + "description": "-", + "createTime": "1995-01-10 00:22:30", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 288, + "name": "User-288", + "type": 2, + "status": 3, + "score": 65, + "experience": 87314, + "sex": "男", + "city": "离岛", + "description": "-", + "createTime": "1985-10-29 13:49:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 289, + "name": "User-289", + "type": 5, + "status": 1, + "score": 25, + "experience": 97910, + "sex": "男", + "city": "离岛", + "description": "-", + "createTime": "2007-04-29 01:09:20", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 290, + "name": "User-290", + "type": 4, + "status": 2, + "score": 41, + "experience": 19698, + "sex": "男", + "city": "新北市", + "description": "-", + "createTime": "2009-03-16 07:50:46", + "parentId": null, + "children": [ + { + "id": 291, + "name": "User-291", + "type": 6, + "status": 2, + "score": 14, + "experience": 60523, + "sex": "男", + "city": "拉萨市", + "description": "-", + "createTime": "2018-06-11 05:19:27", + "parentId": null, + "children": [ + { + "id": 292, + "name": "User-292", + "type": 5, + "status": 1, + "score": 14, + "experience": 87381, + "sex": "男", + "city": "驻马店市", + "description": "-", + "createTime": "2002-03-09 18:35:26", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 293, + "name": "User-293", + "type": 3, + "status": 3, + "score": 12, + "experience": 59971, + "sex": "男", + "city": "重庆市", + "description": "-", + "createTime": "2012-08-30 00:01:37", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 294, + "name": "User-294", + "type": 5, + "status": 1, + "score": 71, + "experience": 74009, + "sex": "男", + "city": "河池市", + "description": "-", + "createTime": "2012-03-24 15:15:00", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 295, + "name": "User-295", + "type": 3, + "status": 1, + "score": 6, + "experience": 87494, + "sex": "男", + "city": "永州市", + "description": "-", + "createTime": "1988-07-31 14:42:20", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 296, + "name": "User-296", + "type": 4, + "status": 3, + "score": 88, + "experience": 78667, + "sex": "女", + "city": "九龙", + "description": "-", + "createTime": "2007-06-11 13:02:07", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 297, + "name": "User-297", + "type": 3, + "status": 2, + "score": 17, + "experience": 11516, + "sex": "女", + "city": "郴州市", + "description": "-", + "createTime": "1983-11-27 13:30:47", + "parentId": null, + "children": [ + { + "id": 298, + "name": "User-298", + "type": 5, + "status": 3, + "score": 97, + "experience": 44819, + "sex": "男", + "city": "上海市", + "description": "-", + "createTime": "1988-07-02 10:53:42", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 299, + "name": "User-299", + "type": 2, + "status": 4, + "score": 88, + "experience": 53431, + "sex": "男", + "city": "香港岛", + "description": "-", + "createTime": "2022-12-23 15:25:05", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 300, + "name": "User-300", + "type": 5, + "status": 3, + "score": 69, + "experience": 24017, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "2003-12-12 04:04:15", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 301, + "name": "User-301", + "type": 6, + "status": 3, + "score": 72, + "experience": 73262, + "sex": "男", + "city": "北京市", + "description": "-", + "createTime": "1985-11-06 02:27:38", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 302, + "name": "User-302", + "type": 5, + "status": 3, + "score": 32, + "experience": 21824, + "sex": "女", + "city": "银川市", + "description": "-", + "createTime": "2012-09-12 05:57:24", + "parentId": null, + "children": [ + { + "id": 303, + "name": "User-303", + "type": 3, + "status": 4, + "score": 8, + "experience": 68289, + "sex": "女", + "city": "镇江市", + "description": "-", + "createTime": "2010-11-13 05:13:14", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 304, + "name": "User-304", + "type": 4, + "status": 3, + "score": 81, + "experience": 76781, + "sex": "男", + "city": "保山市", + "description": "-", + "createTime": "1975-08-13 20:37:37", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 305, + "name": "User-305", + "type": 2, + "status": 2, + "score": 39, + "experience": 17590, + "sex": "女", + "city": "大理白族自治州", + "description": "-", + "createTime": "1974-06-07 22:14:59", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 306, + "name": "User-306", + "type": 4, + "status": 4, + "score": 39, + "experience": 72010, + "sex": "女", + "city": "锡林郭勒盟", + "description": "-", + "createTime": "1984-05-30 20:38:58", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 307, + "name": "User-307", + "type": 5, + "status": 4, + "score": 52, + "experience": 56848, + "sex": "女", + "city": "阿里地区", + "description": "-", + "createTime": "1970-01-10 06:41:10", + "parentId": null, + "children": [ + { + "id": 308, + "name": "User-308", + "type": 4, + "status": 2, + "score": 45, + "experience": 48753, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "1973-06-22 14:59:33", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 309, + "name": "User-309", + "type": 2, + "status": 4, + "score": 45, + "experience": 3713, + "sex": "男", + "city": "郴州市", + "description": "-", + "createTime": "1997-01-21 13:06:44", + "parentId": null, + "children": [ + { + "id": 310, + "name": "User-310", + "type": 2, + "status": 2, + "score": 33, + "experience": 80153, + "sex": "男", + "city": "上海市", + "description": "-", + "createTime": "1982-05-27 16:55:13", + "parentId": null, + "children": [ + { + "id": 311, + "name": "User-311", + "type": 1, + "status": 3, + "score": 67, + "experience": 92653, + "sex": "男", + "city": "乌海市", + "description": "-", + "createTime": "2012-12-19 19:14:46", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 312, + "name": "User-312", + "type": 5, + "status": 2, + "score": 40, + "experience": 99153, + "sex": "女", + "city": "巴中市", + "description": "-", + "createTime": "1978-06-08 02:16:05", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 313, + "name": "User-313", + "type": 2, + "status": 1, + "score": 7, + "experience": 66644, + "sex": "女", + "city": "贵阳市", + "description": "-", + "createTime": "1993-12-13 16:21:03", + "parentId": null, + "children": [ + { + "id": 314, + "name": "User-314", + "type": 6, + "status": 1, + "score": 48, + "experience": 69828, + "sex": "男", + "city": "重庆市", + "description": "-", + "createTime": "1977-09-05 20:19:37", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + }, + { + "id": 315, + "name": "User-315", + "type": 5, + "status": 2, + "score": 30, + "experience": 82185, + "sex": "女", + "city": "安康市", + "description": "-", + "createTime": "2014-10-31 23:50:51", + "parentId": null, + "children": [ + { + "id": 316, + "name": "User-316", + "type": 1, + "status": 4, + "score": 45, + "experience": 4589, + "sex": "女", + "city": "铜仁市", + "description": "-", + "createTime": "2005-09-08 14:35:12", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 317, + "name": "User-317", + "type": 4, + "status": 2, + "score": 48, + "experience": 55422, + "sex": "女", + "city": "宿州市", + "description": "-", + "createTime": "1992-12-31 05:06:18", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 318, + "name": "User-318", + "type": 5, + "status": 1, + "score": 80, + "experience": 3519, + "sex": "男", + "city": "阜阳市", + "description": "-", + "createTime": "1998-11-01 22:11:08", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 319, + "name": "User-319", + "type": 4, + "status": 2, + "score": 64, + "experience": 10387, + "sex": "女", + "city": "新界", + "description": "-", + "createTime": "1995-02-23 03:01:51", + "parentId": null, + "children": [ + { + "id": 320, + "name": "User-320", + "type": 5, + "status": 2, + "score": 92, + "experience": 63866, + "sex": "女", + "city": "新余市", + "description": "-", + "createTime": "2006-09-13 05:20:48", + "parentId": null, + "children": [ + { + "id": 321, + "name": "User-321", + "type": 6, + "status": 2, + "score": 36, + "experience": 32018, + "sex": "男", + "city": "嘉兴市", + "description": "-", + "createTime": "2012-12-23 12:41:04", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 322, + "name": "User-322", + "type": 5, + "status": 3, + "score": 58, + "experience": 86419, + "sex": "女", + "city": "株洲市", + "description": "-", + "createTime": "2010-01-31 03:49:51", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 323, + "name": "User-323", + "type": 1, + "status": 4, + "score": 84, + "experience": 76545, + "sex": "女", + "city": "海北藏族自治州", + "description": "-", + "createTime": "2020-06-28 07:50:36", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 324, + "name": "User-324", + "type": 4, + "status": 2, + "score": 51, + "experience": 28561, + "sex": "男", + "city": "三沙市", + "description": "-", + "createTime": "2021-01-02 13:13:22", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + }, + { + "id": 325, + "name": "User-325", + "type": 3, + "status": 3, + "score": 62, + "experience": 94793, + "sex": "女", + "city": "嘉峪关市", + "description": "-", + "createTime": "1990-02-26 16:03:01", + "parentId": null, + "children": [ + { + "id": 326, + "name": "User-326", + "type": 4, + "status": 4, + "score": 70, + "experience": 19861, + "sex": "男", + "city": "佳木斯市", + "description": "-", + "createTime": "1971-09-13 13:37:06", + "parentId": null, + "children": [ + { + "id": 327, + "name": "User-327", + "type": 1, + "status": 2, + "score": 10, + "experience": 1866, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "1991-08-01 14:53:52", + "parentId": null, + "children": [ + { + "id": 328, + "name": "User-328", + "type": 6, + "status": 3, + "score": 97, + "experience": 81309, + "sex": "女", + "city": "重庆市", + "description": "-", + "createTime": "1973-06-11 16:06:26", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 329, + "name": "User-329", + "type": 5, + "status": 3, + "score": 36, + "experience": 2334, + "sex": "女", + "city": "新界", + "description": "-", + "createTime": "1989-01-06 11:00:47", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 330, + "name": "User-330", + "type": 4, + "status": 2, + "score": 75, + "experience": 19904, + "sex": "女", + "city": "朔州市", + "description": "-", + "createTime": "2003-06-01 14:59:33", + "parentId": null, + "children": [], + "isParent": false + }, + { + "id": 331, + "name": "User-331", + "type": 6, + "status": 4, + "score": 98, + "experience": 30101, + "sex": "女", + "city": "安康市", + "description": "-", + "createTime": "2003-05-14 13:25:56", + "parentId": null, + "children": [], + "isParent": false + } + ], + "isParent": true + } + ], + "isParent": true + } + ], + "isParent": true + } + ] +} diff --git a/tests/visual/assets/json/treeTable/demo-simple.json b/tests/visual/assets/json/treeTable/demo-simple.json new file mode 100644 index 000000000..457b62d66 --- /dev/null +++ b/tests/visual/assets/json/treeTable/demo-simple.json @@ -0,0 +1,123 @@ +{ + "code": 0, + "count": 100, + "data": [ + { + "id": 1, + "name": "User-1", + "type": 1, + "status": 2, + "score": 11, + "experience": 123, + "sex": "女", + "city": "北京市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": null + }, + { + "id": 2, + "name": "User-2", + "type": 1, + "status": 2, + "score": 22, + "experience": 456, + "sex": "男", + "city": "上海市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": 1 + }, + { + "id": 3, + "name": "User-3", + "type": 1, + "status": 2, + "score": 33, + "experience": 777, + "sex": "男", + "city": "广州市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": 2 + }, + { + "id": 4, + "name": "User-4", + "type": 1, + "status": 2, + "score": 44, + "experience": 888, + "sex": "男", + "city": "深圳市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": null + }, + { + "id": 5, + "name": "User-5", + "type": 1, + "status": 2, + "score": 55, + "experience": 999, + "sex": "男", + "city": "重庆市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": null + }, + { + "id": 6, + "name": "User-6", + "type": 1, + "status": 2, + "score": 66, + "experience": 1000, + "sex": "男", + "city": "成都市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": 5 + }, + { + "id": 7, + "name": "User-7", + "type": 1, + "status": 2, + "score": 77, + "experience": 1001, + "sex": "男", + "city": "苏州市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": 5 + }, + { + "id": 8, + "name": "User-8", + "type": 1, + "status": 2, + "score": 88, + "experience": 1002, + "sex": "男", + "city": "杭州市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": null + }, + { + "id": 9, + "name": "User-9", + "type": 1, + "status": 2, + "score": 99, + "experience": 1003, + "sex": "男", + "city": "武汉市", + "description": "-", + "createTime": "2016-10-14 10:00:00", + "parentId": null + } + ] +} diff --git a/tests/visual/assets/modules/@demo/loader/demo1.css b/tests/visual/assets/modules/@demo/loader/demo1.css new file mode 100644 index 000000000..5993e488b --- /dev/null +++ b/tests/visual/assets/modules/@demo/loader/demo1.css @@ -0,0 +1,3 @@ +html { + background-color: var(--lay-gray-100); +} diff --git a/tests/visual/assets/modules/@demo/loader/demo1.js b/tests/visual/assets/modules/@demo/loader/demo1.js new file mode 100644 index 000000000..b9c7fa16b --- /dev/null +++ b/tests/visual/assets/modules/@demo/loader/demo1.js @@ -0,0 +1 @@ +console.log('demo1.js loaded'); diff --git a/tests/visual/assets/modules/@demo/loader/demo2.css b/tests/visual/assets/modules/@demo/loader/demo2.css new file mode 100644 index 000000000..e69de29bb diff --git a/tests/visual/assets/modules/@demo/loader/demo2.js b/tests/visual/assets/modules/@demo/loader/demo2.js new file mode 100644 index 000000000..fc295dbff --- /dev/null +++ b/tests/visual/assets/modules/@demo/loader/demo2.js @@ -0,0 +1 @@ +console.log('demo2.js loaded'); diff --git a/tests/visual/assets/modules/@demo/loader/demo3.css b/tests/visual/assets/modules/@demo/loader/demo3.css new file mode 100644 index 000000000..e69de29bb diff --git a/tests/visual/assets/modules/@demo/loader/demo3.js b/tests/visual/assets/modules/@demo/loader/demo3.js new file mode 100644 index 000000000..87e8a4f07 --- /dev/null +++ b/tests/visual/assets/modules/@demo/loader/demo3.js @@ -0,0 +1 @@ +console.log('demo3.js loaded'); diff --git a/tests/visual/assets/modules/test/test.css b/tests/visual/assets/modules/test/test.css new file mode 100644 index 000000000..4f03eb15c --- /dev/null +++ b/tests/visual/assets/modules/test/test.css @@ -0,0 +1,61 @@ +/** + * Layui Visual Test + */ + +.test-wrapper { + --lay-test-menu-width: 160px; + --padding: 16px; + --border-color: #eee; +} + +.test-side { + position: fixed; + top: 0; + bottom: 0; + left: 0; + width: var(--lay-test-menu-width); + overflow-x: hidden; + box-sizing: border-box; +} + +.test-main { + margin-left: var(--lay-test-menu-width); + padding: 32px; +} + +.test-stats { + padding-bottom: var(--padding); + border-bottom: 1px solid var(--border-color); +} +.test-stats span { + padding-right: var(--padding); +} + +.test-suite { + display: none; +} +.test-suite.active { + display: block; +} + +.test-item { + margin: var(--padding) 0; + padding: var(--padding); + box-shadow: + rgba(0, 0, 0, 0.16) 0px 18px 18px -18px, + rgba(0, 0, 0, 0.05) 0px 0px 18px; +} +.test-item > div { + padding: 5px 0; + color: #16b777; +} + +.test-result ul li { + span { + padding-right: var(--padding); + } + code { + color: #1f1f1f; + font-family: 'Courier New', Consolas, 'Lucida Console', monospace; + } +} diff --git a/tests/visual/assets/modules/test/test.js b/tests/visual/assets/modules/test/test.js new file mode 100644 index 000000000..4f77b01d6 --- /dev/null +++ b/tests/visual/assets/modules/test/test.js @@ -0,0 +1,352 @@ +/** + * test + * 可视化简易单元测试 + * 该模块依赖 Layui umd 版本 + */ + +const { lay, code: layCode, loader, $ } = layui; + +class Test { + constructor(options) { + lay.extend(this.options, options); + this.#init(); + this.#render(); + } + + static stats = { + total: 0, + passes: 0, + failures: 0, + }; + + options = { + elem: '#root', // 容器元素选择器 + sideWidth: '160px', // 侧边栏宽度 + activeIndex: 0, // 默认激活的测试套件索引 + }; + + #init() { + const options = this.options; + + options.el = $(options.elem); + } + + #render() { + const options = this.options; + const { el } = options; + + const wrapperElem = lay.elem('div', { + class: 'test-wrapper', + }); + const sideElem = lay.elem('div', { + class: 'lay-panel test-side', + }); + const menuElem = (this.menuElem = lay.elem('div', { + class: 'lay-menu', + })); + const mainElem = (this.mainElem = lay.elem('div', { + class: 'test-main', + })); + const suitesElem = (this.suitesElem = lay.elem('div', { + class: 'test-suites', + })); + + lay.style({ + target: wrapperElem, + text: ` +.test-wrapper { + --lay-test-menu-width: ${options.sideWidth}; +} + `, + }); + + // 初始化 menu + (function renderMenu(target, items, parentName) { + items.forEach((item) => { + const liElem = lay.elem('li'); + const title = item.title || item.name; + + if (item.type === '-') { + $(liElem).attr('class', 'lay-menu-item-divider'); + } else { + const hasChildren = item.children && item.children.length; + const anchor = hasChildren + ? 'javascript:;' + : `#${parentName ? parentName + '.' : ''}${item.name}`; + + item.hash = anchor; + + $(liElem).addClass('test-menu-item').append(` +
                                            + ${title} +
                                            + `); + + if (hasChildren) { + const ulElem = lay.elem('ul'); + $(liElem).attr('class', 'lay-menu-item-group lay-menu-item-down'); + renderMenu(ulElem, item.children, item.name); + $(liElem).append(ulElem); + } + } + + $(target).append(liElem); + }); + })(menuElem, options.items || []); + + const flatItems = lay.treeToFlat(options.items).filter((item) => { + return item.type !== '-' && !item.children; + }); + // console.log(flatItems); + + // 根据 hash,初始化默认显示的测试套件 + this.initSwitchSuite = () => { + const hash = location.hash; + const foundIndex = flatItems.findIndex((item) => item.hash === hash); + const index = foundIndex >= 0 ? foundIndex : options.activeIndex; + + this.#switchSuite(index >= 0 ? index : 0); + }; + + // hash 切换事件 + window.addEventListener('hashchange', this.initSwitchSuite); + + sideElem.append(menuElem); + mainElem.append(suitesElem); + wrapperElem.append(sideElem); + wrapperElem.append(mainElem); + el.html('').append(wrapperElem); + } + + static tools = { + // 是否纯对象或纯数组 + isPlainObjectOrArray(obj) { + return lay.isPlainObject(obj) || Array.isArray(obj); + }, + // 相等比较 + equal(a, b) { + const isPlainObjectOrArray = Test.tools.isPlainObjectOrArray; + + if (isPlainObjectOrArray(a) || isPlainObjectOrArray(b)) { + a = isPlainObjectOrArray(a) ? JSON.stringify(a) : a; + b = isPlainObjectOrArray(b) ? JSON.stringify(b) : b; + } + return a === b; + }, + // 输出 + output(obj) { + const isPlainObjectOrArray = Test.tools.isPlainObjectOrArray; + if (isPlainObjectOrArray(obj)) { + return JSON.stringify(obj); + } + return obj; + }, + }; + + /** + * 描述测试用例 + * @param {(string|Object)} opts - 描述信息或配置项 + * @param {Function} fn - 测试用例函数 + */ + describe(opts, fn) { + const { el } = this.options; + + if (typeof opts === 'string') { + opts = { + title: opts, + id: opts, + }; + } + + const describer = (this.describer = lay.extend( + { + suiteElem: lay.elem('div', { + class: 'lay-text test-suite', + id: opts.id, + }), + itemsElem: lay.elem('div', { + class: 'test-items', + }), + }, + opts, + )); + + $(describer.suiteElem).append(`

                                            ${opts.title} :

                                            `); + $(describer.suiteElem).append(describer.itemsElem); + $(this.suitesElem).append(describer.suiteElem); + + fn?.(this.#it.bind(this)); + return this; + } + + /** + * 测试用例 + * @param {Object} opts - 配置项 + * @param {string} opts.title - 测试用例标题 + * @param {string} opts.code - 测试用例代码 + * @param {string} opts.expected - 测试用例预期结果 + * @param {Function} opts.assert - 测试用例断言函数 + * @param {Object} opts.vars - 测试用例变量 + * @param {boolean} opts.showActual - 是否显示实际结果 + * @returns {Promise} + */ + async #it(opts = {}) { + let { code, expected, title, assert } = opts; + const describer = this.describer; + const stats = Test.stats; + const startTime = Date.now(); + + // 在沙箱环境中执行测试代码,并获取实际结果 + const actual = await (async () => { + try { + const vars = { + ...this.options.vars, + ...opts.vars, + }; + const sandboxedTestFn = `async function(layui,${Object.keys(vars).join(',')}) { + let result; + const console = Object.assign({}, window.console); + console.log = (a) => result = a; + ${code} + return result; +} + `; + // console.log(sandboxedTestFn); + return new Function(`return ${sandboxedTestFn};`)()( + layui, + ...Object.values(vars), + ); + } catch (e) { + console.error(e); + return e.message; + } + })(); + + const duration = (Date.now() - startTime) / 1000; + + // 是否通过 + const passed = await ( + assert ? assert.bind(arguments[0]) : Test.tools.equal.bind(this) + )(actual, expected); + const result = passed ? '✅' : '❌'; + const output = Test.tools.output; + const itemElem = lay.elem('div', { class: 'test-item' }); + + stats.total++; + title = title || `任务 ${stats.total}`; + + if (passed) { + stats.passes++; + } else { + stats.failures++; + console.error( + `${describer.title} → ${title} : Test failed\nExpected: ${output(expected)}\nActual: ${output(actual)}`, + ); + } + + itemElem.innerHTML = ` +
                                            ${title}:
                                            +
                                            ${code}
                                            +
                                            +
                                              +
                                            • 预期:${output(expected)}
                                            • + ${ + !passed || opts.showActual + ? '
                                            • 实际:' + + output(actual) + + '
                                            • ' + : '' + } +
                                            • + 结果:${output(result)} + +
                                            • +
                                            +
                                            + `; + + const codeInst = layCode({ + elem: $(itemElem).find('.lay-code')[0], + theme: 'dark', + encode: false, + }); + + // 代码高亮 + (async () => { + // 加载 highlight.js + const HLJS_VERSION = '11.11.1'; + const CDN_BASE = `https://cdnjs.cloudflare.com/ajax/libs/highlight.js/${HLJS_VERSION}`; + await loader.script(`${CDN_BASE}/highlight.min.js`); + await loader.css(`${CDN_BASE}/styles/github-dark.min.css`); + codeInst.reload({ + highlighter: 'hljs', + codeRender: (code, opts) => { + code = lay.unescape(code); + return hljs.highlight(code, { + language: 'javascript', + }).value; + }, + }); + })(); + + $(describer.itemsElem).append(itemElem); + + // 更新统计信息 + this.#stats(); + + this.initSwitchSuite(); + + // 测试完成的回调 + opts.done?.({ itemElem, actual, expected, passed, duration }); + } + + // 切换测试套件的显示 + #switchSuite(activeIndex) { + const CLASS_ACTIVE = 'active'; + const CLASS_MENU_ITEM_CHECKED = 'lay-menu-item-checked'; + const menuItem = $(this.menuElem).find('li.test-menu-item'); + + menuItem.removeClass(CLASS_MENU_ITEM_CHECKED); + menuItem.eq(activeIndex).addClass(CLASS_MENU_ITEM_CHECKED); + $(this.suitesElem) + .children('.test-suite') + .eq(activeIndex) + .addClass(CLASS_ACTIVE) + .siblings() + .removeClass(CLASS_ACTIVE); + } + + // 统计 + #stats() { + const options = this.options; + const { el } = options; + const stats = Test.stats; + const statsElem = lay.elem('div', { class: 'test-stats' }); + const existingStatsElem = this.mainElem.querySelector('.test-stats'); + + $(statsElem).html(` + 测试数量 : ${stats.total} + ✅ 通过 : ${stats.passes} + ❌ 失败 : ${stats.failures}${stats.failures > 0 ? '(控制台查看详情)' : ''} + `); + + if (existingStatsElem) { + existingStatsElem.replaceWith(statsElem); + } else { + this.mainElem.prepend(statsElem); + } + } +} + +/** + * 创建测试实例 + * @param {Object} options - 配置项 + * @param {(string|HTMLElement|JQuery)} options.elem - 容器元素选择器或对象 + * @param {Array} options.items - 测试项列表 + * @param {Object} options.vars - 传递给测试沙箱中的变量 + * @param {string} options.sideWidth - 侧边栏宽度 + * @returns {Test} 测试实例 + */ +export function test(options) { + return new Test(options); +} diff --git a/tests/visual/base.html b/tests/visual/base.html new file mode 100644 index 000000000..e941afb02 --- /dev/null +++ b/tests/visual/base.html @@ -0,0 +1,457 @@ + + + + + + 基础方法测试 - layui + + + + +
                                            + + + + diff --git a/tests/visual/button.html b/tests/visual/button.html new file mode 100644 index 000000000..a119b1294 --- /dev/null +++ b/tests/visual/button.html @@ -0,0 +1,165 @@ + + + + + + 按钮 - layui + + + +
                                            + 按钮色系: +
                                            + +
                                            + 原始按钮 +
                                            默认按钮
                                            + + + + +
                                            +
                                            + 原始按钮 + 主色按钮 + + + + +
                                            + +

                                            + + 按钮图标: +
                                            + +
                                            + + + + + + +
                                            + +

                                            + + 按钮尺寸: +
                                            + +
                                            + + + + +
                                            +
                                            + + + + +
                                            + +

                                            + + 按钮圆角: +
                                            + +
                                            + + + + + + +
                                            + +

                                            + + 按钮图文: +
                                            + +
                                            + + + +
                                            + +

                                            + + 按钮组: +
                                            + +
                                            + + + +
                                            + +
                                            + + + + +
                                            + +
                                            + + + + +
                                            + +


                                            +
                                            + + + + + + diff --git a/tests/visual/carousel.html b/tests/visual/carousel.html new file mode 100644 index 000000000..dca583411 --- /dev/null +++ b/tests/visual/carousel.html @@ -0,0 +1,147 @@ + + + + + + 轮播组件 - layui + + + + + + + + +
                                            + + + +
                                            + + + +
                                            + + + + + + + diff --git a/tests/visual/code.html b/tests/visual/code.html new file mode 100644 index 000000000..91f82e607 --- /dev/null +++ b/tests/visual/code.html @@ -0,0 +1,416 @@ + + + + + + Code blocks adorn - Layui + + + + +
                                            +

                                            代码高亮

                                            +
                                            +
                                            +  
                                            +
                                            + +
                                            +

                                            行高亮和聚焦

                                            +
                                            +
                                            +
                                            +
                                            + +
                                            +

                                            diff

                                            +
                                            +
                                            +
                                            +
                                            + +

                                            普通示例

                                            + +
                                            
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            + +
                                            
                                            +    
                                            +
                                            +    
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            + +
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            + +
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            +code line
                                            +code line
                                            +code line
                                            +  
                                            +
                                            +
                                            + +
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +code line
                                            +
                                            +
                                            +
                                            + +
                                            +
                                            + 123 +
                                            +
                                            + +
                                            +  About
                                            +
                                            + + + + + + diff --git a/tests/visual/collapse.html b/tests/visual/collapse.html new file mode 100644 index 000000000..f9865e153 --- /dev/null +++ b/tests/visual/collapse.html @@ -0,0 +1,79 @@ + + + + + + 折叠面板 - Layui + + + +

                                            常规用法:

                                            +
                                            +
                                            +
                                            +

                                            item 1

                                            +
                                            + 旧版,通过给列表的内容添加 lay-show 类开启显示 +
                                            +
                                            +
                                            +

                                            item2

                                            +
                                            content 2
                                            +
                                            +
                                            +

                                            item 3

                                            +
                                            content 3
                                            +
                                            +
                                            + +
                                            + +
                                            +
                                            +

                                            item 111

                                            +
                                            + 新版 2.11.4+,通过给列表项直接添加 lay-show 类开启显示 +
                                            +
                                            +
                                            +

                                            item 222

                                            +
                                            content 2
                                            +
                                            +
                                            +

                                            item 333

                                            +
                                            content 3
                                            +
                                            +
                                            + +
                                            +

                                            开启手风琴:

                                            +
                                            +
                                            +
                                            +

                                            item 1

                                            +
                                            + 旧版,通过给列表的内容添加 lay-show 类开启显示 +
                                            +
                                            +
                                            +

                                            item2

                                            +
                                            content 2
                                            +
                                            +
                                            +

                                            item 3

                                            +
                                            content 3
                                            +
                                            +
                                            + + + + + diff --git a/tests/visual/colorpicker.html b/tests/visual/colorpicker.html new file mode 100644 index 000000000..7d11e904b --- /dev/null +++ b/tests/visual/colorpicker.html @@ -0,0 +1,139 @@ + + + + + + 颜色选择器 - layui + + + + + + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            + + + + + diff --git a/tests/visual/dropdown.html b/tests/visual/dropdown.html new file mode 100644 index 000000000..04fa66be1 --- /dev/null +++ b/tests/visual/dropdown.html @@ -0,0 +1,379 @@ + + + + + + 下拉菜单 - layui + + + + +
                                            +
                                            + + +
                                            + + + +
                                            + testopen + + +
                                            + +
                                            + 鼠标右键菜单 +
                                            + +
                                            + + + + + diff --git a/tests/visual/element.html b/tests/visual/element.html new file mode 100644 index 000000000..d9f90c199 --- /dev/null +++ b/tests/visual/element.html @@ -0,0 +1,176 @@ + + + + + + 常用元素 - layui + + + + + + +
                                              +
                                            • + +
                                              +

                                              2.0.0

                                              +

                                              + 杜甫的思想核心是儒家的仁政思想,他有“致君尧舜上,再使风俗淳”的宏伟抱负。杜甫虽然在世时名声并不显赫,但后来声名 +

                                              +
                                                +
                                              • 思想
                                              • +
                                              • 虽然在
                                              • +
                                              + 哈哈哈 +
                                              +
                                            • +
                                            • + +
                                              +

                                              1.0.9

                                              + 哈哈哈 +
                                              +
                                            • +
                                            • + +
                                              +
                                              标题
                                              + 内容 +
                                              +
                                            • +
                                            + +
                                            + + 徽章: + + + + + + + + + + 6 + 99 + 61728 + + + + 绿 + + + + + + Hot + +
                                            +
                                            + +
                                            +
                                            +
                                            + +
                                            + +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            +
                                            + +
                                            +
                                            +
                                            + +

                                            + +
                                            +

                                            Layui - 原生态模块化前端 UI 组件库

                                            +

                                            Layui - 原生态模块化前端 UI 组件库

                                            +
                                            +
                                            + Layui - 原生态模块化前端 UI 组件库 Layui - 原生态模块化前端 UI 组件库 + Layui - 原生态模块化前端 UI 组件库 Layui - 原生态模块化前端 UI 组件库 + Layui - 原生态模块化前端 UI 组件库 +
                                            + +
                                            + 字段集区块 - 默认风格 +
                                            内容区域
                                            +
                                            + + 默认分割线 +
                                            + + 赤色分割线 +
                                            + + 橙色分割线 +
                                            + + 墨绿分割线 +
                                            + + 青色分割线 +
                                            + + 蓝色分割线 +
                                            + + 黑色分割线 +
                                            + + 灰色分割线 +
                                            + + + + + diff --git a/tests/visual/esm/index.html b/tests/visual/esm/index.html new file mode 100644 index 000000000..b2b5bb4bb --- /dev/null +++ b/tests/visual/esm/index.html @@ -0,0 +1,23 @@ + + + + + + Dev - layui + + + + +
                                            + + + diff --git a/tests/visual/floatbar.html b/tests/visual/floatbar.html new file mode 100644 index 000000000..fe5227a0a --- /dev/null +++ b/tests/visual/floatbar.html @@ -0,0 +1,95 @@ + + + + + + floatbar 组件 - layui + + + +
                                            + +
                                            + + + + + diff --git a/tests/visual/flow.html b/tests/visual/flow.html new file mode 100644 index 000000000..6073aa372 --- /dev/null +++ b/tests/visual/flow.html @@ -0,0 +1,179 @@ + + + + + + 流加载 - layui + + + + +
                                            +
                                              +
                                              +
                                                +
                                                + +
                                                + + + + + + + + + + +
                                                + + + + + diff --git a/tests/visual/form.html b/tests/visual/form.html new file mode 100644 index 000000000..fbe7155b2 --- /dev/null +++ b/tests/visual/form.html @@ -0,0 +1,818 @@ + + + + + 表单模块 - layui + + + + + + + + + + + +
                                                +
                                                +
                                                +
                                                +
                                                前置信息
                                                + +
                                                后置信息
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                + +
                                                +
                                                +
                                                +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                + +
                                                +
                                                + +
                                                +
                                                + +
                                                +
                                                + +
                                                +
                                                +
                                                + +
                                                +
                                                +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                请务必填写用户名
                                                +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                -
                                                +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                + +
                                                +
                                                + +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                + + + + +
                                                +
                                                +
                                                + +
                                                + + + +
                                                +
                                                +
                                                + +
                                                + + +
                                                +
                                                +
                                                + +
                                                + + +
                                                +
                                                +
                                                + +
                                                + + + +
                                                保密
                                                + +
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                +
                                                + + +
                                                +
                                                +
                                                + +


                                                + + + + +

                                                设置 lay-ignore 忽略渲染

                                                +
                                                +
                                                +
                                                +
                                                未设置 ignore 时:
                                                +
                                                + +
                                                +
                                                +
                                                +
                                                忽略指令直接设置:
                                                +
                                                + + + +
                                                +
                                                +
                                                +
                                                忽略指令父元素设置:
                                                +
                                                + + + +
                                                +
                                                +
                                                + +

                                                原始表单调试:

                                                +
                                                +
                                                + + + + + + + + +
                                                + +

                                                + + diff --git a/tests/visual/i18n.html b/tests/visual/i18n.html new file mode 100644 index 000000000..0ceb957ae --- /dev/null +++ b/tests/visual/i18n.html @@ -0,0 +1,571 @@ + + + + + + i18n - Layui + + + + +
                                                + + + + + + diff --git a/tests/visual/laydate.html b/tests/visual/laydate.html new file mode 100644 index 000000000..9c80f02ce --- /dev/null +++ b/tests/visual/laydate.html @@ -0,0 +1,556 @@ + + + + + + + + 日期模块 - layui + + + + + + + +
                                                + +
                                                + +
                                                +
                                                + + 范围选择1: +
                                                + +
                                                + +
                                                +
                                                + +
                                                +
                                                +
                                                + +
                                                +
                                                + +
                                                +
                                                -
                                                +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                +
                                                + + 日期选择器: +
                                                + +
                                                + + 开启快捷面板: +
                                                + +
                                                + +

                                                +
                                                +
                                                + + 年选择器: +
                                                + +
                                                + + 年月选择器: +
                                                + +
                                                + + 时间时间器: +
                                                + +
                                                + +

                                                +
                                                +
                                                + + 时间范围选择 +
                                                + +
                                                + + 自定义重要日: +
                                                + +
                                                + + 标注法定节假日及补班: +
                                                + +
                                                + +

                                                +
                                                +
                                                + + 同时绑定多个: +
                                                + +
                                                +
                                                + +
                                                +
                                                + +
                                                + +

                                                +
                                                +
                                                + + 墨绿主题: +
                                                + +
                                                + + 自定义头部背景色: +
                                                + +
                                                + + 格子主题: +
                                                + +
                                                + +

                                                +
                                                +
                                                + + +
                                                + +
                                                + + +
                                                + +
                                                + +

                                                +
                                                +
                                                + 直接嵌套在指定容器中:

                                                +
                                                +
                                                + + + + + diff --git a/tests/visual/layer.html b/tests/visual/layer.html new file mode 100644 index 000000000..04ecb9968 --- /dev/null +++ b/tests/visual/layer.html @@ -0,0 +1,296 @@ + + + + + + layer 弹层 - layui + + + + +
                                                + + + + + + + + + + + + + 更多例子 +
                                                + + + +
                                                +
                                                + +
                                                +
                                                  +
                                                • + 123 +
                                                • +
                                                • +
                                                +
                                                + + + + + + + + + + + + diff --git a/tests/visual/layout-admin.html b/tests/visual/layout-admin.html new file mode 100644 index 000000000..78ebfe639 --- /dev/null +++ b/tests/visual/layout-admin.html @@ -0,0 +1,139 @@ + + + + + layout 管理界面大布局示例 - Layui + + + + + + +
                                                +
                                                + + + + +
                                                +
                                                + +
                                                +
                                                + +
                                                +
                                                + Layui 框体布局内容主体区域 +
                                                +
                                                +
                                                下面是充数内容,为的是出现滚动条
                                                +
                                                + 充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                充数内容
                                                你还真滑到了底部呀 +
                                                +
                                                +

                                                +
                                                +
                                                + +
                                                + + + + + diff --git a/tests/visual/layout-grid.html b/tests/visual/layout-grid.html new file mode 100644 index 000000000..0dea7759a --- /dev/null +++ b/tests/visual/layout-grid.html @@ -0,0 +1,345 @@ + + + + + + layout 栅格布局 - Layui + + + + + + + +
                                                +
                                                + 始终等比例水平排列 +
                                                + +
                                                +
                                                +
                                                50%
                                                +
                                                +
                                                +
                                                50%
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                + +
                                                + 移动设备、桌面端的不同展现 +
                                                + +
                                                +
                                                +
                                                移动设备:100%、桌面:60%
                                                +
                                                +
                                                +
                                                移动设备:50%、桌面:40%
                                                +
                                                +
                                                +
                                                移动设备:50%、桌面:100%
                                                +
                                                +
                                                + +
                                                + 移动设备、平板、桌面端的不同展现 +
                                                + +
                                                +
                                                +
                                                50% | 33.33% | 33.33%
                                                +
                                                +
                                                +
                                                50% | 66.67% | 33.33%
                                                +
                                                +
                                                +
                                                33.33% | 100% | 33.33%
                                                +
                                                +
                                                +
                                                33.33% | 50% | 66.67%
                                                +
                                                +
                                                +
                                                33.33% | 50% | 33.33%
                                                +
                                                +
                                                + +
                                                + 从小屏幕堆叠到桌面水平排列 +
                                                + +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                +
                                                1/12
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                75%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                50%
                                                +
                                                +
                                                +
                                                50%
                                                +
                                                +
                                                + +
                                                + 分栏间隔 +
                                                + +
                                                +
                                                +
                                                1/4
                                                +
                                                +
                                                +
                                                1/4
                                                +
                                                +
                                                +
                                                1/4
                                                +
                                                +
                                                +
                                                1/4
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                1/3
                                                +
                                                +
                                                +
                                                1/3
                                                +
                                                +
                                                +
                                                1/3
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                75%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                58.33%
                                                +
                                                +
                                                +
                                                41.67%
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                + +
                                                + 列偏移 +
                                                + +
                                                +
                                                +
                                                33.33%
                                                +
                                                +
                                                +
                                                偏移4列
                                                +
                                                +
                                                +
                                                偏移5列
                                                +
                                                +
                                                +
                                                不偏移
                                                +
                                                +
                                                + +
                                                + +
                                                +
                                                +
                                                偏移3列
                                                +
                                                +
                                                +
                                                偏移1列
                                                +
                                                +
                                                + +
                                                + 嵌套 +
                                                + +
                                                +
                                                +
                                                +
                                                +
                                                内部列
                                                +
                                                +
                                                +
                                                内部列
                                                +
                                                +
                                                +
                                                内部列
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                +
                                                内部列
                                                +
                                                +
                                                +
                                                内部列
                                                +
                                                +
                                                +
                                                内部列
                                                +
                                                +
                                                +
                                                +
                                                +
                                                + +
                                                +
                                                + 流体容器(宽度自适应,不固定) +
                                                + +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                25%
                                                +
                                                +
                                                +
                                                + +

                                                + + diff --git a/tests/visual/laypage.html b/tests/visual/laypage.html new file mode 100644 index 000000000..cab0f52c1 --- /dev/null +++ b/tests/visual/laypage.html @@ -0,0 +1,202 @@ + + + + + + 分页 - layui + + + + + + + 总页数低于页码总数: +
                                                + 总页数大于页码总数: +
                                                + 自定义主题: +
                                                + 自定义首页、尾页、上一页、下一页文本: +
                                                + 不显示首页尾页: +
                                                + 开启HASH: +
                                                + 只显示上一页、下一页: +
                                                + 显示完整功能: +
                                                + 自定义排版: +
                                                + +
                                                + 将一段已知数组分页展示 +
                                                + +
                                                + +
                                                  + + + + + diff --git a/tests/visual/laytpl.html b/tests/visual/laytpl.html new file mode 100644 index 000000000..315a69c19 --- /dev/null +++ b/tests/visual/laytpl.html @@ -0,0 +1,319 @@ + + + + + + 模板引擎 - Layui + + + + +
                                                  +
                                                  +
                                                  +
                                                  模板
                                                  + +
                                                  +
                                                  +
                                                  +
                                                  数据
                                                  +
                                                  + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                    +
                                                  • 渲染结果
                                                  • +
                                                  • 源码
                                                  • +
                                                  +
                                                  +
                                                  + +
                                                  +
                                                  + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + + + + + + + + + + + +
                                                  + + + + + diff --git a/tests/visual/loader.html b/tests/visual/loader.html new file mode 100644 index 000000000..6c04d631d --- /dev/null +++ b/tests/visual/loader.html @@ -0,0 +1,230 @@ + + + + + + loader 加载器 - layui + + + + +
                                                  + + + + diff --git a/tests/visual/menu.html b/tests/visual/menu.html new file mode 100644 index 000000000..c0db81cee --- /dev/null +++ b/tests/visual/menu.html @@ -0,0 +1,261 @@ + + + + + + 菜单元素 - layui + + + + +
                                                  +
                                                  + + +
                                                  + +
                                                  +
                                                  +
                                                  +
                                                    +
                                                  • + +
                                                  • +
                                                  • + +
                                                  • +
                                                  • +
                                                  • +
                                                    + menu group +
                                                    +
                                                      +
                                                    • +
                                                      menu item 3-1
                                                      +
                                                    • +
                                                    • +
                                                      menu group 2
                                                      +
                                                        +
                                                      • +
                                                        menu item 3-2-1
                                                        +
                                                      • +
                                                      • +
                                                        menu item 3-2-2
                                                        +
                                                      • +
                                                      +
                                                    • +
                                                    • +
                                                      menu item 3-3
                                                      +
                                                    • +
                                                    +
                                                  • +
                                                  • +
                                                  • +
                                                    + menu item 4 1 +
                                                    +
                                                  • +
                                                  • menu item 5
                                                  • +
                                                  • menu item 6
                                                  • +
                                                  • +
                                                    + menu item 7 Children + +
                                                    +
                                                    +
                                                      +
                                                    • +
                                                      + menu item 7-1 + +
                                                      +
                                                      +
                                                        +
                                                      • +
                                                        + menu item 7-2-1 +
                                                        +
                                                      • +
                                                      • +
                                                        + menu item 7-2-2 +
                                                        +
                                                      • +
                                                      • +
                                                        + menu item 7-2-3 +
                                                        +
                                                      • +
                                                      • +
                                                        + menu item 7-2-4 +
                                                        +
                                                      • +
                                                      +
                                                      +
                                                    • +
                                                    • +
                                                      menu item 7-2
                                                      +
                                                    • +
                                                    • +
                                                      menu item 7-3
                                                      +
                                                    • +
                                                    +
                                                    +
                                                  • +
                                                  • menu item 8
                                                  • +
                                                  • +
                                                  • +
                                                    menu group 9
                                                    +
                                                      +
                                                    • +
                                                      menu item 9-1
                                                      +
                                                    • +
                                                    • +
                                                      + menu item 9-2 + +
                                                      +
                                                      +
                                                        +
                                                      • +
                                                        menu item 9-2-1
                                                        +
                                                      • +
                                                      • +
                                                        menu item 9-2-2
                                                        +
                                                      • +
                                                      • +
                                                        menu item 9-2-3
                                                        +
                                                      • +
                                                      +
                                                      +
                                                    • +
                                                    • +
                                                      menu item 9-31
                                                      +
                                                    • +
                                                    +
                                                  • +
                                                  • +
                                                  • menu item 10
                                                  • +
                                                  +
                                                  +
                                                  + +
                                                  +
                                                  +
                                                    +
                                                  • +
                                                    menu item 1
                                                    +
                                                  • +
                                                  • + +
                                                  • +
                                                  • +
                                                  • +
                                                    menu group
                                                    +
                                                      +
                                                    • +
                                                      menu item 3-1
                                                      +
                                                    • +
                                                    • +
                                                      menu item 3-2
                                                      +
                                                    • +
                                                    +
                                                  • +
                                                  • +
                                                  • +
                                                    menu group 2
                                                    +
                                                      +
                                                    • +
                                                      menu item 4-1
                                                      +
                                                    • +
                                                    • +
                                                      menu item 4-2
                                                      +
                                                    • +
                                                    +
                                                  • +
                                                  • +
                                                  • +
                                                    + menu item 5 + +
                                                    +
                                                    +
                                                      +
                                                    • +
                                                      menu item 5-1
                                                      +
                                                    • +
                                                    • +
                                                      menu item 5-2
                                                      +
                                                    • +
                                                    +
                                                    +
                                                  • +
                                                  • +
                                                    menu item 6
                                                    +
                                                  • +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/nav.html b/tests/visual/nav.html new file mode 100644 index 000000000..16bc1d054 --- /dev/null +++ b/tests/visual/nav.html @@ -0,0 +1,270 @@ + + + + + + 导航 - 常用元素 - layui + + + + + + +
                                                  + + + +
                                                  + + + +
                                                  + + + +
                                                  + + + +
                                                  + +
                                                  +
                                                  + +
                                                  +
                                                  + +
                                                  +
                                                  + +
                                                  +
                                                  + +
                                                  +
                                                  + + + 首页 + 国际新闻 + 亚太地区 + 正文 + + +

                                                  + + + 娱乐 + 八卦 + 体育 + 搞笑 + 视频 + 游戏 + 综艺 + + +





                                                  + + + + + diff --git a/tests/visual/rate.html b/tests/visual/rate.html new file mode 100644 index 000000000..cb4e954de --- /dev/null +++ b/tests/visual/rate.html @@ -0,0 +1,94 @@ + + + + + + 评分组件 - layui + + + +
                                                  +
                                                  +
                                                  +

                                                  基础用法

                                                  +
                                                  +
                                                  +
                                                  +

                                                  选中半星

                                                  +
                                                  +
                                                  +
                                                  +

                                                  显示文本

                                                  +
                                                  + +
                                                  +
                                                  +

                                                  设置只读

                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/responsive.html b/tests/visual/responsive.html new file mode 100644 index 000000000..3c7ffe7ed --- /dev/null +++ b/tests/visual/responsive.html @@ -0,0 +1,29 @@ + + + + + + 响应式测试 - Layui + + + + + + + +
                                                  + 移动:隐藏 +
                                                  平板:inline
                                                  PC:block +
                                                  + + diff --git a/tests/visual/router.html b/tests/visual/router.html new file mode 100644 index 000000000..04f4927d2 --- /dev/null +++ b/tests/visual/router.html @@ -0,0 +1,356 @@ + + + + + + router 前端路由管理器 - layui + + + +
                                                  +
                                                  +
                                                    +
                                                  • hash 模式
                                                  • +
                                                  • history 模式
                                                  • +
                                                  + +
                                                  +
                                                  +
                                                  +

                                                  URL 解析

                                                  +

                                                  用于验证 router.hash() 的返回结果。

                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  
                                                  +            
                                                  + +
                                                  + +
                                                  +

                                                  URL 标准化

                                                  +

                                                  用于验证 hash 模式下的 normalizeUrl()。

                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  
                                                  +            
                                                  + +
                                                  + +
                                                  +

                                                  路由跳转

                                                  +

                                                  用于验证 hash 模式下 navigate()、done 回调与 windowName。

                                                  + +
                                                  + + +
                                                  + + + +
                                                  
                                                  +            
                                                  +
                                                  + +
                                                  +
                                                  +

                                                  URL 解析

                                                  +

                                                  用于验证 router.hash() 的返回结果。

                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  
                                                  +            
                                                  + +
                                                  + +
                                                  +

                                                  URL 标准化

                                                  +

                                                  用于验证 history 模式下 normalizeUrl()。

                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  + +
                                                  
                                                  +            
                                                  + +
                                                  + +
                                                  +

                                                  路由跳转

                                                  +

                                                  + 使用 /base、/button、/router 作为 history + 路径,便于直接刷新验证路径表现。 +

                                                  + +
                                                  + + + +
                                                  + +
                                                  
                                                  +            
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/slider.html b/tests/visual/slider.html new file mode 100644 index 000000000..8b81c1ace --- /dev/null +++ b/tests/visual/slider.html @@ -0,0 +1,72 @@ + + + + + + 滑块 - layui + + + + + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/table-static.html b/tests/visual/table-static.html new file mode 100644 index 000000000..f236647d2 --- /dev/null +++ b/tests/visual/table-static.html @@ -0,0 +1,111 @@ + + + + + + 静态表格 - layui + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                  人物民族格言
                                                  孔子华夏有朋至远方来,不亦乐乎
                                                  孟子华夏穷则独善其身,达则兼济天下
                                                  + +
                                                  + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                  人物民族格言
                                                  孔子华夏有朋至远方来,不亦乐乎
                                                  孟子华夏穷则独善其身,达则兼济天下
                                                  + +
                                                  + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                  人物民族格言
                                                  孔子华夏有朋至远方来,不亦乐乎
                                                  孟子华夏穷则独善其身,达则兼济天下
                                                  + + diff --git a/tests/visual/table-test-border.html b/tests/visual/table-test-border.html new file mode 100644 index 000000000..71534724c --- /dev/null +++ b/tests/visual/table-test-border.html @@ -0,0 +1,154 @@ + + + + + + 表格边框测试 + + + + + + +
                                                  无统计、无分页
                                                  + +
                                                  + +
                                                  有统计、无分页
                                                  + +
                                                  + +
                                                  无统计、有分页
                                                  + +
                                                  + +
                                                  有统计、有分页
                                                  + +
                                                  + + + + + diff --git a/tests/visual/table-test.html b/tests/visual/table-test.html new file mode 100644 index 000000000..a59c7ef00 --- /dev/null +++ b/tests/visual/table-test.html @@ -0,0 +1,763 @@ + + + + + + 表格操作 - layui + + + + + + + + + + + + + + + + + + + + + +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/table.html b/tests/visual/table.html new file mode 100644 index 000000000..4814714a3 --- /dev/null +++ b/tests/visual/table.html @@ -0,0 +1,394 @@ + + + + + + 表格操作 - layui + + + + + + + + +
                                                  +
                                                  +
                                                  +
                                                  + +
                                                  + + + + + + + + + + + + + + + + + +
                                                  联系人金额地址 + 操作 +
                                                  小区单元
                                                  + + + + + + + + + + + + + + + + + + + + + + + +
                                                  联系人 + 金额 + 地址1地址2 + 操作 +
                                                  + 省 + 详细
                                                  小区单元
                                                  + +
                                                  + +
                                                  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                  昵称加入时间签名
                                                  贤心12016-11-28人生就像是一场修行a
                                                  贤心22016-11-29人生就像是一场修行b
                                                  贤心32016-11-30人生就像是一场修行c
                                                  + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
                                                  楼层1单元2单元
                                                  1门2门1门2门
                                                  3楼301302301302
                                                  2楼201202201202
                                                  1楼101102101102
                                                  +
                                                  + + + + + diff --git a/tests/visual/tabs.html b/tests/visual/tabs.html new file mode 100644 index 000000000..85441aba3 --- /dev/null +++ b/tests/visual/tabs.html @@ -0,0 +1,372 @@ + + + + + + 标签页组件 - Layui + + + +
                                                  +

                                                  动态操作

                                                  +
                                                  +
                                                    +
                                                  • Tab1
                                                  • +
                                                  • Tab2
                                                  • +
                                                  • Tab3
                                                  • +
                                                  • Tab4
                                                  • +
                                                  • Tab5
                                                  • +
                                                  • Tab6
                                                  • +
                                                  +
                                                  +
                                                  Tab Content-1
                                                  +
                                                  Tab Content-2
                                                  +
                                                  Tab Content-3
                                                  +
                                                  Tab Content-4
                                                  +
                                                  Tab Content-5
                                                  +
                                                  Tab Content-6
                                                  +
                                                  +
                                                  + +
                                                  + + + + + +
                                                  + +

                                                  方法渲染

                                                  +
                                                  + +

                                                  卡片风格

                                                  +
                                                  +
                                                    +
                                                  • 标题1
                                                  • +
                                                  • 标题2
                                                  • +
                                                  • 跳转项
                                                  • +
                                                  • 禁选项
                                                  • +
                                                  • 标题5
                                                  • +
                                                  • 标题6
                                                  • +
                                                  +
                                                  +
                                                  内容-1
                                                  +
                                                  内容-2
                                                  +
                                                  内容-3
                                                  +
                                                  内容-4
                                                  +
                                                  内容-5
                                                  +
                                                  内容-6
                                                  +
                                                  +
                                                  + +

                                                  卡片 + 边框

                                                  +
                                                  +
                                                    +
                                                  • 标题1
                                                  • +
                                                  • 标题2
                                                  • +
                                                  • 标题3
                                                  • +
                                                  • 标题4
                                                  • +
                                                  • 标题5
                                                  • +
                                                  • 标题6
                                                  • +
                                                  +
                                                  +
                                                  +
                                                  + +
                                                  +
                                                  +
                                                  2
                                                  +
                                                  3
                                                  +
                                                  4
                                                  +
                                                  5
                                                  +
                                                  6
                                                  +
                                                  +
                                                  + +

                                                  打乱标签顺序:

                                                  +
                                                  +
                                                    +
                                                  • Tab6
                                                  • +
                                                  • Tab5
                                                  • +
                                                  • Tab3
                                                  • +
                                                  • Tab2
                                                  • +
                                                  • Tab1
                                                  • +
                                                  • Tab4
                                                  • +
                                                  +
                                                  +
                                                  Tab Content-1
                                                  +
                                                  Tab Content-2
                                                  +
                                                  Tab Content-3
                                                  +
                                                  Tab Content-4
                                                  +
                                                  Tab Content-5
                                                  +
                                                  Tab Content-6
                                                  +
                                                  +
                                                  + +

                                                  标签 HASH 定位

                                                  + + +

                                                  标签嵌套

                                                  +
                                                  +
                                                    +
                                                  • 标题1
                                                  • +
                                                  • 标题2
                                                  • +
                                                  • 标题3
                                                  • +
                                                  +
                                                  +
                                                  +
                                                  +
                                                    +
                                                  • 标题 1-1
                                                  • +
                                                  • 标题 1-2
                                                  • +
                                                  +
                                                  +
                                                  1-1
                                                  +
                                                  1-2
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                    +
                                                  • 标题 2-1
                                                  • +
                                                  • 标题 2-2
                                                  • +
                                                  • 标题 2-3
                                                  • +
                                                  +
                                                  +
                                                  2-1
                                                  +
                                                  2-2
                                                  +
                                                  2-3
                                                  +
                                                  +
                                                  +
                                                  +
                                                  3
                                                  +
                                                  4
                                                  +
                                                  5
                                                  +
                                                  +
                                                  + +

                                                  给任意元素绑定 tabs 切换功能

                                                  +
                                                  + +
                                                  + + + +
                                                  +
                                                  +
                                                  内容 111
                                                  +
                                                  内容 222
                                                  +
                                                  内容 333
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/template/README.md b/tests/visual/template/README.md new file mode 100644 index 000000000..0c782bc03 --- /dev/null +++ b/tests/visual/template/README.md @@ -0,0 +1,3 @@ +# 模板说明 + +该目录文件用于外部构建时所需的模板,无法直接预览。 diff --git a/tests/visual/template/pr-preview/README.md b/tests/visual/template/pr-preview/README.md new file mode 100644 index 000000000..b410c1c01 --- /dev/null +++ b/tests/visual/template/pr-preview/README.md @@ -0,0 +1,4 @@ +# 预览 + +- npm install +- npm run dev diff --git a/tests/visual/template/pr-preview/index.html b/tests/visual/template/pr-preview/index.html new file mode 100644 index 000000000..2a35ab748 --- /dev/null +++ b/tests/visual/template/pr-preview/index.html @@ -0,0 +1,15 @@ + + + + + + layui-example + + + + + + + + + diff --git a/tests/visual/template/pr-preview/index.js b/tests/visual/template/pr-preview/index.js new file mode 100644 index 000000000..66a9ac201 --- /dev/null +++ b/tests/visual/template/pr-preview/index.js @@ -0,0 +1,5 @@ +layui.use(() => { + const { lay, layer, $ } = layui; + + layer.msg(layui.version); +}); diff --git a/tests/visual/template/pr-preview/package.json b/tests/visual/template/pr-preview/package.json new file mode 100644 index 000000000..95211c1a5 --- /dev/null +++ b/tests/visual/template/pr-preview/package.json @@ -0,0 +1,17 @@ +{ + "name": "layui-example", + "private": true, + "version": "0.0.0", + "description": "generated by pkg.pr.new", + "main": "index.js", + "type": "module", + "scripts": { + "dev": "servor --reload" + }, + "dependencies": { + "servor": "^4.0.2", + "layui": "latest" + }, + "author": "pkg.pr.new", + "license": "ISC" +} diff --git a/tests/visual/template/release/test.html b/tests/visual/template/release/test.html new file mode 100644 index 000000000..849fda86f --- /dev/null +++ b/tests/visual/template/release/test.html @@ -0,0 +1,105 @@ + + + + + + 测试 - Layui + + + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + +
                                                  + +
                                                  +
                                                  +
                                                    +
                                                  • + 您当前预览的是:Layui-v +
                                                  • +
                                                  • + Layui 是一套开源免费的 Web + UI(界面)组件库。这是一个极其简洁的演示页面 +
                                                  • +
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git "a/tests/visual/template/release/\345\205\215\350\264\243\345\243\260\346\230\216.html" "b/tests/visual/template/release/\345\205\215\350\264\243\345\243\260\346\230\216.html" new file mode 100644 index 000000000..ec05f1cc3 --- /dev/null +++ "b/tests/visual/template/release/\345\205\215\350\264\243\345\243\260\346\230\216.html" @@ -0,0 +1,15 @@ + + + + + + 免责声明 + + + + diff --git "a/tests/visual/template/release/\345\256\230\346\226\271\346\226\207\346\241\243.html" "b/tests/visual/template/release/\345\256\230\346\226\271\346\226\207\346\241\243.html" new file mode 100644 index 000000000..e42e3fe28 --- /dev/null +++ "b/tests/visual/template/release/\345\256\230\346\226\271\346\226\207\346\241\243.html" @@ -0,0 +1,15 @@ + + + + + + 官方文档 + + + + diff --git a/tests/visual/text.md.html b/tests/visual/text.md.html new file mode 100644 index 000000000..7324b55a4 --- /dev/null +++ b/tests/visual/text.md.html @@ -0,0 +1,85 @@ + + + + + + text for markdown - layui + + + +
                                                  +
                                                  +

                                                  标题1

                                                  +

                                                  + 段落1段落1段落1段落1段落1段落1段落1段落1段落1 + [1] +

                                                  +

                                                  标题2

                                                  +

                                                  + 段落2段落2 加粗 + 强调 + 段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2段落2 +

                                                  +

                                                  + 段落2-1 + inline code + 段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1段落2-1 +

                                                  +

                                                  标题3

                                                  +

                                                  + 段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3段落3 + 链接 +

                                                  +

                                                  标题4

                                                  +
                                                  标题5
                                                  +
                                                  标题6
                                                  +

                                                  段落6段落6段落6段落6段落6段落6段落6段落6段落6

                                                  + +

                                                  无序列表

                                                  +
                                                    +
                                                  • 列表1
                                                  • +
                                                  • + 列表2 +
                                                      +
                                                    • + 列表2-1 +
                                                        +
                                                      • 列表2-1-1
                                                      • +
                                                      +
                                                    • +
                                                    • 列表2-2
                                                    • +
                                                    +
                                                  • +
                                                  • 列表3
                                                  • +
                                                  + +

                                                  有序列表

                                                  +
                                                    +
                                                  1. 列表1
                                                  2. +
                                                  3. 列表2
                                                  4. +
                                                  5. 列表3
                                                  6. +
                                                  + +

                                                  Blockquote

                                                  +
                                                  +

                                                  引用

                                                  +
                                                  + 内嵌引用 +
                                                  内嵌引用
                                                  +
                                                  +
                                                  + +

                                                  Code

                                                  +
                                                  var cp = function(){
                                                  +  return gulp.src('./dist/**/*')
                                                  +  .pipe(gulp.dest(dest));
                                                  +};
                                                  +
                                                  + +
                                                  + +

                                                  REF-1

                                                  +
                                                  +
                                                  + + diff --git a/tests/visual/transfer.html b/tests/visual/transfer.html new file mode 100644 index 000000000..fedeb77b9 --- /dev/null +++ b/tests/visual/transfer.html @@ -0,0 +1,109 @@ + + + + + + 穿梭框 + + + + + +
                                                  + + +
                                                  + +
                                                  + +
                                                  +
                                                  + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + +
                                                  + + + + + diff --git a/tests/visual/tree.html b/tests/visual/tree.html new file mode 100644 index 000000000..a3ca3589c --- /dev/null +++ b/tests/visual/tree.html @@ -0,0 +1,452 @@ + + + + + + 树组件 - layui + + + +
                                                  + + + +
                                                  + +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  +
                                                  + + + + + diff --git a/tests/visual/treeTable-async.html b/tests/visual/treeTable-async.html new file mode 100644 index 000000000..3c28e01da --- /dev/null +++ b/tests/visual/treeTable-async.html @@ -0,0 +1,265 @@ + + + + + + + Document + + + + +
                                                  + + + + +
                                                  +
                                                  + + + + + diff --git a/tests/visual/treeTable-crud.html b/tests/visual/treeTable-crud.html new file mode 100644 index 000000000..d0d3d7151 --- /dev/null +++ b/tests/visual/treeTable-crud.html @@ -0,0 +1,292 @@ + + + + + + + + Document + + + + +
                                                  + + + + + + + + + + + + diff --git a/tests/visual/treeTable-test-reloadData.html b/tests/visual/treeTable-test-reloadData.html new file mode 100644 index 000000000..c96ffc564 --- /dev/null +++ b/tests/visual/treeTable-test-reloadData.html @@ -0,0 +1,77 @@ + + + + + + 树形表格 - layui + + + +
                                                  + + + + + + + diff --git a/tests/visual/treeTable.html b/tests/visual/treeTable.html new file mode 100644 index 000000000..b3514ebfa --- /dev/null +++ b/tests/visual/treeTable.html @@ -0,0 +1,284 @@ + + + + + + 树形表格 - layui + + + +
                                                  + + + + + + + + + + + + diff --git a/tests/visual/upload.html b/tests/visual/upload.html new file mode 100644 index 000000000..53722fc21 --- /dev/null +++ b/tests/visual/upload.html @@ -0,0 +1,407 @@ + + + + + + 上传组件 - layui + + + + + + +
                                                  + + +
                                                  + +

                                                  +
                                                  +
                                                  + +
                                                  +
                                                  +
                                                  + +
                                                  + +
                                                  + +
                                                  +
                                                  + +
                                                  + +
                                                  + +
                                                  + + + + + + + + +
                                                  文件名大小上传进度操作
                                                  +
                                                  + +
                                                  + +
                                                  + +
                                                  + + + + + +
                                                  + +
                                                  + +
                                                  + + +
                                                  + +
                                                  + +
                                                  + + +
                                                  + +
                                                  +
                                                  + +
                                                  + +

                                                  点击上传,或将文件拖拽到此处

                                                  +
                                                  + +
                                                  +
                                                  + + 绑定原始文件域: + + + + + diff --git a/tests/visual/utils.html b/tests/visual/utils.html new file mode 100644 index 000000000..769649329 --- /dev/null +++ b/tests/visual/utils.html @@ -0,0 +1,222 @@ + + + + + + utils - layui + + + +
                                                  +

                                                  默认 body 委托元素

                                                  +
                                                  + + + + + + +
                                                  + +

                                                  自定义委托元素

                                                  +
                                                  + + + + +
                                                  + +

                                                  转换日期格式

                                                  + + 编辑格式: +
                                                  + +
                                                  + + +

                                                  倒计时

                                                  +
                                                  + +

                                                  某个时间在多久前

                                                  +
                                                  +
                                                  + + + + +