diff --git a/.eslintrc b/.eslintrc index 12defcd8a..3fbfc3524 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,8 @@ "env": { "browser": true, "node": true, - "es6": true + "es6": true, + "jest": true }, "globals": { "window": true, @@ -30,7 +31,7 @@ "rules": { "no-param-reassign": "off", "quotes": [2, "double"], - "comma-dangle": ["error", "never"] // 多行对象字面量中要求拖尾逗号 + "comma-dangle": ["error", { "arrays": "never", "objects": "always-multiline"}] // 多行对象字面量中要求拖尾逗号 } }, { "files": ["webpack/*.js", "./*.js", "lib/**/*.js", "lib/*.js", "./bin/*.js", "./bin/**/*.js"], diff --git a/.npmignore b/.npmignore index a5bc0942a..0f0f7d2e4 100644 --- a/.npmignore +++ b/.npmignore @@ -40,3 +40,5 @@ !dist/2.0/bi.min.css !bin/* !bin/**/* +!plugins/* +!plugins/**/* diff --git a/bi.lessconfig.json b/bi.lessconfig.json index 563eaed07..7de7350ae 100644 --- a/bi.lessconfig.json +++ b/bi.lessconfig.json @@ -38,5 +38,7 @@ "@color-bi-color-toast-normal": "#2C60DB", "@color-bi-color-toast-text": "#000A19", "@color-bi-text-header-background": "rgba(9, 30, 64, 0.9)", - "@color-bi-text-header-background-theme-dark": "rgba(255, 255, 255, 0.9)" + "@color-bi-text-header-background-theme-dark": "rgba(255, 255, 255, 0.9)", + "@font-down-triangle": "e70b", + "@font-date": "e733" } \ No newline at end of file diff --git a/bin/cli/worker/cli.worker.js b/bin/cli/worker/cli.worker.js index 0c086db08..555c99cf0 100644 --- a/bin/cli/worker/cli.worker.js +++ b/bin/cli/worker/cli.worker.js @@ -1,17 +1,25 @@ const fs = require('fs'); const path = require('path'); -function scanAndCreate(structure, root = process.cwd()) { +function first2UpperCase(str) { + return str.toLowerCase().replace(/( |^)[a-z]/g, L => L.toUpperCase()); +} + +function scanAndCreate(structure, workerName, root = process.env.INIT_CWD) { Object.keys(structure) .forEach(name => { if (typeof structure[name] === 'object') { fs.mkdirSync(path.resolve(root, name)); - scanAndCreate(structure[name], path.resolve(root, `./${name}`)); + scanAndCreate(structure[name], workerName, path.resolve(root, `./${name}`)); } else if (structure[name] === '') { fs.appendFileSync(path.resolve(root, name), ''); } else if (typeof structure[name] === 'string') { - const content = fs.readFileSync(structure[name]).toString(); + let content = fs.readFileSync(structure[name]).toString(); + + content = content + .replace(/\${WorkerName}/g, first2UpperCase(workerName)) + .replace(/\${workerName}/g, workerName); fs.appendFileSync(path.resolve(root, name), content); } @@ -33,20 +41,26 @@ module.exports = { const structure = { [`${name}_worker`]: { 'main_thread': { - action: {}, - [`${name}_main_thread.ts`]: path.resolve(__dirname, './template/main_thread_template.ts'), + action: { + 'action.worker_ability_test.ts': path.resolve(__dirname, './template/main_thread/action/action.worker_ability_test.t'), + }, + [`${name}_main_thread.ts`]: path.resolve(__dirname, './template/main_thread/main_thread.t'), }, utils: { - 'action_type.ts': '', + 'action_type.ts': path.resolve(__dirname, './template/utils/action_type.t'), + 'payload_type.ts': path.resolve(__dirname, './template/utils/payload_type.t'), }, 'worker_thread': { - action: {}, - [`${name}_worker_thread.ts`]: path.resolve(__dirname, './template/worker_thread_template.ts'), + action: { + 'action.worker_ability_test.ts': path.resolve(__dirname, './template/worker_thread/action/action.worker_ability_test.t'), + }, + [`${name}_worker_thread.ts`]: path.resolve(__dirname, './template/worker_thread/worker_thread.t'), }, + [`${name}_main_thread.helper.ts`]: path.resolve(__dirname, './template/main_thread.helper.t'), }, }; - scanAndCreate(structure); + scanAndCreate(structure, name); }, }; diff --git a/bin/cli/worker/template/main_thread.helper.t b/bin/cli/worker/template/main_thread.helper.t new file mode 100644 index 000000000..19ac36016 --- /dev/null +++ b/bin/cli/worker/template/main_thread.helper.t @@ -0,0 +1,48 @@ +import { ${WorkerName}MainThreadWorker } from './main_thread/${workerName}_main_thread'; +// 不需要一起打包的话则不需要引入这行 +// FuiWorkerPlugin中的属性会同步到fui-worker中,同时支持loader行内传入属性 +// 根据实际需求传入inline,返回格式 true -> blob url,false -> servicePath +import { workerUrl } from 'fui-worker!./worker_thread/${workerName}_worker_thread'; + +export class ${WorkerName}WorkerHelper { + private worker: ${WorkerName}MainThreadWorker; + + /** + * 拿到helper中的worker + */ + public getWorker() { + if (this.worker) { + return this.worker; + } + + this.worker = BI.Workers.createWorker(${WorkerName}MainThreadWorker, { + workerUrl: this.urlFormatter(workerUrl), + workerName: BI.UUID(), + }); + + return this.worker; + } + + /** + * 格式化worker url,比如补充一些环境信息到参数里 + * 可通过 #hash 将参数传入blob url + * @param url worker url + */ + private urlFormatter(url: string) { + return url; + } + + /** + * 终止worker + */ + public terminate() { + this.worker?.terminate(); + } +} + +// 使用示例 +// const workerHelper = new ${WorkerName}WorkerHelper(); + +// workerHelper.getWorker() +// .testCommunication() +// .then(res => console.log(res)); diff --git a/bin/cli/worker/template/main_thread/action/action.worker_ability_test.t b/bin/cli/worker/template/main_thread/action/action.worker_ability_test.t new file mode 100644 index 000000000..42425b859 --- /dev/null +++ b/bin/cli/worker/template/main_thread/action/action.worker_ability_test.t @@ -0,0 +1,13 @@ +import { WorkerAbilityTestActionType } from '../../utils/action_type'; +import { WorkerAbilityTestPayload, WorkerAbilityTestReponse } from '../../utils/payload_type'; + +export class WorkerAbilityTestMainThreadAction extends BI.Workers.WorkerBaseAction { + /** + * 通信能力检测 + */ + public communicationTest(): Promise { + const mainThreadPostTime: WorkerAbilityTestPayload['CommunicationTest'] = Date.now(); + + return this.controller.requestPromise(WorkerAbilityTestActionType.CommunicationTest, mainThreadPostTime); + } +} diff --git a/bin/cli/worker/template/main_thread/main_thread.t b/bin/cli/worker/template/main_thread/main_thread.t new file mode 100644 index 000000000..00fb09177 --- /dev/null +++ b/bin/cli/worker/template/main_thread/main_thread.t @@ -0,0 +1,13 @@ +import { WorkerAbilityTestMainThreadAction } from './action/action.worker_ability_test'; + +export class ${WorkerName}MainThreadWorker extends BI.Workers.MainThreadWorker { + private communicationTest: WorkerAbilityTestMainThreadAction; + + public initActions(): void { + this.communicationTest = this.createAction(WorkerAbilityTestMainThreadAction); + } + + public testCommunication() { + return this.communicationTest.communicationTest(); + } +} diff --git a/bin/cli/worker/template/main_thread_template.ts b/bin/cli/worker/template/main_thread_template.ts deleted file mode 100644 index 8df764495..000000000 --- a/bin/cli/worker/template/main_thread_template.ts +++ /dev/null @@ -1,5 +0,0 @@ -class CrudMainTreadWorker extends BI.Workers.MainThreadWorker { - protected initActions(): void { - // to init some actions - } -} diff --git a/bin/cli/worker/template/utils/action_type.t b/bin/cli/worker/template/utils/action_type.t new file mode 100644 index 000000000..c92de897a --- /dev/null +++ b/bin/cli/worker/template/utils/action_type.t @@ -0,0 +1,8 @@ +/* + * Worker 事务标识 + * 每类事务有命名空间, 包含多个具体事务 + */ + +export const enum WorkerAbilityTestActionType { + CommunicationTest = 'CommunicationTest', +} diff --git a/bin/cli/worker/template/utils/payload_type.t b/bin/cli/worker/template/utils/payload_type.t new file mode 100644 index 000000000..6b9a71509 --- /dev/null +++ b/bin/cli/worker/template/utils/payload_type.t @@ -0,0 +1,13 @@ +/** + * 跨线程通信各事务的发送数据类型声明 + */ +export interface WorkerAbilityTestPayload { + CommunicationTest: number; +} + +/** + * 跨线程通信各事务的响应数据类型声明 + */ +export interface WorkerAbilityTestReponse { + CommunicationTest: number; +} diff --git a/bin/cli/worker/template/worker_thread/action/action.worker_ability_test.t b/bin/cli/worker/template/worker_thread/action/action.worker_ability_test.t new file mode 100644 index 000000000..f7d1248f4 --- /dev/null +++ b/bin/cli/worker/template/worker_thread/action/action.worker_ability_test.t @@ -0,0 +1,24 @@ +import { WorkerAbilityTestActionType } from '../../utils/action_type'; +import { WorkerAbilityTestPayload, WorkerAbilityTestReponse } from '../../utils/payload_type'; + +export class WorkerAbilityTestWorkerThreadAction extends BI.Workers.WorkerBaseAction { + protected addActionHandler(): void { + this.controller.addActionHandler( + WorkerAbilityTestActionType.CommunicationTest, + this.communicationTest.bind(this) + ); + } + + /** + * 通信能力检测的处理器 + */ + private communicationTest( + payload: WorkerAbilityTestPayload['CommunicationTest'] + ): WorkerAbilityTestReponse['CommunicationTest'] { + const mainThreadPostTime = payload; + // 收到主线程信息的耗时 + const workerGetMessageDuration = Date.now() - mainThreadPostTime; + + return workerGetMessageDuration; + } +} diff --git a/bin/cli/worker/template/worker_thread/worker_thread.t b/bin/cli/worker/template/worker_thread/worker_thread.t new file mode 100644 index 000000000..f437bbc23 --- /dev/null +++ b/bin/cli/worker/template/worker_thread/worker_thread.t @@ -0,0 +1,12 @@ +// TODO: 这边需要先import fineui资源 +import { WorkerAbilityTestWorkerThreadAction } from './action/action.worker_ability_test'; + +class ${WorkerName}WorkerTreadWorker extends BI.Workers.WorkerThreadWorker { + public communicationTest: WorkerAbilityTestWorkerThreadAction; + + public initActions(): void { + this.communicationTest = this.createAction(WorkerAbilityTestWorkerThreadAction); + } +} + +export const ${workerName}WorkerTreadWorker = BI.Workers.createWorker(${WorkerName}WorkerTreadWorker); diff --git a/bin/cli/worker/template/worker_thread_template.ts b/bin/cli/worker/template/worker_thread_template.ts deleted file mode 100644 index fc457c9c7..000000000 --- a/bin/cli/worker/template/worker_thread_template.ts +++ /dev/null @@ -1,5 +0,0 @@ -class CrudWorkerTreadWorker extends BI.Workers.MainThreadWorker { - protected initActions(): void { - // to init some actions - } -} diff --git a/demo/config.js b/demo/config.js index 7b86a02b6..a20f13ebe 100644 --- a/demo/config.js +++ b/demo/config.js @@ -15,1381 +15,1381 @@ Demo.CONSTANTS = { title: v }; }), - TREEITEMS: [{pId: "0", id: "0_0", text: "( 共25个 )", value: "", open: true}, { + TREEITEMS: [{ pId: "0", id: "0_0", text: "( 共25个 )", value: "", open: true }, { pId: "0_0", id: "0_0_0", text: "安徽省( 共1个 )", value: "安徽省", open: true - }, {pId: "0_0_0", id: "0_0_0_0", text: "芜湖市", value: "芜湖市", open: true}, { + }, { pId: "0_0_0", id: "0_0_0_0", text: "芜湖市", value: "芜湖市", open: true }, { pId: "0_0", id: "0_0_1", text: "北京市( 共6个 )", value: "北京市", open: true - }, {pId: "0_0_1", id: "0_0_1_0", text: "北京市区", value: "北京市区", open: true}, { + }, { pId: "0_0_1", id: "0_0_1_0", text: "北京市区", value: "北京市区", open: true }, { pId: "0_0_1", id: "0_0_1_1", text: "朝阳区", value: "朝阳区", open: true - }, {pId: "0_0_1", id: "0_0_1_2", text: "东城区", value: "东城区", open: true}, { + }, { pId: "0_0_1", id: "0_0_1_2", text: "东城区", value: "东城区", open: true }, { pId: "0_0_1", id: "0_0_1_3", text: "海淀区4内", value: "海淀区4内", open: true - }, {pId: "0_0_1", id: "0_0_1_4", text: "海淀区4外", value: "海淀区4外", open: true}, { + }, { pId: "0_0_1", id: "0_0_1_4", text: "海淀区4外", value: "海淀区4外", open: true }, { pId: "0_0_1", id: "0_0_1_5", text: "石景山区", value: "石景山区", open: true - }, {pId: "0_0", id: "0_0_2", text: "福建省( 共2个 )", value: "福建省", open: true}, { + }, { pId: "0_0", id: "0_0_2", text: "福建省( 共2个 )", value: "福建省", open: true }, { pId: "0_0_2", id: "0_0_2_0", text: "莆田市", value: "莆田市", open: true - }, {pId: "0_0_2", id: "0_0_2_1", text: "泉州市", value: "泉州市", open: true}, { + }, { pId: "0_0_2", id: "0_0_2_1", text: "泉州市", value: "泉州市", open: true }, { pId: "0_0", id: "0_0_3", text: "甘肃省( 共1个 )", value: "甘肃省", open: true - }, {pId: "0_0_3", id: "0_0_3_0", text: "兰州市", value: "兰州市", open: true}, { + }, { pId: "0_0_3", id: "0_0_3_0", text: "兰州市", value: "兰州市", open: true }, { pId: "0_0", id: "0_0_4", text: "广东省( 共5个 )", value: "广东省", open: true - }, {pId: "0_0_4", id: "0_0_4_0", text: "东莞市", value: "东莞市", open: true}, { + }, { pId: "0_0_4", id: "0_0_4_0", text: "东莞市", value: "东莞市", open: true }, { pId: "0_0_4", id: "0_0_4_1", text: "广州市", value: "广州市", open: true - }, {pId: "0_0_4", id: "0_0_4_2", text: "惠州市", value: "惠州市", open: true}, { + }, { pId: "0_0_4", id: "0_0_4_2", text: "惠州市", value: "惠州市", open: true }, { pId: "0_0_4", id: "0_0_4_3", text: "深圳市", value: "深圳市", open: true - }, {pId: "0_0_4", id: "0_0_4_4", text: "珠海市", value: "珠海市", open: true}, { + }, { pId: "0_0_4", id: "0_0_4_4", text: "珠海市", value: "珠海市", open: true }, { pId: "0_0", id: "0_0_5", text: "广西壮族自治区( 共1个 )", value: "广西壮族自治区", open: true - }, {pId: "0_0_5", id: "0_0_5_0", text: "南宁市", value: "南宁市", open: true}, { + }, { pId: "0_0_5", id: "0_0_5_0", text: "南宁市", value: "南宁市", open: true }, { pId: "0_0", id: "0_0_6", text: "河北省( 共2个 )", value: "河北省", open: true - }, {pId: "0_0_6", id: "0_0_6_0", text: "保定市", value: "保定市", open: true}, { + }, { pId: "0_0_6", id: "0_0_6_0", text: "保定市", value: "保定市", open: true }, { pId: "0_0_6", id: "0_0_6_1", text: "邢台市", value: "邢台市", open: true - }, {pId: "0_0", id: "0_0_7", text: "河南省( 共1个 )", value: "河南省", open: true}, { + }, { pId: "0_0", id: "0_0_7", text: "河南省( 共1个 )", value: "河南省", open: true }, { pId: "0_0_7", id: "0_0_7_0", text: "郑州市", value: "郑州市", open: true - }, {pId: "0_0", id: "0_0_8", text: "黑龙江省( 共7个 )", value: "黑龙江省", open: true}, { + }, { pId: "0_0", id: "0_0_8", text: "黑龙江省( 共7个 )", value: "黑龙江省", open: true }, { pId: "0_0_8", id: "0_0_8_0", text: "大庆市", value: "大庆市", open: true - }, {pId: "0_0_8", id: "0_0_8_1", text: "哈尔滨市", value: "哈尔滨市", open: true}, { + }, { pId: "0_0_8", id: "0_0_8_1", text: "哈尔滨市", value: "哈尔滨市", open: true }, { pId: "0_0_8", id: "0_0_8_2", text: "鸡西市", value: "鸡西市", open: true - }, {pId: "0_0_8", id: "0_0_8_3", text: "佳木斯市", value: "佳木斯市", open: true}, { + }, { pId: "0_0_8", id: "0_0_8_3", text: "佳木斯市", value: "佳木斯市", open: true }, { pId: "0_0_8", id: "0_0_8_4", text: "牡丹江市", value: "牡丹江市", open: true - }, {pId: "0_0_8", id: "0_0_8_5", text: "齐齐哈尔市", value: "齐齐哈尔市", open: true}, { + }, { pId: "0_0_8", id: "0_0_8_5", text: "齐齐哈尔市", value: "齐齐哈尔市", open: true }, { pId: "0_0_8", id: "0_0_8_6", text: "双鸭山市", value: "双鸭山市", open: true - }, {pId: "0_0", id: "0_0_9", text: "湖北省( 共1个 )", value: "湖北省", open: true}, { + }, { pId: "0_0", id: "0_0_9", text: "湖北省( 共1个 )", value: "湖北省", open: true }, { pId: "0_0_9", id: "0_0_9_0", text: "武汉市", value: "武汉市", open: true - }, {pId: "0_0", id: "0_0_10", text: "湖南省( 共3个 )", value: "湖南省", open: true}, { + }, { pId: "0_0", id: "0_0_10", text: "湖南省( 共3个 )", value: "湖南省", open: true }, { pId: "0_0_10", id: "0_0_10_0", text: "常德市", value: "常德市", open: true - }, {pId: "0_0_10", id: "0_0_10_1", text: "长沙市", value: "长沙市", open: true}, { + }, { pId: "0_0_10", id: "0_0_10_1", text: "长沙市", value: "长沙市", open: true }, { pId: "0_0_10", id: "0_0_10_2", text: "邵阳市", value: "邵阳市", open: true - }, {pId: "0_0", id: "0_0_11", text: "吉林省( 共4个 )", value: "吉林省", open: true}, { + }, { pId: "0_0", id: "0_0_11", text: "吉林省( 共4个 )", value: "吉林省", open: true }, { pId: "0_0_11", id: "0_0_11_0", text: "白山市", value: "白山市", open: true - }, {pId: "0_0_11", id: "0_0_11_1", text: "长春市", value: "长春市", open: true}, { + }, { pId: "0_0_11", id: "0_0_11_1", text: "长春市", value: "长春市", open: true }, { pId: "0_0_11", id: "0_0_11_2", text: "松原市", value: "松原市", open: true - }, {pId: "0_0_11", id: "0_0_11_3", text: "通化市", value: "通化市", open: true}, { + }, { pId: "0_0_11", id: "0_0_11_3", text: "通化市", value: "通化市", open: true }, { pId: "0_0", id: "0_0_12", text: "江苏省( 共8个 )", value: "江苏省", open: true - }, {pId: "0_0_12", id: "0_0_12_0", text: "常州市", value: "常州市", open: true}, { + }, { pId: "0_0_12", id: "0_0_12_0", text: "常州市", value: "常州市", open: true }, { pId: "0_0_12", id: "0_0_12_1", text: "南京市", value: "南京市", open: true - }, {pId: "0_0_12", id: "0_0_12_2", text: "南通市", value: "南通市", open: true}, { + }, { pId: "0_0_12", id: "0_0_12_2", text: "南通市", value: "南通市", open: true }, { pId: "0_0_12", id: "0_0_12_3", text: "苏州市", value: "苏州市", open: true - }, {pId: "0_0_12", id: "0_0_12_4", text: "宿迁市", value: "宿迁市", open: true}, { + }, { pId: "0_0_12", id: "0_0_12_4", text: "宿迁市", value: "宿迁市", open: true }, { pId: "0_0_12", id: "0_0_12_5", text: "泰州市", value: "泰州市", open: true - }, {pId: "0_0_12", id: "0_0_12_6", text: "无锡市", value: "无锡市", open: true}, { + }, { pId: "0_0_12", id: "0_0_12_6", text: "无锡市", value: "无锡市", open: true }, { pId: "0_0_12", id: "0_0_12_7", text: "盐城市", value: "盐城市", open: true - }, {pId: "0_0", id: "0_0_13", text: "辽宁省( 共11个 )", value: "辽宁省", open: true}, { + }, { pId: "0_0", id: "0_0_13", text: "辽宁省( 共11个 )", value: "辽宁省", open: true }, { pId: "0_0_13", id: "0_0_13_0", text: "鞍山市", value: "鞍山市", open: true - }, {pId: "0_0_13", id: "0_0_13_1", text: "本溪市", value: "本溪市", open: true}, { + }, { pId: "0_0_13", id: "0_0_13_1", text: "本溪市", value: "本溪市", open: true }, { pId: "0_0_13", id: "0_0_13_2", text: "朝阳市", value: "朝阳市", open: true - }, {pId: "0_0_13", id: "0_0_13_3", text: "大连市", value: "大连市", open: true}, { + }, { pId: "0_0_13", id: "0_0_13_3", text: "大连市", value: "大连市", open: true }, { pId: "0_0_13", id: "0_0_13_4", text: "抚顺市", value: "抚顺市", open: true - }, {pId: "0_0_13", id: "0_0_13_5", text: "葫芦岛市", value: "葫芦岛市", open: true}, { + }, { pId: "0_0_13", id: "0_0_13_5", text: "葫芦岛市", value: "葫芦岛市", open: true }, { pId: "0_0_13", id: "0_0_13_6", text: "锦州市", value: "锦州市", open: true - }, {pId: "0_0_13", id: "0_0_13_7", text: "辽阳市", value: "辽阳市", open: true}, { + }, { pId: "0_0_13", id: "0_0_13_7", text: "辽阳市", value: "辽阳市", open: true }, { pId: "0_0_13", id: "0_0_13_8", text: "盘锦市", value: "盘锦市", open: true - }, {pId: "0_0_13", id: "0_0_13_9", text: "沈阳市", value: "沈阳市", open: true}, { + }, { pId: "0_0_13", id: "0_0_13_9", text: "沈阳市", value: "沈阳市", open: true }, { pId: "0_0_13", id: "0_0_13_10", text: "营口市", value: "营口市", open: true - }, {pId: "0_0", id: "0_0_14", text: "内蒙古( 共1个 )", value: "内蒙古", open: true}, { + }, { pId: "0_0", id: "0_0_14", text: "内蒙古( 共1个 )", value: "内蒙古", open: true }, { pId: "0_0_14", id: "0_0_14_0", text: "鄂尔多斯市", value: "鄂尔多斯市", open: true - }, {pId: "0_0", id: "0_0_15", text: "宁夏回族自治区( 共1个 )", value: "宁夏回族自治区", open: true}, { + }, { pId: "0_0", id: "0_0_15", text: "宁夏回族自治区( 共1个 )", value: "宁夏回族自治区", open: true }, { pId: "0_0_15", id: "0_0_15_0", text: "银川市", value: "银川市", open: true - }, {pId: "0_0", id: "0_0_16", text: "山东省( 共7个 )", value: "山东省", open: true}, { + }, { pId: "0_0", id: "0_0_16", text: "山东省( 共7个 )", value: "山东省", open: true }, { pId: "0_0_16", id: "0_0_16_0", text: "济南市", value: "济南市", open: true - }, {pId: "0_0_16", id: "0_0_16_1", text: "济宁市", value: "济宁市", open: true}, { + }, { pId: "0_0_16", id: "0_0_16_1", text: "济宁市", value: "济宁市", open: true }, { pId: "0_0_16", id: "0_0_16_2", text: "聊城市", value: "聊城市", open: true - }, {pId: "0_0_16", id: "0_0_16_3", text: "临沂市", value: "临沂市", open: true}, { + }, { pId: "0_0_16", id: "0_0_16_3", text: "临沂市", value: "临沂市", open: true }, { pId: "0_0_16", id: "0_0_16_4", text: "青岛市", value: "青岛市", open: true - }, {pId: "0_0_16", id: "0_0_16_5", text: "烟台市", value: "烟台市", open: true}, { + }, { pId: "0_0_16", id: "0_0_16_5", text: "烟台市", value: "烟台市", open: true }, { pId: "0_0_16", id: "0_0_16_6", text: "枣庄市", value: "枣庄市", open: true - }, {pId: "0_0", id: "0_0_17", text: "山西省( 共1个 )", value: "山西省", open: true}, { + }, { pId: "0_0", id: "0_0_17", text: "山西省( 共1个 )", value: "山西省", open: true }, { pId: "0_0_17", id: "0_0_17_0", text: "太原市", value: "太原市", open: true - }, {pId: "0_0", id: "0_0_18", text: "陕西省( 共1个 )", value: "陕西省", open: true}, { + }, { pId: "0_0", id: "0_0_18", text: "陕西省( 共1个 )", value: "陕西省", open: true }, { pId: "0_0_18", id: "0_0_18_0", text: "西安市", value: "西安市", open: true - }, {pId: "0_0", id: "0_0_19", text: "上海市( 共1个 )", value: "上海市", open: true}, { + }, { pId: "0_0", id: "0_0_19", text: "上海市( 共1个 )", value: "上海市", open: true }, { pId: "0_0_19", id: "0_0_19_0", text: "上海市区", value: "上海市区", open: true - }, {pId: "0_0", id: "0_0_20", text: "四川省( 共1个 )", value: "四川省", open: true}, { + }, { pId: "0_0", id: "0_0_20", text: "四川省( 共1个 )", value: "四川省", open: true }, { pId: "0_0_20", id: "0_0_20_0", text: "成都市", value: "成都市", open: true - }, {pId: "0_0", id: "0_0_21", text: "新疆维吾尔族自治区( 共2个 )", value: "新疆维吾尔族自治区", open: true}, { + }, { pId: "0_0", id: "0_0_21", text: "新疆维吾尔族自治区( 共2个 )", value: "新疆维吾尔族自治区", open: true }, { pId: "0_0_21", id: "0_0_21_0", text: "吐鲁番地区", value: "吐鲁番地区", open: true - }, {pId: "0_0_21", id: "0_0_21_1", text: "乌鲁木齐", value: "乌鲁木齐", open: true}, { + }, { pId: "0_0_21", id: "0_0_21_1", text: "乌鲁木齐", value: "乌鲁木齐", open: true }, { pId: "0_0", id: "0_0_22", text: "云南省( 共1个 )", value: "云南省", open: true - }, {pId: "0_0_22", id: "0_0_22_0", text: "昆明市", value: "昆明市", open: true}, { + }, { pId: "0_0_22", id: "0_0_22_0", text: "昆明市", value: "昆明市", open: true }, { pId: "0_0", id: "0_0_23", text: "浙江省( 共5个 )", value: "浙江省", open: true - }, {pId: "0_0_23", id: "0_0_23_0", text: "杭州市", value: "杭州市", open: true}, { + }, { pId: "0_0_23", id: "0_0_23_0", text: "杭州市", value: "杭州市", open: true }, { pId: "0_0_23", id: "0_0_23_1", text: "湖州市", value: "湖州市", open: true - }, {pId: "0_0_23", id: "0_0_23_2", text: "嘉兴市", value: "嘉兴市", open: true}, { + }, { pId: "0_0_23", id: "0_0_23_2", text: "嘉兴市", value: "嘉兴市", open: true }, { pId: "0_0_23", id: "0_0_23_3", text: "宁波市", value: "宁波市", open: true - }, {pId: "0_0_23", id: "0_0_23_4", text: "绍兴市", value: "绍兴市", open: true}, { + }, { pId: "0_0_23", id: "0_0_23_4", text: "绍兴市", value: "绍兴市", open: true }, { pId: "0_0", id: "0_0_24", text: "重庆市( 共1个 )", value: "重庆市", open: true - }, {pId: "0_0_24", id: "0_0_24_0", text: "重庆市区", value: "重庆市区", open: true}, { + }, { pId: "0_0_24", id: "0_0_24_0", text: "重庆市区", value: "重庆市区", open: true }, { pId: "0", id: "0_1", text: "中国( 共34个 )", value: "中国", open: true - }, {pId: "0_1", id: "0_1_0", text: "安徽省( 共19个 )", value: "安徽省", open: true}, { + }, { pId: "0_1", id: "0_1_0", text: "安徽省( 共19个 )", value: "安徽省", open: true }, { pId: "0_1_0", id: "0_1_0_0", text: "安庆市", value: "安庆市", open: true - }, {pId: "0_1_0", id: "0_1_0_1", text: "蚌埠市", value: "蚌埠市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_1", text: "蚌埠市", value: "蚌埠市", open: true }, { pId: "0_1_0", id: "0_1_0_2", text: "亳州市", value: "亳州市", open: true - }, {pId: "0_1_0", id: "0_1_0_3", text: "巢湖市", value: "巢湖市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_3", text: "巢湖市", value: "巢湖市", open: true }, { pId: "0_1_0", id: "0_1_0_4", text: "池州市", value: "池州市", open: true - }, {pId: "0_1_0", id: "0_1_0_5", text: "滁州市", value: "滁州市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_5", text: "滁州市", value: "滁州市", open: true }, { pId: "0_1_0", id: "0_1_0_6", text: "阜阳市", value: "阜阳市", open: true - }, {pId: "0_1_0", id: "0_1_0_7", text: "毫州市", value: "毫州市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_7", text: "毫州市", value: "毫州市", open: true }, { pId: "0_1_0", id: "0_1_0_8", text: "合肥市", value: "合肥市", open: true - }, {pId: "0_1_0", id: "0_1_0_9", text: "淮北市", value: "淮北市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_9", text: "淮北市", value: "淮北市", open: true }, { pId: "0_1_0", id: "0_1_0_10", text: "淮南市", value: "淮南市", open: true - }, {pId: "0_1_0", id: "0_1_0_11", text: "黄山市", value: "黄山市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_11", text: "黄山市", value: "黄山市", open: true }, { pId: "0_1_0", id: "0_1_0_12", text: "六安市", value: "六安市", open: true - }, {pId: "0_1_0", id: "0_1_0_13", text: "马鞍山市", value: "马鞍山市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_13", text: "马鞍山市", value: "马鞍山市", open: true }, { pId: "0_1_0", id: "0_1_0_14", text: "濮阳市", value: "濮阳市", open: true - }, {pId: "0_1_0", id: "0_1_0_15", text: "宿州市", value: "宿州市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_15", text: "宿州市", value: "宿州市", open: true }, { pId: "0_1_0", id: "0_1_0_16", text: "铜陵市", value: "铜陵市", open: true - }, {pId: "0_1_0", id: "0_1_0_17", text: "芜湖市", value: "芜湖市", open: true}, { + }, { pId: "0_1_0", id: "0_1_0_17", text: "芜湖市", value: "芜湖市", open: true }, { pId: "0_1_0", id: "0_1_0_18", text: "宣城市", value: "宣城市", open: true - }, {pId: "0_1", id: "0_1_1", text: "澳门特别行政区( 共1个 )", value: "澳门特别行政区", open: true}, { + }, { pId: "0_1", id: "0_1_1", text: "澳门特别行政区( 共1个 )", value: "澳门特别行政区", open: true }, { pId: "0_1_1", id: "0_1_1_0", text: "澳门", value: "澳门", open: true - }, {pId: "0_1", id: "0_1_2", text: "北京市( 共17个 )", value: "北京市", open: true}, { + }, { pId: "0_1", id: "0_1_2", text: "北京市( 共17个 )", value: "北京市", open: true }, { pId: "0_1_2", id: "0_1_2_0", text: "北京市区", value: "北京市区", open: true - }, {pId: "0_1_2", id: "0_1_2_1", text: "昌平区", value: "昌平区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_1", text: "昌平区", value: "昌平区", open: true }, { pId: "0_1_2", id: "0_1_2_2", text: "朝阳区", value: "朝阳区", open: true - }, {pId: "0_1_2", id: "0_1_2_3", text: "大兴区", value: "大兴区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_3", text: "大兴区", value: "大兴区", open: true }, { pId: "0_1_2", id: "0_1_2_4", text: "东城区", value: "东城区", open: true - }, {pId: "0_1_2", id: "0_1_2_5", text: "房山区", value: "房山区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_5", text: "房山区", value: "房山区", open: true }, { pId: "0_1_2", id: "0_1_2_6", text: "丰台区", value: "丰台区", open: true - }, {pId: "0_1_2", id: "0_1_2_7", text: "海淀区", value: "海淀区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_7", text: "海淀区", value: "海淀区", open: true }, { pId: "0_1_2", id: "0_1_2_8", text: "海淀区4内", value: "海淀区4内", open: true - }, {pId: "0_1_2", id: "0_1_2_9", text: "海淀区4外", value: "海淀区4外", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_9", text: "海淀区4外", value: "海淀区4外", open: true }, { pId: "0_1_2", id: "0_1_2_10", text: "门头沟区", value: "门头沟区", open: true - }, {pId: "0_1_2", id: "0_1_2_11", text: "平谷区", value: "平谷区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_11", text: "平谷区", value: "平谷区", open: true }, { pId: "0_1_2", id: "0_1_2_12", text: "石景山区", value: "石景山区", open: true - }, {pId: "0_1_2", id: "0_1_2_13", text: "顺义区", value: "顺义区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_13", text: "顺义区", value: "顺义区", open: true }, { pId: "0_1_2", id: "0_1_2_14", text: "通州区", value: "通州区", open: true - }, {pId: "0_1_2", id: "0_1_2_15", text: "西城区", value: "西城区", open: true}, { + }, { pId: "0_1_2", id: "0_1_2_15", text: "西城区", value: "西城区", open: true }, { pId: "0_1_2", id: "0_1_2_16", text: "西城区 ", value: "西城区 ", open: true - }, {pId: "0_1", id: "0_1_3", text: "福建省( 共9个 )", value: "福建省", open: true}, { + }, { pId: "0_1", id: "0_1_3", text: "福建省( 共9个 )", value: "福建省", open: true }, { pId: "0_1_3", id: "0_1_3_0", text: "福州市", value: "福州市", open: true - }, {pId: "0_1_3", id: "0_1_3_1", text: "龙岩市", value: "龙岩市", open: true}, { + }, { pId: "0_1_3", id: "0_1_3_1", text: "龙岩市", value: "龙岩市", open: true }, { pId: "0_1_3", id: "0_1_3_2", text: "南平市", value: "南平市", open: true - }, {pId: "0_1_3", id: "0_1_3_3", text: "宁德市", value: "宁德市", open: true}, { + }, { pId: "0_1_3", id: "0_1_3_3", text: "宁德市", value: "宁德市", open: true }, { pId: "0_1_3", id: "0_1_3_4", text: "莆田市", value: "莆田市", open: true - }, {pId: "0_1_3", id: "0_1_3_5", text: "泉州市", value: "泉州市", open: true}, { + }, { pId: "0_1_3", id: "0_1_3_5", text: "泉州市", value: "泉州市", open: true }, { pId: "0_1_3", id: "0_1_3_6", text: "三明市", value: "三明市", open: true - }, {pId: "0_1_3", id: "0_1_3_7", text: "厦门市", value: "厦门市", open: true}, { + }, { pId: "0_1_3", id: "0_1_3_7", text: "厦门市", value: "厦门市", open: true }, { pId: "0_1_3", id: "0_1_3_8", text: "漳州市", value: "漳州市", open: true - }, {pId: "0_1", id: "0_1_4", text: "甘肃省( 共12个 )", value: "甘肃省", open: true}, { + }, { pId: "0_1", id: "0_1_4", text: "甘肃省( 共12个 )", value: "甘肃省", open: true }, { pId: "0_1_4", id: "0_1_4_0", text: "白银市", value: "白银市", open: true - }, {pId: "0_1_4", id: "0_1_4_1", text: "嘉峪关市", value: "嘉峪关市", open: true}, { + }, { pId: "0_1_4", id: "0_1_4_1", text: "嘉峪关市", value: "嘉峪关市", open: true }, { pId: "0_1_4", id: "0_1_4_2", text: "金昌市", value: "金昌市", open: true - }, {pId: "0_1_4", id: "0_1_4_3", text: "酒泉市", value: "酒泉市", open: true}, { + }, { pId: "0_1_4", id: "0_1_4_3", text: "酒泉市", value: "酒泉市", open: true }, { pId: "0_1_4", id: "0_1_4_4", text: "兰州市", value: "兰州市", open: true - }, {pId: "0_1_4", id: "0_1_4_5", text: "陇南市", value: "陇南市", open: true}, { + }, { pId: "0_1_4", id: "0_1_4_5", text: "陇南市", value: "陇南市", open: true }, { pId: "0_1_4", id: "0_1_4_6", text: "平凉市", value: "平凉市", open: true - }, {pId: "0_1_4", id: "0_1_4_7", text: "庆阳市", value: "庆阳市", open: true}, { + }, { pId: "0_1_4", id: "0_1_4_7", text: "庆阳市", value: "庆阳市", open: true }, { pId: "0_1_4", id: "0_1_4_8", text: "天津市区", value: "天津市区", open: true - }, {pId: "0_1_4", id: "0_1_4_9", text: "天水市", value: "天水市", open: true}, { + }, { pId: "0_1_4", id: "0_1_4_9", text: "天水市", value: "天水市", open: true }, { pId: "0_1_4", id: "0_1_4_10", text: "武威市", value: "武威市", open: true - }, {pId: "0_1_4", id: "0_1_4_11", text: "张掖市", value: "张掖市", open: true}, { + }, { pId: "0_1_4", id: "0_1_4_11", text: "张掖市", value: "张掖市", open: true }, { pId: "0_1", id: "0_1_5", text: "广东省( 共21个 )", value: "广东省", open: true - }, {pId: "0_1_5", id: "0_1_5_0", text: "潮州市", value: "潮州市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_0", text: "潮州市", value: "潮州市", open: true }, { pId: "0_1_5", id: "0_1_5_1", text: "东莞市", value: "东莞市", open: true - }, {pId: "0_1_5", id: "0_1_5_2", text: "佛山市", value: "佛山市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_2", text: "佛山市", value: "佛山市", open: true }, { pId: "0_1_5", id: "0_1_5_3", text: "广州市", value: "广州市", open: true - }, {pId: "0_1_5", id: "0_1_5_4", text: "河源市", value: "河源市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_4", text: "河源市", value: "河源市", open: true }, { pId: "0_1_5", id: "0_1_5_5", text: "惠州市", value: "惠州市", open: true - }, {pId: "0_1_5", id: "0_1_5_6", text: "江门市", value: "江门市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_6", text: "江门市", value: "江门市", open: true }, { pId: "0_1_5", id: "0_1_5_7", text: "揭阳市", value: "揭阳市", open: true - }, {pId: "0_1_5", id: "0_1_5_8", text: "茂名市", value: "茂名市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_8", text: "茂名市", value: "茂名市", open: true }, { pId: "0_1_5", id: "0_1_5_9", text: "梅州市", value: "梅州市", open: true - }, {pId: "0_1_5", id: "0_1_5_10", text: "清远市", value: "清远市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_10", text: "清远市", value: "清远市", open: true }, { pId: "0_1_5", id: "0_1_5_11", text: "汕头市", value: "汕头市", open: true - }, {pId: "0_1_5", id: "0_1_5_12", text: "汕尾市", value: "汕尾市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_12", text: "汕尾市", value: "汕尾市", open: true }, { pId: "0_1_5", id: "0_1_5_13", text: "韶关市", value: "韶关市", open: true - }, {pId: "0_1_5", id: "0_1_5_14", text: "深圳市", value: "深圳市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_14", text: "深圳市", value: "深圳市", open: true }, { pId: "0_1_5", id: "0_1_5_15", text: "阳江市", value: "阳江市", open: true - }, {pId: "0_1_5", id: "0_1_5_16", text: "云浮市", value: "云浮市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_16", text: "云浮市", value: "云浮市", open: true }, { pId: "0_1_5", id: "0_1_5_17", text: "湛江市", value: "湛江市", open: true - }, {pId: "0_1_5", id: "0_1_5_18", text: "肇庆市", value: "肇庆市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_18", text: "肇庆市", value: "肇庆市", open: true }, { pId: "0_1_5", id: "0_1_5_19", text: "中山市", value: "中山市", open: true - }, {pId: "0_1_5", id: "0_1_5_20", text: "珠海市", value: "珠海市", open: true}, { + }, { pId: "0_1_5", id: "0_1_5_20", text: "珠海市", value: "珠海市", open: true }, { pId: "0_1", id: "0_1_6", text: "广西壮族自治区( 共14个 )", value: "广西壮族自治区", open: true - }, {pId: "0_1_6", id: "0_1_6_0", text: "百色市", value: "百色市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_0", text: "百色市", value: "百色市", open: true }, { pId: "0_1_6", id: "0_1_6_1", text: "北海市", value: "北海市", open: true - }, {pId: "0_1_6", id: "0_1_6_2", text: "崇左市", value: "崇左市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_2", text: "崇左市", value: "崇左市", open: true }, { pId: "0_1_6", id: "0_1_6_3", text: "防城港市", value: "防城港市", open: true - }, {pId: "0_1_6", id: "0_1_6_4", text: "桂林市", value: "桂林市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_4", text: "桂林市", value: "桂林市", open: true }, { pId: "0_1_6", id: "0_1_6_5", text: "贵港市", value: "贵港市", open: true - }, {pId: "0_1_6", id: "0_1_6_6", text: "河池市", value: "河池市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_6", text: "河池市", value: "河池市", open: true }, { pId: "0_1_6", id: "0_1_6_7", text: "贺州市", value: "贺州市", open: true - }, {pId: "0_1_6", id: "0_1_6_8", text: "来宾市", value: "来宾市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_8", text: "来宾市", value: "来宾市", open: true }, { pId: "0_1_6", id: "0_1_6_9", text: "柳州市", value: "柳州市", open: true - }, {pId: "0_1_6", id: "0_1_6_10", text: "南宁市", value: "南宁市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_10", text: "南宁市", value: "南宁市", open: true }, { pId: "0_1_6", id: "0_1_6_11", text: "钦州市", value: "钦州市", open: true - }, {pId: "0_1_6", id: "0_1_6_12", text: "梧州市", value: "梧州市", open: true}, { + }, { pId: "0_1_6", id: "0_1_6_12", text: "梧州市", value: "梧州市", open: true }, { pId: "0_1_6", id: "0_1_6_13", text: "玉林市", value: "玉林市", open: true - }, {pId: "0_1", id: "0_1_7", text: "贵州省( 共9个 )", value: "贵州省", open: true}, { + }, { pId: "0_1", id: "0_1_7", text: "贵州省( 共9个 )", value: "贵州省", open: true }, { pId: "0_1_7", id: "0_1_7_0", text: "安顺市", value: "安顺市", open: true - }, {pId: "0_1_7", id: "0_1_7_1", text: "毕节地区", value: "毕节地区", open: true}, { + }, { pId: "0_1_7", id: "0_1_7_1", text: "毕节地区", value: "毕节地区", open: true }, { pId: "0_1_7", id: "0_1_7_2", text: "贵阳市", value: "贵阳市", open: true - }, {pId: "0_1_7", id: "0_1_7_3", text: "六盘水市", value: "六盘水市", open: true}, { + }, { pId: "0_1_7", id: "0_1_7_3", text: "六盘水市", value: "六盘水市", open: true }, { pId: "0_1_7", id: "0_1_7_4", text: "黔东南州", value: "黔东南州", open: true - }, {pId: "0_1_7", id: "0_1_7_5", text: "黔南州", value: "黔南州", open: true}, { + }, { pId: "0_1_7", id: "0_1_7_5", text: "黔南州", value: "黔南州", open: true }, { pId: "0_1_7", id: "0_1_7_6", text: "黔西南市", value: "黔西南市", open: true - }, {pId: "0_1_7", id: "0_1_7_7", text: "铜仁地区", value: "铜仁地区", open: true}, { + }, { pId: "0_1_7", id: "0_1_7_7", text: "铜仁地区", value: "铜仁地区", open: true }, { pId: "0_1_7", id: "0_1_7_8", text: "遵义市", value: "遵义市", open: true - }, {pId: "0_1", id: "0_1_8", text: "海南省( 共2个 )", value: "海南省", open: true}, { + }, { pId: "0_1", id: "0_1_8", text: "海南省( 共2个 )", value: "海南省", open: true }, { pId: "0_1_8", id: "0_1_8_0", text: "海口市", value: "海口市", open: true - }, {pId: "0_1_8", id: "0_1_8_1", text: "三亚市", value: "三亚市", open: true}, { + }, { pId: "0_1_8", id: "0_1_8_1", text: "三亚市", value: "三亚市", open: true }, { pId: "0_1", id: "0_1_9", text: "河北省( 共12个 )", value: "河北省", open: true - }, {pId: "0_1_9", id: "0_1_9_0", text: "保定市", value: "保定市", open: true}, { + }, { pId: "0_1_9", id: "0_1_9_0", text: "保定市", value: "保定市", open: true }, { pId: "0_1_9", id: "0_1_9_1", text: "沧州市", value: "沧州市", open: true - }, {pId: "0_1_9", id: "0_1_9_2", text: "承德市", value: "承德市", open: true}, { + }, { pId: "0_1_9", id: "0_1_9_2", text: "承德市", value: "承德市", open: true }, { pId: "0_1_9", id: "0_1_9_3", text: "邯郸市", value: "邯郸市", open: true - }, {pId: "0_1_9", id: "0_1_9_4", text: "衡水市", value: "衡水市", open: true}, { + }, { pId: "0_1_9", id: "0_1_9_4", text: "衡水市", value: "衡水市", open: true }, { pId: "0_1_9", id: "0_1_9_5", text: "廊坊市", value: "廊坊市", open: true - }, {pId: "0_1_9", id: "0_1_9_6", text: "秦皇岛市", value: "秦皇岛市", open: true}, { + }, { pId: "0_1_9", id: "0_1_9_6", text: "秦皇岛市", value: "秦皇岛市", open: true }, { pId: "0_1_9", id: "0_1_9_7", text: "石家庄市", value: "石家庄市", open: true - }, {pId: "0_1_9", id: "0_1_9_8", text: "唐山市", value: "唐山市", open: true}, { + }, { pId: "0_1_9", id: "0_1_9_8", text: "唐山市", value: "唐山市", open: true }, { pId: "0_1_9", id: "0_1_9_9", text: "天津市区", value: "天津市区", open: true - }, {pId: "0_1_9", id: "0_1_9_10", text: "邢台市", value: "邢台市", open: true}, { + }, { pId: "0_1_9", id: "0_1_9_10", text: "邢台市", value: "邢台市", open: true }, { pId: "0_1_9", id: "0_1_9_11", text: "张家口市", value: "张家口市", open: true - }, {pId: "0_1", id: "0_1_10", text: "河南省( 共19个 )", value: "河南省", open: true}, { + }, { pId: "0_1", id: "0_1_10", text: "河南省( 共19个 )", value: "河南省", open: true }, { pId: "0_1_10", id: "0_1_10_0", text: "安阳市", value: "安阳市", open: true - }, {pId: "0_1_10", id: "0_1_10_1", text: "鹤壁市", value: "鹤壁市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_1", text: "鹤壁市", value: "鹤壁市", open: true }, { pId: "0_1_10", id: "0_1_10_2", text: "济源市", value: "济源市", open: true - }, {pId: "0_1_10", id: "0_1_10_3", text: "焦作市", value: "焦作市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_3", text: "焦作市", value: "焦作市", open: true }, { pId: "0_1_10", id: "0_1_10_4", text: "开封市", value: "开封市", open: true - }, {pId: "0_1_10", id: "0_1_10_5", text: "廊坊市", value: "廊坊市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_5", text: "廊坊市", value: "廊坊市", open: true }, { pId: "0_1_10", id: "0_1_10_6", text: "洛阳市", value: "洛阳市", open: true - }, {pId: "0_1_10", id: "0_1_10_7", text: "漯河市", value: "漯河市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_7", text: "漯河市", value: "漯河市", open: true }, { pId: "0_1_10", id: "0_1_10_8", text: "南阳市", value: "南阳市", open: true - }, {pId: "0_1_10", id: "0_1_10_9", text: "平顶山市", value: "平顶山市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_9", text: "平顶山市", value: "平顶山市", open: true }, { pId: "0_1_10", id: "0_1_10_10", text: "濮阳市", value: "濮阳市", open: true - }, {pId: "0_1_10", id: "0_1_10_11", text: "三门峡市", value: "三门峡市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_11", text: "三门峡市", value: "三门峡市", open: true }, { pId: "0_1_10", id: "0_1_10_12", text: "商丘市", value: "商丘市", open: true - }, {pId: "0_1_10", id: "0_1_10_13", text: "新乡市", value: "新乡市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_13", text: "新乡市", value: "新乡市", open: true }, { pId: "0_1_10", id: "0_1_10_14", text: "信阳市", value: "信阳市", open: true - }, {pId: "0_1_10", id: "0_1_10_15", text: "许昌市", value: "许昌市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_15", text: "许昌市", value: "许昌市", open: true }, { pId: "0_1_10", id: "0_1_10_16", text: "郑州市", value: "郑州市", open: true - }, {pId: "0_1_10", id: "0_1_10_17", text: "周口市", value: "周口市", open: true}, { + }, { pId: "0_1_10", id: "0_1_10_17", text: "周口市", value: "周口市", open: true }, { pId: "0_1_10", id: "0_1_10_18", text: "驻马店市", value: "驻马店市", open: true - }, {pId: "0_1", id: "0_1_11", text: "黑龙江省( 共13个 )", value: "黑龙江省", open: true}, { + }, { pId: "0_1", id: "0_1_11", text: "黑龙江省( 共13个 )", value: "黑龙江省", open: true }, { pId: "0_1_11", id: "0_1_11_0", text: "大庆市", value: "大庆市", open: true - }, {pId: "0_1_11", id: "0_1_11_1", text: "大兴安岭地区", value: "大兴安岭地区", open: true}, { + }, { pId: "0_1_11", id: "0_1_11_1", text: "大兴安岭地区", value: "大兴安岭地区", open: true }, { pId: "0_1_11", id: "0_1_11_2", text: "大兴安岭市", value: "大兴安岭市", open: true - }, {pId: "0_1_11", id: "0_1_11_3", text: "哈尔滨市", value: "哈尔滨市", open: true}, { + }, { pId: "0_1_11", id: "0_1_11_3", text: "哈尔滨市", value: "哈尔滨市", open: true }, { pId: "0_1_11", id: "0_1_11_4", text: "鹤港市", value: "鹤港市", open: true - }, {pId: "0_1_11", id: "0_1_11_5", text: "黑河市", value: "黑河市", open: true}, { + }, { pId: "0_1_11", id: "0_1_11_5", text: "黑河市", value: "黑河市", open: true }, { pId: "0_1_11", id: "0_1_11_6", text: "佳木斯市", value: "佳木斯市", open: true - }, {pId: "0_1_11", id: "0_1_11_7", text: "牡丹江市", value: "牡丹江市", open: true}, { + }, { pId: "0_1_11", id: "0_1_11_7", text: "牡丹江市", value: "牡丹江市", open: true }, { pId: "0_1_11", id: "0_1_11_8", text: "七台河市", value: "七台河市", open: true - }, {pId: "0_1_11", id: "0_1_11_9", text: "齐齐哈尔市", value: "齐齐哈尔市", open: true}, { + }, { pId: "0_1_11", id: "0_1_11_9", text: "齐齐哈尔市", value: "齐齐哈尔市", open: true }, { pId: "0_1_11", id: "0_1_11_10", text: "双鸭山市", value: "双鸭山市", open: true - }, {pId: "0_1_11", id: "0_1_11_11", text: "绥化市", value: "绥化市", open: true}, { + }, { pId: "0_1_11", id: "0_1_11_11", text: "绥化市", value: "绥化市", open: true }, { pId: "0_1_11", id: "0_1_11_12", text: "伊春市", value: "伊春市", open: true - }, {pId: "0_1", id: "0_1_12", text: "湖北省( 共16个 )", value: "湖北省", open: true}, { + }, { pId: "0_1", id: "0_1_12", text: "湖北省( 共16个 )", value: "湖北省", open: true }, { pId: "0_1_12", id: "0_1_12_0", text: "鄂州市", value: "鄂州市", open: true - }, {pId: "0_1_12", id: "0_1_12_1", text: "恩施土家族苗族自治州", value: "恩施土家族苗族自治州", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_1", text: "恩施土家族苗族自治州", value: "恩施土家族苗族自治州", open: true }, { pId: "0_1_12", id: "0_1_12_2", text: "黄冈市", value: "黄冈市", open: true - }, {pId: "0_1_12", id: "0_1_12_3", text: "黄石市", value: "黄石市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_3", text: "黄石市", value: "黄石市", open: true }, { pId: "0_1_12", id: "0_1_12_4", text: "荆门市", value: "荆门市", open: true - }, {pId: "0_1_12", id: "0_1_12_5", text: "荆州市", value: "荆州市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_5", text: "荆州市", value: "荆州市", open: true }, { pId: "0_1_12", id: "0_1_12_6", text: "神农架市", value: "神农架市", open: true - }, {pId: "0_1_12", id: "0_1_12_7", text: "十堰市", value: "十堰市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_7", text: "十堰市", value: "十堰市", open: true }, { pId: "0_1_12", id: "0_1_12_8", text: "随州市", value: "随州市", open: true - }, {pId: "0_1_12", id: "0_1_12_9", text: "天门市", value: "天门市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_9", text: "天门市", value: "天门市", open: true }, { pId: "0_1_12", id: "0_1_12_10", text: "武汉市", value: "武汉市", open: true - }, {pId: "0_1_12", id: "0_1_12_11", text: "咸宁市", value: "咸宁市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_11", text: "咸宁市", value: "咸宁市", open: true }, { pId: "0_1_12", id: "0_1_12_12", text: "襄樊市", value: "襄樊市", open: true - }, {pId: "0_1_12", id: "0_1_12_13", text: "襄阳市", value: "襄阳市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_13", text: "襄阳市", value: "襄阳市", open: true }, { pId: "0_1_12", id: "0_1_12_14", text: "孝感市", value: "孝感市", open: true - }, {pId: "0_1_12", id: "0_1_12_15", text: "宜昌市", value: "宜昌市", open: true}, { + }, { pId: "0_1_12", id: "0_1_12_15", text: "宜昌市", value: "宜昌市", open: true }, { pId: "0_1", id: "0_1_13", text: "湖南省( 共15个 )", value: "湖南省", open: true - }, {pId: "0_1_13", id: "0_1_13_0", text: "常德市", value: "常德市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_0", text: "常德市", value: "常德市", open: true }, { pId: "0_1_13", id: "0_1_13_1", text: "长沙市", value: "长沙市", open: true - }, {pId: "0_1_13", id: "0_1_13_2", text: "郴州市", value: "郴州市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_2", text: "郴州市", value: "郴州市", open: true }, { pId: "0_1_13", id: "0_1_13_3", text: "衡阳市", value: "衡阳市", open: true - }, {pId: "0_1_13", id: "0_1_13_4", text: "怀化市", value: "怀化市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_4", text: "怀化市", value: "怀化市", open: true }, { pId: "0_1_13", id: "0_1_13_5", text: "娄底市", value: "娄底市", open: true - }, {pId: "0_1_13", id: "0_1_13_6", text: "邵阳市", value: "邵阳市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_6", text: "邵阳市", value: "邵阳市", open: true }, { pId: "0_1_13", id: "0_1_13_7", text: "湘潭市", value: "湘潭市", open: true - }, {pId: "0_1_13", id: "0_1_13_8", text: "湘西市", value: "湘西市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_8", text: "湘西市", value: "湘西市", open: true }, { pId: "0_1_13", id: "0_1_13_9", text: "湘西土家族苗族自治州", value: "湘西土家族苗族自治州", open: true - }, {pId: "0_1_13", id: "0_1_13_10", text: "益阳市", value: "益阳市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_10", text: "益阳市", value: "益阳市", open: true }, { pId: "0_1_13", id: "0_1_13_11", text: "永州市", value: "永州市", open: true - }, {pId: "0_1_13", id: "0_1_13_12", text: "岳阳市", value: "岳阳市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_12", text: "岳阳市", value: "岳阳市", open: true }, { pId: "0_1_13", id: "0_1_13_13", text: "张家界市", value: "张家界市", open: true - }, {pId: "0_1_13", id: "0_1_13_14", text: "株洲市", value: "株洲市", open: true}, { + }, { pId: "0_1_13", id: "0_1_13_14", text: "株洲市", value: "株洲市", open: true }, { pId: "0_1", id: "0_1_14", text: "吉林省( 共10个 )", value: "吉林省", open: true - }, {pId: "0_1_14", id: "0_1_14_0", text: "白城市", value: "白城市", open: true}, { + }, { pId: "0_1_14", id: "0_1_14_0", text: "白城市", value: "白城市", open: true }, { pId: "0_1_14", id: "0_1_14_1", text: "白山市", value: "白山市", open: true - }, {pId: "0_1_14", id: "0_1_14_2", text: "长春市", value: "长春市", open: true}, { + }, { pId: "0_1_14", id: "0_1_14_2", text: "长春市", value: "长春市", open: true }, { pId: "0_1_14", id: "0_1_14_3", text: "大庆市", value: "大庆市", open: true - }, {pId: "0_1_14", id: "0_1_14_4", text: "吉林市", value: "吉林市", open: true}, { + }, { pId: "0_1_14", id: "0_1_14_4", text: "吉林市", value: "吉林市", open: true }, { pId: "0_1_14", id: "0_1_14_5", text: "辽源市", value: "辽源市", open: true - }, {pId: "0_1_14", id: "0_1_14_6", text: "四平市", value: "四平市", open: true}, { + }, { pId: "0_1_14", id: "0_1_14_6", text: "四平市", value: "四平市", open: true }, { pId: "0_1_14", id: "0_1_14_7", text: "松原市", value: "松原市", open: true - }, {pId: "0_1_14", id: "0_1_14_8", text: "通化市", value: "通化市", open: true}, { + }, { pId: "0_1_14", id: "0_1_14_8", text: "通化市", value: "通化市", open: true }, { pId: "0_1_14", id: "0_1_14_9", text: "延边朝鲜族自治州", value: "延边朝鲜族自治州", open: true - }, {pId: "0_1", id: "0_1_15", text: "江苏省( 共13个 )", value: "江苏省", open: true}, { + }, { pId: "0_1", id: "0_1_15", text: "江苏省( 共13个 )", value: "江苏省", open: true }, { pId: "0_1_15", id: "0_1_15_0", text: "常州市", value: "常州市", open: true - }, {pId: "0_1_15", id: "0_1_15_1", text: "淮安市", value: "淮安市", open: true}, { + }, { pId: "0_1_15", id: "0_1_15_1", text: "淮安市", value: "淮安市", open: true }, { pId: "0_1_15", id: "0_1_15_2", text: "连云港市", value: "连云港市", open: true - }, {pId: "0_1_15", id: "0_1_15_3", text: "南京市", value: "南京市", open: true}, { + }, { pId: "0_1_15", id: "0_1_15_3", text: "南京市", value: "南京市", open: true }, { pId: "0_1_15", id: "0_1_15_4", text: "南通市", value: "南通市", open: true - }, {pId: "0_1_15", id: "0_1_15_5", text: "苏州市", value: "苏州市", open: true}, { + }, { pId: "0_1_15", id: "0_1_15_5", text: "苏州市", value: "苏州市", open: true }, { pId: "0_1_15", id: "0_1_15_6", text: "宿迁市", value: "宿迁市", open: true - }, {pId: "0_1_15", id: "0_1_15_7", text: "泰州市", value: "泰州市", open: true}, { + }, { pId: "0_1_15", id: "0_1_15_7", text: "泰州市", value: "泰州市", open: true }, { pId: "0_1_15", id: "0_1_15_8", text: "无锡市", value: "无锡市", open: true - }, {pId: "0_1_15", id: "0_1_15_9", text: "徐州市", value: "徐州市", open: true}, { + }, { pId: "0_1_15", id: "0_1_15_9", text: "徐州市", value: "徐州市", open: true }, { pId: "0_1_15", id: "0_1_15_10", text: "盐城市", value: "盐城市", open: true - }, {pId: "0_1_15", id: "0_1_15_11", text: "扬州市", value: "扬州市", open: true}, { + }, { pId: "0_1_15", id: "0_1_15_11", text: "扬州市", value: "扬州市", open: true }, { pId: "0_1_15", id: "0_1_15_12", text: "镇江市", value: "镇江市", open: true - }, {pId: "0_1", id: "0_1_16", text: "江西省( 共10个 )", value: "江西省", open: true}, { + }, { pId: "0_1", id: "0_1_16", text: "江西省( 共10个 )", value: "江西省", open: true }, { pId: "0_1_16", id: "0_1_16_0", text: "抚州市", value: "抚州市", open: true - }, {pId: "0_1_16", id: "0_1_16_1", text: "赣州市", value: "赣州市", open: true}, { + }, { pId: "0_1_16", id: "0_1_16_1", text: "赣州市", value: "赣州市", open: true }, { pId: "0_1_16", id: "0_1_16_2", text: "景德镇市", value: "景德镇市", open: true - }, {pId: "0_1_16", id: "0_1_16_3", text: "九江市", value: "九江市", open: true}, { + }, { pId: "0_1_16", id: "0_1_16_3", text: "九江市", value: "九江市", open: true }, { pId: "0_1_16", id: "0_1_16_4", text: "南昌市", value: "南昌市", open: true - }, {pId: "0_1_16", id: "0_1_16_5", text: "萍乡市", value: "萍乡市", open: true}, { + }, { pId: "0_1_16", id: "0_1_16_5", text: "萍乡市", value: "萍乡市", open: true }, { pId: "0_1_16", id: "0_1_16_6", text: "上饶市", value: "上饶市", open: true - }, {pId: "0_1_16", id: "0_1_16_7", text: "新余市", value: "新余市", open: true}, { + }, { pId: "0_1_16", id: "0_1_16_7", text: "新余市", value: "新余市", open: true }, { pId: "0_1_16", id: "0_1_16_8", text: "宜春市", value: "宜春市", open: true - }, {pId: "0_1_16", id: "0_1_16_9", text: "鹰潭市", value: "鹰潭市", open: true}, { + }, { pId: "0_1_16", id: "0_1_16_9", text: "鹰潭市", value: "鹰潭市", open: true }, { pId: "0_1", id: "0_1_17", text: "辽宁省( 共14个 )", value: "辽宁省", open: true - }, {pId: "0_1_17", id: "0_1_17_0", text: "鞍山市", value: "鞍山市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_0", text: "鞍山市", value: "鞍山市", open: true }, { pId: "0_1_17", id: "0_1_17_1", text: "本溪市", value: "本溪市", open: true - }, {pId: "0_1_17", id: "0_1_17_2", text: "朝阳市", value: "朝阳市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_2", text: "朝阳市", value: "朝阳市", open: true }, { pId: "0_1_17", id: "0_1_17_3", text: "大连市", value: "大连市", open: true - }, {pId: "0_1_17", id: "0_1_17_4", text: "丹东市", value: "丹东市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_4", text: "丹东市", value: "丹东市", open: true }, { pId: "0_1_17", id: "0_1_17_5", text: "抚顺市", value: "抚顺市", open: true - }, {pId: "0_1_17", id: "0_1_17_6", text: "阜新市", value: "阜新市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_6", text: "阜新市", value: "阜新市", open: true }, { pId: "0_1_17", id: "0_1_17_7", text: "葫芦岛市", value: "葫芦岛市", open: true - }, {pId: "0_1_17", id: "0_1_17_8", text: "锦州市", value: "锦州市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_8", text: "锦州市", value: "锦州市", open: true }, { pId: "0_1_17", id: "0_1_17_9", text: "辽阳市", value: "辽阳市", open: true - }, {pId: "0_1_17", id: "0_1_17_10", text: "盘锦市", value: "盘锦市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_10", text: "盘锦市", value: "盘锦市", open: true }, { pId: "0_1_17", id: "0_1_17_11", text: "沈阳市", value: "沈阳市", open: true - }, {pId: "0_1_17", id: "0_1_17_12", text: "铁岭市", value: "铁岭市", open: true}, { + }, { pId: "0_1_17", id: "0_1_17_12", text: "铁岭市", value: "铁岭市", open: true }, { pId: "0_1_17", id: "0_1_17_13", text: "营口市", value: "营口市", open: true - }, {pId: "0_1", id: "0_1_18", text: "内蒙古( 共10个 )", value: "内蒙古", open: true}, { + }, { pId: "0_1", id: "0_1_18", text: "内蒙古( 共10个 )", value: "内蒙古", open: true }, { pId: "0_1_18", id: "0_1_18_0", text: "包头市", value: "包头市", open: true - }, {pId: "0_1_18", id: "0_1_18_1", text: "赤峰市", value: "赤峰市", open: true}, { + }, { pId: "0_1_18", id: "0_1_18_1", text: "赤峰市", value: "赤峰市", open: true }, { pId: "0_1_18", id: "0_1_18_2", text: "鄂尔多斯市", value: "鄂尔多斯市", open: true - }, {pId: "0_1_18", id: "0_1_18_3", text: "呼和浩特市", value: "呼和浩特市", open: true}, { + }, { pId: "0_1_18", id: "0_1_18_3", text: "呼和浩特市", value: "呼和浩特市", open: true }, { pId: "0_1_18", id: "0_1_18_4", text: "呼伦贝尔市", value: "呼伦贝尔市", open: true - }, {pId: "0_1_18", id: "0_1_18_5", text: "通辽市", value: "通辽市", open: true}, { + }, { pId: "0_1_18", id: "0_1_18_5", text: "通辽市", value: "通辽市", open: true }, { pId: "0_1_18", id: "0_1_18_6", text: "乌海市", value: "乌海市", open: true - }, {pId: "0_1_18", id: "0_1_18_7", text: "锡林郭勒市", value: "锡林郭勒市", open: true}, { + }, { pId: "0_1_18", id: "0_1_18_7", text: "锡林郭勒市", value: "锡林郭勒市", open: true }, { pId: "0_1_18", id: "0_1_18_8", text: "兴安市", value: "兴安市", open: true - }, {pId: "0_1_18", id: "0_1_18_9", text: "运城市", value: "运城市", open: true}, { + }, { pId: "0_1_18", id: "0_1_18_9", text: "运城市", value: "运城市", open: true }, { pId: "0_1", id: "0_1_19", text: "宁夏回族自治区( 共5个 )", value: "宁夏回族自治区", open: true - }, {pId: "0_1_19", id: "0_1_19_0", text: "固原市", value: "固原市", open: true}, { + }, { pId: "0_1_19", id: "0_1_19_0", text: "固原市", value: "固原市", open: true }, { pId: "0_1_19", id: "0_1_19_1", text: "石嘴山市", value: "石嘴山市", open: true - }, {pId: "0_1_19", id: "0_1_19_2", text: "吴忠市", value: "吴忠市", open: true}, { + }, { pId: "0_1_19", id: "0_1_19_2", text: "吴忠市", value: "吴忠市", open: true }, { pId: "0_1_19", id: "0_1_19_3", text: "银川市", value: "银川市", open: true - }, {pId: "0_1_19", id: "0_1_19_4", text: "中卫市", value: "中卫市", open: true}, { + }, { pId: "0_1_19", id: "0_1_19_4", text: "中卫市", value: "中卫市", open: true }, { pId: "0_1", id: "0_1_20", text: "青海省( 共4个 )", value: "青海省", open: true - }, {pId: "0_1_20", id: "0_1_20_0", text: "海东地区", value: "海东地区", open: true}, { + }, { pId: "0_1_20", id: "0_1_20_0", text: "海东地区", value: "海东地区", open: true }, { pId: "0_1_20", id: "0_1_20_1", text: "海南藏族自治州", value: "海南藏族自治州", open: true - }, {pId: "0_1_20", id: "0_1_20_2", text: "海西蒙古族藏族自治州", value: "海西蒙古族藏族自治州", open: true}, { + }, { pId: "0_1_20", id: "0_1_20_2", text: "海西蒙古族藏族自治州", value: "海西蒙古族藏族自治州", open: true }, { pId: "0_1_20", id: "0_1_20_3", text: "西宁市", value: "西宁市", open: true - }, {pId: "0_1", id: "0_1_21", text: "山东省( 共17个 )", value: "山东省", open: true}, { + }, { pId: "0_1", id: "0_1_21", text: "山东省( 共17个 )", value: "山东省", open: true }, { pId: "0_1_21", id: "0_1_21_0", text: "滨州市", value: "滨州市", open: true - }, {pId: "0_1_21", id: "0_1_21_1", text: "德州市", value: "德州市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_1", text: "德州市", value: "德州市", open: true }, { pId: "0_1_21", id: "0_1_21_2", text: "东营市", value: "东营市", open: true - }, {pId: "0_1_21", id: "0_1_21_3", text: "菏泽市", value: "菏泽市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_3", text: "菏泽市", value: "菏泽市", open: true }, { pId: "0_1_21", id: "0_1_21_4", text: "济南市", value: "济南市", open: true - }, {pId: "0_1_21", id: "0_1_21_5", text: "济宁市", value: "济宁市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_5", text: "济宁市", value: "济宁市", open: true }, { pId: "0_1_21", id: "0_1_21_6", text: "莱芜市", value: "莱芜市", open: true - }, {pId: "0_1_21", id: "0_1_21_7", text: "聊城市", value: "聊城市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_7", text: "聊城市", value: "聊城市", open: true }, { pId: "0_1_21", id: "0_1_21_8", text: "临沂市", value: "临沂市", open: true - }, {pId: "0_1_21", id: "0_1_21_9", text: "青岛市", value: "青岛市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_9", text: "青岛市", value: "青岛市", open: true }, { pId: "0_1_21", id: "0_1_21_10", text: "日照市", value: "日照市", open: true - }, {pId: "0_1_21", id: "0_1_21_11", text: "泰安市", value: "泰安市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_11", text: "泰安市", value: "泰安市", open: true }, { pId: "0_1_21", id: "0_1_21_12", text: "威海市", value: "威海市", open: true - }, {pId: "0_1_21", id: "0_1_21_13", text: "潍坊市", value: "潍坊市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_13", text: "潍坊市", value: "潍坊市", open: true }, { pId: "0_1_21", id: "0_1_21_14", text: "烟台市", value: "烟台市", open: true - }, {pId: "0_1_21", id: "0_1_21_15", text: "枣庄市", value: "枣庄市", open: true}, { + }, { pId: "0_1_21", id: "0_1_21_15", text: "枣庄市", value: "枣庄市", open: true }, { pId: "0_1_21", id: "0_1_21_16", text: "淄博市", value: "淄博市", open: true - }, {pId: "0_1", id: "0_1_22", text: "山西省( 共12个 )", value: "山西省", open: true}, { + }, { pId: "0_1", id: "0_1_22", text: "山西省( 共12个 )", value: "山西省", open: true }, { pId: "0_1_22", id: "0_1_22_0", text: "长治市", value: "长治市", open: true - }, {pId: "0_1_22", id: "0_1_22_1", text: "大同市", value: "大同市", open: true}, { + }, { pId: "0_1_22", id: "0_1_22_1", text: "大同市", value: "大同市", open: true }, { pId: "0_1_22", id: "0_1_22_2", text: "晋城市", value: "晋城市", open: true - }, {pId: "0_1_22", id: "0_1_22_3", text: "晋中市", value: "晋中市", open: true}, { + }, { pId: "0_1_22", id: "0_1_22_3", text: "晋中市", value: "晋中市", open: true }, { pId: "0_1_22", id: "0_1_22_4", text: "临汾市", value: "临汾市", open: true - }, {pId: "0_1_22", id: "0_1_22_5", text: "吕梁市", value: "吕梁市", open: true}, { + }, { pId: "0_1_22", id: "0_1_22_5", text: "吕梁市", value: "吕梁市", open: true }, { pId: "0_1_22", id: "0_1_22_6", text: "青岛市", value: "青岛市", open: true - }, {pId: "0_1_22", id: "0_1_22_7", text: "朔州市", value: "朔州市", open: true}, { + }, { pId: "0_1_22", id: "0_1_22_7", text: "朔州市", value: "朔州市", open: true }, { pId: "0_1_22", id: "0_1_22_8", text: "太原市", value: "太原市", open: true - }, {pId: "0_1_22", id: "0_1_22_9", text: "忻州市", value: "忻州市", open: true}, { + }, { pId: "0_1_22", id: "0_1_22_9", text: "忻州市", value: "忻州市", open: true }, { pId: "0_1_22", id: "0_1_22_10", text: "阳泉市", value: "阳泉市", open: true - }, {pId: "0_1_22", id: "0_1_22_11", text: "运城市", value: "运城市", open: true}, { + }, { pId: "0_1_22", id: "0_1_22_11", text: "运城市", value: "运城市", open: true }, { pId: "0_1", id: "0_1_23", text: "陕西省( 共9个 )", value: "陕西省", open: true - }, {pId: "0_1_23", id: "0_1_23_0", text: "安康市", value: "安康市", open: true}, { + }, { pId: "0_1_23", id: "0_1_23_0", text: "安康市", value: "安康市", open: true }, { pId: "0_1_23", id: "0_1_23_1", text: "宝鸡市", value: "宝鸡市", open: true - }, {pId: "0_1_23", id: "0_1_23_2", text: "汉中市", value: "汉中市", open: true}, { + }, { pId: "0_1_23", id: "0_1_23_2", text: "汉中市", value: "汉中市", open: true }, { pId: "0_1_23", id: "0_1_23_3", text: "商洛市", value: "商洛市", open: true - }, {pId: "0_1_23", id: "0_1_23_4", text: "渭南市", value: "渭南市", open: true}, { + }, { pId: "0_1_23", id: "0_1_23_4", text: "渭南市", value: "渭南市", open: true }, { pId: "0_1_23", id: "0_1_23_5", text: "西安市", value: "西安市", open: true - }, {pId: "0_1_23", id: "0_1_23_6", text: "咸阳市", value: "咸阳市", open: true}, { + }, { pId: "0_1_23", id: "0_1_23_6", text: "咸阳市", value: "咸阳市", open: true }, { pId: "0_1_23", id: "0_1_23_7", text: "延安市", value: "延安市", open: true - }, {pId: "0_1_23", id: "0_1_23_8", text: "榆林市", value: "榆林市", open: true}, { + }, { pId: "0_1_23", id: "0_1_23_8", text: "榆林市", value: "榆林市", open: true }, { pId: "0_1", id: "0_1_24", text: "上海市( 共19个 )", value: "上海市", open: true - }, {pId: "0_1_24", id: "0_1_24_0", text: "宝山区", value: "宝山区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_0", text: "宝山区", value: "宝山区", open: true }, { pId: "0_1_24", id: "0_1_24_1", text: "长宁区", value: "长宁区", open: true - }, {pId: "0_1_24", id: "0_1_24_2", text: "崇明县", value: "崇明县", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_2", text: "崇明县", value: "崇明县", open: true }, { pId: "0_1_24", id: "0_1_24_3", text: "奉贤区", value: "奉贤区", open: true - }, {pId: "0_1_24", id: "0_1_24_4", text: "虹口区", value: "虹口区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_4", text: "虹口区", value: "虹口区", open: true }, { pId: "0_1_24", id: "0_1_24_5", text: "黄浦区", value: "黄浦区", open: true - }, {pId: "0_1_24", id: "0_1_24_6", text: "嘉定区", value: "嘉定区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_6", text: "嘉定区", value: "嘉定区", open: true }, { pId: "0_1_24", id: "0_1_24_7", text: "金山区", value: "金山区", open: true - }, {pId: "0_1_24", id: "0_1_24_8", text: "静安区", value: "静安区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_8", text: "静安区", value: "静安区", open: true }, { pId: "0_1_24", id: "0_1_24_9", text: "昆明市", value: "昆明市", open: true - }, {pId: "0_1_24", id: "0_1_24_10", text: "闵行区", value: "闵行区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_10", text: "闵行区", value: "闵行区", open: true }, { pId: "0_1_24", id: "0_1_24_11", text: "普陀区", value: "普陀区", open: true - }, {pId: "0_1_24", id: "0_1_24_12", text: "浦东新区", value: "浦东新区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_12", text: "浦东新区", value: "浦东新区", open: true }, { pId: "0_1_24", id: "0_1_24_13", text: "青浦区", value: "青浦区", open: true - }, {pId: "0_1_24", id: "0_1_24_14", text: "上海市区", value: "上海市区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_14", text: "上海市区", value: "上海市区", open: true }, { pId: "0_1_24", id: "0_1_24_15", text: "松江区", value: "松江区", open: true - }, {pId: "0_1_24", id: "0_1_24_16", text: "徐汇区", value: "徐汇区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_16", text: "徐汇区", value: "徐汇区", open: true }, { pId: "0_1_24", id: "0_1_24_17", text: "杨浦区", value: "杨浦区", open: true - }, {pId: "0_1_24", id: "0_1_24_18", text: "闸北区", value: "闸北区", open: true}, { + }, { pId: "0_1_24", id: "0_1_24_18", text: "闸北区", value: "闸北区", open: true }, { pId: "0_1", id: "0_1_25", text: "四川省( 共21个 )", value: "四川省", open: true - }, {pId: "0_1_25", id: "0_1_25_0", text: "阿坝藏族羌族自治州", value: "阿坝藏族羌族自治州", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_0", text: "阿坝藏族羌族自治州", value: "阿坝藏族羌族自治州", open: true }, { pId: "0_1_25", id: "0_1_25_1", text: "巴中市", value: "巴中市", open: true - }, {pId: "0_1_25", id: "0_1_25_2", text: "成都市", value: "成都市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_2", text: "成都市", value: "成都市", open: true }, { pId: "0_1_25", id: "0_1_25_3", text: "达州市", value: "达州市", open: true - }, {pId: "0_1_25", id: "0_1_25_4", text: "德阳市", value: "德阳市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_4", text: "德阳市", value: "德阳市", open: true }, { pId: "0_1_25", id: "0_1_25_5", text: "甘孜市", value: "甘孜市", open: true - }, {pId: "0_1_25", id: "0_1_25_6", text: "广安市", value: "广安市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_6", text: "广安市", value: "广安市", open: true }, { pId: "0_1_25", id: "0_1_25_7", text: "广元市", value: "广元市", open: true - }, {pId: "0_1_25", id: "0_1_25_8", text: "乐山市", value: "乐山市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_8", text: "乐山市", value: "乐山市", open: true }, { pId: "0_1_25", id: "0_1_25_9", text: "凉山市", value: "凉山市", open: true - }, {pId: "0_1_25", id: "0_1_25_10", text: "泸州市", value: "泸州市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_10", text: "泸州市", value: "泸州市", open: true }, { pId: "0_1_25", id: "0_1_25_11", text: "眉山市", value: "眉山市", open: true - }, {pId: "0_1_25", id: "0_1_25_12", text: "绵阳市", value: "绵阳市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_12", text: "绵阳市", value: "绵阳市", open: true }, { pId: "0_1_25", id: "0_1_25_13", text: "南充市", value: "南充市", open: true - }, {pId: "0_1_25", id: "0_1_25_14", text: "内江市", value: "内江市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_14", text: "内江市", value: "内江市", open: true }, { pId: "0_1_25", id: "0_1_25_15", text: "攀枝花市", value: "攀枝花市", open: true - }, {pId: "0_1_25", id: "0_1_25_16", text: "遂宁市", value: "遂宁市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_16", text: "遂宁市", value: "遂宁市", open: true }, { pId: "0_1_25", id: "0_1_25_17", text: "雅安市", value: "雅安市", open: true - }, {pId: "0_1_25", id: "0_1_25_18", text: "宜宾市", value: "宜宾市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_18", text: "宜宾市", value: "宜宾市", open: true }, { pId: "0_1_25", id: "0_1_25_19", text: "资阳市", value: "资阳市", open: true - }, {pId: "0_1_25", id: "0_1_25_20", text: "自贡市", value: "自贡市", open: true}, { + }, { pId: "0_1_25", id: "0_1_25_20", text: "自贡市", value: "自贡市", open: true }, { pId: "0_1", id: "0_1_26", text: "台湾( 共1个 )", value: "台湾", open: true - }, {pId: "0_1_26", id: "0_1_26_0", text: "台北市", value: "台北市", open: true}, { + }, { pId: "0_1_26", id: "0_1_26_0", text: "台北市", value: "台北市", open: true }, { pId: "0_1", id: "0_1_27", text: "天津市( 共1个 )", value: "天津市", open: true - }, {pId: "0_1_27", id: "0_1_27_0", text: "天津市区", value: "天津市区", open: true}, { + }, { pId: "0_1_27", id: "0_1_27_0", text: "天津市区", value: "天津市区", open: true }, { pId: "0_1", id: "0_1_28", text: "西藏自治区( 共2个 )", value: "西藏自治区", open: true - }, {pId: "0_1_28", id: "0_1_28_0", text: "阿里市", value: "阿里市", open: true}, { + }, { pId: "0_1_28", id: "0_1_28_0", text: "阿里市", value: "阿里市", open: true }, { pId: "0_1_28", id: "0_1_28_1", text: "日喀则市", value: "日喀则市", open: true - }, {pId: "0_1", id: "0_1_29", text: "香港特别行政区( 共1个 )", value: "香港特别行政区", open: true}, { + }, { pId: "0_1", id: "0_1_29", text: "香港特别行政区( 共1个 )", value: "香港特别行政区", open: true }, { pId: "0_1_29", id: "0_1_29_0", text: "香港", @@ -1401,141 +1401,141 @@ Demo.CONSTANTS = { text: "新疆维吾尔族自治区( 共11个 )", value: "新疆维吾尔族自治区", open: true - }, {pId: "0_1_30", id: "0_1_30_0", text: "巴音郭楞市", value: "巴音郭楞市", open: true}, { + }, { pId: "0_1_30", id: "0_1_30_0", text: "巴音郭楞市", value: "巴音郭楞市", open: true }, { pId: "0_1_30", id: "0_1_30_1", text: "哈密市", value: "哈密市", open: true - }, {pId: "0_1_30", id: "0_1_30_2", text: "和田市", value: "和田市", open: true}, { + }, { pId: "0_1_30", id: "0_1_30_2", text: "和田市", value: "和田市", open: true }, { pId: "0_1_30", id: "0_1_30_3", text: "喀什地区", value: "喀什地区", open: true - }, {pId: "0_1_30", id: "0_1_30_4", text: "克拉玛依市", value: "克拉玛依市", open: true}, { + }, { pId: "0_1_30", id: "0_1_30_4", text: "克拉玛依市", value: "克拉玛依市", open: true }, { pId: "0_1_30", id: "0_1_30_5", text: "克孜勒苏柯州", value: "克孜勒苏柯州", open: true - }, {pId: "0_1_30", id: "0_1_30_6", text: "石河子市", value: "石河子市", open: true}, { + }, { pId: "0_1_30", id: "0_1_30_6", text: "石河子市", value: "石河子市", open: true }, { pId: "0_1_30", id: "0_1_30_7", text: "塔城市", value: "塔城市", open: true - }, {pId: "0_1_30", id: "0_1_30_8", text: "吐鲁番地区", value: "吐鲁番地区", open: true}, { + }, { pId: "0_1_30", id: "0_1_30_8", text: "吐鲁番地区", value: "吐鲁番地区", open: true }, { pId: "0_1_30", id: "0_1_30_9", text: "乌鲁木齐", value: "乌鲁木齐", open: true - }, {pId: "0_1_30", id: "0_1_30_10", text: "伊犁市", value: "伊犁市", open: true}, { + }, { pId: "0_1_30", id: "0_1_30_10", text: "伊犁市", value: "伊犁市", open: true }, { pId: "0_1", id: "0_1_31", text: "云南省( 共12个 )", value: "云南省", open: true - }, {pId: "0_1_31", id: "0_1_31_0", text: "保山市", value: "保山市", open: true}, { + }, { pId: "0_1_31", id: "0_1_31_0", text: "保山市", value: "保山市", open: true }, { pId: "0_1_31", id: "0_1_31_1", text: "楚雄彝族自治州", value: "楚雄彝族自治州", open: true - }, {pId: "0_1_31", id: "0_1_31_2", text: "大理白族自治州", value: "大理白族自治州", open: true}, { + }, { pId: "0_1_31", id: "0_1_31_2", text: "大理白族自治州", value: "大理白族自治州", open: true }, { pId: "0_1_31", id: "0_1_31_3", text: "红河哈尼族彝族自治州", value: "红河哈尼族彝族自治州", open: true - }, {pId: "0_1_31", id: "0_1_31_4", text: "昆明市", value: "昆明市", open: true}, { + }, { pId: "0_1_31", id: "0_1_31_4", text: "昆明市", value: "昆明市", open: true }, { pId: "0_1_31", id: "0_1_31_5", text: "丽江市", value: "丽江市", open: true - }, {pId: "0_1_31", id: "0_1_31_6", text: "临沧市", value: "临沧市", open: true}, { + }, { pId: "0_1_31", id: "0_1_31_6", text: "临沧市", value: "临沧市", open: true }, { pId: "0_1_31", id: "0_1_31_7", text: "曲靖市", value: "曲靖市", open: true - }, {pId: "0_1_31", id: "0_1_31_8", text: "思茅市", value: "思茅市", open: true}, { + }, { pId: "0_1_31", id: "0_1_31_8", text: "思茅市", value: "思茅市", open: true }, { pId: "0_1_31", id: "0_1_31_9", text: "文山市", value: "文山市", open: true - }, {pId: "0_1_31", id: "0_1_31_10", text: "玉溪市", value: "玉溪市", open: true}, { + }, { pId: "0_1_31", id: "0_1_31_10", text: "玉溪市", value: "玉溪市", open: true }, { pId: "0_1_31", id: "0_1_31_11", text: "昭通市", value: "昭通市", open: true - }, {pId: "0_1", id: "0_1_32", text: "浙江省( 共12个 )", value: "浙江省", open: true}, { + }, { pId: "0_1", id: "0_1_32", text: "浙江省( 共12个 )", value: "浙江省", open: true }, { pId: "0_1_32", id: "0_1_32_0", text: "杭州市", value: "杭州市", open: true - }, {pId: "0_1_32", id: "0_1_32_1", text: "湖州市", value: "湖州市", open: true}, { + }, { pId: "0_1_32", id: "0_1_32_1", text: "湖州市", value: "湖州市", open: true }, { pId: "0_1_32", id: "0_1_32_2", text: "嘉兴市", value: "嘉兴市", open: true - }, {pId: "0_1_32", id: "0_1_32_3", text: "金华市", value: "金华市", open: true}, { + }, { pId: "0_1_32", id: "0_1_32_3", text: "金华市", value: "金华市", open: true }, { pId: "0_1_32", id: "0_1_32_4", text: "丽水市", value: "丽水市", open: true - }, {pId: "0_1_32", id: "0_1_32_5", text: "宁波市", value: "宁波市", open: true}, { + }, { pId: "0_1_32", id: "0_1_32_5", text: "宁波市", value: "宁波市", open: true }, { pId: "0_1_32", id: "0_1_32_6", text: "衢州市", value: "衢州市", open: true - }, {pId: "0_1_32", id: "0_1_32_7", text: "绍兴市", value: "绍兴市", open: true}, { + }, { pId: "0_1_32", id: "0_1_32_7", text: "绍兴市", value: "绍兴市", open: true }, { pId: "0_1_32", id: "0_1_32_8", text: "台州市", value: "台州市", open: true - }, {pId: "0_1_32", id: "0_1_32_9", text: "温州市", value: "温州市", open: true}, { + }, { pId: "0_1_32", id: "0_1_32_9", text: "温州市", value: "温州市", open: true }, { pId: "0_1_32", id: "0_1_32_10", text: "浙江省", value: "浙江省", open: true - }, {pId: "0_1_32", id: "0_1_32_11", text: "舟山市", value: "舟山市", open: true}, { + }, { pId: "0_1_32", id: "0_1_32_11", text: "舟山市", value: "舟山市", open: true }, { pId: "0_1", id: "0_1_33", text: "重庆市( 共1个 )", value: "重庆市", open: true - }, {pId: "0_1_33", id: "0_1_33_0", text: "重庆市区", value: "重庆市区", open: true}], + }, { pId: "0_1_33", id: "0_1_33_0", text: "重庆市区", value: "重庆市区", open: true }], - TREE: [{id: -1, pId: -2, value: "根目录", text: "根目录"}, - {id: 1, pId: -1, value: "第一级目录1", text: "第一级目录1"}, - {id: 11, pId: 1, value: "第二级文件1", text: "第二级文件1"}, - {id: 12, pId: 1, value: "第二级目录2", text: "第二级目录2"}, - {id: 121, pId: 12, value: "第三级目录1", text: "第三级目录1"}, - {id: 122, pId: 12, value: "第三级文件1", text: "第三级文件1"}, - {id: 1211, pId: 121, value: "第四级目录1", text: "第四级目录1"}, + TREE: [{ id: -1, pId: -2, value: "根目录", text: "根目录" }, + { id: 1, pId: -1, value: "1", text: "第一级目录1", disabled: true }, + { id: 11, pId: 1, value: "11", text: "第二级文件1" }, + { id: 12, pId: 1, value: "12", text: "第二级目录2" }, + { id: 121, pId: 12, value: "121", text: "第三级目录1" }, + { id: 122, pId: 12, value: "122", text: "第三级文件1" }, + { id: 1211, pId: 121, value: "1211", text: "第四级目录1" }, { id: 12111, pId: 1211, - value: "第五级文件1", + value: "12111", text: "第五级文件111111111111111111111111111111111111111111111111111111111111111111111111111111111111111" }, - {id: 2, pId: -1, value: "第一级目录2", text: "第一级目录2"}, - {id: 21, pId: 2, value: "第二级目录3", text: "第二级目录3"}, - {id: 22, pId: 2, value: "第二级文件2", text: "第二级文件2"}, - {id: 211, pId: 21, value: "第三级目录2", text: "第三级目录2"}, - {id: 212, pId: 21, value: "第三级文件2", text: "第三级文件2"}, - {id: 2111, pId: 211, value: "第四级文件1", text: "第四级文件1"}], + { id: 2, pId: -1, value: "2", text: "第一级目录2" }, + { id: 21, pId: 2, value: "21", text: "第二级目录3" }, + { id: 22, pId: 2, value: "22", text: "第二级文件2" }, + { id: 211, pId: 21, value: "211", text: "第三级目录2" }, + { id: 212, pId: 21, value: "212", text: "第三级文件2" }, + { id: 2111, pId: 211, value: "2111", text: "第四级文件1" }], LEVELTREE: [{ id: 1, text: "第一项", diff --git a/demo/js/base/button/demo.button.js b/demo/js/base/button/demo.button.js index d0b14aaff..651d98e4a 100644 --- a/demo/js/base/button/demo.button.js +++ b/demo/js/base/button/demo.button.js @@ -1,277 +1,304 @@ +(function () { + var JokerIcon = BI.inherit(BI.Widget, { + render: function () { + var self = this; + + return { + type: "bi.label", + cls: "anim-rotate", + ref: function(ref) { + self.text = ref; + }, + }; + }, + loading: function () { + this.text.setText("🤡"); + }, + loaded: function () { + this.text.setText(""); + }, + }); + BI.shortcut("demo.joker.icon", JokerIcon); +}()); + Demo.Button = BI.inherit(BI.Widget, { props: { - baseCls: "demo-button" + baseCls: "demo-button", }, render: function () { var items = [{ type: "bi.button", - text: "一般按钮", + text: "一般按钮1111111111111", level: "common", - height: 30 + whiteSpace: "nowrap", + width: 100, + height: 30, + handler() { + console.log("触发点击事件"); + this.loading(); + setTimeout(() => { + this.loaded(); + }, 5 * 1000); + }, }, { type: "bi.button", text: "表示成功状态按钮", level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "表示警告状态的按钮", level: "warning", - height: 30 + height: 30, }, { type: "bi.button", text: "表示错误状态的按钮", level: "error", - height: 30 + height: 30, }, { type: "bi.button", text: "表示忽略状态的按钮", level: "ignore", - height: 30 + height: 30, }, { type: "bi.button", text: "普通灰化按钮", disabled: true, level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "忽略状态灰化按钮", disabled: true, level: "ignore", - height: 30 + height: 30, }, { type: "bi.button", text: "带图标的按钮", // level: 'ignore', iconCls: "close-font", - height: 30 + height: 30, }, { type: "bi.button", text: "一般按钮", block: true, level: "common", - height: 30 + height: 30, }, { type: "bi.button", text: "表示成功状态按钮", block: true, level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "表示警告状态的按钮", block: true, level: "warning", - height: 30 + height: 30, }, { type: "bi.button", text: "表示忽略状态的按钮", block: true, level: "ignore", - height: 30 + height: 30, }, { type: "bi.button", text: "普通灰化按钮", block: true, disabled: true, level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "忽略状态灰化按钮", block: true, disabled: true, level: "ignore", - height: 30 + height: 30, }, { type: "bi.button", text: "带图标的按钮", block: true, // level: 'ignore', iconCls: "close-font", - height: 30 + height: 30, }, { type: "bi.button", text: "一般按钮", clear: true, level: "common", - height: 30 + height: 30, }, { type: "bi.button", text: "表示成功状态按钮", clear: true, level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "表示警告状态的按钮", clear: true, level: "warning", - height: 30 + height: 30, }, { type: "bi.button", text: "表示忽略状态的按钮", clear: true, level: "ignore", - height: 30 + height: 30, }, { type: "bi.button", text: "普通灰化按钮", clear: true, disabled: true, level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "忽略状态灰化按钮", clear: true, disabled: true, level: "ignore", - height: 30 + height: 30, }, { type: "bi.button", text: "带图标的按钮", clear: true, // level: 'ignore', iconCls: "close-font", - height: 30 + height: 30, }, { type: "bi.text_button", text: "文字按钮", - height: 30 + height: 30, }, { type: "bi.button", text: "幽灵按钮(common)", ghost: true, - height: 30 + height: 30, }, { type: "bi.button", iconCls: "plus-font", text: "幽灵按钮(common)", ghost: true, - height: 30 + height: 30, }, { type: "bi.button", iconCls: "plus-font", text: "幽灵按钮(common)", ghost: true, level: "warning", - height: 30 + height: 30, }, { type: "bi.button", iconCls: "plus-font", text: "幽灵按钮(common)", ghost: true, level: "error", - height: 30 + height: 30, }, { type: "bi.button", iconCls: "plus-font", text: "幽灵按钮(common)", ghost: true, level: "success", - height: 30 + height: 30, }, { type: "bi.button", text: "幽灵按钮(common)灰化", disabled: true, ghost: true, - height: 30 + height: 30, }, { type: "bi.button", text: "弹出bubble", bubble: function () { - return BI.parseInt(Math.random() * 100) % 10 + "提示" + return BI.parseInt(Math.random() * 100) % 10 + "提示"; }, handler: function () { BI.Msg.toast("1111"); }, - height: 30 + height: 30, }, { type: "bi.button", - text: "图标在上面的按钮,而且可以自动撑开高度", + text: "自动撑开", iconCls: "close-font", - iconGap: 24, - iconPosition: "top" - },{ - type: "bi.button", - text: "自动撑开高度", - iconCls: "close-font", - textHeight: 32, - iconGap: 24, + // textHeight: 32, + // height: 32, + iconGap: 64, vgap: 16, hgap: 100, - iconPosition: "top" + iconPosition: "bottom", }, { type: "bi.button", text: "图标在下面的按钮", iconCls: "close-font", - iconPosition: "bottom" + iconPosition: "bottom", }, { type: "bi.button", text: "图标在左边的按钮", iconCls: "close-font", - iconPosition: "left" + iconPosition: "left", }, { type: "bi.button", text: "图标在右边的按钮", iconCls: "close-font", - iconPosition: "right" + iconPosition: "right", }, { type: "bi.button", text: "浅色的一般按钮", iconCls: "plus-font", - light: true + light: true, }, { type: "bi.button", text: "浅色的成功按钮", level: "success", iconCls: "plus-font", - light: true + light: true, }, { type: "bi.button", text: "浅色的警告按钮", level: "warning", iconCls: "plus-font", - light: true + light: true, }, { type: "bi.button", iconCls: "plus-font", text: "浅色的失败按钮", level: "error", cls: "hover-mask", - light: true + light: true, }, { type: "bi.button", iconCls: "plus-font", text: "朴素的按钮", level: "common", - plain: true + plain: true, }, { type: "bi.button", iconCls: "plus-font", text: "朴素的按钮", level: "success", - plain: true + plain: true, }, { type: "bi.button", iconCls: "plus-font", text: "朴素的按钮", level: "error", - plain: true + plain: true, }, { type: "bi.button", iconCls: "plus-font", text: "朴素的按钮", level: "warning", - plain: true + plain: true, }, { type: "bi.button", iconCls: "plus-font", text: "朴素的按钮", level: "ignore", - plain: true + plain: true, }, { type: "bi.button", iconCls: "plus-font", @@ -282,20 +309,78 @@ Demo.Button = BI.inherit(BI.Widget, { iconCls: "plus-font", text: "朴素的按钮", plain: true, - disabled: true + disabled: true, }, { type: "bi.button", iconCls: "plus-font", text: "点我,更改图标", handler() { - this.i = this.i === undefined ? 0 : ++this.i; + this.i = this.i === undefined ? 0 : ++this.i; const arr = ["text-background-font", "check-mark-ha-font", "close-font", "search-font", "date-change-h-font"]; - if(this.i >= arr.length) { + if (this.i >= arr.length) { this.i = 0; } this.setIcon(arr[this.i]); }, - height: 24 + height: 24, + }, { + type: "bi.button", + text: "带加载的按钮", + handler() { + console.log("触发点击事件"); + this.loading(); + setTimeout(() => { + this.loaded(); + }, 5 * 1000); + }, + }, { + type: "bi.button", + text: "带加载的按钮", + iconCls: "circle-close-font", + handler() { + console.log("触发点击事件"); + this.loading(); + setTimeout(() => { + this.loaded(); + }, 5 * 1000); + }, + }, { + type: "bi.button", + clear: true, + text: "带加载的按钮", + iconCls: "circle-close-font", + handler() { + console.log("触发点击事件"); + this.loading(); + setTimeout(() => { + this.loaded(); + }, 5 * 1000); + }, + }, { + type: "bi.button", + text: "加载中的按钮", + loading: true, + handler() { + console.log("我是无法被触发的!"); + }, + }, { + type: "bi.button", + text: "自定义图标按钮(点我修改)", + icon: { + type: "demo.joker.icon", + }, + handler() { + console.log("触发点击事件"); + this.loading(); + setTimeout(() => { + this.loaded(); + }, 5 * 1000); + }, + }, { + type: "bi.button", + text: "文字偏左的按钮", + textAlign: "left", + width: 200, }]; return { @@ -305,10 +390,10 @@ Demo.Button = BI.inherit(BI.Widget, { hgap: 20, items: BI.map(items, function (index, value) { return { - el: value - } - }) + el: value, + }; + }), }; - } + }, }); BI.shortcut("demo.button", Demo.Button); diff --git a/demo/js/case/combo/demo.text_value_combo.js b/demo/js/case/combo/demo.text_value_combo.js index 9e2c0d6f3..50e3fea43 100644 --- a/demo/js/case/combo/demo.text_value_combo.js +++ b/demo/js/case/combo/demo.text_value_combo.js @@ -6,58 +6,207 @@ Demo.TextValueCombo = BI.inherit(BI.Widget, { baseCls: "" }, render: function () { - var combo, wrapper; + var combo1, combo2; + + var items = [{ + text: "MVC-1", + iconCls: "date-font", + value: 1 + }, { + text: "MVC-2", + iconCls: "search-font", + value: 2 + }, { + text: "MVC-3", + iconCls: "pull-right-font", + value: 3 + }]; + + // 创建下拉框各种场景用例 return { - type: "bi.button_group", - items: [{ - type: "bi.text_value_combo", - ref: function () { - combo = this; - }, - text: "默认值", - value: 22, - width: 300, - items: [{ - text: "MVC-1", - iconCls: "date-font", - value: 1 - }, { - text: "MVC-2", - iconCls: "search-font", - value: 2 + type: "bi.vertical", + vgap: 20, + hgap: 20, + items: [ + this.createCombo("无初始值,带提示文字", { + type: "bi.text_value_combo", + ref: (ref) => { + this.combo1 = ref; + }, + defaultText: "请选择", + width: 300, + items: items, + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }), + this.createCombo("自动根据value匹配text", { + type: "bi.text_value_combo", + ref: function () { + combo = this; + }, + defaultText: "请选择", + width: 300, + value: 1, + items: items, + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }), + this.createCombo("无初始值,可以清空", { + type: "bi.text_value_combo", + ref: function () { + combo = this; + }, + defaultText: "请选择", + width: 300, + items: items, + allowClear: true, + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }), + this.createCombo("有初始值,可以清空", { + type: "bi.text_value_combo", + ref: function () { + combo = this; + }, + defaultText: "请选择", + width: 300, + value: 1, + items: items, + allowClear: true, + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }), + this.createCombo("有初始值,value不匹配,自动标红,指定标红文字", { + type: "bi.text_value_combo", + ref: function () { + combo = this; + }, + width: 300, + text: "MVC-111", + value: 111, + items: items, + allowClear: true, + defaultText: "请选择", + warningTitle: "value值不合法", + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }), + this.createCombo("无初始值,外部受控调用setValue", { + type: "bi.vertical", + items: [ + { + type: "bi.text_value_combo", + ref: function () { + combo1 = this; + }, + width: 300, + items: items, + allowClear: true, + defaultText: "请选择", + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }, { + el: { + type: "bi.button", + text: "setValue(1)", + handler: function () { + combo1.setValue(); + }, + }, + vgap: 10, + } + ] + }), + this.createCombo("无初始值,外部受控调用setStatus", { + type: "bi.vertical", + items: [ + { + type: "bi.text_value_combo", + ref: function () { + combo2 = this; + }, + width: 300, + items: items, + allowClear: true, + defaultText: "请选择", + listeners: [ + { + eventName: BI.TextValueCombo.EVENT_CHANGE, + action: function () { + console.log(this.getValue()); + } + } + ] + }, { + el: { + type: "bi.button", + text: "setStatus()", + handler: function () { + combo2.setStatus("error"); + }, + }, + vgap: 10, + } + ] + }) + ] + }; + }, + + createCombo: function (text, combo) { + return { + type: "bi.vertical", + items: [ + { + el: { + type: "bi.label", + textAlign: "left", + text, + }, + bgap: 10 }, { - text: "MVC-3", - iconCls: "pull-right-font", - value: 3 - }] - }, { - type: "bi.search_multi_text_value_combo", - items: Demo.CONSTANTS.ITEMS, - width: 200, - value: { - type: 1, - value: ["1", "2", "3"] - } - }, { - type: "bi.button", - width: 90, - height: 25, - handler: function () { - wrapper.populate(); - } - }, { - type: 'bi.label', - height: 1000 - }], - ref: function () { - wrapper = this; - }, - layouts: [{ - type: "bi.vertical", - vgap: 20 - }] + el: combo, + bgap: 10, + }, + ] }; } }); -BI.shortcut("demo.text_value_combo", Demo.TextValueCombo); \ No newline at end of file +BI.shortcut("demo.text_value_combo", Demo.TextValueCombo); diff --git a/demo/js/case/tree/demo.level_tree.js b/demo/js/case/tree/demo.level_tree.js index f21c21707..4b4ac061c 100644 --- a/demo/js/case/tree/demo.level_tree.js +++ b/demo/js/case/tree/demo.level_tree.js @@ -42,6 +42,11 @@ Demo.Func = BI.inherit(BI.Widget, { pId: 1, text: "子项3", value: 13 + }, { + id: 111, + pId: 11, + text: "子项1-1", + value: 111 }, { id: 21, pId: 2, diff --git a/demo/js/component/demo.treevaluechoosercombo.js b/demo/js/component/demo.treevaluechoosercombo.js index 8fa557ee1..9a38fe428 100644 --- a/demo/js/component/demo.treevaluechoosercombo.js +++ b/demo/js/component/demo.treevaluechoosercombo.js @@ -10,7 +10,8 @@ Demo.TreeValueChooser = BI.inherit(BI.Widget, { // items: BI.deepClone(Demo.CONSTANTS.TREEITEMS), itemsCreator: function (op, callback) { callback(BI.deepClone(Demo.CONSTANTS.TREEITEMS)); - } + }, + defaultText: "请选择", }); return { type: "bi.vertical", diff --git a/demo/js/widget/selecttree/demo.multilayer_select_tree_combo.js b/demo/js/widget/selecttree/demo.multilayer_select_tree_combo.js index 645c28fcd..25ac4e518 100644 --- a/demo/js/widget/selecttree/demo.multilayer_select_tree_combo.js +++ b/demo/js/widget/selecttree/demo.multilayer_select_tree_combo.js @@ -16,7 +16,7 @@ Demo.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { ref: function (_ref) { self.tree = _ref; }, - text: "默认值", + defaultText: "请选择", items: items, width: 300, value: ["第五级文件1"] @@ -40,4 +40,4 @@ Demo.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { } }); -BI.shortcut("demo.multilayer_select_tree_combo", Demo.MultiLayerSelectTreeCombo); \ No newline at end of file +BI.shortcut("demo.multilayer_select_tree_combo", Demo.MultiLayerSelectTreeCombo); diff --git a/demo/js/widget/singletree/demo.multilayer_single_tree_combo.js b/demo/js/widget/singletree/demo.multilayer_single_tree_combo.js index 109d0c489..1a699c2ea 100644 --- a/demo/js/widget/singletree/demo.multilayer_single_tree_combo.js +++ b/demo/js/widget/singletree/demo.multilayer_single_tree_combo.js @@ -16,7 +16,7 @@ Demo.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { ref: function (_ref) { self.tree = _ref; }, - text: "默认值", + defaultText: "请选择", items: items, width: 300 }, { @@ -39,4 +39,4 @@ Demo.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { } }); -BI.shortcut("demo.multilayer_single_tree_combo", Demo.MultiLayerSingleTreeCombo); \ No newline at end of file +BI.shortcut("demo.multilayer_single_tree_combo", Demo.MultiLayerSingleTreeCombo); diff --git a/demo/js/widget/singletree/demo.single_tree_combo.js b/demo/js/widget/singletree/demo.single_tree_combo.js index 087b28888..d3c94508e 100644 --- a/demo/js/widget/singletree/demo.single_tree_combo.js +++ b/demo/js/widget/singletree/demo.single_tree_combo.js @@ -16,7 +16,7 @@ Demo.SingleTreeCombo = BI.inherit(BI.Widget, { ref: function (_ref) { self.tree = _ref; }, - text: "默认值", + defaultText: "请选择", items: items, width: 300, value: "11" @@ -40,4 +40,4 @@ Demo.SingleTreeCombo = BI.inherit(BI.Widget, { } }); -BI.shortcut("demo.single_tree_combo", Demo.SingleTreeCombo); \ No newline at end of file +BI.shortcut("demo.single_tree_combo", Demo.SingleTreeCombo); diff --git a/demo/js/widget/tree/demo.multilayer_select_level_tree.js b/demo/js/widget/tree/demo.multilayer_select_level_tree.js index 0a9054c3a..357b32a23 100644 --- a/demo/js/widget/tree/demo.multilayer_select_level_tree.js +++ b/demo/js/widget/tree/demo.multilayer_select_level_tree.js @@ -33,7 +33,7 @@ Demo.MultiLayerSelectLevelTree = BI.inherit(BI.Widget, { height: 25, text: "setValue (第二级文件1)", handler: function () { - tree.setValue(["第二级文件1"]); + tree.setValue(["11"]); } }, height: 25 diff --git a/demo/js/widget/tree/demo.multilayer_single_level_tree.js b/demo/js/widget/tree/demo.multilayer_single_level_tree.js index 967c8d5f4..9aa4ab15c 100644 --- a/demo/js/widget/tree/demo.multilayer_single_level_tree.js +++ b/demo/js/widget/tree/demo.multilayer_single_level_tree.js @@ -46,27 +46,27 @@ Demo.MultiLayerSingleLevelTree = BI.inherit(BI.Widget, { mounted: function () { var tree = [ // {id: -2, pId: 0, value: "根目录1", text: "根目录1"}, - {id: -1, pId: 0, value: "根目录", text: "根目录"}, - {id: 1, pId: -1, value: "第一级目录1", text: "第一级目录1"}, - {id: 11, pId: 1, value: "第二级文件1", text: "第二级文件1"}, - {id: 12, pId: 1, value: "第二级目录2", text: "第二级目录2"}, - {id: 121, pId: 12, value: "第三级目录1", text: "第三级目录1"}, - {id: 122, pId: 12, value: "第三级文件1", text: "第三级文件1"}, - {id: 1211, pId: 121, value: "第四级目录1", text: "第四级目录1"}, - {id: 2, pId: -1, value: "第一级目录2", text: "第一级目录2"}, - {id: 21, pId: 2, value: "第二级目录3", text: "第二级目录3"}, - {id: 22, pId: 2, value: "第二级文件2", text: "第二级文件2"}, - {id: 211, pId: 21, value: "第三级目录2", text: "第三级目录2"}, - {id: 212, pId: 21, value: "第三级文件2", text: "第三级文件2"}, - {id: 2111, pId: 211, value: "第四级文件1", text: "第四级文件1"}, - {id: 3, pId: -1, value: "第一级目录3", text: "第一级目录3"}, - {id: 31, pId: 3, value: "第二级文件2", text: "第二级文件2"}, - {id: 33, pId: 3, value: "第二级目录3", text: "第二级目录1"}, - {id: 32, pId: 3, value: "第二级文件3", text: "第二级文件3"}, - {id: 331, pId: 33, value: "第三级文件1", text: "第三级文件1"} + { id: -1, pId: 0, value: "根目录", text: "根目录" }, + { id: 1, pId: -1, value: "第一级目录1", text: "第一级目录1" }, + { id: 11, pId: 1, value: "第二级文件1", text: "第二级文件1" }, + { id: 12, pId: 1, value: "第二级目录2", text: "第二级目录2", disabled: true }, + { id: 121, pId: 12, value: "第三级目录1", text: "第三级目录1" }, + { id: 122, pId: 12, value: "第三级文件1", text: "第三级文件1" }, + { id: 1211, pId: 121, value: "第四级目录1", text: "第四级目录1" }, + { id: 2, pId: -1, value: "第一级目录2", text: "第一级目录2" }, + { id: 21, pId: 2, value: "第二级目录3", text: "第二级目录3" }, + { id: 22, pId: 2, value: "第二级文件2", text: "第二级文件2" }, + { id: 211, pId: 21, value: "第三级目录2", text: "第三级目录2" }, + { id: 212, pId: 21, value: "第三级文件2", text: "第三级文件2" }, + { id: 2111, pId: 211, value: "第四级文件1", text: "第四级文件1" }, + { id: 3, pId: -1, value: "第一级目录3", text: "第一级目录3" }, + { id: 31, pId: 3, value: "第二级文件2", text: "第二级文件2" }, + { id: 33, pId: 3, value: "第二级目录3", text: "第二级目录1" }, + { id: 32, pId: 3, value: "第二级文件3", text: "第二级文件3" }, + { id: 331, pId: 33, value: "第三级文件1", text: "第三级文件1" } ]; this.tree.populate(tree); } }); -BI.shortcut("demo.multilayer_single_level_tree", Demo.MultiLayerSingleLevelTree); \ No newline at end of file +BI.shortcut("demo.multilayer_single_level_tree", Demo.MultiLayerSingleLevelTree); diff --git a/dist/font/iconfont.eot b/dist/font/iconfont.eot index 6cd1f1cf2..9bf132980 100644 Binary files a/dist/font/iconfont.eot and b/dist/font/iconfont.eot differ diff --git a/dist/font/iconfont.svg b/dist/font/iconfont.svg index c70fa76fe..d2d51982b 100644 --- a/dist/font/iconfont.svg +++ b/dist/font/iconfont.svg @@ -14,11 +14,111 @@ /> - + - + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -26,7 +126,7 @@ - + @@ -44,11 +144,11 @@ - + - + @@ -58,11 +158,9 @@ - - - + @@ -76,7 +174,7 @@ - + @@ -86,9 +184,9 @@ - + - + @@ -98,11 +196,11 @@ - + - + - + @@ -140,7 +238,7 @@ - + @@ -156,9 +254,9 @@ - + - + @@ -184,14 +282,10 @@ - - - + - - @@ -216,15 +310,9 @@ - - - - - + - - - + @@ -244,8 +332,6 @@ - - @@ -262,7 +348,7 @@ - + @@ -302,12 +388,6 @@ - - - - - - @@ -316,17 +396,13 @@ - - - - - + @@ -338,16 +414,8 @@ - - - - - - - - @@ -364,52 +432,14 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @@ -520,17 +550,17 @@ - + - + - + - + @@ -568,7 +598,7 @@ - + @@ -580,7 +610,7 @@ - + @@ -616,19 +646,19 @@ - + - + - + @@ -640,13 +670,13 @@ - + - + @@ -658,19 +688,19 @@ - + - + - + @@ -700,19 +730,19 @@ - + - + - + @@ -720,7 +750,7 @@ - + @@ -736,7 +766,7 @@ - + @@ -754,7 +784,7 @@ - + @@ -762,13 +792,13 @@ - + - + @@ -798,21 +828,21 @@ - + - + - + - + @@ -820,27 +850,27 @@ - + - + - + - + - + @@ -900,33 +930,33 @@ - + - + - + - + - + - + - + @@ -936,7 +966,7 @@ - + @@ -948,115 +978,113 @@ - + - + - + - + - + - + - + - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + @@ -1084,7 +1112,7 @@ - + @@ -1094,7 +1122,7 @@ - + @@ -1114,7 +1142,7 @@ - + @@ -1152,7 +1180,7 @@ - + @@ -1182,7 +1210,7 @@ - + @@ -1194,7 +1222,7 @@ - + @@ -1248,7 +1276,7 @@ - + @@ -1296,7 +1324,7 @@ - + @@ -1312,71 +1340,71 @@ - + - + - + - + - + - + - + - + - + - + - + - + - + @@ -1398,67 +1426,63 @@ - + - + - + - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - - + @@ -1470,23 +1494,23 @@ - + - + - + - + - + - + @@ -1550,7 +1574,7 @@ - + @@ -1558,11 +1582,11 @@ - + - + @@ -1600,15 +1624,15 @@ - + - + - + - + - + @@ -1630,7 +1654,7 @@ - + @@ -1640,19 +1664,19 @@ - + - + - + - + - + @@ -1666,13 +1690,13 @@ - + - + - + @@ -1740,7 +1764,7 @@ - + @@ -1772,9 +1796,9 @@ - + - + @@ -1796,7 +1820,7 @@ - + @@ -1804,11 +1828,11 @@ - + - + @@ -1844,7 +1868,7 @@ - + diff --git a/dist/font/iconfont.ttf b/dist/font/iconfont.ttf index 76debf9d2..75f0d4f57 100644 Binary files a/dist/font/iconfont.ttf and b/dist/font/iconfont.ttf differ diff --git a/dist/font/iconfont.woff b/dist/font/iconfont.woff index ea016fed7..92c2c1a53 100644 Binary files a/dist/font/iconfont.woff and b/dist/font/iconfont.woff differ diff --git a/dist/font/iconfont.woff2 b/dist/font/iconfont.woff2 index 1d6e0c461..0ef218ef3 100644 Binary files a/dist/font/iconfont.woff2 and b/dist/font/iconfont.woff2 differ diff --git a/dist/images/2x/icon/dark/tree_solid_collapse_1.png b/dist/images/2x/icon/dark/tree_solid_collapse_1.png index 9bd5051d1..1b39baa92 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_collapse_1.png and b/dist/images/2x/icon/dark/tree_solid_collapse_1.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_collapse_2.png b/dist/images/2x/icon/dark/tree_solid_collapse_2.png index a111825f4..37029e095 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_collapse_2.png and b/dist/images/2x/icon/dark/tree_solid_collapse_2.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_collapse_3.png b/dist/images/2x/icon/dark/tree_solid_collapse_3.png index c16ac4fc3..ff6c4f653 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_collapse_3.png and b/dist/images/2x/icon/dark/tree_solid_collapse_3.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_collapse_4.png b/dist/images/2x/icon/dark/tree_solid_collapse_4.png index f8b7f8ef2..fb8e354d3 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_collapse_4.png and b/dist/images/2x/icon/dark/tree_solid_collapse_4.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_collapse_5.png b/dist/images/2x/icon/dark/tree_solid_collapse_5.png index 5620b0886..b3c53e8a0 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_collapse_5.png and b/dist/images/2x/icon/dark/tree_solid_collapse_5.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_expand_1.png b/dist/images/2x/icon/dark/tree_solid_expand_1.png index edae4d431..05a11cd9c 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_expand_1.png and b/dist/images/2x/icon/dark/tree_solid_expand_1.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_expand_2.png b/dist/images/2x/icon/dark/tree_solid_expand_2.png index 5951e659f..6a744dbb0 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_expand_2.png and b/dist/images/2x/icon/dark/tree_solid_expand_2.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_expand_3.png b/dist/images/2x/icon/dark/tree_solid_expand_3.png index de68cf779..09e0ad07d 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_expand_3.png and b/dist/images/2x/icon/dark/tree_solid_expand_3.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_expand_4.png b/dist/images/2x/icon/dark/tree_solid_expand_4.png index dee6827fb..066a7cb3f 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_expand_4.png and b/dist/images/2x/icon/dark/tree_solid_expand_4.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_expand_5.png b/dist/images/2x/icon/dark/tree_solid_expand_5.png index 6b6a559f9..039b0e1cc 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_expand_5.png and b/dist/images/2x/icon/dark/tree_solid_expand_5.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_vertical_line_1.png b/dist/images/2x/icon/dark/tree_solid_vertical_line_1.png index 2c674dfd9..3bc014f46 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_vertical_line_1.png and b/dist/images/2x/icon/dark/tree_solid_vertical_line_1.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_vertical_line_2.png b/dist/images/2x/icon/dark/tree_solid_vertical_line_2.png index ab5584b5f..22688bcaf 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_vertical_line_2.png and b/dist/images/2x/icon/dark/tree_solid_vertical_line_2.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_vertical_line_3.png b/dist/images/2x/icon/dark/tree_solid_vertical_line_3.png index adf63d3d5..d155fcdad 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_vertical_line_3.png and b/dist/images/2x/icon/dark/tree_solid_vertical_line_3.png differ diff --git a/dist/images/2x/icon/dark/tree_solid_vertical_line_4.png b/dist/images/2x/icon/dark/tree_solid_vertical_line_4.png index 17c39572d..9af333f28 100644 Binary files a/dist/images/2x/icon/dark/tree_solid_vertical_line_4.png and b/dist/images/2x/icon/dark/tree_solid_vertical_line_4.png differ diff --git a/dist/images/2x/icon/tree_solid_collapse_1.png b/dist/images/2x/icon/tree_solid_collapse_1.png index 3aa9463ad..94ed363d4 100644 Binary files a/dist/images/2x/icon/tree_solid_collapse_1.png and b/dist/images/2x/icon/tree_solid_collapse_1.png differ diff --git a/dist/images/2x/icon/tree_solid_collapse_2.png b/dist/images/2x/icon/tree_solid_collapse_2.png index b0be8e5c0..0796aaf5a 100644 Binary files a/dist/images/2x/icon/tree_solid_collapse_2.png and b/dist/images/2x/icon/tree_solid_collapse_2.png differ diff --git a/dist/images/2x/icon/tree_solid_collapse_3.png b/dist/images/2x/icon/tree_solid_collapse_3.png index b592b6a14..125a28dc7 100644 Binary files a/dist/images/2x/icon/tree_solid_collapse_3.png and b/dist/images/2x/icon/tree_solid_collapse_3.png differ diff --git a/dist/images/2x/icon/tree_solid_collapse_4.png b/dist/images/2x/icon/tree_solid_collapse_4.png index f9b67b9cd..643f0123b 100644 Binary files a/dist/images/2x/icon/tree_solid_collapse_4.png and b/dist/images/2x/icon/tree_solid_collapse_4.png differ diff --git a/dist/images/2x/icon/tree_solid_collapse_5.png b/dist/images/2x/icon/tree_solid_collapse_5.png index 55e059d6f..0cb0d5d73 100644 Binary files a/dist/images/2x/icon/tree_solid_collapse_5.png and b/dist/images/2x/icon/tree_solid_collapse_5.png differ diff --git a/dist/images/2x/icon/tree_solid_expand_1.png b/dist/images/2x/icon/tree_solid_expand_1.png index 751eac8f4..d607d042c 100644 Binary files a/dist/images/2x/icon/tree_solid_expand_1.png and b/dist/images/2x/icon/tree_solid_expand_1.png differ diff --git a/dist/images/2x/icon/tree_solid_expand_2.png b/dist/images/2x/icon/tree_solid_expand_2.png index 2a94194d1..bde83809a 100644 Binary files a/dist/images/2x/icon/tree_solid_expand_2.png and b/dist/images/2x/icon/tree_solid_expand_2.png differ diff --git a/dist/images/2x/icon/tree_solid_expand_3.png b/dist/images/2x/icon/tree_solid_expand_3.png index 2300dad28..e16463b19 100644 Binary files a/dist/images/2x/icon/tree_solid_expand_3.png and b/dist/images/2x/icon/tree_solid_expand_3.png differ diff --git a/dist/images/2x/icon/tree_solid_expand_4.png b/dist/images/2x/icon/tree_solid_expand_4.png index 7eb88716c..9738216c4 100644 Binary files a/dist/images/2x/icon/tree_solid_expand_4.png and b/dist/images/2x/icon/tree_solid_expand_4.png differ diff --git a/dist/images/2x/icon/tree_solid_expand_5.png b/dist/images/2x/icon/tree_solid_expand_5.png index 7ae297dd6..74bd1198e 100644 Binary files a/dist/images/2x/icon/tree_solid_expand_5.png and b/dist/images/2x/icon/tree_solid_expand_5.png differ diff --git a/dist/images/2x/icon/tree_solid_vertical_line_2.png b/dist/images/2x/icon/tree_solid_vertical_line_2.png index 429f958ac..56c00c080 100644 Binary files a/dist/images/2x/icon/tree_solid_vertical_line_2.png and b/dist/images/2x/icon/tree_solid_vertical_line_2.png differ diff --git a/dist/images/2x/icon/tree_solid_vertical_line_3.png b/dist/images/2x/icon/tree_solid_vertical_line_3.png index a44f13db0..43aab5d89 100644 Binary files a/dist/images/2x/icon/tree_solid_vertical_line_3.png and b/dist/images/2x/icon/tree_solid_vertical_line_3.png differ diff --git a/dist/images/2x/icon/tree_solid_vertical_line_4.png b/dist/images/2x/icon/tree_solid_vertical_line_4.png index 7de47eeed..4b40cc497 100644 Binary files a/dist/images/2x/icon/tree_solid_vertical_line_4.png and b/dist/images/2x/icon/tree_solid_vertical_line_4.png differ diff --git a/dist/images/2x/icon/tree_vertical_line_1.png b/dist/images/2x/icon/tree_vertical_line_1.png index ea9e933a0..c6b8e799c 100644 Binary files a/dist/images/2x/icon/tree_vertical_line_1.png and b/dist/images/2x/icon/tree_vertical_line_1.png differ diff --git a/examples/worker_new/index.js b/examples/worker_new/index.js index 67646a1ec..b95fbbad6 100644 --- a/examples/worker_new/index.js +++ b/examples/worker_new/index.js @@ -42,7 +42,7 @@ const HeartBeatCheckAction = BI.inherit(BI.Workers.WorkerBaseAction, { } }); -var WorkerThreadWorker = BI.inherit(BI.Workers.MainThreadWorker, { +var MainThreadWorker = BI.inherit(BI.Workers.MainThreadWorker, { initActions: function() { this.cookieAction = this.createAction(CookieAction); @@ -64,7 +64,7 @@ var WorkerThreadWorker = BI.inherit(BI.Workers.MainThreadWorker, { } }); -var mainThreadWorker = new WorkerThreadWorker({ +var mainThreadWorker = BI.Workers.createWorker(MainThreadWorker, { workerUrl: "./worker_new/worker.js", workerName: "demo" }); diff --git a/examples/worker_new/worker.js b/examples/worker_new/worker.js index f30856b21..96e88e542 100644 --- a/examples/worker_new/worker.js +++ b/examples/worker_new/worker.js @@ -58,7 +58,7 @@ const HeartBeatCheckAction = BI.inherit(BI.Workers.WorkerBaseAction, { } }); -var WorkerThreadWorker = BI.inherit(BI.Workers.WorkerThreadWorker, { +var MainThreadWorker = BI.inherit(BI.Workers.WorkerThreadWorker, { initActions: function() { this.cookieAction = this.createAction(CookieAction); @@ -75,6 +75,6 @@ var WorkerThreadWorker = BI.inherit(BI.Workers.WorkerThreadWorker, { } }); -var workerThreadWorker = new WorkerThreadWorker(); +var workerThreadWorker = BI.Workers.createWorker(MainThreadWorker); workerThreadWorker.fetchCookie(); diff --git a/lodash.md b/lodash.md index 770200a82..8faeb0142 100644 --- a/lodash.md +++ b/lodash.md @@ -1 +1 @@ -lodash core plus="debounce,throttle,get,set,findIndex,findLastIndex,findKey,findLastKey,isArrayLike,invert,invertBy,uniq,uniqBy,omit,omitBy,zip,unzip,rest,range,random,reject,intersection,drop,countBy,union,zipObject,initial,cloneDeep,clamp,isPlainObject,take,takeRight,without,difference,defaultsDeep,trim,merge,groupBy,uniqBy,before,after,unescape" +lodash core plus="debounce,throttle,get,set,findIndex,findLastIndex,findKey,findLastKey,isArrayLike,invert,invertBy,uniq,uniqBy,omit,omitBy,zip,unzip,rest,range,random,reject,intersection,drop,countBy,union,zipObject,initial,cloneDeep,clamp,isPlainObject,take,takeRight,without,difference,defaultsDeep,trim,merge,groupBy,uniqBy,before,after,unescape,chunk" diff --git a/package.json b/package.json index 8f235e458..6ccd9486e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "fineui", - "version": "2.0.20220720140353", + "version": "2.0.20220826175704", "description": "fineui", "main": "dist/fineui_without_conflict.min.js", "types": "dist/lib/index.d.ts", @@ -11,7 +11,7 @@ "@babel/core": "^7.17.4", "@babel/polyfill": "7.6.0", "@fui/babel-preset-fineui": "^2.0.0", - "@fui/eslint-plugin": "1.0.15", + "@fui/eslint-plugin": "^1.0.15", "@types/node": "15.6.1", "autoprefixer": "9.6.1", "babel-loader": "8.0.6", diff --git a/plugins/webpack-fui-worker-plugin/constants.js b/plugins/webpack-fui-worker-plugin/constants.js new file mode 100644 index 000000000..7b80ac3dc --- /dev/null +++ b/plugins/webpack-fui-worker-plugin/constants.js @@ -0,0 +1,9 @@ +const WorkerPluginName = 'FuiWorkerPlugin'; +const WorkerLoaderName = 'FuiWorkerWorkerLoader'; +const FileNamePrefix = 'worker-'; + +module.exports = { + WorkerPluginName, + WorkerLoaderName, + FileNamePrefix, +}; diff --git a/bin/cli/worker/template/action_type.ts b/plugins/webpack-fui-worker-plugin/empty.js similarity index 100% rename from bin/cli/worker/template/action_type.ts rename to plugins/webpack-fui-worker-plugin/empty.js diff --git a/plugins/webpack-fui-worker-plugin/index.js b/plugins/webpack-fui-worker-plugin/index.js new file mode 100644 index 000000000..2fa9b3ed0 --- /dev/null +++ b/plugins/webpack-fui-worker-plugin/index.js @@ -0,0 +1,79 @@ +/* + * worker-plugin + */ + +const path = require('path'); +const webpack = require('webpack'); +const { WorkerPluginName } = require('./constants'); +const ModuleFilenameHelpers = require('webpack/lib/ModuleFilenameHelpers'); + +class FuiWorkerPlugin { + constructor(options = {}) { + this.options = options; + } + + apply(compiler) { + // 为主线程构建添加 __WORKER__ 环境变量, 构建中区分不同线程源码, 实现代码拆减 + compiler.hooks.afterPlugins.tap(WorkerPluginName, compiler => { + new webpack.DefinePlugin({ + // __WORKER__ 表示当前所在线程是否是 worker 线程 + // 主线程构建中为 false + __WORKER__: false, + }).apply(compiler); + }); + + // 添加自定义的worker entry-loader + compiler.hooks.afterResolvers.tap(WorkerPluginName, compiler => { + /** + * https://webpack.js.org/configuration/resolve/#resolveloader + * 使用 resolveloader 添加自定义的 worker loader + */ + if (!compiler.options.resolveLoader) { + compiler.options.resolveLoader = { + alias: {}, + }; + } + if (!compiler.options.resolveLoader.alias) { + compiler.options.resolveLoader.alias = {}; + } + + // 动态添加 worker 的 worker-loader, 命名为 "fui-worker" + compiler.options.resolveLoader.alias['fui-worker'] = path.resolve(__dirname, './worker-loader.js'); + }); + + // 将FuiWorkerPlugin的参数传递给fui-worker loader + compiler.hooks.compilation.tap(WorkerPluginName, compilation => { + compilation.hooks.normalModuleLoader.tap(WorkerPluginName, (context, module) => { + // 仅提供给fui-worker + const fuiLoader = module.loaders.find(loader => loader.loader.indexOf('fui-worker') !== -1); + + if (fuiLoader) { + const resource = module.resource; + + if (!resource) return; + + // fui-worker通过options读取 + context.options = context.options || {}; + + const index = resource.indexOf('?'); + + if (ModuleFilenameHelpers.matchObject( + this.options, + index < 0 ? resource : resource.substr(0, index) + )) { + for (const key of Object.keys(this.options)) { + // 忽略关键属性 + if (key === "include" || key === "exclude" || key === "test") { + continue; + } + + context.options[key] = this.options[key]; + } + } + } + }) + }) + } +} + +module.exports = FuiWorkerPlugin; diff --git a/plugins/webpack-fui-worker-plugin/worker-loader.js b/plugins/webpack-fui-worker-plugin/worker-loader.js new file mode 100644 index 000000000..23be31927 --- /dev/null +++ b/plugins/webpack-fui-worker-plugin/worker-loader.js @@ -0,0 +1,137 @@ +/* + * fui-worker worker-loader + */ + +const webpack = require('webpack'); +const loaderUtils = require('loader-utils'); +const SingleEntryPlugin = require('webpack/lib/SingleEntryPlugin'); +const { WorkerLoaderName, FileNamePrefix } = require('./constants'); +const { resolve } = require('path'); + +// 正常 loader 处理逻辑 +function loader() { + const callback = this.async(); + this.cacheable(false); + + // 过滤掉当前的 worker-loader, 保留 worker 侧构建需要的其他 loader(babel-loader/ts-loader 等) + const otherLoaders = this.loaders.filter((loader, index) => { + if (index === this.loaderIndex) { + return false; + } + + return true; + }); + /** + * 拼接构建需要的 loader 字符串, 用于指定 childCompiler 的构建 loader + * 比如: /path/to/babel-loader/lib/index.js!/path/to/ts-loader/index.js! + */ + const loaderPath = otherLoaders.reduce((pre, loader) => `${pre}${loader.path}!`, ''); + + /** + * worker 独立构建的 entry + * 构建 loader + worker 源码入口文件路径 + * + * https://webpack.js.org/concepts/loaders/#inline + * `!!` 实现在 childCompiler 中忽略其他所有 loader, 只保留主构建的 loader + * 不然 worker 入口在 childCompiler 中会继续由 worker-loader 处理, 造成死循环 + */ + const workerEntry = `!!${loaderPath}${this.resourcePath}`; + + // 把资源纳入构建流程的依赖, 实现 dev 模式下的 watch + this.addDependency(workerEntry); + + // 生成的 service 独立 bundle 名称 + const entryFileName = `${FileNamePrefix}index`; + + // 获取传递给 loader 的 options + const options = Object.assign(loaderUtils.getOptions(this) || {}, this.options); + + // 创建 childCompiler, 用于实现 worker 构建为独立 js 资源 + const childCompiler = this._compilation.createChildCompiler(WorkerLoaderName, { + globalObject: 'this', + }); + childCompiler.context = this._compiler.context; + + // 指定独立构建的 entry 和生成 js 资源名称 + new SingleEntryPlugin(this.context, workerEntry, entryFileName).apply(childCompiler); + + // 设置 worker 侧的环境变量 + new webpack.DefinePlugin({ + __WORKER__: true, + }).apply(childCompiler); + + // 添加 window 全局对象, 映射为 worker 线程全局对象 self + // 如果在 worker 源码中添加, 可能没有前置到所有引用模块前 + new webpack.BannerPlugin({ + banner: 'self.window = self;', + raw: true, + entryOnly: true, + }).apply(childCompiler); + + // 去除源码中的less css引用 + const regExp = /\.(css|less)$/; + + new webpack.NormalModuleReplacementPlugin( + regExp, + result => { + if (regExp.test(result.request)) { + result.request = resolve(__dirname, './empty.js'); + } + + if (regExp.test(result.resource)) { + result.resource = resolve(__dirname, './empty.js'); + } + }, + ).apply(childCompiler); + + const subCache = `subcache ${__dirname} ${workerEntry}`; + childCompiler.hooks.compilation.tap(WorkerLoaderName, compilation => { + if (compilation.cache) { + if (!compilation.cache[subCache]) compilation.cache[subCache] = {}; + compilation.cache = compilation.cache[subCache]; + } + }); + + childCompiler.runAsChild((error, entries, compilation) => { + if (!error && compilation.errors && compilation.errors.length) { + // eslint-disable-next-line no-param-reassign + error = compilation.errors[0]; + } + + // compatible with Array (v4) and Set (v5) prototypes + const entry = entries && entries[0] && entries[0].files.values().next().value; + if (!error && !entry) { + // eslint-disable-next-line no-param-reassign + error = Error(`${WorkerLoaderName}, no entry for ${workerEntry}`); + } + + if (error) { + return callback(error); + } + + // 支持blob url形式 + return options.inline + ? callback( + null, + // 插入代码的转译和压缩由主构建配置的 babel/ts loader 处理, 不需要 worker-worker 来处理 + // 添加 @ts-nocheck 避免 ts-check 报错 + // 修复export const 下 const不会被转译的问题 + `// @ts-nocheck + const blob = new Blob([${JSON.stringify(compilation.assets[entry].source())}]); + const workerUrl = window.URL.createObjectURL(blob); + export default workerUrl; + ` + ) + : callback( + null, + `// @ts-nocheck + const servicePath = __webpack_public_path__ + ${JSON.stringify(entry)}; + export default servicePath; + ` + ) + }); + + return; +} + +module.exports = loader; diff --git a/src/base/0.base.js b/src/base/0.base.js index a8aa11a21..1100c0709 100644 --- a/src/base/0.base.js +++ b/src/base/0.base.js @@ -1,11 +1,9 @@ -BI.prepares.push(function () { - BI.Resizers = new BI.ResizeController(); - BI.Layers = new BI.LayerController(); - BI.Maskers = new BI.MaskersController(); - BI.Bubbles = new BI.BubblesController(); - BI.Tooltips = new BI.TooltipsController(); - BI.Popovers = new BI.PopoverController(); - BI.Drawers = new BI.DrawerController(); - BI.Broadcasts = new BI.BroadcastController(); - BI.StyleLoaders = new BI.StyleLoaderManager(); -}); +BI.Resizers = new BI.ResizeController(); +BI.Layers = new BI.LayerController(); +BI.Maskers = new BI.MaskersController(); +BI.Bubbles = new BI.BubblesController(); +BI.Tooltips = new BI.TooltipsController(); +BI.Popovers = new BI.PopoverController(); +BI.Drawers = new BI.DrawerController(); +BI.Broadcasts = new BI.BroadcastController(); +BI.StyleLoaders = new BI.StyleLoaderManager(); diff --git a/src/base/1.pane.js b/src/base/1.pane.js index 074d6a492..d628ae7bf 100644 --- a/src/base/1.pane.js +++ b/src/base/1.pane.js @@ -15,7 +15,7 @@ BI.Pane = BI.inherit(BI.Widget, { loadingText: "", loadingSize: "small", overlap: true, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, }); }, @@ -32,8 +32,8 @@ BI.Pane = BI.inherit(BI.Widget, { }, cls: "bi-tips", text: o.tipText, - height: 25 - }] + height: 25, + }], }); } }, @@ -42,7 +42,7 @@ BI.Pane = BI.inherit(BI.Widget, { var self = this, o = this.options; var loadingAnimation = BI.createWidget(BI.Providers.getProvider("bi.provider.system").getLoading({ loadingSize: o.loadingSize, - context: this + context: this, })); // pane在同步方式下由items决定tipText的显示与否 // loading的异步情况下由loaded后对面板的populate的时机决定 @@ -53,7 +53,7 @@ BI.Pane = BI.inherit(BI.Widget, { type: "bi.center_adapt", cls: "loading-container", items: this._getLoadingTipItems(loadingAnimation), - element: BI.Layers.make(this.getName() + "-loading", this) + element: BI.Layers.make(this.getName() + "-loading", this), }); } BI.Layers.show(self.getName() + "-loading"); @@ -63,7 +63,7 @@ BI.Pane = BI.inherit(BI.Widget, { type: "bi.center_adapt", element: this, cls: "loading-container", - items: this._getLoadingTipItems(loadingAnimation) + items: this._getLoadingTipItems(loadingAnimation), }); } self.fireEvent(BI.Pane.EVENT_LOADING); @@ -78,12 +78,12 @@ BI.Pane = BI.inherit(BI.Widget, { var self = this, o = this.options; var loadingTipItems = [{ type: "bi.horizontal_adapt", - items: [loadingTip] + items: [loadingTip], }]; BI.isNotEmptyString(o.loadingText) && loadingTipItems.push({ type: "bi.text", text: o.loadingText, - tgap: this._getSize(10) + tgap: this._getSize(10), }); return [{ @@ -91,7 +91,7 @@ BI.Pane = BI.inherit(BI.Widget, { ref: function (_ref) { self._loading = _ref; }, - items: loadingTipItems + items: loadingTipItems, }]; }, @@ -125,7 +125,7 @@ BI.Pane = BI.inherit(BI.Widget, { populate: function (items) { this.options.items = items || []; this.check(); - } + }, }); BI.Pane.EVENT_LOADED = "EVENT_LOADED"; BI.Pane.EVENT_LOADING = "EVENT_LOADING"; diff --git a/src/base/collection/__test__/collection.test.js b/src/base/collection/__test__/collection.test.js index 381735ac3..380b84d4b 100644 --- a/src/base/collection/__test__/collection.test.js +++ b/src/base/collection/__test__/collection.test.js @@ -5,7 +5,6 @@ */ describe("CollectionTest", function () { - /** * test_author_windy */ @@ -15,7 +14,7 @@ describe("CollectionTest", function () { for (var i = 0; i < cellCount; i++) { items[i] = { type: "bi.label", - text: i + text: i, }; } var grid = BI.Test.createWidget({ @@ -28,11 +27,11 @@ describe("CollectionTest", function () { x: index % 10 * 50, y: Math.floor(index / 10) * 50, width: 50, - height: 50 + height: 50, }; - } + }, }); // TODO 列表展示类控件不知道该测什么,先标记一下 grid.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/collection/collection.js b/src/base/collection/collection.js index 8605e70c5..0ad681faa 100644 --- a/src/base/collection/collection.js +++ b/src/base/collection/collection.js @@ -24,7 +24,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { items: [], itemFormatter: function (item, index) { return item; - } + }, }); }, @@ -38,7 +38,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { self._scrollLock = false; }, 1000 / 60); this.container = BI._lazyCreateWidget({ - type: "bi.absolute" + type: "bi.absolute", }); this.element.scroll(function () { if (self._scrollLock === true) { @@ -49,7 +49,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { self._calculateChildrenToRender(); self.fireEvent(BI.CollectionView.EVENT_SCROLL, { scrollLeft: o.scrollLeft, - scrollTop: o.scrollTop + scrollTop: o.scrollTop, }); }); // 兼容一下 @@ -58,7 +58,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { if (o.overflowY === false) { scrollable = false; } else { - scrollable = "y" + scrollable = "y"; } } else { if (o.overflowY === false) { @@ -71,7 +71,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { scrollable: scrollable, scrolly: scrolly, scrollx: scrollx, - items: [this.container] + items: [this.container], }); o.items = BI.isFunction(o.items) ? this.__watch(o.items, function (context, newValue) { self.populate(newValue); @@ -84,7 +84,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { // mounted之后绑定事件 mounted: function () { - var o = this.options; + var o = this.options; if (o.scrollLeft !== 0 || o.scrollTop !== 0) { this.element.scrollTop(o.scrollTop); this.element.scrollLeft(o.scrollLeft); @@ -101,10 +101,10 @@ BI.CollectionView = BI.inherit(BI.Widget, { for (var index = 0, len = o.items.length; index < len; index++) { var cellMetadatum = o.cellSizeAndPositionGetter(index); - if (cellMetadatum.height == null || isNaN(cellMetadatum.height) || - cellMetadatum.width == null || isNaN(cellMetadatum.width) || - cellMetadatum.x == null || isNaN(cellMetadatum.x) || - cellMetadatum.y == null || isNaN(cellMetadatum.y)) { + if (BI.isNull(cellMetadatum.height) || isNaN(cellMetadatum.height) || + BI.isNull(cellMetadatum.width) || isNaN(cellMetadatum.width) || + BI.isNull(cellMetadatum.x) || isNaN(cellMetadatum.x) || + BI.isNull(cellMetadatum.y) || isNaN(cellMetadatum.y)) { throw Error(); } @@ -124,16 +124,18 @@ BI.CollectionView = BI.inherit(BI.Widget, { _cellRenderers: function (height, width, x, y) { this._lastRenderedCellIndices = this._sectionManager.getCellIndices(height, width, x, y); + return this._cellGroupRenderer(); }, _cellGroupRenderer: function () { - var self = this, o = this.options; + var self = this; var rendered = []; BI.each(this._lastRenderedCellIndices, function (i, index) { var cellMetadata = self._sectionManager.getCellMetadata(index); rendered.push(cellMetadata); }); + return rendered; }, @@ -167,16 +169,16 @@ BI.CollectionView = BI.inherit(BI.Widget, { var topMap = BI.invert(tops); // 存储上下左右四个边界 var leftBorder = {}, rightBorder = {}, topBorder = {}, bottomBorder = {}; - var assertMinBorder = function (border, offset) { - if (border[offset] == null) { + function assertMinBorder(border, offset) { + if (BI.isNull(border[offset])) { border[offset] = Number.MAX_VALUE; } - }; - var assertMaxBorder = function (border, offset) { - if (border[offset] == null) { + } + function assertMaxBorder(border, offset) { + if (BI.isNull(border[offset])) { border[offset] = 0; } - }; + } for (var i = 0, len = childrenToDisplay.length; i < len; i++) { var datum = childrenToDisplay[i]; var index = this.renderedKeys[datum.index] && this.renderedKeys[datum.index][1]; @@ -194,7 +196,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { this.renderedCells[index].el.element.css("left", datum.x / BI.pixRatio + BI.pixUnit); // } // if (this.renderedCells[index]._top !== datum.y) { - this.renderedCells[index].el.element.css("top", datum.y / BI.pixRatio + BI.pixUnit); + this.renderedCells[index].el.element.css("top", datum.y / BI.pixRatio + BI.pixUnit); // } renderedCells.push(child = this.renderedCells[index]); } else { @@ -202,11 +204,11 @@ BI.CollectionView = BI.inherit(BI.Widget, { child = BI._lazyCreateWidget(BI.extend({ type: "bi.label", width: datum.width, - height: datum.height + height: datum.height, }, item, { cls: (item.cls || "") + " collection-cell" + (datum.y === 0 ? " first-row" : "") + (datum.x === 0 ? " first-col" : ""), _left: datum.x, - _top: datum.y + _top: datum.y, })); renderedCells.push({ el: child, @@ -280,7 +282,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { var minY = BI.max(topBorder); var maxY = BI.min(bottomBorder); - this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; + this.renderRange = { minX: minX, minY: minY, maxX: maxX, maxY: maxY }; } }, @@ -339,7 +341,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { if (this.options.overflowX !== !!b) { this.options.overflowX = !!b; BI.nextTick(function () { - self.element.css({overflowX: b ? "auto" : "hidden"}); + self.element.css({ overflowX: b ? "auto" : "hidden" }); }); } }, @@ -349,7 +351,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { if (this.options.overflowY !== !!b) { this.options.overflowY = !!b; BI.nextTick(function () { - self.element.css({overflowY: b ? "auto" : "hidden"}); + self.element.css({ overflowY: b ? "auto" : "hidden" }); }); } }, @@ -396,7 +398,7 @@ BI.CollectionView = BI.inherit(BI.Widget, { this.restore(); } this._populate(items); - } + }, }); BI.CollectionView.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut("bi.collection_view", BI.CollectionView); diff --git a/src/base/combination/bubble.js b/src/base/combination/bubble.js index f698b4a1a..d4c240b17 100644 --- a/src/base/combination/bubble.js +++ b/src/base/combination/bubble.js @@ -6,17 +6,18 @@ BI.Bubble = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.Bubble.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-popper", attributes: { - tabIndex: -1 + tabIndex: -1, }, trigger: "click", // click || hover || click-hover || "" toggle: true, direction: "", placement: "bottom-start", // top-start/top/top-end/bottom-start/bottom/bottom-end/left-start/left/left-end/right-start/right/right-end logic: { - dynamic: true + dynamic: true, }, container: null, // popupview放置的容器,默认为this.element isDefaultInit: false, @@ -81,11 +82,11 @@ }); BI.createWidget(BI.extend({ - element: this + element: this, }, BI.LogicFactory.createLogic("vertical", BI.extend(o.logic, { items: [ { el: this.combo } - ] + ], })))); o.isDefaultInit && (this._assertPopupView()); }, @@ -104,14 +105,14 @@ _initPullDownAction: function () { var self = this, o = this.options; var evs = (this.options.trigger || "").split(","); - var st = function (e) { + function st (e) { if (o.stopEvent) { e.stopEvent(); } if (o.stopPropagation) { e.stopPropagation(); } - }; + } var enterPopup = false; @@ -171,7 +172,7 @@ } }, BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); self.element.off(ev + "." + self.getName()).on(ev + "." + self.getName(), function (e) { debounce(e); @@ -194,7 +195,7 @@ } }, BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); self.element.off("click." + self.getName()).on("click." + self.getName(), function (e) { debounce(e); @@ -217,23 +218,25 @@ } }); break; + default: + break; } }); }, _initCombo: function () { this.combo = BI.createWidget(this.options.el, { - value: this.options.value + value: this.options.value, }); }, _assertPopupView: function () { var self = this, o = this.options; - if (this.popupView == null) { + if (BI.isNull(this.popupView)) { this.popupView = BI.createWidget(BI.isFunction(this.options.popup) ? this.options.popup() : this.options.popup, { type: "bi.bubble_popup_view", showArrow: o.showArrow, - value: o.value + value: o.value, }, this); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (type === BI.Events.CLICK) { @@ -258,7 +261,7 @@ element: this.options.container || this, items: [ { el: this.popupView } - ] + ], }); this._rendered = true; } @@ -286,6 +289,7 @@ return; } this._hideView(e); + return true; }, @@ -319,7 +323,7 @@ }, _popupView: function (e) { - var self = this, o = this.options; + var o = this.options; this._assertPopupViewRender(); this.fireEvent(BI.Bubble.EVENT_BEFORE_POPUPVIEW); // popupVisible是为了获取其宽高, 放到可视范围之外以防止在IE下闪一下 @@ -335,22 +339,22 @@ options: { offset: function () { return [o.adjustXOffset, (o.showArrow ? 12 : 0) + (o.adjustYOffset + o.adjustLength)]; - } - } + }, + }, }]; if (this.options.showArrow) { modifiers.push({ name: "arrow", options: { padding: 4, - element: this.popupView.arrow.element[0] - } + element: this.popupView.arrow.element[0], + }, }); } this.popper = BI.Popper.createPopper(this.combo.element[0], this.popupView.element[0], { placement: o.placement, strategy: "fixed", - modifiers: modifiers + modifiers: modifiers, }); // this.adjustHeight(e); @@ -478,7 +482,7 @@ this.popper && this.popper.destroy(); this.popper = null; this.popupView && this.popupView._destroy(); - } + }, }); BI.Bubble.EVENT_TRIGGER_CHANGE = "EVENT_TRIGGER_CHANGE"; BI.Bubble.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/combination/combo.js b/src/base/combination/combo.js index 27d00fc6a..5fc2f8008 100644 --- a/src/base/combination/combo.js +++ b/src/base/combination/combo.js @@ -1,26 +1,28 @@ !(function () { var needHideWhenAnotherComboOpen = {}; var currentOpenedCombos = {}; + /** * @class BI.Combo * @extends BI.Widget */ BI.Combo = BI.inherit(BI.Bubble, { _const: { - TRIANGLE_LENGTH: 12 + TRIANGLE_LENGTH: 12, }, _defaultConfig: function () { var conf = BI.Combo.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-combo" + (BI.isIE() ? " hack" : ""), attributes: { - tabIndex: -1 + tabIndex: -1, }, trigger: "click", // click || hover || click-hover || "" toggle: true, direction: "bottom", // top||bottom||left||right||top,left||top,right||bottom,left||bottom,right||right,innerRight||right,innerLeft||innerRight||innerLeft logic: { - dynamic: true + dynamic: true, }, container: null, // popupview放置的容器,默认为this.element isDefaultInit: false, @@ -42,7 +44,7 @@ popup: {}, comboClass: "bi-combo-popup", hoverClass: "bi-combo-hover", - belowMouse: false + belowMouse: false, }); }, @@ -90,11 +92,11 @@ }); BI.createWidget(BI.extend({ - element: this + element: this, }, BI.LogicFactory.createLogic("vertical", BI.extend(o.logic, { items: [ { el: this.combo } - ] + ], })))); o.isDefaultInit && (this._assertPopupView()); BI.Resizers.add(this.getName(), BI.bind(function (e) { @@ -107,11 +109,11 @@ _assertPopupView: function () { var self = this, o = this.options; - if (this.popupView == null) { + if (BI.isNull(this.popupView)) { this.popupView = BI.createWidget(BI.isFunction(this.options.popup) ? this.options.popup() : this.options.popup, { type: "bi.popup_view", showArrow: o.showArrow, - value: o.value + value: o.value, }, this); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { if (type === BI.Events.CLICK) { @@ -195,7 +197,7 @@ offset: function () { return { left: e.pageX, - top: e.pageY + top: e.pageY, }; }, bounds: function () { @@ -204,7 +206,7 @@ x: e.offsetX, y: e.offsetY, width: 0, - height: 24 + height: 24, }; }, outerWidth: function () { @@ -212,8 +214,8 @@ }, outerHeight: function () { return 24; - } - } + }, + }, } : this.combo; switch (o.direction) { case "bottom": @@ -280,10 +282,12 @@ delete p.adaptHeight; p.dir = "right"; break; + default: + break; } if ("adaptHeight" in p) { - this.resetListHeight(p["adaptHeight"]); + this.resetListHeight(p.adaptHeight); } var width = this.combo.element.outerWidth(); var height = this.combo.element.outerHeight(); @@ -293,16 +297,16 @@ offsetStyle: o.offsetStyle, adjustXOffset: o.adjustXOffset, adjustYOffset: o.adjustYOffset, - offset: this.combo.element.offset() + offset: this.combo.element.offset(), }); if ("left" in p) { this.popupView.element.css({ - left: p.left + left: p.left, }); } if ("top" in p) { this.popupView.element.css({ - top: p.top + top: p.top, }); } this.position = p; @@ -322,7 +326,7 @@ this.popupView && this.popupView._destroy(); delete needHideWhenAnotherComboOpen[this.getName()]; delete currentOpenedCombos[this.getName()]; - } + }, }); BI.Combo.closeAll = function () { BI.each(currentOpenedCombos, function (i, combo) { diff --git a/src/base/combination/expander.js b/src/base/combination/expander.js index 407413c40..60b3dd471 100644 --- a/src/base/combination/expander.js +++ b/src/base/combination/expander.js @@ -17,7 +17,7 @@ BI.Expander = BI.inherit(BI.Widget, { el: {}, popup: {}, expanderClass: "bi-expander-popup", - hoverClass: "bi-expander-hover" + hoverClass: "bi-expander-hover", }); }, @@ -66,7 +66,7 @@ BI.Expander = BI.inherit(BI.Widget, { element: this, items: [ { el: this.expander } - ] + ], }); o.isDefaultInit && this._assertPopupView(); if (this.expander.isOpened() === true) { @@ -122,10 +122,12 @@ BI.Expander = BI.inherit(BI.Widget, { } }, BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, })); } break; + default: + break; } }); }, @@ -136,16 +138,16 @@ BI.Expander = BI.inherit(BI.Widget, { _assertPopupView: function () { var self = this, o = this.options; - if (this.popupView == null) { + if (BI.isNull(this.popupView)) { this.popupView = BI.createWidget(this.options.popup, { type: "bi.button_group", cls: "expander-popup", layouts: [{ type: "bi.vertical", hgap: 0, - vgap: 0 + vgap: 0, }], - value: o.value + value: o.value, }, this); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -170,7 +172,7 @@ BI.Expander = BI.inherit(BI.Widget, { element: this, items: [ { el: this.popupView } - ] + ], }); this._rendered = true; } @@ -255,6 +257,7 @@ BI.Expander = BI.inherit(BI.Widget, { if (this.expander.options.id === id) { return this.expander; } + return this.popupView && this.popupView.getNodeById(id); }, @@ -262,12 +265,13 @@ BI.Expander = BI.inherit(BI.Widget, { if (this.expander.getValue() === value) { return this.expander; } + return this.popupView && this.popupView.getNodeByValue(value); }, destroy: function () { BI.Expander.superclass.destroy.apply(this, arguments); - } + }, }); BI.Expander.EVENT_EXPAND = "EVENT_EXPAND"; BI.Expander.EVENT_COLLAPSE = "EVENT_COLLAPSE"; diff --git a/src/base/combination/group.button.js b/src/base/combination/group.button.js index b9e8f7127..49d56167c 100644 --- a/src/base/combination/group.button.js +++ b/src/base/combination/group.button.js @@ -15,8 +15,8 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { layouts: [{ type: "bi.center", hgap: 0, - vgap: 0 - }] + vgap: 0, + }], }); }, @@ -25,7 +25,7 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { var behaviors = {}; BI.each(o.behaviors, function (key, rule) { behaviors[key] = BI.BehaviorFactory.createBehavior(key, { - rule: rule + rule: rule, }); }); this.behaviors = behaviors; @@ -42,9 +42,8 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { }, _createBtns: function (items) { - var o = this.options; return BI.createWidgets(BI.createItems(items, { - type: "bi.text_button" + type: "bi.text_button", }), this); }, @@ -66,6 +65,8 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { case BI.ButtonGroup.CHOOSE_TYPE_NONE: self.setValue([]); break; + default: + break; } self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); self.fireEvent(BI.ButtonGroup.EVENT_CHANGE, value, obj); @@ -89,23 +90,26 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { return BI.extend({}, layouts[i], { items: [ BI.extend({}, layouts[i].el, { - el: it + el: it, }) - ] + ], }); }); } + return btns; }, _packageSimpleItems: function (btns) { var o = this.options; + return BI.map(o.items, function (i, item) { if (BI.stripEL(item) === item) { return btns[i]; } + return BI.extend({}, item, { - el: btns[i] + el: btns[i], }); }); }, @@ -122,12 +126,14 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { lay = BI.formatEL(lay.items[0]).el; } lay.items = items; + return layout; }, // 如果是一个简单的layout _isSimpleLayout: function () { var o = this.options; + return BI.isArray(o.layouts) ? (o.layouts.length === 1 && !BI.isArray(o.items[0])) : true; }, @@ -140,12 +146,12 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { }, prependItems: function (items) { - var o = this.options; var btns = this._btnsCreator.apply(this, arguments); this.buttons = BI.concat(btns, this.buttons); if (this._isSimpleLayout() && this.layouts && this.layouts.prependItems) { this.layouts.prependItems(btns); + return; } @@ -154,13 +160,13 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { }, addItems: function (items) { - var o = this.options; var btns = this._btnsCreator.apply(this, arguments); this.buttons = BI.concat(this.buttons, btns); // 如果是一个简单的layout if (this._isSimpleLayout() && this.layouts && this.layouts.addItems) { this.layouts.addItems(btns); + return; } @@ -257,6 +263,7 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { v.push(item.getValue()); } }); + return v; }, @@ -267,6 +274,7 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { v.push(item.getValue()); } }); + return v; }, @@ -285,6 +293,7 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { btns.push(item); } }); + return btns; }, @@ -295,6 +304,7 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { btns.push(item); } }); + return btns; }, @@ -303,9 +313,11 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { BI.any(this.buttons, function (i, item) { if (item.isEnabled() && item.getValue() === value) { index = i; + return true; } }); + return index; }, @@ -314,9 +326,11 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { BI.any(this.buttons, function (i, item) { if (item.isEnabled() && item.options.id === id) { node = item; + return true; } }); + return node; }, @@ -325,9 +339,11 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { BI.any(this.buttons, function (i, item) { if (item.isEnabled() && item.getValue() === value) { node = item; + return true; } }); + return node; }, @@ -349,14 +365,14 @@ BI.ButtonGroup = BI.inherit(BI.Widget, { destroy: function () { BI.ButtonGroup.superclass.destroy.apply(this, arguments); this.options.items = []; - } + }, }); BI.extend(BI.ButtonGroup, { CHOOSE_TYPE_SINGLE: BI.Selection.Single, CHOOSE_TYPE_MULTI: BI.Selection.Multi, CHOOSE_TYPE_ALL: BI.Selection.All, CHOOSE_TYPE_NONE: BI.Selection.None, - CHOOSE_TYPE_DEFAULT: BI.Selection.Default + CHOOSE_TYPE_DEFAULT: BI.Selection.Default, }); BI.ButtonGroup.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/combination/group.combo.js b/src/base/combination/group.combo.js index 7c07445ee..2f8b0c72e 100644 --- a/src/base/combination/group.combo.js +++ b/src/base/combination/group.combo.js @@ -15,7 +15,7 @@ BI.ComboGroup = BI.inherit(BI.Widget, { isNeedAdjustHeight: false, isNeedAdjustWidth: false, - el: {type: "bi.text_button", text: "", value: ""}, + el: { type: "bi.text_button", text: "", value: "" }, items: [], popup: { @@ -23,10 +23,10 @@ BI.ComboGroup = BI.inherit(BI.Widget, { type: "bi.button_tree", chooseType: 0, layouts: [{ - type: "bi.vertical" - }] - } - } + type: "bi.vertical", + }], + }, + }, }); }, @@ -71,9 +71,9 @@ BI.ComboGroup = BI.inherit(BI.Widget, { el: item, popup: BI.extend({}, o.popup, { el: BI.extend({ - items: children - }, o.popup.el) - }) + items: children, + }, o.popup.el), + }), }); this.combo.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -89,7 +89,7 @@ BI.ComboGroup = BI.inherit(BI.Widget, { setValue: function (v) { this.combo.setValue(v); - } + }, }); BI.ComboGroup.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/combination/group.virtual.js b/src/base/combination/group.virtual.js index d42c7a5b7..40e7c09f4 100644 --- a/src/base/combination/group.virtual.js +++ b/src/base/combination/group.virtual.js @@ -6,8 +6,8 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { layouts: [{ type: "bi.center", hgap: 0, - vgap: 0 - }] + vgap: 0, + }], }); }, @@ -29,9 +29,10 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { var o = this.options; var map = this.buttonMap = {}; var layouts = BI.isArray(o.layouts) ? o.layouts : [o.layouts]; - for (var i = layouts.length - 1; i > 0; i--) { + for (let i = layouts.length - 1; i > 0; i--) { items = BI.map(items, function (k, it) { var el = BI.stripEL(it); + return BI.extend({}, layouts[i], { items: [ BI.extend({}, layouts[i].el, { @@ -40,13 +41,14 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { if (BI.isKey(map[el.value])) { map[el.value] = _ref; } - } - }, el) + }, + }, el), }) - ] + ], }); }); } + return items; }, @@ -60,6 +62,7 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { lay = BI.formatEL(lay.items[0]).el; } lay.items = items; + return layout; }, @@ -93,6 +96,7 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { } } }); + return v; }, @@ -119,6 +123,7 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { } } }); + return v; }, @@ -130,10 +135,10 @@ BI.VirtualGroup = BI.inherit(BI.Widget, { this.layouts = BI.createWidget(BI.extend({ element: this }, this._packageLayout(items))); } else { this.layouts.populate(items, { - context: this + context: this, }); } - } + }, }); BI.VirtualGroup.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/combination/loader.js b/src/base/combination/loader.js index a56e72708..cf548b024 100644 --- a/src/base/combination/loader.js +++ b/src/base/combination/loader.js @@ -14,12 +14,12 @@ BI.Loader = BI.inherit(BI.Widget, { isDefaultInit: true, // 是否默认初始化数据 logic: { dynamic: true, - scrolly: true + scrolly: true, }, // 下面是button_group的属性 el: { - type: "bi.button_group" + type: "bi.button_group", }, items: [], @@ -31,14 +31,14 @@ BI.Loader = BI.inherit(BI.Widget, { prev: false, next: {}, hasPrev: BI.emptyFn, - hasNext: BI.emptyFn + hasNext: BI.emptyFn, }); }, _prevLoad: function () { var self = this, o = this.options; this.prev.setLoading(); - o.itemsCreator.apply(this, [{times: --this.times}, function () { + o.itemsCreator.apply(this, [{ times: --this.times }, function () { self.prev.setLoaded(); self.prependItems.apply(self, arguments); }]); @@ -47,7 +47,7 @@ BI.Loader = BI.inherit(BI.Widget, { _nextLoad: function () { var self = this, o = this.options; this.next.setLoading(); - o.itemsCreator.apply(this, [{times: ++this.times}, function () { + o.itemsCreator.apply(this, [{ times: ++this.times }, function () { self.next.setLoaded(); self.addItems.apply(self, arguments); }]); @@ -61,7 +61,7 @@ BI.Loader = BI.inherit(BI.Widget, { } if (o.prev !== false) { this.prev = BI.createWidget(BI.extend({ - type: "bi.loading_bar" + type: "bi.loading_bar", }, o.prev)); this.prev.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { @@ -76,9 +76,9 @@ BI.Loader = BI.inherit(BI.Widget, { items: o.items, behaviors: {}, layouts: [{ - type: "bi.vertical" + type: "bi.vertical", }], - value: o.value + value: o.value, }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -89,7 +89,7 @@ BI.Loader = BI.inherit(BI.Widget, { if (o.next !== false) { this.next = BI.createWidget(BI.extend({ - type: "bi.loading_bar" + type: "bi.loading_bar", }, o.next)); this.next.on(BI.Controller.EVENT_CHANGE, function (type) { if (type === BI.Events.CLICK) { @@ -99,11 +99,11 @@ BI.Loader = BI.inherit(BI.Widget, { } BI.createWidget(BI.extend({ - element: this + element: this, }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({ - scrolly: true + scrolly: true, }, o.logic, { - items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.prev, this.button_group, this.next) + items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.prev, this.button_group, this.next), })))); o.isDefaultInit && BI.isEmpty(o.items) && BI.nextTick(BI.bind(function () { @@ -122,9 +122,10 @@ BI.Loader = BI.inherit(BI.Widget, { if (BI.isNumber(o.count)) { return this.count < o.count; } + return !!o.hasPrev.apply(this, [{ times: this.times, - count: this.count + count: this.count, }]); }, @@ -133,9 +134,10 @@ BI.Loader = BI.inherit(BI.Widget, { if (BI.isNumber(o.count)) { return this.count < o.count; } + return !!o.hasNext.apply(this, [{ times: this.times, - count: this.count + count: this.count, }]); }, @@ -168,13 +170,14 @@ BI.Loader = BI.inherit(BI.Widget, { _populate: function (items) { var self = this, o = this.options; if (arguments.length === 0 && (BI.isFunction(o.itemsCreator))) { - o.itemsCreator.apply(this, [{times: 1}, function () { + o.itemsCreator.apply(this, [{ times: 1 }, function () { if (arguments.length === 0) { throw new Error("参数不能为空"); } self.populate.apply(self, arguments); o.onLoaded(); }]); + return false; } this.options.items = items; @@ -195,6 +198,7 @@ BI.Loader = BI.inherit(BI.Widget, { this.prev.invisible(); } } + return true; }, @@ -255,7 +259,7 @@ BI.Loader = BI.inherit(BI.Widget, { destroy: function () { BI.Loader.superclass.destroy.apply(this, arguments); - } + }, }); BI.Loader.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.loader", BI.Loader); diff --git a/src/base/combination/navigation.js b/src/base/combination/navigation.js index b2d5ae867..971ec9ba9 100644 --- a/src/base/combination/navigation.js +++ b/src/base/combination/navigation.js @@ -7,7 +7,7 @@ BI.Navigation = BI.inherit(BI.Widget, { return BI.extend(BI.Navigation.superclass._defaultConfig.apply(this, arguments), { direction: "bottom", // top, bottom, left, right, custom logic: { - dynamic: false + dynamic: false, }, single: false, showIndex: false, @@ -17,22 +17,22 @@ BI.Navigation = BI.inherit(BI.Widget, { }, afterCardCreated: BI.emptyFn, - afterCardShow: BI.emptyFn + afterCardShow: BI.emptyFn, }); }, render: function () { var self = this, o = this.options; - this.tab = BI.createWidget(this.options.tab, {type: "bi.button_group"}); + this.tab = BI.createWidget(this.options.tab, { type: "bi.button_group" }); this.cardMap = {}; this.showIndex = 0; this.layout = BI.createWidget({ - type: "bi.card" + type: "bi.card", }); BI.createWidget(BI.extend({ - element: this + element: this, }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { - items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout) + items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout), })))); @@ -45,16 +45,17 @@ BI.Navigation = BI.inherit(BI.Widget, { cardCreator: function (v) { var card = o.cardCreator(v); self.cardMap[v] = card; + return card; }, afterCardCreated: BI.bind(this.afterCardCreated, this), - afterCardShow: BI.bind(this.afterCardShow, this) + afterCardShow: BI.bind(this.afterCardShow, this), }); if (BI.isFunction(o.showIndex)) { this.__watch(o.showIndex, function (context, newValue) { self.setSelect(newValue); - }) + }); } }, @@ -161,7 +162,7 @@ BI.Navigation = BI.inherit(BI.Widget, { destroy: function () { BI.Navigation.superclass.destroy.apply(this, arguments); - } + }, }); BI.Navigation.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/combination/searcher.js b/src/base/combination/searcher.js index 0989b4c8a..2098f4ce0 100644 --- a/src/base/combination/searcher.js +++ b/src/base/combination/searcher.js @@ -28,17 +28,17 @@ BI.Searcher = BI.inherit(BI.Widget, { }, el: { - type: "bi.search_editor" + type: "bi.search_editor", }, popup: { - type: "bi.searcher_view" + type: "bi.searcher_view", }, adapter: null, masker: { // masker层 - offset: {} - } + offset: {}, + }, }); }, @@ -46,7 +46,7 @@ BI.Searcher = BI.inherit(BI.Widget, { var self = this, o = this.options; this.editor = BI.createWidget(o.el, { - type: "bi.search_editor" + type: "bi.search_editor", }); BI.createWidget({ @@ -58,13 +58,13 @@ BI.Searcher = BI.inherit(BI.Widget, { bgap: o.bgap, vgap: o.vgap, hgap: o.hgap, - items: [this.editor] + items: [this.editor], }); o.isDefaultInit && (this._assertPopupView()); var search = BI.debounce(BI.bind(this._search, this), BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); this.editor.on(BI.Controller.EVENT_CHANGE, function (type) { switch (type) { @@ -82,6 +82,8 @@ BI.Searcher = BI.inherit(BI.Widget, { self._pauseSearch(); } break; + default: + break; } }); }, @@ -91,7 +93,7 @@ BI.Searcher = BI.inherit(BI.Widget, { if ((o.masker && !BI.Maskers.has(this.getName())) || (o.masker === false && !this.popupView)) { this.popupView = BI.createWidget(o.popup, { type: "bi.searcher_view", - chooseType: o.chooseType + chooseType: o.chooseType, }); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -109,6 +111,8 @@ BI.Searcher = BI.inherit(BI.Widget, { values.push(obj.getValue()); o.adapter && o.adapter.setValue(values); break; + default: + break; } } self.fireEvent(BI.Searcher.EVENT_CHANGE, value, obj); @@ -121,7 +125,7 @@ BI.Searcher = BI.inherit(BI.Widget, { if (o.masker && !BI.Maskers.has(this.getName())) { BI.Maskers.create(this.getName(), o.adapter, BI.extend({ container: this, - render: this.popupView + render: this.popupView, }, o.masker), this); } }, @@ -140,7 +144,6 @@ BI.Searcher = BI.inherit(BI.Widget, { }, _pauseSearch: function () { - var o = this.options, name = this.getName(); this._stop = true; BI.nextTick(function (name) { BI.Maskers.hide(name); @@ -153,7 +156,7 @@ BI.Searcher = BI.inherit(BI.Widget, { }, _stopSearch: function () { - var o = this.options, name = this.getName(); + var name = this.getName(); this._stop = true; BI.Maskers.hide(name); if (this._isSearching === true) { @@ -175,13 +178,14 @@ BI.Searcher = BI.inherit(BI.Widget, { this.popupView.populate(find, match, keyword); o.isAutoSync && o.adapter && o.adapter.getValue && this.popupView.setValue(o.adapter.getValue()); self.fireEvent(BI.Searcher.EVENT_SEARCHING); + return; } this.popupView.loading && this.popupView.loading(); o.onSearch({ times: 1, keyword: keyword, - selectedValues: o.adapter && o.adapter.getValue() + selectedValues: o.adapter && o.adapter.getValue(), }, function (searchResult, matchResult) { if (!self._stop && keyword === self.editor.getValue()) { var args = [].slice.call(arguments); @@ -203,6 +207,7 @@ BI.Searcher = BI.inherit(BI.Widget, { if (BI.isEmptyString(res[res.length - 1])) { res = res.slice(0, res.length - 1); } + return BI.isNull(res) ? "" : res[res.length - 1]; } }, @@ -246,6 +251,7 @@ BI.Searcher = BI.inherit(BI.Widget, { hasMatched: function () { this._assertPopupView(); + return this.popupView.hasMatched(); }, @@ -288,8 +294,8 @@ BI.Searcher = BI.inherit(BI.Widget, { if (BI.isNull(this.popupView)) { return o.popup.value; } - return this.popupView.getValue(); + return this.popupView.getValue(); }, populate: function (result, searchResult, keyword) { @@ -319,7 +325,7 @@ BI.Searcher = BI.inherit(BI.Widget, { setWaterMark: function (v) { this.editor.setWaterMark(v); - } + }, }); BI.Searcher.EVENT_CHANGE = "EVENT_CHANGE"; BI.Searcher.EVENT_START = "EVENT_START"; diff --git a/src/base/combination/switcher.js b/src/base/combination/switcher.js index 1a929f704..419711595 100644 --- a/src/base/combination/switcher.js +++ b/src/base/combination/switcher.js @@ -18,7 +18,7 @@ BI.Switcher = BI.inherit(BI.Widget, { adapter: null, masker: {}, switcherClass: "bi-switcher-popup", - hoverClass: "bi-switcher-hover" + hoverClass: "bi-switcher-hover", }); }, @@ -66,7 +66,7 @@ BI.Switcher = BI.inherit(BI.Widget, { element: this, items: [ { el: this.switcher } - ] + ], }); o.isDefaultInit && (this._assertPopupView()); }, @@ -119,7 +119,7 @@ BI.Switcher = BI.inherit(BI.Widget, { } }, BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, })); } break; @@ -129,7 +129,7 @@ BI.Switcher = BI.inherit(BI.Widget, { _initSwitcher: function () { this.switcher = BI.createWidget(this.options.el, { - value: this.options.value + value: this.options.value, }); }, @@ -143,9 +143,9 @@ BI.Switcher = BI.inherit(BI.Widget, { layouts: [{ type: "bi.vertical", hgap: 0, - vgap: 0 + vgap: 0, }], - value: o.value + value: o.value, }, this); this.popupView.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -160,7 +160,7 @@ BI.Switcher = BI.inherit(BI.Widget, { element: this, items: [ { el: this.popupView } - ] + ], }); } this._created = true; @@ -265,6 +265,7 @@ BI.Switcher = BI.inherit(BI.Widget, { if (this.switcher.attr("id") === id) { return this.switcher; } + return this.popupView && this.popupView.getNodeById(id); }, @@ -272,12 +273,13 @@ BI.Switcher = BI.inherit(BI.Widget, { if (this.switcher.getValue() === value) { return this.switcher; } + return this.popupView && this.popupView.getNodeByValue(value); }, empty: function () { this.popupView && this.popupView.empty(); - } + }, }); BI.Switcher.EVENT_EXPAND = "EVENT_EXPAND"; BI.Switcher.EVENT_COLLAPSE = "EVENT_COLLAPSE"; diff --git a/src/base/combination/tab.js b/src/base/combination/tab.js index 90a788a17..fe5904804 100644 --- a/src/base/combination/tab.js +++ b/src/base/combination/tab.js @@ -9,14 +9,14 @@ BI.Tab = BI.inherit(BI.Widget, { direction: "top", // top, bottom, left, right, custom single: false, // 是不是单页面 logic: { - dynamic: false + dynamic: false, }, showIndex: false, tab: false, cardCreator: function (v) { return BI.createWidget(); }, - keepAlives: [] + keepAlives: [], }); }, @@ -30,13 +30,13 @@ BI.Tab = BI.inherit(BI.Widget, { } this.cardMap = {}; this.layout = BI.createWidget({ - type: "bi.card" + type: "bi.card", }); BI.createWidget(BI.extend({ - element: this + element: this, }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { - items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout) + items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tab, this.layout), })))); var listener = new BI.ShowListener({ @@ -51,7 +51,7 @@ BI.Tab = BI.inherit(BI.Widget, { afterCardShow: function (v) { self._deleteOtherCards(v); self.curr = v; - } + }, }); listener.on(BI.ShowListener.EVENT_CHANGE, function (value) { self.fireEvent(BI.Tab.EVENT_CHANGE, value, self); @@ -112,7 +112,7 @@ BI.Tab = BI.inherit(BI.Widget, { }, removeTab: function (cardname) { - var self = this, o = this.options; + var self = this; BI.any(this.cardMap, function (name, card) { if (BI.isEqual(name, (cardname + ""))) { self.layout.deleteCardByName(name); @@ -170,7 +170,7 @@ BI.Tab = BI.inherit(BI.Widget, { destroy: function () { this.cardMap = {}; BI.Tab.superclass.destroy.apply(this, arguments); - } + }, }); BI.Tab.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/combination/tree.button.js b/src/base/combination/tree.button.js index 45b436b8a..cfa9a3c3b 100644 --- a/src/base/combination/tree.button.js +++ b/src/base/combination/tree.button.js @@ -7,7 +7,7 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { _defaultConfig: function () { return BI.extend(BI.ButtonTree.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-button-tree" + baseCls: "bi-button-tree", }); }, @@ -16,6 +16,7 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (!BI.isFunction(item.setSelected)) { item.setNotSelectedValue(v); + return; } if (BI.deepContains(v, item.getValue())) { @@ -31,6 +32,7 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (BI.isFunction(item.setEnabledValue)) { item.setEnabledValue(v); + return; } if (BI.deepContains(v, item.getValue())) { @@ -46,6 +48,7 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (!BI.isFunction(item.setSelected)) { item.setValue(v); + return; } if (BI.deepContains(v, item.getValue())) { @@ -61,12 +64,14 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { v = BI.concat(v, item.getNotSelectedValue()); + return; } if (item.isEnabled() && item.isSelected && !item.isSelected()) { v.push(item.getValue()); } }); + return v; }, @@ -75,12 +80,14 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { v = BI.concat(v, item.getValue()); + return; } if (item.isEnabled() && item.isSelected && item.isSelected()) { v.push(item.getValue()); } }); + return v; }, @@ -89,12 +96,14 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { btns = btns.concat(item.getSelectedButtons()); + return; } if (item.isSelected && item.isSelected()) { btns.push(item); } }); + return btns; }, @@ -103,12 +112,14 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { btns = btns.concat(item.getNotSelectedButtons()); + return; } if (item.isSelected && !item.isSelected()) { btns.push(item); } }); + return btns; }, @@ -118,12 +129,14 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.each(this.buttons, function (i, item) { if (item.isEnabled() && !BI.isFunction(item.setSelected)) { leaves = leaves.concat(item.getAllLeaves()); + return; } if (item.isEnabled()) { leaves.push(item); } }); + return leaves; }, @@ -133,9 +146,11 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { var vs = item.getValue(); if (item.isEnabled() && (vs === value || BI.contains(vs, value))) { index = i; + return true; } }); + return index; }, @@ -145,14 +160,17 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { if (item.isEnabled()) { if (item.attr("id") === id) { node = item; + return true; } else if (BI.isFunction(item.getNodeById)) { - if (node = item.getNodeById(id)) { + node = item.getNodeById(id); + if (node) { return true; } } } }); + return node; }, @@ -161,17 +179,20 @@ BI.ButtonTree = BI.inherit(BI.ButtonGroup, { BI.any(this.buttons, function (i, item) { if (item.isEnabled()) { if (BI.isFunction(item.getNodeByValue)) { - if (node = item.getNodeByValue(value)) { + node = item.getNodeByValue(value); + if (node) { return true; } } else if (item.attr("value") === value) { node = item; + return true; } } }); + return node; - } + }, }); BI.ButtonTree.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/context.js b/src/base/context.js index ecaf5febf..67ef704c0 100644 --- a/src/base/context.js +++ b/src/base/context.js @@ -10,13 +10,13 @@ BI.Context = BI.inherit(BI.Widget, { context: "", watch: {}, el: {}, - items: [] + items: [], }, render: function () { var self = this, o = this.options; this.context = BI.createWidget(o.items[0] || o.el, { - element: this + element: this, }); this.context.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -40,6 +40,6 @@ BI.Context = BI.inherit(BI.Widget, { populate: function () { this.context.populate.apply(this, arguments); - } + }, }); BI.shortcut("bi.context", BI.Context); diff --git a/src/base/el.js b/src/base/el.js index 6feb40f42..885c04ac5 100644 --- a/src/base/el.js +++ b/src/base/el.js @@ -9,14 +9,14 @@ BI.EL = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.EL.superclass._defaultConfig.apply(this, arguments), { baseCls: "bi-el", - el: {} + el: {}, }); }, render: function () { var self = this, o = this.options; this.ele = BI.createWidget(o.el, { - element: this + element: this, }); this.ele.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -33,6 +33,6 @@ BI.EL = BI.inherit(BI.Widget, { populate: function () { this.ele.populate.apply(this, arguments); - } + }, }); BI.shortcut("bi.el", BI.EL); diff --git a/src/base/foundation/__test__/message.test.js b/src/base/foundation/__test__/message.test.js index 7097c50ff..ac391bc07 100644 --- a/src/base/foundation/__test__/message.test.js +++ b/src/base/foundation/__test__/message.test.js @@ -4,7 +4,6 @@ * Created by windy on 2020/3/9 */ describe("MessageTest", function () { - /** * test_author_windy */ @@ -24,7 +23,7 @@ describe("MessageTest", function () { */ it("toast_hand_close", function (done) { BI.Msg.toast("message", { - autoClose: false + autoClose: false, }); var body = BI.Widget._renderEngine.createElement("body"); expect(body.find(".bi-toast").length).to.equal(1); @@ -44,4 +43,3 @@ describe("MessageTest", function () { expect(body.find(".bi-toast").length).to.equal(1); }); }); - diff --git a/src/base/foundation/message.js b/src/base/foundation/message.js index 156297c9d..380e12039 100644 --- a/src/base/foundation/message.js +++ b/src/base/foundation/message.js @@ -3,8 +3,7 @@ * 弹出提示消息框,用于模拟阻塞操作(通过回调函数实现) * @class BI.Msg */ -BI.Msg = function () { - +BI.Msg = ((function () { var $mask, $pop; var messageShows = []; @@ -22,7 +21,7 @@ BI.Msg = function () { // BI.Msg.prompt(title, message, value, callback, min_width); }, toast: function (message, options, context) { - BI.isString(options) && (options = { level: options }) + BI.isString(options) && (options = { level: options }); options = options || {}; context = context || BI.Widget._renderEngine.createElement("body"); var level = options.level || "common"; @@ -41,12 +40,12 @@ BI.Msg = function () { BI.remove(toastStack, toast.element); var _height = BI.SIZE_CONSANTS.TOAST_TOP; BI.each(toastStack, function (i, element) { - element.css({"top": _height}); + element.css({ "top": _height }); _height += element.outerHeight() + 10; }); callback(); - } - }] + }, + }], }); var height = BI.SIZE_CONSANTS.TOAST_TOP; BI.each(toastStack, function (i, element) { @@ -58,20 +57,21 @@ BI.Msg = function () { items: [{ el: toast, left: "50%", - top: height - }] + top: height, + }], }); toastStack.push(toast.element); - toast.element.css({"margin-left": -1 * toast.element.outerWidth() / 2}); + toast.element.css({ "margin-left": -1 * toast.element.outerWidth() / 2 }); toast.element.removeClass("bi-message-leave").addClass("bi-message-enter"); autoClose && BI.delay(function () { toast.element.removeClass("bi-message-enter").addClass("bi-message-leave"); - toast.destroy(); + toast.destroy?.(); }, 5000); + return function () { toast.element.removeClass("bi-message-enter").addClass("bi-message-leave"); - toast.destroy(); + toast.destroy?.(); }; }, _show: function (hasCancel, title, message, callback) { @@ -82,7 +82,7 @@ BI.Msg = function () { left: 0, right: 0, bottom: 0, - opacity: 0.5 + opacity: 0.5, }).appendTo("body")); $pop = BI.Widget._renderEngine.createElement("
").css({ position: "absolute", @@ -90,16 +90,16 @@ BI.Msg = function () { top: 0, left: 0, right: 0, - bottom: 0 + bottom: 0, }).appendTo("body"); - var close = function () { + function close () { messageShows[messageShows.length - 1].destroy(); messageShows.pop(); if (messageShows.length === 0) { $mask.remove(); $mask = null; } - }; + } var controlItems = []; if (hasCancel === true) { controlItems.push({ @@ -112,8 +112,8 @@ BI.Msg = function () { if (BI.isFunction(callback)) { callback.apply(null, [false]); } - } - } + }, + }, }); } controlItems.push({ @@ -125,8 +125,8 @@ BI.Msg = function () { if (BI.isFunction(callback)) { callback.apply(null, [true]); } - } - } + }, + }, }); var conf = { element: $pop, @@ -135,7 +135,7 @@ BI.Msg = function () { { type: "bi.border", attributes: { - tabIndex: 1 + tabIndex: 1, }, mounted: function () { this.element.keyup(function (e) { @@ -173,8 +173,8 @@ BI.Msg = function () { text: title || BI.i18nText("BI-Basic_Prompt"), textAlign: "left", hgap: 20, - height: 40 - } + height: 40, + }, }, east: { el: { @@ -186,13 +186,13 @@ BI.Msg = function () { if (BI.isFunction(callback)) { callback.apply(null, [false]); } - } + }, }, - width: 56 - } - } + width: 56, + }, + }, }, - height: 40 + height: 40, }, center: { el: BI.isPlainObject(message) ? message : { @@ -200,8 +200,8 @@ BI.Msg = function () { vgap: 10, hgap: 20, whiteSpace: "normal", - text: message - } + text: message, + }, }, south: { el: { @@ -210,25 +210,25 @@ BI.Msg = function () { el: { type: "bi.right_vertical_adapt", lgap: 10, - items: controlItems + items: controlItems, }, top: 0, left: 20, right: 20, - bottom: 0 - }] + bottom: 0, + }], }, - height: 44 - } + height: 44, + }, }, width: 450, - height: 200 + height: 200, } - ] + ], }; messageShows[messageShows.length] = BI.createWidget(conf); - } + }, }; -}(); +})()); diff --git a/src/base/grid/__test__/grid.test.js b/src/base/grid/__test__/grid.test.js index d65c3d24c..6ff920b4f 100644 --- a/src/base/grid/__test__/grid.test.js +++ b/src/base/grid/__test__/grid.test.js @@ -4,7 +4,6 @@ * Created by windy on 2020/3/20 */ describe("GridTest", function () { - /** * test_author_windy */ @@ -16,7 +15,7 @@ describe("GridTest", function () { for (var j = 0; j < columnCount; j++) { items[i][j] = { type: "bi.label", - text: i + "-" + j + text: i + "-" + j, }; } } @@ -33,9 +32,9 @@ describe("GridTest", function () { }, columnWidthGetter: function () { return 100; - } + }, }); // TODO 性能展示类控件,不知道要测啥,标记一下 grid.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/grid/grid.js b/src/base/grid/grid.js index 334851235..81853b77a 100644 --- a/src/base/grid/grid.js +++ b/src/base/grid/grid.js @@ -27,7 +27,7 @@ BI.GridView = BI.inherit(BI.Widget, { items: [], itemFormatter: function (item, row, col) { return item; - } + }, }); }, @@ -41,7 +41,7 @@ BI.GridView = BI.inherit(BI.Widget, { self._scrollLock = false; }, 1000 / 60); this.container = BI._lazyCreateWidget({ - type: "bi.absolute" + type: "bi.absolute", }); this.element.scroll(function () { if (self._scrollLock === true) { @@ -52,7 +52,7 @@ BI.GridView = BI.inherit(BI.Widget, { self._calculateChildrenToRender(); self.fireEvent(BI.GridView.EVENT_SCROLL, { scrollLeft: o.scrollLeft, - scrollTop: o.scrollTop + scrollTop: o.scrollTop, }); }); // 兼容一下 @@ -61,7 +61,7 @@ BI.GridView = BI.inherit(BI.Widget, { if (o.overflowY === false) { scrollable = false; } else { - scrollable = "y" + scrollable = "y"; } } else { if (o.overflowY === false) { @@ -74,7 +74,7 @@ BI.GridView = BI.inherit(BI.Widget, { scrollable: scrollable, scrolly: scrolly, scrollx: scrollx, - items: [this.container] + items: [this.container], }); o.items = BI.isFunction(o.items) ? this.__watch(o.items, function (context, newValue) { self.populate(newValue); @@ -115,7 +115,7 @@ BI.GridView = BI.inherit(BI.Widget, { _getOverscanIndices: function (cellCount, overscanCellsCount, startIndex, stopIndex) { return { overscanStartIndex: Math.max(0, startIndex - overscanCellsCount), - overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount) + overscanStopIndex: Math.min(cellCount - 1, stopIndex + overscanCellsCount), }; }, @@ -197,20 +197,20 @@ BI.GridView = BI.inherit(BI.Widget, { child = BI._lazyCreateWidget(BI.extend({ type: "bi.label", width: columnDatum.size, - height: rowDatum.size + height: rowDatum.size, }, item, { cls: (item.cls || "") + " grid-cell" + (rowIndex === 0 ? " first-row" : "") + (columnIndex === 0 ? " first-col" : ""), _rowIndex: rowIndex, _columnIndex: columnIndex, _left: columnDatum.offset + horizontalOffsetAdjustment, - _top: rowDatum.offset + verticalOffsetAdjustment + _top: rowDatum.offset + verticalOffsetAdjustment, }), this); renderedCells.push({ el: child, left: columnDatum.offset + horizontalOffsetAdjustment, top: rowDatum.offset + verticalOffsetAdjustment, _left: columnDatum.offset + horizontalOffsetAdjustment, - _top: rowDatum.offset + verticalOffsetAdjustment + _top: rowDatum.offset + verticalOffsetAdjustment, // _width: columnDatum.size, // _height: rowDatum.size }); @@ -258,7 +258,7 @@ BI.GridView = BI.inherit(BI.Widget, { this.container.attr("items", renderedCells); this.renderedCells = renderedCells; this.renderedKeys = renderedKeys; - this.renderRange = {minX: minX, minY: minY, maxX: maxX, maxY: maxY}; + this.renderRange = { minX: minX, minY: minY, maxX: maxX, maxY: maxY }; } }, @@ -279,7 +279,7 @@ BI.GridView = BI.inherit(BI.Widget, { }, _populate: function (items) { - var self = this, o = this.options; + var o = this.options; this._reRange(); if (items && items !== this.options.items) { this.options.items = items; @@ -333,7 +333,7 @@ BI.GridView = BI.inherit(BI.Widget, { if (this.options.overflowX !== !!b) { this.options.overflowX = !!b; BI.nextTick(function () { - self.element.css({overflowX: b ? "auto" : "hidden"}); + self.element.css({ overflowX: b ? "auto" : "hidden" }); }); } }, @@ -343,7 +343,7 @@ BI.GridView = BI.inherit(BI.Widget, { if (this.options.overflowY !== !!b) { this.options.overflowY = !!b; BI.nextTick(function () { - self.element.css({overflowY: b ? "auto" : "hidden"}); + self.element.css({ overflowY: b ? "auto" : "hidden" }); }); } }, @@ -398,7 +398,7 @@ BI.GridView = BI.inherit(BI.Widget, { this.restore(); } this._populate(items); - } + }, }); BI.GridView.EVENT_SCROLL = "EVENT_SCROLL"; BI.shortcut("bi.grid_view", BI.GridView); diff --git a/src/base/layer/__test__/layer.popover.test.js b/src/base/layer/__test__/layer.popover.test.js index 1830744a8..d9766f823 100644 --- a/src/base/layer/__test__/layer.popover.test.js +++ b/src/base/layer/__test__/layer.popover.test.js @@ -5,7 +5,6 @@ */ describe("PopoverTest", function () { - /** * test_author_windy */ @@ -17,12 +16,12 @@ describe("PopoverTest", function () { size: "normal", header: { type: "bi.label", - text: "这个是header" + text: "这个是header", }, body: { type: "bi.label", - text: "这个是body" - } + text: "这个是body", + }, }).open(id); BI.delay(function () { expect(BI.Widget._renderEngine.createElement("body").find(".bi-popup-view .bi-z-index-mask").length).to.equal(1); @@ -30,4 +29,4 @@ describe("PopoverTest", function () { done(); }, 100); }); -}); \ No newline at end of file +}); diff --git a/src/base/layer/layer.drawer.js b/src/base/layer/layer.drawer.js index e62c272dc..23ef8b8c5 100644 --- a/src/base/layer/layer.drawer.js +++ b/src/base/layer/layer.drawer.js @@ -7,7 +7,7 @@ BI.Drawer = BI.inherit(BI.Widget, { SIZE: { SMALL: "small", NORMAL: "normal", - BIG: "big" + BIG: "big", }, props: { baseCls: "bi-drawer bi-card", @@ -19,7 +19,7 @@ BI.Drawer = BI.inherit(BI.Widget, { closable: true, // BI-40839 是否显示右上角的关闭按钮 bodyHgap: 20, bodyTgap: 10, - bodyBgap: 10 + bodyBgap: 10, }, render: function () { @@ -33,20 +33,20 @@ BI.Drawer = BI.inherit(BI.Widget, { type: "bi.absolute", items: [{ el: BI.isPlainObject(o.header) ? BI.extend({}, o.header, { - extraCls: "bi-font-bold" + extraCls: "bi-font-bold", }) : { type: "bi.label", cls: "bi-font-bold", height: o.headerHeight, text: o.header, title: o.header, - textAlign: "left" + textAlign: "left", }, left: 20, top: 0, right: 0, - bottom: 0 - }] + bottom: 0, + }], }, { el: o.closable ? { type: "bi.icon_button", @@ -54,15 +54,15 @@ BI.Drawer = BI.inherit(BI.Widget, { height: o.headerHeight, handler: function () { self.close(); - } + }, } : { - type: "bi.layout" + type: "bi.layout", }, - width: 56 + width: 56, }], - height: o.headerHeight + height: o.headerHeight, }, - height: o.headerHeight + height: o.headerHeight, }, { el: { type: "bi.vertical", @@ -72,17 +72,17 @@ BI.Drawer = BI.inherit(BI.Widget, { self.body = this; }, items: [{ - el: o.body - }] + el: o.body, + }], }, hgap: o.bodyHgap, tgap: o.bodyTgap, - bgap: o.bodyBgap + bgap: o.bodyBgap, }]; return BI.extend({ type: "bi.vtape", - items: items + items: items, }, this._getSuitableSize()); }, @@ -103,12 +103,12 @@ BI.Drawer = BI.inherit(BI.Widget, { } if (o.placement === "top" || o.placement === "bottom") { return { - height: o.height || size + height: o.height || size, }; } if (o.placement === "left" || o.placement === "right") { return { - width: o.width || size + width: o.width || size, }; } }, @@ -120,30 +120,32 @@ BI.Drawer = BI.inherit(BI.Widget, { self.element.css({ top: 0, left: "100%", - bottom: 0 + bottom: 0, }); break; case "left": self.element.css({ top: 0, right: "100%", - bottom: 0 + bottom: 0, }); break; case "top": self.element.css({ left: 0, right: 0, - bottom: "100%" + bottom: "100%", }); break; case "bottom": self.element.css({ left: 0, right: 0, - top: "100%" + top: "100%", }); break; + default: + break; } }, @@ -154,24 +156,26 @@ BI.Drawer = BI.inherit(BI.Widget, { switch (o.placement) { case "right": self.element.css({ - transform: "translateX(-" + size.width + "px)" + left: "calc(100% - " + size.width + "px)", }); break; case "left": self.element.css({ - transform: "translateX(" + size.width + "px)" + right: "calc(100% - " + size.width + "px)", }); break; case "top": self.element.css({ - transform: "translateY(" + size.height + "px)" + bottom: "calc(100% - " + size.height + "px)", }); break; case "bottom": self.element.css({ - transform: "translateY(-" + size.height + "px)" + top: "calc(100% - " + size.height + "px)", }); break; + default: + break; } callback && callback(); }); @@ -182,17 +186,27 @@ BI.Drawer = BI.inherit(BI.Widget, { requestAnimationFrame(function () { switch (o.placement) { case "right": + self.element.css({ + left: "100%", + }); + break; case "left": self.element.css({ - transform: "translateX(0px)" + right: "100%", }); break; case "top": + self.element.css({ + bottom: "100%", + }); + break; case "bottom": self.element.css({ - transform: "translateY(0px)" + top: "100%", }); break; + default: + break; } setTimeout(callback, 300); }); @@ -213,11 +227,11 @@ BI.Drawer = BI.inherit(BI.Widget, { }, setZindex: function (zindex) { - this.element.css({"z-index": zindex}); + this.element.css({ "z-index": zindex }); }, destroyed: function () { - } + }, }); BI.shortcut("bi.drawer", BI.Drawer); diff --git a/src/base/layer/layer.popover.js b/src/base/layer/layer.popover.js index bce738ef3..2a4453472 100644 --- a/src/base/layer/layer.popover.js +++ b/src/base/layer/layer.popover.js @@ -8,9 +8,9 @@ BI.Popover = BI.inherit(BI.Widget, { SIZE: { SMALL: "small", NORMAL: "normal", - BIG: "big" + BIG: "big", }, - MAX_HEIGHT: 600 + MAX_HEIGHT: 600, }, props: function () { @@ -18,7 +18,7 @@ BI.Popover = BI.inherit(BI.Widget, { baseCls: "bi-popover bi-card bi-border-radius", size: "normal", // small, normal, big logic: { - dynamic: false + dynamic: false, }, header: null, headerHeight: 40, @@ -27,7 +27,7 @@ BI.Popover = BI.inherit(BI.Widget, { footerHeight: 44, closable: true, // BI-40839 是否显示右上角的关闭按钮 bodyHgap: BI.SIZE_CONSANTS.H_GAP_SIZE, - bodyTgap: BI.SIZE_CONSANTS.V_GAP_SIZE + bodyTgap: BI.SIZE_CONSANTS.V_GAP_SIZE, }; }, @@ -45,11 +45,11 @@ BI.Popover = BI.inherit(BI.Widget, { self.startY += deltaY; self.element.css({ left: BI.clamp(self.startX, 0, W - self.element.width()) + "px", - top: BI.clamp(self.startY, 0, H - self.element.height()) + "px" + top: BI.clamp(self.startY, 0, H - self.element.height()) + "px", }); // BI-12134 没有什么特别好的方法 BI.Resizers._resize({ - target: self.element[0] + target: self.element[0], }); }, function () { self.tracker.releaseMouseMoves(); @@ -66,21 +66,21 @@ BI.Popover = BI.inherit(BI.Widget, { }, items: [{ el: BI.isPlainObject(o.header) ? BI.extend({}, o.header, { - extraCls: "bi-font-bold" + extraCls: "bi-font-bold", }) : { type: "bi.label", cls: "bi-font-bold", height: o.headerHeight, text: o.header, title: o.header, - textAlign: "left" + textAlign: "left", }, top: 0, bottom: 0, left: BI.SIZE_CONSANTS.H_GAP_SIZE, - right: o.closable ? 0 : BI.SIZE_CONSANTS.H_GAP_SIZE - }] - } + right: o.closable ? 0 : BI.SIZE_CONSANTS.H_GAP_SIZE, + }], + }, }, o.closable ? { el: { type: "bi.icon_button", @@ -88,13 +88,13 @@ BI.Popover = BI.inherit(BI.Widget, { height: o.headerHeight, handler: function () { self.close(); - } + }, }, - width: 56 + width: 56, } : null], - height: o.headerHeight + height: o.headerHeight, }, - height: o.headerHeight + height: o.headerHeight, }, o.logic.dynamic ? { el: { type: "bi.vertical", @@ -105,14 +105,14 @@ BI.Popover = BI.inherit(BI.Widget, { }, css: { "max-height": this._getSuitableBodyHeight(c.MAX_HEIGHT - o.headerHeight - (o.footer ? o.footerHeight : 0) - o.bodyTgap), - "min-height": this._getSuitableBodyHeight(size.height - o.headerHeight - (o.footer ? o.footerHeight : 0) - o.bodyTgap) + "min-height": this._getSuitableBodyHeight(size.height - o.headerHeight - (o.footer ? o.footerHeight : 0) - o.bodyTgap), }, items: [{ - el: o.body + el: o.body, }], hgap: o.bodyHgap, - tgap: o.bodyTgap - } + tgap: o.bodyTgap, + }, } : { el: { type: "bi.absolute", @@ -121,9 +121,9 @@ BI.Popover = BI.inherit(BI.Widget, { left: o.bodyHgap, top: o.bodyTgap, right: o.bodyHgap, - bottom: 0 - }] - } + bottom: 0, + }], + }, }]; if (o.footer) { items.push({ @@ -134,41 +134,39 @@ BI.Popover = BI.inherit(BI.Widget, { left: BI.SIZE_CONSANTS.H_GAP_SIZE, top: 0, right: BI.SIZE_CONSANTS.H_GAP_SIZE, - bottom: 0 + bottom: 0, }], - height: o.footerHeight + height: o.footerHeight, }, - height: o.footerHeight + height: o.footerHeight, }); } return BI.extend({ items: items, - width: this._getSuitableWidth(size.width) + width: this._getSuitableWidth(size.width), }, o.logic.dynamic ? { type: "bi.vertical", - scrolly: false + scrolly: false, } : { type: "bi.vtape", - height: this._getSuitableHeight(size.height) + height: this._getSuitableHeight(size.height), }); }, // mounted之后绑定事件 mounted: function () { var self = this; - var o = this.options; this.dragger.element.mousedown(function (e) { - var pos = self.element.offset(); - self.startX = pos.left; - self.startY = pos.top; + self.startX = self.element[0].offsetLeft; + self.startY = self.element[0].offsetTop; self.tracker.captureMouseMoves(e); }); }, _getSuitableBodyHeight: function (height) { var o = this.options; - var c = this._constant; + return BI.clamp(height, 0, BI.Widget._renderEngine.createElement("body")[0].clientHeight - o.headerHeight - (o.footer ? o.footerHeight : 0) - o.bodyTgap); }, @@ -205,7 +203,7 @@ BI.Popover = BI.inherit(BI.Widget, { return { width: o.width || size.width, height: o.height || size.height, - type: size.type || "default" + type: size.type || "default", }; }, @@ -224,11 +222,11 @@ BI.Popover = BI.inherit(BI.Widget, { }, setZindex: function (zindex) { - this.element.css({"z-index": zindex}); + this.element.css({ "z-index": zindex }); }, destroyed: function () { - } + }, }); BI.shortcut("bi.popover", BI.Popover); @@ -236,7 +234,7 @@ BI.shortcut("bi.popover", BI.Popover); BI.BarPopover = BI.inherit(BI.Popover, { _defaultConfig: function () { return BI.extend(BI.BarPopover.superclass._defaultConfig.apply(this, arguments), { - btns: [BI.i18nText("BI-Basic_OK"), BI.i18nText("BI-Basic_Cancel")] + btns: [BI.i18nText("BI-Basic_OK"), BI.i18nText("BI-Basic_Cancel")], }); }, @@ -254,7 +252,7 @@ BI.BarPopover = BI.inherit(BI.Popover, { handler: function (v) { self.fireEvent(BI.Popover.EVENT_CANCEL, v); self.close(v); - } + }, }, { type: "bi.button", text: this.options.btns[0], @@ -263,10 +261,10 @@ BI.BarPopover = BI.inherit(BI.Popover, { handler: function (v) { self.fireEvent(BI.Popover.EVENT_CONFIRM, v); self.close(v); - } - }] + }, + }], }); - } + }, }); BI.shortcut("bi.bar_popover", BI.BarPopover); diff --git a/src/base/layer/layer.popup.js b/src/base/layer/layer.popup.js index 8e747d24f..ef7d55749 100644 --- a/src/base/layer/layer.popup.js +++ b/src/base/layer/layer.popup.js @@ -5,7 +5,7 @@ */ BI.PopupView = BI.inherit(BI.Widget, { _const: { - TRIANGLE_LENGTH: 12 + TRIANGLE_LENGTH: 12, }, _defaultConfig: function (props) { return BI.extend(BI.PopupView.superclass._defaultConfig.apply(this, arguments), { @@ -29,7 +29,7 @@ BI.PopupView = BI.inherit(BI.Widget, { stopEvent: false, // 是否停止mousedown、mouseup事件 stopPropagation: false, // 是否停止mousedown、mouseup向上冒泡 logic: { - dynamic: true + dynamic: true, }, tool: false, // 自定义工具栏 @@ -42,30 +42,32 @@ BI.PopupView = BI.inherit(BI.Widget, { chooseType: 0, behaviors: {}, layouts: [{ - type: "bi.vertical" - }] - } + type: "bi.vertical", + }], + }, }); }, render: function () { var self = this, o = this.options; - var fn = function (e) { + function fn (e) { e.stopPropagation(); - }, stop = function (e) { + } + function stop (e) { e.stopEvent(); + return false; - }; + } this.element.css({ "z-index": BI.zIndex_popup, "min-width": BI.isNumeric(o.minWidth) ? (o.minWidth / BI.pixRatio + BI.pixUnit) : o.minWidth, - "max-width": BI.isNumeric(o.maxWidth) ? (o.maxWidth / BI.pixRatio + BI.pixUnit) : o.maxWidth - }).bind({click: fn}); + "max-width": BI.isNumeric(o.maxWidth) ? (o.maxWidth / BI.pixRatio + BI.pixUnit) : o.maxWidth, + }).bind({ click: fn }); this.element.bind("mousewheel", fn); - o.stopPropagation && this.element.bind({mousedown: fn, mouseup: fn, mouseover: fn}); - o.stopEvent && this.element.bind({mousedown: stop, mouseup: stop, mouseover: stop}); + o.stopPropagation && this.element.bind({ mousedown: fn, mouseup: fn, mouseover: fn }); + o.stopEvent && this.element.bind({ mousedown: stop, mouseup: stop, mouseover: stop }); this.tool = this._createTool(); this.tab = this._createTab(); this.view = this._createView(); @@ -79,7 +81,7 @@ BI.PopupView = BI.inherit(BI.Widget, { }); BI.createWidget(BI.extend({ - element: this + element: this, }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { scrolly: false, lgap: o.lgap, @@ -89,11 +91,11 @@ BI.PopupView = BI.inherit(BI.Widget, { vgap: o.vgap, hgap: o.hgap, items: BI.LogicFactory.createLogicItemsByDirection(o.direction, BI.extend({ - cls: "list-view-outer bi-card list-view-shadow" + (o.primary ? " bi-primary" : "") + cls: "list-view-outer bi-card list-view-shadow" + (o.primary ? " bi-primary" : ""), }, BI.LogicFactory.createLogic(BI.LogicFactory.createLogicTypeByDirection(o.direction), BI.extend({}, o.logic, { - items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tool, this.tab, this.view, this.toolbar) + items: BI.LogicFactory.createLogicItemsByDirection(o.direction, this.tool, this.tab, this.view, this.toolbar), }))) - ) + ), })))); if (o.showArrow) { this.arrow = BI.createWidget({ @@ -101,19 +103,19 @@ BI.PopupView = BI.inherit(BI.Widget, { cls: "bi-bubble-arrow", items: [{ type: "bi.layout", - cls: "bubble-arrow" - }] + cls: "bubble-arrow", + }], }); this.arrowWrapper = BI.createWidget({ type: "bi.absolute", cls: "bi-bubble-arrow-wrapper", items: [{ el: this.arrow, - }] + }], }); // 因为三角符号的原因位置变大了,需要占位 this.placeholder = BI.createWidget({ - type: "bi.layout" + type: "bi.layout", }); BI.createWidget({ type: "bi.absolute", @@ -123,22 +125,23 @@ BI.PopupView = BI.inherit(BI.Widget, { left: 0, top: 0, }, { - el: this.placeholder - }] + el: this.placeholder, + }], }); } }, _createView: function () { var o = this.options; - this.button_group = BI.createWidget(o.el, {type: "bi.button_group", value: o.value}); + this.button_group = BI.createWidget(o.el, { type: "bi.button_group", value: o.value }); this.button_group.element.css({ "min-height": BI.isNumeric(o.minHeight) ? (o.minHeight / BI.pixRatio + BI.pixUnit) : o.minHeight, "padding-top": o.innerVgap / BI.pixRatio + BI.pixUnit, "padding-bottom": o.innerVgap / BI.pixRatio + BI.pixUnit, "padding-left": o.innerHgap / BI.pixRatio + BI.pixUnit, - "padding-right": o.innerHgap / BI.pixRatio + BI.pixUnit + "padding-right": o.innerHgap / BI.pixRatio + BI.pixUnit, }); + return this.button_group; }, @@ -147,6 +150,7 @@ BI.PopupView = BI.inherit(BI.Widget, { if (false === o.tool) { return; } + return BI.createWidget(o.tool); }, @@ -155,12 +159,13 @@ BI.PopupView = BI.inherit(BI.Widget, { if (o.tabs.length === 0) { return; } + return BI.createWidget({ type: "bi.center", cls: "list-view-tab", height: 25, items: o.tabs, - value: o.value + value: o.value, }); }, @@ -177,8 +182,8 @@ BI.PopupView = BI.inherit(BI.Widget, { items: BI.createItems(o.buttons, { once: false, shadow: true, - isShadowShowingOnSelected: true - }) + isShadowShowingOnSelected: true, + }), }); }, @@ -212,7 +217,7 @@ BI.PopupView = BI.inherit(BI.Widget, { direction = "bottom"; style = { // 5表示留出一定的空间 - left: BI.clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft) + left: BI.clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft), }; wrapperStyle = { top: o.tgap + o.vgap, @@ -225,13 +230,13 @@ BI.PopupView = BI.inherit(BI.Widget, { right: 0, height: this._const.TRIANGLE_LENGTH, top: -this._const.TRIANGLE_LENGTH, - bottom: "" + bottom: "", }; break; case "bottom,left": direction = "bottom"; style = { - right: BI.clamp(((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8, minRight, maxRight) + right: BI.clamp(((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8, minRight, maxRight), }; wrapperStyle = { top: o.bgap + o.vgap, @@ -244,14 +249,14 @@ BI.PopupView = BI.inherit(BI.Widget, { right: 0, height: this._const.TRIANGLE_LENGTH, top: -this._const.TRIANGLE_LENGTH, - bottom: "" + bottom: "", }; break; case "top": case "top,right": direction = "top"; style = { - left: BI.clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft) + left: BI.clamp(((middle ? popupWidth : position.width) - adjustXOffset) / 2 - 8, minLeft, maxLeft), }; wrapperStyle = { bottom: o.bgap + o.vgap, @@ -270,7 +275,7 @@ BI.PopupView = BI.inherit(BI.Widget, { case "top,left": direction = "top"; style = { - right: BI.clamp(((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8, minRight, maxRight) + right: BI.clamp(((middle ? popupWidth : position.width) + adjustXOffset) / 2 - 8, minRight, maxRight), }; wrapperStyle = { bottom: o.bgap + o.vgap, @@ -290,7 +295,7 @@ BI.PopupView = BI.inherit(BI.Widget, { case "left,bottom": direction = "left"; style = { - top: BI.clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop) + top: BI.clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop), }; wrapperStyle = { right: o.rgap + o.hgap, @@ -303,13 +308,13 @@ BI.PopupView = BI.inherit(BI.Widget, { bottom: 0, width: this._const.TRIANGLE_LENGTH, right: -this._const.TRIANGLE_LENGTH, - left: "" + left: "", }; break; case "left,top": direction = "left"; style = { - bottom: BI.clamp(((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8, minBottom, maxBottom) + bottom: BI.clamp(((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8, minBottom, maxBottom), }; wrapperStyle = { right: o.rgap + o.hgap, @@ -322,14 +327,14 @@ BI.PopupView = BI.inherit(BI.Widget, { bottom: 0, width: this._const.TRIANGLE_LENGTH, right: -this._const.TRIANGLE_LENGTH, - left: "" + left: "", }; break; case "right": case "right,bottom": direction = "right"; style = { - top: BI.clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop) + top: BI.clamp(((middle ? popupHeight : position.height) - adjustYOffset) / 2 - 8, minTop, maxTop), }; wrapperStyle = { left: o.lgap + o.hgap, @@ -342,13 +347,13 @@ BI.PopupView = BI.inherit(BI.Widget, { bottom: 0, width: this._const.TRIANGLE_LENGTH, left: -this._const.TRIANGLE_LENGTH, - right: "" + right: "", }; break; case "right,top": direction = "right"; style = { - bottom: BI.clamp(((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8, minBottom, maxBottom) + bottom: BI.clamp(((middle ? popupHeight : position.height) + adjustYOffset) / 2 - 8, minBottom, maxBottom), }; wrapperStyle = { left: o.lgap + o.hgap, @@ -361,7 +366,7 @@ BI.PopupView = BI.inherit(BI.Widget, { bottom: 0, width: this._const.TRIANGLE_LENGTH, left: -this._const.TRIANGLE_LENGTH, - right: "" + right: "", }; break; case "right,innerRight": @@ -372,8 +377,15 @@ BI.PopupView = BI.inherit(BI.Widget, { break; case "innerLeft": break; + default: + break; } - this.element.removeClass("left").removeClass("right").removeClass("top").removeClass("bottom").addClass(direction); + this.element + .removeClass("left") + .removeClass("right") + .removeClass("top") + .removeClass("bottom") + .addClass(direction); this.arrow.element.css(style); this.arrowWrapper.element.css(wrapperStyle); this.placeholder.element.css(placeholderStyle); @@ -399,7 +411,7 @@ BI.PopupView = BI.inherit(BI.Widget, { toolHeight = ((this.tool && this.tool.attr("height")) || 24) * ((this.tool && this.tool.isVisible()) ? 1 : 0); var resetHeight = h - tbHeight - tabHeight - toolHeight - 2 * this.options.innerVgap; this.view.resetHeight ? this.view.resetHeight(resetHeight) : - this.view.element.css({"max-height": resetHeight / BI.pixRatio + BI.pixUnit}); + this.view.element.css({ "max-height": resetHeight / BI.pixRatio + BI.pixUnit }); }, setValue: function (selectedValues) { @@ -409,7 +421,7 @@ BI.PopupView = BI.inherit(BI.Widget, { getValue: function () { return this.view.getValue(); - } + }, }); BI.PopupView.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.popup_view", BI.PopupView); diff --git a/src/base/layer/layer.searcher.js b/src/base/layer/layer.searcher.js index 12867ed93..b9d8d2b41 100644 --- a/src/base/layer/layer.searcher.js +++ b/src/base/layer/layer.searcher.js @@ -9,35 +9,36 @@ BI.SearcherView = BI.inherit(BI.Pane, { _defaultConfig: function () { var conf = BI.SearcherView.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-searcher-view bi-card", tipText: BI.i18nText("BI-No_Select"), chooseType: BI.Selection.Single, - matcher: {// 完全匹配的构造器 + matcher: { // 完全匹配的构造器 type: "bi.button_group", behaviors: { redmark: function () { return true; - } + }, }, items: [], layouts: [{ - type: "bi.vertical" - }] + type: "bi.vertical", + }], }, searcher: { type: "bi.button_group", behaviors: { redmark: function () { return true; - } + }, }, items: [], layouts: [{ - type: "bi.vertical" - }] - } + type: "bi.vertical", + }], + }, }); }, @@ -50,12 +51,12 @@ BI.SearcherView = BI.inherit(BI.Pane, { behaviors: { redmark: function () { return true; - } + }, }, layouts: [{ - type: "bi.vertical" + type: "bi.vertical", }], - value: o.value + value: o.value, }); this.matcher.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -70,8 +71,8 @@ BI.SearcherView = BI.inherit(BI.Pane, { items: [{ type: "bi.layout", height: 1, - cls: "searcher-view-spliter bi-background" - }] + cls: "searcher-view-spliter bi-background", + }], }); this.searcher = BI.createWidget(o.searcher, { type: "bi.button_group", @@ -79,12 +80,12 @@ BI.SearcherView = BI.inherit(BI.Pane, { behaviors: { redmark: function () { return true; - } + }, }, layouts: [{ - type: "bi.vertical" + type: "bi.vertical", }], - value: o.value + value: o.value, }); this.searcher.on(BI.Controller.EVENT_CHANGE, function (type, val, ob) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -96,7 +97,7 @@ BI.SearcherView = BI.inherit(BI.Pane, { BI.createWidget({ type: "bi.vertical", element: this, - items: [this.matcher, this.spliter, this.searcher] + items: [this.matcher, this.spliter, this.searcher], }); }, @@ -133,7 +134,7 @@ BI.SearcherView = BI.inherit(BI.Pane, { hasMatched: function () { return this.matcher.getAllButtons().length > 0; - } + }, }); BI.SearcherView.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/list/__test__/listview.test.js b/src/base/list/__test__/listview.test.js index 4be8993c5..0f35c711e 100644 --- a/src/base/list/__test__/listview.test.js +++ b/src/base/list/__test__/listview.test.js @@ -6,7 +6,6 @@ // TODO 展示类控件测什么没想好标记一下 describe("ListView && VirtualList", function () { - /** * test_author_windy */ @@ -14,16 +13,16 @@ describe("ListView && VirtualList", function () { var a = BI.Test.createWidget({ type: "bi.list_view", el: { - type: "bi.left" + type: "bi.left", }, items: BI.map(BI.range(0, 100), function (i, item) { return BI.extend({}, item, { type: "bi.label", width: 200, height: 200, - text: (i + 1) + text: (i + 1), }); - }) + }), }); a.destroy(); }); @@ -39,10 +38,10 @@ describe("ListView && VirtualList", function () { return BI.extend({}, item, { type: "bi.label", height: 30, - text: (i + 1) + "." + item.text + text: (i + 1) + "." + item.text, }); - }) + }), }); a.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/list/listview.js b/src/base/list/listview.js index 65f777a99..7028132bc 100644 --- a/src/base/list/listview.js +++ b/src/base/list/listview.js @@ -16,18 +16,18 @@ BI.ListView = BI.inherit(BI.Widget, { items: [], itemFormatter: function (item, index) { return item; - } + }, }; }, init: function () { - var self = this; this.renderedIndex = -1; this.cache = {}; }, render: function () { var self = this, o = this.options; + return { type: "bi.vertical", items: [BI.extend({ @@ -35,9 +35,9 @@ BI.ListView = BI.inherit(BI.Widget, { scrolly: false, ref: function (_ref) { self.container = _ref; - } + }, }, o.el)], - element: this + element: this, }; }, @@ -72,10 +72,13 @@ BI.ListView = BI.inherit(BI.Widget, { var index = (this.cache[this.renderedIndex] && (this.cache[this.renderedIndex].index + o.blockSize)) || 0; var cnt = this.renderedIndex + 1; var lastHeight; - var getElementHeight = function () { + + function getElementHeight() { return self.container.element.height(); - }; - while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { + } + + lastHeight = getElementHeight(); + while ((lastHeight) < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items.map(function (item, i) { return o.itemFormatter(item, index + i); @@ -84,16 +87,16 @@ BI.ListView = BI.inherit(BI.Widget, { this.cache[cnt] = { index: index, scrollTop: lastHeight, - height: addedHeight + height: addedHeight, }; this.renderedIndex = cnt; cnt++; index += o.blockSize; + lastHeight = getElementHeight(); } }, _calculateBlocksToRender: function () { - var o = this.options; this._renderMoreIf(); }, @@ -127,7 +130,7 @@ BI.ListView = BI.inherit(BI.Widget, { destroyed: function () { this.restore(); - } + }, }); BI.shortcut("bi.list_view", BI.ListView); diff --git a/src/base/list/virtualgrouplist.js b/src/base/list/virtualgrouplist.js index cb8d1b533..a1836ba94 100644 --- a/src/base/list/virtualgrouplist.js +++ b/src/base/list/virtualgrouplist.js @@ -17,7 +17,7 @@ BI.VirtualGroupList = BI.inherit(BI.Widget, { el: {}, itemFormatter: function (item, index) { return item; - } + }, }; }, @@ -27,13 +27,14 @@ BI.VirtualGroupList = BI.inherit(BI.Widget, { render: function () { var self = this, o = this.options; + return { type: "bi.vertical", items: [{ type: "bi.layout", ref: function () { self.topBlank = this; - } + }, }, { type: "bi.virtual_group", height: o.rowHeight * o.items.length, @@ -42,15 +43,15 @@ BI.VirtualGroupList = BI.inherit(BI.Widget, { }, layouts: [BI.extend({ type: "bi.vertical", - scrolly: false - }, o.el)] + scrolly: false, + }, o.el)], }, { type: "bi.layout", ref: function () { self.bottomBlank = this; - } + }, }], - element: this + element: this, }; }, @@ -87,10 +88,11 @@ BI.VirtualGroupList = BI.inherit(BI.Widget, { var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.renderedIndex + 1) * o.blockSize, cnt = this.renderedIndex + 1; var lastHeight; - var getElementHeight = function () { + function getElementHeight () { return self.container.element.height() + self.topBlank.element.height() + self.bottomBlank.element.height(); - }; - while ((lastHeight = this.renderedIndex === -1 ? 0 : getElementHeight()) < minContentHeight && index < o.items.length) { + } + lastHeight = this.renderedIndex === -1 ? 0 : getElementHeight(); + while (lastHeight < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container[self.renderedIndex === -1 ? "populate" : "addItems"](items.map(function (item, i) { return o.itemFormatter(item, index + i); @@ -100,6 +102,7 @@ BI.VirtualGroupList = BI.inherit(BI.Widget, { this.renderedIndex = cnt; cnt++; index += o.blockSize; + lastHeight = this.renderedIndex === -1 ? 0 : getElementHeight(); } }, @@ -176,7 +179,7 @@ BI.VirtualGroupList = BI.inherit(BI.Widget, { populate: function (items) { this._populate(items); - } + }, }); BI.shortcut("bi.virtual_group_list", BI.VirtualGroupList); diff --git a/src/base/list/virtuallist.js b/src/base/list/virtuallist.js index d5881b30b..2715008cb 100644 --- a/src/base/list/virtuallist.js +++ b/src/base/list/virtuallist.js @@ -15,36 +15,36 @@ BI.VirtualList = BI.inherit(BI.Widget, { items: [], itemFormatter: function (item, index) { return item; - } + }, }; }, init: function () { - var self = this; this.renderedIndex = -1; this.cache = {}; }, render: function () { - var self = this, o = this.options; + var self = this; + return { type: "bi.vertical", items: [{ type: "bi.layout", ref: function () { self.topBlank = this; - } + }, }, { type: "bi.vertical", scrolly: false, ref: function () { self.container = this; - } + }, }, { type: "bi.layout", ref: function () { self.bottomBlank = this; - } + }, }], }; }, @@ -71,10 +71,11 @@ BI.VirtualList = BI.inherit(BI.Widget, { var minContentHeight = o.scrollTop + height + o.overscanHeight; var index = (this.renderedIndex + 1) * o.blockSize, cnt = this.renderedIndex + 1; var lastHeight; - var getElementHeight = function () { + function getElementHeight() { return self.container.element.height() + self.topBlank.element.height() + self.bottomBlank.element.height(); - }; - while ((lastHeight = getElementHeight()) < minContentHeight && index < o.items.length) { + } + lastHeight = getElementHeight(); + while (lastHeight < minContentHeight && index < o.items.length) { var items = o.items.slice(index, index + o.blockSize); this.container.addItems(items.map(function (item, i) { return o.itemFormatter(item, index + i); @@ -84,6 +85,7 @@ BI.VirtualList = BI.inherit(BI.Widget, { this.renderedIndex = cnt; cnt++; index += o.blockSize; + lastHeight = getElementHeight(); } }, @@ -202,7 +204,7 @@ BI.VirtualList = BI.inherit(BI.Widget, { destroyed: function () { this.cache = {}; this.renderedIndex = -1; - } + }, }); BI.shortcut("bi.virtual_list", BI.VirtualList); diff --git a/src/base/pager/pager.js b/src/base/pager/pager.js index 64ea9a942..129db1b8d 100644 --- a/src/base/pager/pager.js +++ b/src/base/pager/pager.js @@ -13,7 +13,7 @@ BI.Pager = BI.inherit(BI.Widget, { layouts: [{ type: "bi.horizontal", hgap: 10, - vgap: 0 + vgap: 0, }], dynamicShow: true, // 是否动态显示上一页、下一页、首页、尾页, 若为false,则指对其设置使能状态 @@ -36,12 +36,11 @@ BI.Pager = BI.inherit(BI.Widget, { return 1; }, hasPrev: BI.emptyFn, // pages不可用时有效 - hasNext: BI.emptyFn // pages不可用时有效 + hasNext: BI.emptyFn, // pages不可用时有效 }); }, render: function () { - var self = this; this.currPage = BI.result(this.options, "curr"); // 翻页太灵敏 // this._lock = false; @@ -79,13 +78,13 @@ BI.Pager = BI.inherit(BI.Widget, { view.push({ text: prev, value: "prev", - disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false) + disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false), }); } else { view.push({ el: BI.extend({ - disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false) - }, prev) + disabled: pages === false ? o.hasPrev(curr) === false : !(curr > 1 && prev !== false), + }, prev), }); } } @@ -95,13 +94,13 @@ BI.Pager = BI.inherit(BI.Widget, { view.push({ text: first, value: "first", - disabled: !(dict.index > 1 && groups !== 0) + disabled: !(dict.index > 1 && groups !== 0), }); if (dict.index > 1 && groups !== 0 && groups !== pages - 1) { view.push({ type: "bi.label", cls: "page-ellipsis", - text: "\u2026" + text: "\u2026", }); } } @@ -127,12 +126,12 @@ BI.Pager = BI.inherit(BI.Widget, { view.push({ text: s, value: s, - selected: true + selected: true, }); } else { view.push({ text: s, - value: s + value: s, }); } } @@ -143,13 +142,13 @@ BI.Pager = BI.inherit(BI.Widget, { view.push({ type: "bi.label", cls: "page-ellipsis", - text: "\u2026" + text: "\u2026", }); } view.push({ text: last, value: "last", - disabled: !(pages > groups && dict.end < pages && groups !== 0) + disabled: !(pages > groups && dict.end < pages && groups !== 0), }); } @@ -171,8 +170,8 @@ BI.Pager = BI.inherit(BI.Widget, { return { el: BI.extend({ - disabled: pages === false ? o.hasNext(curr) === false : !(curr !== pages && next || dict.flow) - }, next) + disabled: pages === false ? o.hasNext(curr) === false : !(curr !== pages && next || dict.flow), + }, next), }; }())); } @@ -185,13 +184,13 @@ BI.Pager = BI.inherit(BI.Widget, { cls: "bi-list-item-select bi-border-radius", height: 23, hgap: v.el ? 0 : 10, - stopPropagation: true + stopPropagation: true, }, BI.stripEL(v)); return BI.formatEL(v); }), behaviors: o.behaviors, - layouts: o.layouts + layouts: o.layouts, }); this.button_group.on(BI.Controller.EVENT_CHANGE, function (type, value, obj) { // if (self._lock === true) { @@ -220,7 +219,7 @@ BI.Pager = BI.inherit(BI.Widget, { } o.jump.apply(self, [{ pages: pages, - curr: self.currPage + curr: self.currPage, }]); self._populate(); self.fireEvent(BI.Pager.EVENT_CHANGE, obj); @@ -293,7 +292,7 @@ BI.Pager = BI.inherit(BI.Widget, { populate: function () { this._populate(); - } + }, }); BI.Pager.EVENT_CHANGE = "EVENT_CHANGE"; BI.Pager.EVENT_AFTER_POPULATE = "EVENT_AFTER_POPULATE"; diff --git a/src/base/single/0.single.js b/src/base/single/0.single.js index 47dc6718f..e271cb5ad 100644 --- a/src/base/single/0.single.js +++ b/src/base/single/0.single.js @@ -15,13 +15,14 @@ var delayingTooltips; BI.Single = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.Single.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { readonly: false, title: null, warningTitle: null, tipType: null, // success或warning - belowMouse: false, // title是否跟随鼠标 - enableHover: false + belowMouse: false, // title是否跟随鼠标 + enableHover: false, }); }, @@ -70,7 +71,7 @@ BI.Single = BI.inherit(BI.Widget, { || BI.isFunction(o.title) || BI.isFunction(o.warningTitle)) { this.enableHover({ belowMouse: o.belowMouse, - container: o.container + container: o.container, }); } }, @@ -136,7 +137,6 @@ BI.Single = BI.inherit(BI.Widget, { } } }, 500); - }); this.element.on("mouseleave.title" + this.getName(), function (e) { self._e = null; @@ -193,6 +193,7 @@ BI.Single = BI.inherit(BI.Widget, { if (BI.isFunction(title)) { return title(); } + return title; }, @@ -201,6 +202,7 @@ BI.Single = BI.inherit(BI.Widget, { if (BI.isFunction(title)) { return title(); } + return title; }, @@ -222,6 +224,6 @@ BI.Single = BI.inherit(BI.Widget, { this.showTimeout = null; } BI.Tooltips.remove(this.getName()); - } + }, }); BI.shortcut("bi.single", BI.Single); diff --git a/src/base/single/1.text.js b/src/base/single/1.text.js index 4a22bf531..2eb0fe1df 100644 --- a/src/base/single/1.text.js +++ b/src/base/single/1.text.js @@ -19,58 +19,58 @@ tgap: 0, bgap: 0, py: "", - highLight: false + highLight: false, }, render: function () { var self = this, o = this.options; if (o.hgap + o.lgap > 0) { this.element.css({ - "padding-left": (o.hgap + o.lgap) / BI.pixRatio + BI.pixUnit + "padding-left": (o.hgap + o.lgap) / BI.pixRatio + BI.pixUnit, }); } if (o.hgap + o.rgap > 0) { this.element.css({ - "padding-right": (o.hgap + o.rgap) / BI.pixRatio + BI.pixUnit + "padding-right": (o.hgap + o.rgap) / BI.pixRatio + BI.pixUnit, }); } if (o.vgap + o.tgap > 0) { this.element.css({ - "padding-top": (o.vgap + o.tgap) / BI.pixRatio + BI.pixUnit + "padding-top": (o.vgap + o.tgap) / BI.pixRatio + BI.pixUnit, }); } if (o.vgap + o.bgap > 0) { this.element.css({ - "padding-bottom": (o.vgap + o.bgap) / BI.pixRatio + BI.pixUnit + "padding-bottom": (o.vgap + o.bgap) / BI.pixRatio + BI.pixUnit, }); } if (BI.isWidthOrHeight(o.height)) { - this.element.css({lineHeight: BI.isNumber(o.height) ? (o.height / BI.pixRatio + BI.pixUnit) : o.height}); + this.element.css({ lineHeight: BI.isNumber(o.height) ? (o.height / BI.pixRatio + BI.pixUnit) : o.height }); } if (BI.isWidthOrHeight(o.lineHeight)) { - this.element.css({lineHeight: BI.isNumber(o.lineHeight) ? (o.lineHeight / BI.pixRatio + BI.pixUnit) : o.lineHeight}); + this.element.css({ lineHeight: BI.isNumber(o.lineHeight) ? (o.lineHeight / BI.pixRatio + BI.pixUnit) : o.lineHeight }); } if (BI.isWidthOrHeight(o.maxWidth)) { - this.element.css({maxWidth: BI.isNumber(o.maxWidth) ? (o.maxWidth / BI.pixRatio + BI.pixUnit) : o.maxWidth}); + this.element.css({ maxWidth: BI.isNumber(o.maxWidth) ? (o.maxWidth / BI.pixRatio + BI.pixUnit) : o.maxWidth }); } this.element.css({ textAlign: o.textAlign, whiteSpace: this._getTextWrap(), textOverflow: o.whiteSpace === "nowrap" ? "ellipsis" : "", - overflow: o.whiteSpace === "nowrap" ? "" : (BI.isWidthOrHeight(o.height) ? "auto" : "") + overflow: o.whiteSpace === "nowrap" ? "" : (BI.isWidthOrHeight(o.height) ? "auto" : ""), }); if (o.handler && o.handler !== BI.emptyFn) { this.text = BI.createWidget({ type: "bi.layout", - tagName: "span" + tagName: "span", }); this.text.element.click(function (e) { - o.handler.call(self, self.getValue(), self, e); + !o.disabled && o.invalid && o.handler.call(self, self.getValue(), self, e); }); BI.createWidget({ type: "bi.default", element: this, - items: [this.text] + items: [this.text], }); } else { this.text = this; @@ -108,6 +108,7 @@ _getShowText: function () { var o = this.options; var text = BI.isFunction(o.text) ? o.text() : o.text; + return BI.isKey(text) ? BI.Text.formatText(text + "") : text; }, @@ -153,7 +154,7 @@ BI.Text.superclass.setText.apply(this, arguments); this.options.text = text; this._doRedMark(this.options.keyword); - } + }, }); var formatters = []; BI.Text.addTextFormatter = function (formatter) { @@ -165,6 +166,7 @@ text = formatters[i](text); } } + return text; }; BI.shortcut("bi.text", BI.Text); diff --git a/src/base/single/__test__/text.test.js b/src/base/single/__test__/text.test.js index 9549b2d7e..bea099e8d 100644 --- a/src/base/single/__test__/text.test.js +++ b/src/base/single/__test__/text.test.js @@ -2,13 +2,12 @@ * Created by windy on 2018/01/23. */ describe("TextTest", function () { - /** * test_author_windy */ it("setText", function () { var text = BI.Test.createWidget({ - type: "bi.text" + type: "bi.text", }); text.setText("AAA"); expect(text.element.text()).to.equal("AAA"); @@ -20,9 +19,9 @@ describe("TextTest", function () { */ it("setStyle", function () { var text = BI.Test.createWidget({ - type: "bi.text" + type: "bi.text", }); - text.setStyle({"color": "red"}); + text.setStyle({ "color": "red" }); expect(text.element.getStyle("color")).to.equal("rgb(255, 0, 0)"); text.destroy(); }); @@ -34,7 +33,7 @@ describe("TextTest", function () { var text = BI.Test.createWidget({ type: "bi.text", text: "AAA", - highLight: true + highLight: true, }); expect(text.element.getStyle("color")).to.equal("rgb(54, 133, 242)"); text.destroy(); @@ -47,7 +46,7 @@ describe("TextTest", function () { var text = BI.Test.createWidget({ type: "bi.text", text: "我是要标红的A", - keyword: "A" + keyword: "A", }); expect(text.element.children(".bi-keyword-red-mark").length).to.not.equal(0); text.destroy(); @@ -61,7 +60,7 @@ describe("TextTest", function () { var text = BI.Test.createWidget({ type: "bi.text", text: "AAA", - highLight: true + highLight: true, }); text.unHighLight(); expect(text.element.getStyle("color")).to.not.equal("rgb(54, 133, 242)"); @@ -75,7 +74,7 @@ describe("TextTest", function () { var text = BI.Test.createWidget({ type: "bi.text", text: "我是要标红的A", - keyword: "A" + keyword: "A", }); text.unRedMark(); expect(text.element.children(".bi-keyword-red-mark").length).to.equal(0); @@ -103,7 +102,7 @@ describe("TextTest", function () { type: "bi.text", text: "我是要标红的A", vgap: 10, - hgap: 10 + hgap: 10, }); expect(text.element.css("padding")).to.equal("10px"); text.destroy(); @@ -129,7 +128,7 @@ describe("TextTest", function () { type: "bi.text", text: "我是A", lineHeight: 12, - height: 24 + height: 24, }); expect(text.element.css("height")).to.equal("24px"); expect(text.element.css("line-height")).to.equal("12px"); @@ -145,7 +144,7 @@ describe("TextTest", function () { text: "我是A", handler: function () { text.setText("handler"); - } + }, }); BI.nextTick(function () { text.text.element.click(); @@ -162,7 +161,7 @@ describe("TextTest", function () { var text = BI.Test.createWidget({ type: "bi.text", text: "", - value: "aaaa" + value: "aaaa", }); expect(text.element.text()).to.equal(""); text.destroy(); @@ -174,7 +173,7 @@ describe("TextTest", function () { it("text的value属性1", function () { var text = BI.Test.createWidget({ type: "bi.text", - value: "aaaa" + value: "aaaa", }); expect(text.element.text()).to.equal("aaaa"); text.destroy(); @@ -187,7 +186,7 @@ describe("TextTest", function () { var text = BI.Test.createWidget({ type: "bi.text", text: null, - value: "aaaa" + value: "aaaa", }); expect(text.element.text()).to.equal(""); text.destroy(); diff --git a/src/base/single/a/__test__/a.test.js b/src/base/single/a/__test__/a.test.js index 6a78187c2..77cdd5f40 100644 --- a/src/base/single/a/__test__/a.test.js +++ b/src/base/single/a/__test__/a.test.js @@ -2,16 +2,15 @@ * Created by windy on 2018/01/23. */ describe("ALinkTest", function () { - /** * test_author_windy */ it("A初始化测试", function () { var a = BI.Test.createWidget({ type: "bi.a", - text: "CCC" + text: "CCC", }); - expect(a.element.is('a')).to.equal(true); + expect(a.element.is("a")).to.equal(true); a.destroy(); }); @@ -23,10 +22,10 @@ describe("ALinkTest", function () { type: "bi.a", text: "DDD", el: { - type: "bi.label" - } + type: "bi.label", + }, }); - expect(a.element.is('a') && a.element.hasClass("bi-label")).to.equal(true); + expect(a.element.is("a") && a.element.hasClass("bi-label")).to.equal(true); a.destroy(); }); }); diff --git a/src/base/single/a/a.js b/src/base/single/a/a.js index 2bab1ea6d..9159f0a46 100644 --- a/src/base/single/a/a.js +++ b/src/base/single/a/a.js @@ -9,25 +9,26 @@ BI.A = BI.inherit(BI.Text, { _defaultConfig: function () { var conf = BI.A.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-a display-block", href: "", target: "_blank", el: null, - tagName: "a" + tagName: "a", }); }, render: function () { var o = this.options; BI.A.superclass.render.apply(this, arguments); - this.element.attr({href: o.href, target: o.target}); + this.element.attr({ href: o.href, target: o.target }); if (o.el) { BI.createWidget(o.el, { - element: this + element: this, }); } - } + }, }); BI.shortcut("bi.a", BI.A); diff --git a/src/base/single/bar/bar.loading.js b/src/base/single/bar/bar.loading.js index 27b54cd69..801331b15 100644 --- a/src/base/single/bar/bar.loading.js +++ b/src/base/single/bar/bar.loading.js @@ -6,10 +6,11 @@ BI.LoadingBar = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.LoadingBar.superclass._defaultConfig.apply(this, arguments); - return BI.extend( conf, { + + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-loading-bar bi-tips", height: 30, - handler: BI.emptyFn + handler: BI.emptyFn, }); }, @@ -20,7 +21,7 @@ BI.LoadingBar = BI.inherit(BI.Single, { cls: "loading-text bi-list-item-simple", text: BI.i18nText("BI-Load_More"), width: 120, - handler: this.options.handler + handler: this.options.handler, }); this.loaded.on(BI.Controller.EVENT_CHANGE, function (type) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -30,26 +31,26 @@ BI.LoadingBar = BI.inherit(BI.Single, { type: "bi.layout", width: this.options.height, height: this.options.height, - cls: "loading-background cursor-default" + cls: "loading-background cursor-default", }); var loaded = BI.createWidget({ type: "bi.center_adapt", - items: [this.loaded] + items: [this.loaded], }); var loading = BI.createWidget({ type: "bi.center_adapt", - items: [this.loading] + items: [this.loading], }); this.cardLayout = BI.createWidget({ type: "bi.card", element: this, items: [{ el: loaded, - cardName: "loaded" + cardName: "loaded", }, { el: loading, - cardName: "loading" - }] + cardName: "loading", + }], }); this.invisible(); }, @@ -74,7 +75,7 @@ BI.LoadingBar = BI.inherit(BI.Single, { setLoading: function () { this._reset(); this.cardLayout.showCardByName("loading"); - } + }, }); BI.shortcut("bi.loading_bar", BI.LoadingBar); diff --git a/src/base/single/button/button.basic.js b/src/base/single/button/button.basic.js index da7791890..8fa304890 100644 --- a/src/base/single/button/button.basic.js +++ b/src/base/single/button/button.basic.js @@ -8,6 +8,7 @@ BI.BasicButton = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.BasicButton.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { _baseCls: (conf._baseCls || "") + " bi-basic-button" + (conf.invalid ? "" : " cursor-pointer") + ((BI.isIE() && BI.getIEVersion() < 10) ? " hack" : ""), // el: {} // 可以通过el来创建button元素 @@ -21,10 +22,10 @@ BI.BasicButton = BI.inherit(BI.Single, { disableSelected: false, // 使能选中 shadow: false, - isShadowShowingOnSelected: false, // 选中状态下是否显示阴影 + isShadowShowingOnSelected: false, // 选中状态下是否显示阴影 trigger: null, handler: BI.emptyFn, - bubble: null + bubble: null, }); }, @@ -63,11 +64,11 @@ BI.BasicButton = BI.inherit(BI.Single, { _createShadow: function () { var self = this, o = this.options; - var assertMask = function () { + function assertMask() { if (!self.$mask) { self.$mask = BI.createWidget(BI.isObject(o.shadow) ? o.shadow : {}, { type: "bi.layout", - cls: "bi-button-mask" + cls: "bi-button-mask", }); self.$mask.invisible(); BI.createWidget({ @@ -78,11 +79,11 @@ BI.BasicButton = BI.inherit(BI.Single, { left: 0, right: 0, top: 0, - bottom: 0 - }] + bottom: 0, + }], }); } - }; + } this.element.mouseup(function () { if (!self._hover && !o.isShadowShowingOnSelected) { @@ -223,7 +224,7 @@ BI.BasicButton = BI.inherit(BI.Single, { // 之后的300ms点击无效 var onClick = BI.debounce(this._doClick, BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); function ev(e) { @@ -257,7 +258,7 @@ BI.BasicButton = BI.inherit(BI.Single, { }, el: { type: "bi.layout", - height: "100%" + height: "100%", }, popup: { type: "bi.text_bubble_bar_popup_view", @@ -272,21 +273,21 @@ BI.BasicButton = BI.inherit(BI.Single, { if (v) { onClick.apply(self, arguments); } - } - }] + }, + }], }, listeners: [{ eventName: BI.BubbleCombo.EVENT_BEFORE_POPUPVIEW, action: function () { popup.populate(getBubble()); - } - }] + }, + }], }, left: 0, right: 0, bottom: 0, - top: 0 - }] + top: 0, + }], }); } if (self.combo.isViewVisible()) { @@ -294,6 +295,7 @@ BI.BasicButton = BI.inherit(BI.Single, { } else { self.combo.showView(); } + return; } onClick.apply(self, arguments); @@ -304,6 +306,7 @@ BI.BasicButton = BI.inherit(BI.Single, { if (BI.isFunction(bubble)) { return bubble(); } + return bubble; } }, @@ -332,14 +335,22 @@ BI.BasicButton = BI.inherit(BI.Single, { _doClick: function (e) { if (this.isValid()) { - this.beforeClick(e); + var isIntercepted = this.beforeClick(e); + // 如果事件已经被消费掉了,就不再触发点击事件 + if (isIntercepted) { + return; + } } + this._trigger(e); if (this.isValid()) { this.doClick(e); } }, + /** + * 子类可以得写这个方法,如果返回为 true,则可以阻止 handler 的触发 + */ beforeClick: function () { }, @@ -428,7 +439,7 @@ BI.BasicButton = BI.inherit(BI.Single, { empty: function () { BI.Widget._renderEngine.createElement(document).unbind("mouseup." + this.getName()); BI.BasicButton.superclass.empty.apply(this, arguments); - } + }, }); BI.BasicButton.EVENT_CHANGE = "BasicButton.EVENT_CHANGE"; BI.shortcut("bi.basic_button", BI.BasicButton); diff --git a/src/base/single/button/button.node.js b/src/base/single/button/button.node.js index 8e17a4ea5..ae4bd9045 100644 --- a/src/base/single/button/button.node.js +++ b/src/base/single/button/button.node.js @@ -9,9 +9,11 @@ BI.NodeButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.NodeButton.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { _baseCls: (conf._baseCls || "") + " bi-node", - open: false + open: false, + once: false, }); }, @@ -27,10 +29,6 @@ BI.NodeButton = BI.inherit(BI.BasicButton, { this.setOpened(!this.isOpened()); }, - isOnce: function () { - return false; - }, - isOpened: function () { return !!this.options.open; }, @@ -51,6 +49,6 @@ BI.NodeButton = BI.inherit(BI.BasicButton, { this.setOpened(true); this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EXPAND, this.getValue(), this); } - } + }, }); BI.shortcut("bi.node_button", BI.NodeButton); diff --git a/src/base/single/button/buttons/__test__/button.test.js b/src/base/single/button/buttons/__test__/button.test.js index 2ef4e0c82..b5d9865d2 100644 --- a/src/base/single/button/buttons/__test__/button.test.js +++ b/src/base/single/button/buttons/__test__/button.test.js @@ -2,7 +2,6 @@ * Created by windy on 2018/01/23. */ describe("ButtonTest", function () { - /** * test_author_windy */ @@ -12,7 +11,7 @@ describe("ButtonTest", function () { text: "CCC", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { button.element.click(); @@ -20,7 +19,6 @@ describe("ButtonTest", function () { button.destroy(); done(); }); - }); @@ -34,7 +32,7 @@ describe("ButtonTest", function () { trigger: "mousedown", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { button.element.mousedown(); @@ -42,7 +40,6 @@ describe("ButtonTest", function () { button.destroy(); done(); }); - }); /** @@ -55,7 +52,7 @@ describe("ButtonTest", function () { trigger: "mouseup", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { button.element.mousedown(); @@ -64,7 +61,6 @@ describe("ButtonTest", function () { button.destroy(); done(); }); - }); /** @@ -77,7 +73,7 @@ describe("ButtonTest", function () { trigger: "dblclick", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { button.element.dblclick(); @@ -85,7 +81,6 @@ describe("ButtonTest", function () { button.destroy(); done(); }); - }); /** @@ -101,8 +96,8 @@ describe("ButtonTest", function () { eventName: BI.Button.EVENT_CHANGE, action: function () { clickNum++; - } - }] + }, + }], }); BI.nextTick(function () { button.element.mousedown(); @@ -112,6 +107,5 @@ describe("ButtonTest", function () { done(); }, 360); }); - }); }); diff --git a/src/base/single/button/buttons/button.icon.js b/src/base/single/button/buttons/button.icon.js index 3def60551..82048a029 100644 --- a/src/base/single/button/buttons/button.icon.js +++ b/src/base/single/button/buttons/button.icon.js @@ -6,6 +6,7 @@ BI.IconButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.IconButton.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { _baseCls: (conf._baseCls || "") + " bi-icon-button horizon-center", hgap: 0, @@ -15,19 +16,19 @@ BI.IconButton = BI.inherit(BI.BasicButton, { lgap: 0, rgap: 0, iconWidth: null, - iconHeight: null + iconHeight: null, }); }, render: function () { var o = this.options; this.element.css({ - textAlign: "center" + textAlign: "center", }); this.icon = BI.createWidget({ type: "bi.icon", width: o.iconWidth, - height: o.iconHeight + height: o.iconHeight, }); if (BI.isNumber(o.height) && o.height > 0 && BI.isNull(o.iconWidth) && BI.isNull(o.iconHeight)) { this.element.css("lineHeight", o.height / BI.pixRatio + BI.pixUnit); @@ -40,7 +41,7 @@ BI.IconButton = BI.inherit(BI.BasicButton, { rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, - items: [this.icon] + items: [this.icon], }); } else { this.element.css("lineHeight", "1"); @@ -53,7 +54,7 @@ BI.IconButton = BI.inherit(BI.BasicButton, { rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, - items: [this.icon] + items: [this.icon], }); } }, @@ -63,7 +64,7 @@ BI.IconButton = BI.inherit(BI.BasicButton, { if (this.isValid()) { this.fireEvent(BI.IconButton.EVENT_CHANGE, this); } - } + }, }); BI.IconButton.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_button", BI.IconButton); diff --git a/src/base/single/button/buttons/button.image.js b/src/base/single/button/buttons/button.image.js index 58be4351e..6eeeffbf1 100644 --- a/src/base/single/button/buttons/button.image.js +++ b/src/base/single/button/buttons/button.image.js @@ -8,11 +8,12 @@ BI.ImageButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.ImageButton.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-image-button", src: "", iconWidth: "100%", - iconHeight: "100%" + iconHeight: "100%", }); }, @@ -22,20 +23,20 @@ BI.ImageButton = BI.inherit(BI.BasicButton, { type: "bi.img", width: o.iconWidth, height: o.iconHeight, - src: o.src + src: o.src, }); if (BI.isNumber(o.iconWidth) || BI.isNumber(o.iconHeight)) { BI.createWidget({ type: "bi.center_adapt", element: this, - items: [this.image] + items: [this.image], }); } else { BI.createWidget({ type: "bi.adaptive", element: this, items: [this.image], - scrollable: false + scrollable: false, }); } }, @@ -80,7 +81,7 @@ BI.ImageButton = BI.inherit(BI.BasicButton, { if (this.isValid()) { this.fireEvent(BI.ImageButton.EVENT_CHANGE, this); } - } + }, }); BI.ImageButton.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.image_button", BI.ImageButton); diff --git a/src/base/single/button/buttons/button.js b/src/base/single/button/buttons/button.js index 420b5f7aa..94b590f84 100644 --- a/src/base/single/button/buttons/button.js +++ b/src/base/single/button/buttons/button.js @@ -3,6 +3,8 @@ return position === "top" || position === "bottom"; } + var loadingCls = "button-loading-font anim-rotate"; + /** * 文字类型的按钮 * @class BI.Button @@ -14,7 +16,7 @@ BI.Button = BI.inherit(BI.BasicButton, { _const: { - iconWidth: 18 + iconWidth: 18, }, _defaultConfig: function (props) { @@ -35,7 +37,7 @@ return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-button" + ((BI.isIE() && BI.isIE9Below()) ? " hack" : ""), attributes: { - tabIndex: 1 + tabIndex: 1, }, minWidth: clearMinWidth ? 0 : 80, height: isVertical(props.iconPosition) ? adaptiveHeight : 24, @@ -54,14 +56,15 @@ whiteSpace: "nowrap", textWidth: null, textHeight: null, - hgap: props.clear ? 0 : 10, + hgap: props.clear ? 0 : (props.plain && !props.text ? 4 : 10), vgap: 0, tgap: 0, bgap: 0, lgap: 0, rgap: 0, + icon: "", iconGap: 0, - iconPosition: "left" + iconPosition: "left", }); }, @@ -86,71 +89,70 @@ textHeight = lineHeight; } } - if (BI.isKey(o.iconCls)) { + + var iconInvisible = !o.loading && !o.iconCls && !o.icon; + if (BI.isPlainObject(o.icon) && !o.loading) { + this.icon = BI.createWidget(o.icon); + } else { this.icon = BI.createWidget({ type: "bi.icon_label", - cls: o.iconCls, + cls: o.loading ? loadingCls : (o.iconCls || o.icon), width: this._const.iconWidth, height: lineHeight, lineHeight: lineHeight, // 不设置,自定义按钮无法居中 iconWidth: o.iconWidth, - iconHeight: o.iconHeight - }); - this.text = BI.createWidget({ - type: "bi.label", - text: o.text, - textWidth: BI.isNotNull(o.textWidth) ? o.textWidth - this._const.iconWidth : null, - textHeight: textHeight, - height: lineHeight, - value: o.value - }); - var layoutType = "bi.horizontal"; - var gapContainer = { - lgap: o.iconPosition === "left" && o.text ? o.iconGap : 0, - rgap: o.iconPosition === "right" ? o.iconGap : 0, - tgap: o.iconPosition === "top" ? o.iconGap : 0, - bgap: o.iconPosition === "bottom" ? o.iconGap : 0 - }; - var items = [this.icon, BI.extend({ el: this.text }, gapContainer)]; - if (isVertical(o.iconPosition)) { - layoutType = "bi.vertical"; - } - if (o.iconPosition === "right" || o.iconPosition === "bottom") { - items = [BI.extend({ el: this.text }, gapContainer), this.icon]; - } - BI.createWidget({ - type: "bi.center_adapt", - element: this, - hgap: o.hgap, - vgap: o.vgap, - items: [{ - type: layoutType, - horizontalAlign: "center", - verticalAlign: "middle", - items: items - }] - }); - } else { - this.text = BI.createWidget({ - type: "bi.label", - height: o.height, - textAlign: o.textAlign, - whiteSpace: o.whiteSpace, - textWidth: o.textWidth, - textHeight: textHeight, - hgap: o.hgap, - vgap: o.vgap, - tgap: o.tgap, - bgap: o.bgap, - lgap: o.lgap, - rgap: o.rgap, - element: this, - text: o.text, - value: o.value, - title: null, + iconHeight: o.iconHeight, + invisible: iconInvisible, }); } + + // 用于 whiteSpace + var textWidth = iconInvisible && o.width ? o.width - o.hgap * 2 : null; + if (BI.isNotNull(o.textWidth)) { + // textWidth 需要减去图标 + textWidth = o.textWidth - (iconInvisible || isVertical(o.iconPosition) ? 0 : this._const.iconWidth); + } + this.text = BI.createWidget({ + type: "bi.label", + text: o.text, + whiteSpace: o.whiteSpace, + textAlign: o.textAlign, + textWidth: textWidth, + textHeight: textHeight, + height: lineHeight, + value: o.value, + title: null, + }); + var layoutType = "bi.horizontal"; + var gapContainer = { + lgap: o.iconPosition === "left" && o.text ? o.iconGap : 0, + rgap: o.iconPosition === "right" ? o.iconGap : 0, + tgap: o.iconPosition === "top" ? o.iconGap : 0, + bgap: o.iconPosition === "bottom" ? o.iconGap : 0, + }; + var items = [this.icon, BI.extend({el: this.text}, gapContainer)]; + if (isVertical(o.iconPosition)) { + layoutType = "bi.vertical"; + } + if (o.iconPosition === "right" || o.iconPosition === "bottom") { + items = [BI.extend({el: this.text}, gapContainer), this.icon]; + } + // bi.center_adapt 作用:让 hgap 不影响 iconGap。 + BI.createWidget({ + type: "bi.center_adapt", + horizontalAlign: o.textAlign, + element: this, + hgap: o.hgap, + vgap: o.vgap, + items: [{ + type: layoutType, + horizontalAlign: "center", + verticalAlign: "middle", + items: items, + }], + }); + var classArr = ["block", "clear", "ghost", "plain", "loading", "light"]; // 如果 options 对应的属性为 true 则给元素添加 class BI.each(classArr, function (_, clz) { @@ -180,11 +182,34 @@ } }, - setLoading: function (loading) { - if (loading) { - this.element.addClass("loading"); + beforeClick: function () { + return this.isLoading(); + }, + + isLoading: function () { + return this._loading === undefined ? this.options.loading : this._loading; + }, + + loading: function () { + this._loading = true; + this.element.addClass("loading"); + if (this.icon.loading) { + this.icon.loading(); + } else { + // loadingCls 可以覆盖 iconCls 所以不需要移除 iconCls + this.icon.element.addClass(loadingCls); + this.icon.setVisible(true); + } + }, + + loaded: function () { + this._loading = false; + this.element.removeClass("loading"); + if (this.icon.loaded) { + this.icon.loaded(); } else { - this.element.removeClass("loading"); + this.icon.element.removeClass(loadingCls); + this.icon.setVisible(!!this.options.iconCls); } }, @@ -222,7 +247,7 @@ unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); - } + }, }); BI.shortcut("bi.button", BI.Button); BI.Button.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/single/button/buttons/button.text.js b/src/base/single/button/buttons/button.text.js index bbb3e0e50..38470c291 100644 --- a/src/base/single/button/buttons/button.text.js +++ b/src/base/single/button/buttons/button.text.js @@ -8,6 +8,7 @@ BI.TextButton = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.TextButton.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-button", textAlign: "center", @@ -18,7 +19,7 @@ BI.TextButton = BI.inherit(BI.BasicButton, { lgap: 0, rgap: 0, vgap: 0, - py: "" + py: "", }); }, @@ -40,7 +41,7 @@ BI.TextButton = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, py: o.py, - keyword: o.keyword + keyword: o.keyword, }); }, @@ -83,7 +84,7 @@ BI.TextButton = BI.inherit(BI.BasicButton, { text = BI.isArray(text) ? text.join(",") : text; this.text.setValue(text); } - } + }, }); BI.TextButton.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_button", BI.TextButton); diff --git a/src/base/single/button/listitem/blankiconicontextitem.js b/src/base/single/button/listitem/blankiconicontextitem.js index 2f1531835..1f6419008 100644 --- a/src/base/single/button/listitem/blankiconicontextitem.js +++ b/src/base/single/button/listitem/blankiconicontextitem.js @@ -9,6 +9,7 @@ BI.BlankIconIconTextItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.BlankIconIconTextItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-blank-icon-icon-text-item", iconCls1: "", @@ -19,7 +20,7 @@ BI.BlankIconIconTextItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -31,21 +32,21 @@ BI.BlankIconIconTextItem = BI.inherit(BI.BasicButton, { columnSize: [o.blankWidth, o.leftIconWrapperWidth || o.height, o.rightIconWrapperWidth || o.height, "fill"], items: [{ type: "bi.layout", - width: o.blankWidth + width: o.blankWidth, }, { type: "bi.icon_label", cls: o.iconCls1, width: o.leftIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { type: "bi.icon_label", cls: o.iconCls2, width: o.rightIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -60,9 +61,9 @@ BI.BlankIconIconTextItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } - }] + height: o.height, + }, + }], }; }, @@ -111,7 +112,7 @@ BI.BlankIconIconTextItem = BI.inherit(BI.BasicButton, { unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); - } + }, }); BI.BlankIconIconTextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.blank_icon_icon_text_item", BI.BlankIconIconTextItem); diff --git a/src/base/single/button/listitem/blankicontexticonitem.js b/src/base/single/button/listitem/blankicontexticonitem.js index aeb876e9c..34dc9e7d8 100644 --- a/src/base/single/button/listitem/blankicontexticonitem.js +++ b/src/base/single/button/listitem/blankicontexticonitem.js @@ -10,6 +10,7 @@ BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.BlankIconTextIconItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-blank-icon-text-icon-item", iconCls1: "", @@ -20,7 +21,7 @@ BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -32,14 +33,14 @@ BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, { columnSize: [o.blankWidth, o.leftIconWrapperWidth || o.height, "fill", o.rightIconWrapperWidth || o.height], items: [{ type: "bi.layout", - width: o.blankWidth + width: o.blankWidth, }, { type: "bi.icon_label", cls: o.iconCls1, width: o.leftIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -54,16 +55,16 @@ BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } + height: o.height, + }, }, { type: "bi.icon_label", cls: o.iconCls2, width: o.rightIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight - }] + iconHeight: o.iconHeight, + }], }; }, @@ -106,7 +107,7 @@ BI.BlankIconTextIconItem = BI.inherit(BI.BasicButton, { getText: function () { return this.text.getText(); - } + }, }); BI.BlankIconTextIconItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.blank_icon_text_icon_item", BI.BlankIconTextIconItem); diff --git a/src/base/single/button/listitem/blankicontextitem.js b/src/base/single/button/listitem/blankicontextitem.js index 158d05bf6..08f13d22d 100644 --- a/src/base/single/button/listitem/blankicontextitem.js +++ b/src/base/single/button/listitem/blankicontextitem.js @@ -9,6 +9,7 @@ BI.BlankIconTextItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.BlankIconTextItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-blank-icon-text-item", blankWidth: 0, @@ -18,7 +19,7 @@ BI.BlankIconTextItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -30,14 +31,14 @@ BI.BlankIconTextItem = BI.inherit(BI.BasicButton, { columnSize: [o.blankWidth, o.iconWrapperWidth || o.height, "fill"], items: [{ type: "bi.layout", - width: o.blankWidth + width: o.blankWidth, }, { type: "bi.icon_label", cls: o.iconCls, width: o.iconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -53,9 +54,9 @@ BI.BlankIconTextItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } - }] + height: o.height, + }, + }], }; }, @@ -98,7 +99,7 @@ BI.BlankIconTextItem = BI.inherit(BI.BasicButton, { unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); - } + }, }); BI.BlankIconTextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.blank_icon_text_item", BI.BlankIconTextItem); diff --git a/src/base/single/button/listitem/icontexticonitem.js b/src/base/single/button/listitem/icontexticonitem.js index 4658bc471..425f47d90 100644 --- a/src/base/single/button/listitem/icontexticonitem.js +++ b/src/base/single/button/listitem/icontexticonitem.js @@ -10,6 +10,7 @@ BI.IconTextIconItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.IconTextIconItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-icon-item", iconCls1: "", @@ -19,7 +20,7 @@ BI.IconTextIconItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -35,7 +36,7 @@ BI.IconTextIconItem = BI.inherit(BI.BasicButton, { width: o.leftIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -50,16 +51,16 @@ BI.IconTextIconItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } + height: o.height, + }, }, { type: "bi.icon_label", cls: o.iconCls2, width: o.rightIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight - }] + iconHeight: o.iconHeight, + }], }; }, @@ -102,7 +103,7 @@ BI.IconTextIconItem = BI.inherit(BI.BasicButton, { getText: function () { return this.text.getText(); - } + }, }); BI.IconTextIconItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_icon_item", BI.IconTextIconItem); diff --git a/src/base/single/button/listitem/icontextitem.js b/src/base/single/button/listitem/icontextitem.js index a54da86f4..8fff16335 100644 --- a/src/base/single/button/listitem/icontextitem.js +++ b/src/base/single/button/listitem/icontextitem.js @@ -9,6 +9,7 @@ BI.IconTextItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.IconTextItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-item", direction: BI.Direction.Left, @@ -19,7 +20,7 @@ BI.IconTextItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -35,7 +36,7 @@ BI.IconTextItem = BI.inherit(BI.BasicButton, { width: o.iconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -51,9 +52,9 @@ BI.IconTextItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } - }] + height: o.height, + }, + }], }; }, @@ -96,7 +97,7 @@ BI.IconTextItem = BI.inherit(BI.BasicButton, { unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); - } + }, }); BI.IconTextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_item", BI.IconTextItem); diff --git a/src/base/single/button/listitem/texticonitem.js b/src/base/single/button/listitem/texticonitem.js index a423195d4..a0ece74e6 100644 --- a/src/base/single/button/listitem/texticonitem.js +++ b/src/base/single/button/listitem/texticonitem.js @@ -10,6 +10,7 @@ BI.TextIconItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.TextIconItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-icon-item", iconWrapperWidth: null, @@ -19,7 +20,7 @@ BI.TextIconItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -44,16 +45,16 @@ BI.TextIconItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } + height: o.height, + }, }, { type: "bi.icon_label", cls: o.iconCls, width: o.iconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight - }] + iconHeight: o.iconHeight, + }], }; }, @@ -96,7 +97,7 @@ BI.TextIconItem = BI.inherit(BI.BasicButton, { unHighLight: function () { this.text.unHighLight.apply(this.text, arguments); - } + }, }); BI.TextIconItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_icon_item", BI.TextIconItem); diff --git a/src/base/single/button/listitem/textitem.js b/src/base/single/button/listitem/textitem.js index ffbcc1efd..c4c810295 100644 --- a/src/base/single/button/listitem/textitem.js +++ b/src/base/single/button/listitem/textitem.js @@ -10,6 +10,7 @@ BI.TextItem = BI.inherit(BI.BasicButton, { _defaultConfig: function () { var conf = BI.TextItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-item", textAlign: "left", @@ -17,7 +18,7 @@ BI.TextItem = BI.inherit(BI.BasicButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -28,7 +29,7 @@ BI.TextItem = BI.inherit(BI.BasicButton, { element: this, textAlign: o.textAlign, whiteSpace: o.whiteSpace, - textHeight: o.whiteSpace == "nowrap" ? o.height : o.textHeight, + textHeight: o.whiteSpace === "nowrap" ? o.height : o.textHeight, height: o.height, hgap: o.textHgap, vgap: o.textVgap, @@ -37,7 +38,7 @@ BI.TextItem = BI.inherit(BI.BasicButton, { text: o.text, value: o.value, keyword: o.keyword, - py: o.py + py: o.py, }); }, @@ -80,7 +81,7 @@ BI.TextItem = BI.inherit(BI.BasicButton, { getText: function () { return this.text.getText(); - } + }, }); BI.TextItem.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_item", BI.TextItem); diff --git a/src/base/single/button/node/__test__/icontexticonnode.test.js b/src/base/single/button/node/__test__/icontexticonnode.test.js index ae2a8fbb4..b76324283 100644 --- a/src/base/single/button/node/__test__/icontexticonnode.test.js +++ b/src/base/single/button/node/__test__/icontexticonnode.test.js @@ -4,13 +4,12 @@ */ describe("IconTextIconNodeTest", function () { - /** * test_author_kobi */ it("setText", function () { var iconTextIconNode = BI.Test.createWidget({ - type: "bi.icon_text_icon_node" + type: "bi.icon_text_icon_node", }); iconTextIconNode.setText("AAA"); expect(iconTextIconNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -34,7 +33,7 @@ describe("IconTextIconNodeTest", function () { */ it("setValue", function () { var iconTextIconNode = BI.Test.createWidget({ - type: "bi.icon_text_icon_node" + type: "bi.icon_text_icon_node", }); iconTextIconNode.setValue("AAA"); expect(iconTextIconNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -48,7 +47,7 @@ describe("IconTextIconNodeTest", function () { var iconTextIconNode = BI.Test.createWidget({ type: "bi.icon_text_icon_node", value: "AAA", - readonly: true + readonly: true, }); iconTextIconNode.setValue("BBB"); expect(iconTextIconNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -61,7 +60,7 @@ describe("IconTextIconNodeTest", function () { it("getValue", function () { var iconTextIconNode = BI.Test.createWidget({ type: "bi.icon_text_icon_node", - value: "AAA" + value: "AAA", }); expect(iconTextIconNode.getValue()).to.equal("AAA"); iconTextIconNode.destroy(); @@ -91,7 +90,7 @@ describe("IconTextIconNodeTest", function () { text: "AAA", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { iconTextIconNode.element.click(); @@ -100,5 +99,4 @@ describe("IconTextIconNodeTest", function () { done(); }); }); - }); diff --git a/src/base/single/button/node/__test__/icontextnode.test.js b/src/base/single/button/node/__test__/icontextnode.test.js index 2319e23e2..25b6ebc9f 100644 --- a/src/base/single/button/node/__test__/icontextnode.test.js +++ b/src/base/single/button/node/__test__/icontextnode.test.js @@ -4,13 +4,12 @@ */ describe("IconTextNodeTest", function () { - /** * test_author_kobi */ it("setText", function () { var iconTextNode = BI.Test.createWidget({ - type: "bi.icon_text_node" + type: "bi.icon_text_node", }); iconTextNode.setText("AAA"); expect(iconTextNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -34,7 +33,7 @@ describe("IconTextNodeTest", function () { */ it("setValue", function () { var iconTextNode = BI.Test.createWidget({ - type: "bi.icon_text_node" + type: "bi.icon_text_node", }); iconTextNode.setValue("AAA"); expect(iconTextNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -48,7 +47,7 @@ describe("IconTextNodeTest", function () { var iconTextNode = BI.Test.createWidget({ type: "bi.icon_text_node", value: "AAA", - readonly: true + readonly: true, }); iconTextNode.setValue("BBB"); expect(iconTextNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -61,7 +60,7 @@ describe("IconTextNodeTest", function () { it("getValue", function () { var iconTextNode = BI.Test.createWidget({ type: "bi.icon_text_node", - value: "AAA" + value: "AAA", }); expect(iconTextNode.getValue()).to.equal("AAA"); iconTextNode.destroy(); @@ -91,7 +90,7 @@ describe("IconTextNodeTest", function () { text: "AAA", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { iconTextNode.element.click(); @@ -100,5 +99,4 @@ describe("IconTextNodeTest", function () { done(); }); }); - }); diff --git a/src/base/single/button/node/__test__/texticonnode.test.js b/src/base/single/button/node/__test__/texticonnode.test.js index 9eb4ec2db..1523f8ce6 100644 --- a/src/base/single/button/node/__test__/texticonnode.test.js +++ b/src/base/single/button/node/__test__/texticonnode.test.js @@ -4,13 +4,12 @@ */ describe("TextIconNodeTest", function () { - /** * test_author_kobi */ it("setText", function () { var textIconNode = BI.Test.createWidget({ - type: "bi.text_icon_node" + type: "bi.text_icon_node", }); textIconNode.setText("AAA"); expect(textIconNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -34,7 +33,7 @@ describe("TextIconNodeTest", function () { */ it("setValue", function () { var textIconNode = BI.Test.createWidget({ - type: "bi.text_icon_node" + type: "bi.text_icon_node", }); textIconNode.setValue("AAA"); expect(textIconNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -48,7 +47,7 @@ describe("TextIconNodeTest", function () { var textIconNode = BI.Test.createWidget({ type: "bi.text_icon_node", value: "AAA", - readonly: true + readonly: true, }); textIconNode.setValue("BBB"); expect(textIconNode.element.find(".bi-text").text()).to.equal("AAA"); @@ -61,7 +60,7 @@ describe("TextIconNodeTest", function () { it("getValue", function () { var textIconNode = BI.Test.createWidget({ type: "bi.text_icon_node", - value: "AAA" + value: "AAA", }); expect(textIconNode.getValue()).to.equal("AAA"); textIconNode.destroy(); @@ -91,7 +90,7 @@ describe("TextIconNodeTest", function () { text: "AAA", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { textIconNode.element.click(); @@ -100,5 +99,4 @@ describe("TextIconNodeTest", function () { done(); }); }); - }); diff --git a/src/base/single/button/node/__test__/textnode.test.js b/src/base/single/button/node/__test__/textnode.test.js index 5674ae263..7b78bbb6b 100644 --- a/src/base/single/button/node/__test__/textnode.test.js +++ b/src/base/single/button/node/__test__/textnode.test.js @@ -4,13 +4,12 @@ */ describe("TextNodeTest", function () { - /** * test_author_kobi */ it("setText", function () { var textNode = BI.Test.createWidget({ - type: "bi.text_node" + type: "bi.text_node", }); textNode.setText("AAA"); expect(textNode.element.children(".bi-text").text()).to.equal("AAA"); @@ -24,7 +23,7 @@ describe("TextNodeTest", function () { var textNode = BI.Test.createWidget({ type: "bi.text_node", text: "AAA", - whiteSpace: "normal" + whiteSpace: "normal", }); expect(textNode.getText()).to.equal("AAA"); textNode.destroy(); @@ -35,7 +34,7 @@ describe("TextNodeTest", function () { */ it("setValue", function () { var textNode = BI.Test.createWidget({ - type: "bi.text_node" + type: "bi.text_node", }); textNode.setValue("AAA"); expect(textNode.element.children(".bi-text").text()).to.equal("AAA"); @@ -49,7 +48,7 @@ describe("TextNodeTest", function () { var textNode = BI.Test.createWidget({ type: "bi.text_node", value: "AAA", - readonly: true + readonly: true, }); textNode.setValue("BBB"); expect(textNode.element.children(".bi-text").text()).to.equal("AAA"); @@ -62,7 +61,7 @@ describe("TextNodeTest", function () { it("getValue", function () { var textNode = BI.Test.createWidget({ type: "bi.text_node", - value: "AAA" + value: "AAA", }); expect(textNode.getValue()).to.equal("AAA"); textNode.destroy(); @@ -92,7 +91,7 @@ describe("TextNodeTest", function () { text: "AAA", handler: function () { this.setText("click"); - } + }, }); BI.nextTick(function () { textNode.element.click(); @@ -101,6 +100,4 @@ describe("TextNodeTest", function () { done(); }); }); - - }); diff --git a/src/base/single/button/node/icontexticonnode.js b/src/base/single/button/node/icontexticonnode.js index 13d967425..7569490eb 100644 --- a/src/base/single/button/node/icontexticonnode.js +++ b/src/base/single/button/node/icontexticonnode.js @@ -8,6 +8,7 @@ BI.IconTextIconNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.IconTextIconNode.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-icon-node", iconCls1: "close-ha-font", @@ -17,7 +18,7 @@ BI.IconTextIconNode = BI.inherit(BI.NodeButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -33,7 +34,7 @@ BI.IconTextIconNode = BI.inherit(BI.NodeButton, { width: o.leftIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -48,16 +49,16 @@ BI.IconTextIconNode = BI.inherit(BI.NodeButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } + height: o.height, + }, }, { type: "bi.icon_label", cls: o.iconCls2, width: o.rightIconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight - }] + iconHeight: o.iconHeight, + }], }; }, @@ -92,7 +93,7 @@ BI.IconTextIconNode = BI.inherit(BI.NodeButton, { getText: function () { return this.text.getText(); - } + }, }); BI.IconTextIconNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_icon_node", BI.IconTextIconNode); diff --git a/src/base/single/button/node/icontextnode.js b/src/base/single/button/node/icontextnode.js index 5c9f1a4ca..16383cc7d 100644 --- a/src/base/single/button/node/icontextnode.js +++ b/src/base/single/button/node/icontextnode.js @@ -8,6 +8,7 @@ BI.IconTextNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.IconTextNode.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-icon-text-node", cls: "close-ha-font", @@ -16,7 +17,7 @@ BI.IconTextNode = BI.inherit(BI.NodeButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -32,7 +33,7 @@ BI.IconTextNode = BI.inherit(BI.NodeButton, { width: o.iconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight + iconHeight: o.iconHeight, }, { el: { type: "bi.label", @@ -48,9 +49,9 @@ BI.IconTextNode = BI.inherit(BI.NodeButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } - }] + height: o.height, + }, + }], }; }, @@ -85,7 +86,7 @@ BI.IconTextNode = BI.inherit(BI.NodeButton, { unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); - } + }, }); BI.IconTextNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.icon_text_node", BI.IconTextNode); diff --git a/src/base/single/button/node/texticonnode.js b/src/base/single/button/node/texticonnode.js index 6671c19a1..01167b009 100644 --- a/src/base/single/button/node/texticonnode.js +++ b/src/base/single/button/node/texticonnode.js @@ -7,6 +7,7 @@ BI.TextIconNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.TextIconNode.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-icon-node", cls: "close-ha-font", @@ -15,7 +16,7 @@ BI.TextIconNode = BI.inherit(BI.NodeButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -40,16 +41,16 @@ BI.TextIconNode = BI.inherit(BI.NodeButton, { text: o.text, value: o.value, keyword: o.keyword, - height: o.height - } + height: o.height, + }, }, { type: "bi.icon_label", cls: o.iconCls, width: o.iconWrapperWidth || o.height, height: o.height, iconWidth: o.iconWidth, - iconHeight: o.iconHeight - }] + iconHeight: o.iconHeight, + }], }; }, @@ -84,7 +85,7 @@ BI.TextIconNode = BI.inherit(BI.NodeButton, { unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); - } + }, }); BI.TextIconNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_icon_node", BI.TextIconNode); diff --git a/src/base/single/button/node/textnode.js b/src/base/single/button/node/textnode.js index 74974456c..6ecaa3fbf 100644 --- a/src/base/single/button/node/textnode.js +++ b/src/base/single/button/node/textnode.js @@ -9,6 +9,7 @@ BI.TextNode = BI.inherit(BI.NodeButton, { _defaultConfig: function () { var conf = BI.TextNode.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-text-node", textAlign: "left", @@ -16,7 +17,7 @@ BI.TextNode = BI.inherit(BI.NodeButton, { textHgap: 0, textVgap: 0, textLgap: 0, - textRgap: 0 + textRgap: 0, }); }, @@ -27,7 +28,7 @@ BI.TextNode = BI.inherit(BI.NodeButton, { element: this, textAlign: o.textAlign, whiteSpace: o.whiteSpace, - textHeight: o.whiteSpace == "nowrap" ? o.height : o.textHeight, + textHeight: o.whiteSpace === "nowrap" ? o.height : o.textHeight, height: o.height, hgap: o.textHgap, vgap: o.textVgap, @@ -36,7 +37,7 @@ BI.TextNode = BI.inherit(BI.NodeButton, { text: o.text, value: o.value, keyword: o.keyword, - py: o.py + py: o.py, }); }, @@ -71,7 +72,7 @@ BI.TextNode = BI.inherit(BI.NodeButton, { getText: function () { return this.text.getText(); - } + }, }); BI.TextNode.EVENT_CHANGE = "EVENT_CHANGE"; BI.shortcut("bi.text_node", BI.TextNode); diff --git a/src/base/single/editor/editor.js b/src/base/single/editor/editor.js index 5322124d9..ac9e779e9 100644 --- a/src/base/single/editor/editor.js +++ b/src/base/single/editor/editor.js @@ -38,7 +38,7 @@ BI.Editor = BI.inherit(BI.Single, { watermark: o.watermark, validationChecker: o.validationChecker, quitChecker: o.quitChecker, - allowBlank: o.allowBlank + allowBlank: o.allowBlank, })); this.editor.element.css({ width: "100%", @@ -46,7 +46,7 @@ BI.Editor = BI.inherit(BI.Single, { border: "none", outline: "none", padding: "0", - margin: "0" + margin: "0", }); var items = [{ @@ -60,19 +60,19 @@ BI.Editor = BI.inherit(BI.Single, { left: 0, right: 0, top: 0, - bottom: 0 - }] + bottom: 0, + }], }, left: o.hgap + o.lgap, right: o.hgap + o.rgap, top: o.vgap + o.tgap, - bottom: o.vgap + o.bgap + bottom: o.vgap + o.bgap, }]; BI.createWidget({ type: "bi.absolute", element: this, - items: items + items: items, }); this.setWaterMark(this.options.watermark); @@ -159,6 +159,7 @@ BI.Editor = BI.inherit(BI.Single, { }); this.element.click(function (e) { e.stopPropagation(); + return false; }); if (BI.isKey(this.options.value) || BI.isEmptyString(this.options.value)) { @@ -194,7 +195,7 @@ BI.Editor = BI.inherit(BI.Single, { height: o.height - 2 * o.vgap - o.tgap, hgap: 2, whiteSpace: "nowrap", - textAlign: "left" + textAlign: "left", }); this.watermark.element.bind({ mousedown: function (e) { @@ -204,7 +205,7 @@ BI.Editor = BI.inherit(BI.Single, { self.editor.isEditing() && self.editor.blur(); } e.stopEvent(); - } + }, }); this.watermark.element.bind("click", function (e) { if (self.isEnabled()) { @@ -240,7 +241,6 @@ BI.Editor = BI.inherit(BI.Single, { }, setWaterMark: function (v) { - this.options.watermark = v; if (BI.isNull(this.watermark)) { @@ -269,7 +269,7 @@ BI.Editor = BI.inherit(BI.Single, { } if (!this.disabledError && BI.isKey(errorText)) { BI.Bubbles[b ? "show" : "hide"](this.getName(), errorText, this, { - adjustYOffset: o.simple ? 1 : 2 + adjustYOffset: o.simple ? 1 : 2, }); this._checkToolTip(); } @@ -332,6 +332,7 @@ BI.Editor = BI.inherit(BI.Single, { if (!this.isValid()) { return BI.trim(this.editor.getLastValidValue()); } + return BI.trim(this.editor.getValue()); }, @@ -345,7 +346,7 @@ BI.Editor = BI.inherit(BI.Single, { destroyed: function () { BI.Bubbles.remove(this.getName()); - } + }, }); BI.Editor.EVENT_CHANGE = "EVENT_CHANGE"; BI.Editor.EVENT_FOCUS = "EVENT_FOCUS"; diff --git a/src/base/single/editor/editor.multifile.js b/src/base/single/editor/editor.multifile.js index ae0d5e0a9..21765474d 100644 --- a/src/base/single/editor/editor.multifile.js +++ b/src/base/single/editor/editor.multifile.js @@ -9,12 +9,13 @@ BI.MultifileEditor = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.MultifileEditor.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-multifile-editor", multiple: false, maxSize: -1, // 1024 * 1024 accept: "", - url: "" + url: "", }); }, @@ -57,13 +58,13 @@ BI.MultifileEditor = BI.inherit(BI.Widget, { el: { type: "bi.adaptive", scrollable: false, - items: [this.file] + items: [this.file], }, top: 0, right: 0, left: 0, - bottom: 0 - }] + bottom: 0, + }], }); }, @@ -104,7 +105,7 @@ BI.MultifileEditor = BI.inherit(BI.Widget, { reset: function () { this._reset(); - } + }, }); BI.MultifileEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.MultifileEditor.EVENT_UPLOADSTART = "EVENT_UPLOADSTART"; diff --git a/src/base/single/editor/editor.textarea.js b/src/base/single/editor/editor.textarea.js index 67a197ddd..9f91b0ce4 100644 --- a/src/base/single/editor/editor.textarea.js +++ b/src/base/single/editor/editor.textarea.js @@ -39,13 +39,13 @@ BI.TextAreaEditor = BI.inherit(BI.Single, { items: [{ el: { type: "bi.adaptive", - items: [this.content] + items: [this.content], }, left: 4, right: 4, top: 2, - bottom: 2 - }] + bottom: 2, + }], }); this.content.element.on("input propertychange", function (e) { @@ -139,8 +139,8 @@ BI.TextAreaEditor = BI.inherit(BI.Single, { el: this.watermark, left: 0, top: 0, - right: 0 - }] + right: 0, + }], }); } else { this.watermark.setText(o.watermark); @@ -221,7 +221,7 @@ BI.TextAreaEditor = BI.inherit(BI.Single, { this.style = style; this.element.css(style); this.content.element.css(BI.extend({}, style, { - color: style.color || BI.DOM.getContrastColor(BI.DOM.isRGBColor(style.backgroundColor) ? BI.DOM.rgb2hex(style.backgroundColor) : style.backgroundColor) + color: style.color || BI.DOM.getContrastColor(BI.DOM.isRGBColor(style.backgroundColor) ? BI.DOM.rgb2hex(style.backgroundColor) : style.backgroundColor), })); }, @@ -243,7 +243,7 @@ BI.TextAreaEditor = BI.inherit(BI.Single, { _setEnable: function (b) { BI.TextAreaEditor.superclass._setEnable.apply(this, [b]); this.content && (this.content.element[0].disabled = !b); - } + }, }); BI.TextAreaEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.TextAreaEditor.EVENT_BLUR = "EVENT_BLUR"; diff --git a/src/base/single/html/__test__/html.test.js b/src/base/single/html/__test__/html.test.js index 2d599ecd7..1414b1e59 100644 --- a/src/base/single/html/__test__/html.test.js +++ b/src/base/single/html/__test__/html.test.js @@ -5,14 +5,13 @@ */ describe("HtmlTest", function () { - /** * test_author_windy */ it("html_h1", function () { var a = BI.Test.createWidget({ type: "bi.html", - text: "

在bi.html标签中使用html原生标签

" + text: "

在bi.html标签中使用html原生标签

", }); expect(a.element.find("h1").length).to.equal(1); a.destroy(); @@ -32,11 +31,11 @@ describe("HtmlTest", function () { highLight: true, hgap: 10, vgap: 10, - handler: BI.emptyFn + handler: BI.emptyFn, }); a.setValue("DDDDD"); - a.setStyle({"background-color": "red"}); + a.setStyle({ "background-color": "red" }); expect(a.text.element.css("background-color")).to.equal("rgb(255, 0, 0)"); a.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/single/html/html.js b/src/base/single/html/html.js index af88bac2c..9abbb2149 100644 --- a/src/base/single/html/html.js +++ b/src/base/single/html/html.js @@ -25,43 +25,43 @@ BI.Html = BI.inherit(BI.Single, { var self = this, o = this.options; if (o.hgap + o.lgap > 0) { this.element.css({ - "padding-left": (o.hgap + o.lgap) / BI.pixRatio + BI.pixUnit + "padding-left": (o.hgap + o.lgap) / BI.pixRatio + BI.pixUnit, }); } if (o.hgap + o.rgap > 0) { this.element.css({ - "padding-right": (o.hgap + o.rgap) / BI.pixRatio + BI.pixUnit + "padding-right": (o.hgap + o.rgap) / BI.pixRatio + BI.pixUnit, }); } if (o.vgap + o.tgap > 0) { this.element.css({ - "padding-top": (o.vgap + o.tgap) / BI.pixRatio + BI.pixUnit + "padding-top": (o.vgap + o.tgap) / BI.pixRatio + BI.pixUnit, }); } if (o.vgap + o.bgap > 0) { this.element.css({ - "padding-bottom": (o.vgap + o.bgap) / BI.pixRatio + BI.pixUnit + "padding-bottom": (o.vgap + o.bgap) / BI.pixRatio + BI.pixUnit, }); } if (BI.isNumber(o.height)) { - this.element.css({lineHeight: o.height / BI.pixRatio + BI.pixUnit}); + this.element.css({ lineHeight: o.height / BI.pixRatio + BI.pixUnit }); } if (BI.isNumber(o.lineHeight)) { - this.element.css({lineHeight: o.lineHeight / BI.pixRatio + BI.pixUnit}); + this.element.css({ lineHeight: o.lineHeight / BI.pixRatio + BI.pixUnit }); } if (BI.isWidthOrHeight(o.maxWidth)) { - this.element.css({maxWidth: o.maxWidth}); + this.element.css({ maxWidth: o.maxWidth }); } this.element.css({ textAlign: o.textAlign, whiteSpace: o.whiteSpace, - textOverflow: o.whiteSpace === 'nowrap' ? "ellipsis" : "", - overflow: o.whiteSpace === "nowrap" ? "" : "auto" + textOverflow: o.whiteSpace === "nowrap" ? "ellipsis" : "", + overflow: o.whiteSpace === "nowrap" ? "" : "auto", }); if (o.handler) { this.text = BI.createWidget({ type: "bi.layout", - tagName: "span" + tagName: "span", }); this.text.element.click(function () { o.handler(self.getValue()); @@ -69,7 +69,7 @@ BI.Html = BI.inherit(BI.Single, { BI.createWidget({ type: "bi.default", element: this, - items: [this.text] + items: [this.text], }); } else { this.text = this; @@ -108,7 +108,7 @@ BI.Html = BI.inherit(BI.Single, { BI.Html.superclass.setText.apply(this, arguments); this.options.text = text; this.text.element.html(text); - } + }, }); BI.shortcut("bi.html", BI.Html); diff --git a/src/base/single/icon/icon.js b/src/base/single/icon/icon.js index 112ea539a..916206bbd 100644 --- a/src/base/single/icon/icon.js +++ b/src/base/single/icon/icon.js @@ -6,9 +6,10 @@ BI.Icon = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Icon.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { tagName: "i", - baseCls: (conf.baseCls || "") + " x-icon b-font horizon-center display-block" + baseCls: (conf.baseCls || "") + " x-icon b-font horizon-center display-block", }); }, @@ -16,6 +17,6 @@ BI.Icon = BI.inherit(BI.Single, { if (BI.isIE9Below && BI.isIE9Below()) { this.element.addClass("hack"); } - } + }, }); BI.shortcut("bi.icon", BI.Icon); diff --git a/src/base/single/iframe/__test__/iframe.test.js b/src/base/single/iframe/__test__/iframe.test.js index 8e99a48a0..9a9049ebc 100644 --- a/src/base/single/iframe/__test__/iframe.test.js +++ b/src/base/single/iframe/__test__/iframe.test.js @@ -5,13 +5,12 @@ */ describe("IframeTest", function () { - /** * test_author_windy */ it("directionPager", function () { var a = BI.Test.createWidget({ - type: "bi.iframe" + type: "bi.iframe", }); a.setSrc("http://www.baidu.com"); a.setName("testIFrame"); @@ -20,4 +19,4 @@ describe("IframeTest", function () { expect(a.getName(), "testIFrame"); a.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/single/iframe/iframe.js b/src/base/single/iframe/iframe.js index a7137fa58..e2df49e25 100644 --- a/src/base/single/iframe/iframe.js +++ b/src/base/single/iframe/iframe.js @@ -7,6 +7,7 @@ BI.Iframe = BI.inherit(BI.Single, { _defaultConfig: function (config) { var conf = BI.Iframe.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { tagName: "iframe", baseCls: (conf.baseCls || "") + " bi-iframe", @@ -14,7 +15,7 @@ BI.Iframe = BI.inherit(BI.Single, { name: "", attributes: {}, width: "100%", - height: "100%" + height: "100%", }); }, @@ -31,7 +32,7 @@ BI.Iframe = BI.inherit(BI.Single, { this.options.attributes = BI.extend({ frameborder: 0, src: o.src, - name: o.name + name: o.name, }, this.options.attributes); }, @@ -51,7 +52,7 @@ BI.Iframe = BI.inherit(BI.Single, { getName: function () { return this.options.name; - } + }, }); BI.shortcut("bi.iframe", BI.Iframe); diff --git a/src/base/single/img/__test__/img.test.js b/src/base/single/img/__test__/img.test.js index d16ca92d8..95c892b58 100644 --- a/src/base/single/img/__test__/img.test.js +++ b/src/base/single/img/__test__/img.test.js @@ -5,7 +5,6 @@ */ describe("ImgTest", function () { - /** * test_author_windy */ @@ -13,11 +12,11 @@ describe("ImgTest", function () { var a = BI.Test.createWidget({ type: "bi.img", iconWidth: 36, - iconHeight: 36 + iconHeight: 36, }); a.setSrc("test.png"); expect(a.element.attr("src")).to.equal("test.png"); expect(a.getSrc()).to.equal("test.png"); a.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/single/img/img.js b/src/base/single/img/img.js index aa90aaf40..ca715fb79 100644 --- a/src/base/single/img/img.js +++ b/src/base/single/img/img.js @@ -9,13 +9,14 @@ BI.Img = BI.inherit(BI.Single, { _defaultConfig: function (config) { var conf = BI.Img.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { tagName: "img", baseCls: (conf.baseCls || "") + " bi-img display-block", src: "", attributes: config.src ? { src: config.src } : {}, width: "100%", - height: "100%" + height: "100%", }); }, @@ -23,7 +24,7 @@ BI.Img = BI.inherit(BI.Single, { BI.Img.superclass._initProps.apply(this, arguments); var o = this.options; this.options.attributes = BI.extend({ - src: o.src + src: o.src, }, this.options.attributes); }, @@ -34,7 +35,7 @@ BI.Img = BI.inherit(BI.Single, { getSrc: function () { return this.options.src; - } + }, }); BI.shortcut("bi.img", BI.Img); diff --git a/src/base/single/input/checkbox/checkbox.image.js b/src/base/single/input/checkbox/checkbox.image.js index dc1703567..0400f6530 100644 --- a/src/base/single/input/checkbox/checkbox.image.js +++ b/src/base/single/input/checkbox/checkbox.image.js @@ -6,6 +6,7 @@ BI.ImageCheckbox = BI.inherit(BI.IconButton, { _defaultConfig: function () { var conf = BI.ImageCheckbox.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-image-checkbox check-box-icon", selected: false, @@ -13,10 +14,10 @@ BI.ImageCheckbox = BI.inherit(BI.IconButton, { width: 16, height: 16, iconWidth: 16, - iconHeight: 16 + iconHeight: 16, }); - } + }, }); BI.ImageCheckbox.EVENT_CHANGE = BI.IconButton.EVENT_CHANGE; -BI.shortcut("bi.image_checkbox", BI.ImageCheckbox); \ No newline at end of file +BI.shortcut("bi.image_checkbox", BI.ImageCheckbox); diff --git a/src/base/single/input/checkbox/checkbox.js b/src/base/single/input/checkbox/checkbox.js index 4a72f431f..b25d743e8 100644 --- a/src/base/single/input/checkbox/checkbox.js +++ b/src/base/single/input/checkbox/checkbox.js @@ -12,11 +12,12 @@ BI.Checkbox = BI.inherit(BI.BasicButton, { width: 14, height: 14, iconWidth: 14, - iconHeight: 14 + iconHeight: 14, }, render: function () { var self = this, o = this.options; + return { type: "bi.center_adapt", items: [{ @@ -26,8 +27,8 @@ BI.Checkbox = BI.inherit(BI.BasicButton, { }, cls: "checkbox-content", width: o.iconWidth, - height: o.iconHeight - }] + height: o.iconHeight, + }], }; }, @@ -42,7 +43,7 @@ BI.Checkbox = BI.inherit(BI.BasicButton, { doClick: function () { BI.Checkbox.superclass.doClick.apply(this, arguments); - if(this.isValid()) { + if (this.isValid()) { this.fireEvent(BI.Checkbox.EVENT_CHANGE); } }, @@ -54,7 +55,7 @@ BI.Checkbox = BI.inherit(BI.BasicButton, { } else { this.checkbox.element.removeClass("bi-high-light-background"); } - } + }, }); BI.Checkbox.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/single/input/file.js b/src/base/single/input/file.js index ff211e6f1..290970141 100644 --- a/src/base/single/input/file.js +++ b/src/base/single/input/file.js @@ -6,24 +6,24 @@ * @extends BI.Single * @abstract */ -(function (document) { - +((function (document) { /** * @description normalize input.files. create if not present, add item method if not present * @param Object generated wrap object * @return Object the wrap object itself */ - var F = (function (item) { + var F = ((function (item) { return function (input) { var files = input.files || [input]; if (!files.item) { files.item = item; } + return files; }; })(function (i) { return this[i]; - }); + })); var event = { @@ -37,10 +37,12 @@ add: document.addEventListener ? function (node, name, callback) { node.addEventListener(name, callback, false); + return this; } : function (node, name, callback) { node.attachEvent("on" + name, callback); + return this; }, @@ -54,10 +56,12 @@ del: document.removeEventListener ? function (node, name, callback) { node.removeEventListener(name, callback, false); + return this; } : function (node, name, callback) { node.detachEvent("on" + name, callback); + return this; }, @@ -77,11 +81,16 @@ } return false; - } + }, }; var sendFile = (function (toString) { - var multipart = function (boundary, name, file) { + var split = "onabort.onerror.onloadstart.onprogress".split("."), + length = split.length, + CRLF = "\r\n", + xhr = new XMLHttpRequest, + sendFile; + function multipart(boundary, name, file) { return "--".concat( boundary, CRLF, "Content-Disposition: form-data; name=\"", name, "\"; filename=\"", _global.encodeURIComponent(file.fileName), "\"", CRLF, @@ -90,15 +99,11 @@ file.getAsBinary(), CRLF, "--", boundary, "--", CRLF ); - }, - isFunction = function (Function) { + } + function isFunction (Function) { return toString.call(Function) === "[object Function]"; - }, - split = "onabort.onerror.onloadstart.onprogress".split("."), - length = split.length, - CRLF = "\r\n", - xhr = XMLHttpRequest ? new XMLHttpRequest : new ActiveXObject("Microsoft.XMLHTTP"), - sendFile; + } + // FireFox 3+, Safari 4 beta (Chrome 2 beta file is buggy and will not work) if (xhr.upload || xhr.sendAsBinary) { @@ -108,14 +113,14 @@ if (isFunction(handler.onerror)) { handler.onerror(); } - return; + + return; } - for (var - xhr = new XMLHttpRequest, + for (var xhr = new XMLHttpRequest, upload = xhr.upload || { addEventListener: function (event, callback) { this["on" + event] = callback; - } + }, }, i = 0; i < length; @@ -123,13 +128,14 @@ ) { upload.addEventListener( split[i].substring(2), + // eslint-disable-next-line no-loop-func (function (event) { return function (rpe) { if (isFunction(handler[event])) { handler[event](rpe, xhr); } }; - })(split[i]), + }(split[i])), false ); } @@ -174,49 +180,53 @@ }; xhr.onreadystatechange = function () { switch (xhr.readyState) { - case 2: - case 3: + case 2: + case 3: if (rpe.total <= rpe.loaded) { rpe.loaded = rpe.total; } upload.onprogress(rpe); break; - case 4: + case 4: clearInterval(rpe.interval); rpe.interval = 0; rpe.loaded = rpe.total; upload.onprogress(rpe); if (199 < xhr.status && xhr.status < 400) { - upload["onload"]({}); + upload.onload({}); var attachO = BI.jsonDecode(xhr.responseText); attachO.filename = handler.file.fileName; - if (handler.file.type.indexOf("image") != -1) { + if (handler.file.type.indexOf("image") !== -1) { attachO.attach_type = "image"; } handler.attach_array[current] = attachO; } else { - upload["onerror"]({}); + upload.onerror({}); } break; + default: + break; } }; upload.onloadstart(rpe); } else { xhr.onreadystatechange = function () { switch (xhr.readyState) { - case 4: + case 4: var attachO = BI.jsonDecode(xhr.responseText); - if (handler.file.type.indexOf("image") != -1) { + if (handler.file.type.indexOf("image") !== -1) { attachO.attach_type = "image"; } attachO.filename = handler.file.fileName; - if (handler.maxLength == 1) { + if (handler.maxLength === 1) { handler.attach_array[0] = attachO; // handler.attach_array.push(attachO); } else { handler.attach_array[current] = attachO; } break; + default: + break; } }; if (isFunction(upload.onloadstart)) { @@ -235,13 +245,13 @@ form.append("FileData", handler.file); xhr.send(form); } + return handler; }; - } - // Internet Explorer, Opera, others - else { + } else { + // Internet Explorer, Opera, others sendFile = function (handler, maxSize, width, height) { - var current = handler.current; + var current = handler.current, iframe, form; var url = handler.url.concat(-1 === handler.url.indexOf("?") ? "?" : "&", "AjaxUploadFrame=true"), rpe = { loaded: 1, total: 100, simulation: true, interval: setInterval(function () { @@ -251,9 +261,10 @@ if (isFunction(handler.onprogress)) { handler.onprogress(rpe, {}); } - }, 100) + }, 100), }, - onload = function () { + target = ["AjaxUpload", (new Date).getTime(), String(Math.random()).substring(2)].join("_"); + function onload() { iframe.onreadystatechange = iframe.onload = iframe.onerror = null; form.parentNode.removeChild(form); form = null; @@ -262,7 +273,7 @@ try { var responseText = (iframe.contentWindow.document || iframe.contentWindow.contentDocument).body.innerHTML; var attachO = BI.jsonDecode(responseText); - if (handler.file.type.indexOf("image") != -1) { + if (handler.file.type.indexOf("image") !== -1) { attachO.attach_type = "image"; } @@ -273,7 +284,7 @@ } catch (e) { attachO.filename = handler.file.fileName; } - if (handler.maxLength == 1) { + if (handler.maxLength === 1) { handler.attach_array[0] = attachO; } else { handler.attach_array[current] = attachO; @@ -286,8 +297,8 @@ if (isFunction(handler.onload)) { handler.onload(rpe, { responseText: responseText }); } - }, - target = ["AjaxUpload", (new Date).getTime(), String(Math.random()).substring(2)].join("_"); + } + try { // IE < 8 does not accept enctype attribute ... var form = document.createElement("
"), iframe = handler.iframe || (handler.iframe = document.createElement("")); @@ -320,8 +331,8 @@ loading: 2, interactive: 3, loaded: 4, - complete: 4 - }[iframe.readyState] || 1 + complete: 4, + }[iframe.readyState] || 1, }); } }; @@ -342,13 +353,12 @@ }; } xhr = null; + return sendFile; - })(Object.prototype.toString); - - var sendFiles = function (handler, maxSize, width, height) { + }(Object.prototype.toString)); + function sendFiles(handler, maxSize, width, height) { var length = handler.files.length, - i = 0, onload = handler.onload, onloadstart = handler.onloadstart; handler.current = 0; @@ -401,11 +411,12 @@ } }; } + return handler; - }; + } - var r1 = /\.([^.]+)$/; // .png - var r2 = /\/([^/]+)$/; // image/png + var r1 = /\.([^.]+)$/; // .png + var r2 = /\/([^/]+)$/; // image/png /** * 校验文件类型是否合法,同时兼容旧版形式 @@ -413,7 +424,7 @@ * @param fileType * @returns {boolean} */ - var fileTypeValidate = function (fileName, fileType) { + function fileTypeValidate(fileName, fileType) { if (!fileType) { return true; } @@ -421,25 +432,29 @@ if (mimes[0] === fileType) { mimes = (fileType + "").split(";"); } + return BI.some(mimes, function (index, mime) { var matches; - if (matches = mime.match(r1)) { + matches = mime.match(r1); + if (matches) { return fileName.toLowerCase().indexOf(matches[1]) > -1; } - if (matches = mime.match(r2)) { + matches = mime.match(r2); + if (matches) { return matches[1] === "*" ? true : fileName.toLowerCase().indexOf(matches[1]) > -1; } }); - }; + } BI.File = BI.inherit(BI.Widget, { _defaultConfig: function () { var conf = BI.File.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-file display-block", tagName: "input", attributes: { - type: "file" + type: "file", }, name: "", url: "", @@ -452,7 +467,7 @@ }, render: function () { - var self = this, o = this.options; + var o = this.options; if (o.multiple === true) { this.element.attr("multiple", "multiple"); } @@ -484,9 +499,9 @@ if (this.file.fileSize !== -1) { // simulation property indicates when the progress event is fake if (rpe.simulation) { - + // empty } else { - + // empty } } else { // if fileSIze is -1 browser is using an iframe because it does @@ -498,7 +513,7 @@ file: this.file, total: rpe.total, loaded: rpe.loaded, - simulation: rpe.simulation + simulation: rpe.simulation, }); }; @@ -522,19 +537,21 @@ if (200 > xhr.status || xhr.status > 399) { BI.Msg.toast(BI.i18nText("BI-Upload_File_Error"), { level: "error" }); self.fireEvent(BI.File.EVENT_ERROR); + return; } var error = BI.some(_wrap.attach_array, function (index, attach) { if (attach.errorCode) { BI.Msg.toast(BI.i18nText(attach.errorMsg), { level: "error" }); self.fireEvent(BI.File.EVENT_ERROR, attach); + return true; } }); !error && self.fireEvent(BI.File.EVENT_UPLOADED); }; _wrap.url = o.url; - _wrap.fileType = o.accept; // 文件类型限制 + _wrap.fileType = o.accept; // 文件类型限制 _wrap.attach_array = []; _wrap.attach_names = []; _wrap.attachNum = 0; @@ -548,35 +565,34 @@ var files = F(wrap.dom.input); if (o.maxLength !== -1 && o.maxLength < files.length) { self.fireEvent(BI.File.EVENT_ERROR, { - errorType: 2 + errorType: 2, }); } else { for (var i = 0; i < files.length; i++) { var item = files.item(i); var tempFile = item.value || item.name; var value = item.fileName || (item.fileName = tempFile.split("\\").pop()), - ext = -1 !== value.indexOf(".") ? value.split(".").pop().toLowerCase() : "unknown", size = item.fileSize || item.size; var validateFileType = fileTypeValidate(value, wrap.fileType); if (!validateFileType) { // 文件类型不支持 BI.Msg.toast(o.errorText({ errorType: 0, - file: item + file: item, }) || BI.i18nText("BI-Upload_File_Type_Error", wrap.fileType), { level: "error" }); self.fireEvent(BI.File.EVENT_ERROR, { errorType: 0, - file: item + file: item, }); } else if (wrap.maxSize !== -1 && size && wrap.maxSize < size) { // 文件大小不支持 BI.Msg.toast(o.errorText({ errorType: 1, - file: item + file: item, }) || BI.i18nText("BI-Upload_File_Size_Error", Math.ceil(wrap.maxSize / 1024 / 1024)), { level: "error" }); self.fireEvent(BI.File.EVENT_ERROR, { errorType: 1, - file: item + file: item, }); } else { wrap.files.unshift(item); @@ -584,18 +600,19 @@ } } wrap.files.length > 0 && self.fireEvent(BI.File.EVENT_CHANGE, { - files: wrap.files + files: wrap.files, }); input.value = ""; wrap.dom.input.parentNode.replaceChild(input, wrap.dom.input); wrap.dom.input = input; event.add(wrap.dom.input, "change", arguments.callee); }); + return wrap; }, _wrap: function () { - var self = this, o = this.options; + var o = this.options; // be sure input accept multiple files var input = this.element[0]; if (o.multiple === true) { @@ -608,14 +625,14 @@ // DOM namespace dom: { - input: input, // input file - disabled: false // internal use, checks input file state + input: input, // input file + disabled: false, // internal use, checks input file state }, - name: input.name, // name to send for each file ($_FILES[{name}] in the server) + name: input.name, // name to send for each file ($_FILES[{name}] in the server) // maxSize is the maximum amount of bytes for each file maxSize: o.maxSize ? o.maxSize >> 0 : -1, maxLength: o.maxLength, - files: [], // file list + files: [], // file list // remove every file from the noswfupload component clean: function () { @@ -632,6 +649,7 @@ } } sendFiles(this, this.maxSize); + return this; }, @@ -651,7 +669,7 @@ this.dom.disabled = true; this.dom.input.setAttribute("disabled", "disabled"); } - } + }, }); }, @@ -710,7 +728,7 @@ } else { this.element.attr("disabled", "disabled"); } - } + }, }); BI.File.EVENT_CHANGE = "EVENT_CHANGE"; BI.File.EVENT_UPLOADSTART = "EVENT_UPLOADSTART"; @@ -718,4 +736,4 @@ BI.File.EVENT_PROGRESS = "EVENT_PROGRESS"; BI.File.EVENT_UPLOADED = "EVENT_UPLOADED"; BI.shortcut("bi.file", BI.File); -})(_global.document || {}); +})(_global.document || {})); diff --git a/src/base/single/input/input.js b/src/base/single/input/input.js index e868a5747..8f20bddbb 100644 --- a/src/base/single/input/input.js +++ b/src/base/single/input/input.js @@ -7,12 +7,13 @@ BI.Input = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Input.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-input display-block overflow-dot", tagName: "input", validationChecker: BI.emptyFn, quitChecker: BI.emptyFn, // 按确定键能否退出编辑 - allowBlank: false + allowBlank: false, }); }, @@ -27,15 +28,15 @@ BI.Input = BI.inherit(BI.Single, { }, BI.EVENT_RESPONSE_TIME); var _clk = BI.debounce(BI.bind(this._click, this), BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); this._focusDebounce = BI.debounce(BI.bind(this._focus, this), BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); this._blurDebounce = BI.debounce(BI.bind(this._blur, this), BI.EVENT_RESPONSE_TIME, { "leading": true, - "trailing": false + "trailing": false, }); this.element .keydown(function (e) { @@ -86,7 +87,7 @@ BI.Input = BI.inherit(BI.Single, { this.element.addClass("bi-input-focus"); this._checkValidationOnValueChange(); this._isEditing = true; - if (this.getValue() == "") { + if (this.getValue() === "") { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this); this.fireEvent(BI.Input.EVENT_EMPTY); } @@ -139,7 +140,7 @@ BI.Input = BI.inherit(BI.Single, { this._checkValidationOnValueChange(); } if (this.isValid() && BI.trim(this.getValue()) !== "") { - if (BI.trim(this.getValue()) !== this._lastValue && (!this._start || this._lastValue == null || this._lastValue === "") + if (BI.trim(this.getValue()) !== this._lastValue && (!this._start || BI.isNull(this._lastValue) || this._lastValue === "") || (this._pause === true && !/(\s|\u00A0)$/.test(this.getValue()))) { this._start = true; this._pause = false; @@ -147,7 +148,7 @@ BI.Input = BI.inherit(BI.Single, { this.fireEvent(BI.Input.EVENT_START); } } - if (keyCode == BI.KeyCode.ENTER) { + if (BI.isEqual(keyCode, BI.KeyCode.ENTER)) { if (this.isValid() || this.options.quitChecker.apply(this, [BI.trim(this.getValue())]) !== false) { this.blur(); this.fireEvent(BI.Input.EVENT_ENTER); @@ -155,20 +156,20 @@ BI.Input = BI.inherit(BI.Single, { this.fireEvent(BI.Input.EVENT_RESTRICT); } } - if (keyCode == BI.KeyCode.SPACE) { + if (BI.isEqual(keyCode, BI.KeyCode.SPACE)) { this.fireEvent(BI.Input.EVENT_SPACE); } - if (keyCode == BI.KeyCode.BACKSPACE && this._lastValue == "") { + if (BI.isEqual(keyCode, BI.KeyCode.BACKSPACE) && this._lastValue === "") { this.fireEvent(BI.Input.EVENT_REMOVE); } - if (keyCode == BI.KeyCode.BACKSPACE || keyCode == BI.KeyCode.DELETE) { + if (BI.isEqual(keyCode, BI.KeyCode.BACKSPACE) || BI.isEqual(keyCode, BI.KeyCode.DELETE)) { this.fireEvent(BI.Input.EVENT_BACKSPACE); } this.fireEvent(BI.Input.EVENT_KEY_DOWN, arguments); // _valueChange中会更新_lastValue, 这边缓存用以后续STOP事件服务 var lastValue = this._lastValue; - if(BI.trim(this.getValue()) !== BI.trim(this._lastValue || "")){ + if (BI.trim(this.getValue()) !== BI.trim(this._lastValue || "")) { this._valueChange(); } if (BI.isEndWithBlank(this.getValue())) { @@ -185,7 +186,7 @@ BI.Input = BI.inherit(BI.Single, { // 初始状态 _defaultState: function () { - if (this.getValue() == "") { + if (this.getValue() === "") { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this); this.fireEvent(BI.Input.EVENT_EMPTY); } @@ -199,7 +200,7 @@ BI.Input = BI.inherit(BI.Single, { this.fireEvent(BI.Input.EVENT_CHANGE); this._lastSubmitValue = BI.trim(this.getValue()); } - if (this.getValue() == "") { + if (this.getValue() === "") { this.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.EMPTY, this.getValue(), this); this.fireEvent(BI.Input.EVENT_EMPTY); } @@ -209,14 +210,16 @@ BI.Input = BI.inherit(BI.Single, { _checkValidationOnValueChange: function (callback) { var self = this, o = this.options; var v = this.getValue(); - if (o.allowBlank === true && BI.trim(v) == "") { + if (o.allowBlank === true && BI.trim(v) === "") { this.setValid(true); callback && callback(); + return; } - if (BI.trim(v) == "") { + if (BI.trim(v) === "") { this.setValid(false); callback && callback(); + return; } var checker = o.validationChecker.apply(this, [BI.trim(v)]); @@ -224,7 +227,7 @@ BI.Input = BI.inherit(BI.Single, { checker.then(function (validate) { self.setValid(validate !== false); callback && callback(); - }) + }); } else { this.setValid(checker !== false); callback && callback(); @@ -306,7 +309,7 @@ BI.Input = BI.inherit(BI.Single, { _setEnable: function (b) { BI.Input.superclass._setEnable.apply(this, [b]); this.element[0].disabled = !b; - } + }, }); BI.Input.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/single/input/radio/radio.image.js b/src/base/single/input/radio/radio.image.js index e362592e4..f9d870f63 100644 --- a/src/base/single/input/radio/radio.image.js +++ b/src/base/single/input/radio/radio.image.js @@ -6,6 +6,7 @@ BI.ImageRadio = BI.inherit(BI.IconButton, { _defaultConfig: function () { var conf = BI.ImageRadio.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-radio radio-icon", selected: false, @@ -13,16 +14,16 @@ BI.ImageRadio = BI.inherit(BI.IconButton, { width: 16, height: 16, iconWidth: 16, - iconHeight: 16 + iconHeight: 16, }); }, doClick: function () { BI.ImageRadio.superclass.doClick.apply(this, arguments); - if(this.isValid()) { + if (this.isValid()) { this.fireEvent(BI.ImageRadio.EVENT_CHANGE); } - } + }, }); BI.ImageRadio.EVENT_CHANGE = BI.IconButton.EVENT_CHANGE; diff --git a/src/base/single/input/radio/radio.js b/src/base/single/input/radio/radio.js index f17e79e9e..d842196ae 100644 --- a/src/base/single/input/radio/radio.js +++ b/src/base/single/input/radio/radio.js @@ -12,11 +12,12 @@ BI.Radio = BI.inherit(BI.BasicButton, { width: 14, height: 14, iconWidth: 14, - iconHeight: 14 + iconHeight: 14, }, render: function () { var self = this, o = this.options; + return { type: "bi.center_adapt", items: [{ @@ -26,8 +27,8 @@ BI.Radio = BI.inherit(BI.BasicButton, { self.radio = _ref; }, width: o.iconWidth, - height: o.iconHeight - }] + height: o.iconHeight, + }], }; }, @@ -42,7 +43,7 @@ BI.Radio = BI.inherit(BI.BasicButton, { doClick: function () { BI.Radio.superclass.doClick.apply(this, arguments); - if(this.isValid()) { + if (this.isValid()) { this.fireEvent(BI.Radio.EVENT_CHANGE); } }, @@ -54,7 +55,7 @@ BI.Radio = BI.inherit(BI.BasicButton, { } else { this.radio.element.removeClass("bi-high-light-background"); } - } + }, }); BI.Radio.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/base/single/label/abstract.label.js b/src/base/single/label/abstract.label.js index 46e5e7969..c0443b39d 100644 --- a/src/base/single/label/abstract.label.js +++ b/src/base/single/label/abstract.label.js @@ -6,6 +6,7 @@ _defaultConfig: function (props) { var conf = BI.AbstractLabel.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { textAlign: "center", whiteSpace: "nowrap", // normal or nowrap @@ -36,11 +37,13 @@ if (BI.isFunction(text)) { return text(); } + return text; }, _createJson: function () { var o = this.options; + return { type: "bi.text", textAlign: o.textAlign, @@ -52,7 +55,7 @@ py: o.py, keyword: o.keyword, highLight: o.highLight, - handler: o.handler + handler: o.handler, }; }, @@ -80,10 +83,11 @@ element: this, items: [ { - el: (this.text = BI.createWidget(json)) + el: (this.text = BI.createWidget(json)), } - ] + ], }); + return; } BI.createWidget({ // 1.2 @@ -93,10 +97,11 @@ element: this, items: [ { - el: (this.text = BI.createWidget(json)) + el: (this.text = BI.createWidget(json)), } - ] + ], }); + return; } if (o.whiteSpace === "normal") { // 1.3 @@ -106,7 +111,7 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, }); this.text = BI.createWidget(json); BI.createWidget({ @@ -114,13 +119,14 @@ columnSize: ["auto"], // important! 让文字在flex布局下shrink为1 scrollable: o.whiteSpace === "normal", element: this, - items: [this.text] + items: [this.text], }); + return; } if (BI.isNumber(o.height) && o.height > 0) { // 1.4 this.element.css({ - "line-height": o.height / BI.pixRatio + BI.pixUnit + "line-height": o.height / BI.pixRatio + BI.pixUnit, }); json.textAlign = o.textAlign; delete json.maxWidth; @@ -131,8 +137,9 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, })); + return; } BI.extend(json, { // 1.5 @@ -142,7 +149,7 @@ rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, - maxWidth: "100%" + maxWidth: "100%", }); this.text = BI.createWidget(json); BI.createWidget({ @@ -150,11 +157,12 @@ columnSize: ["auto"], // important! 让文字在flex布局下shrink为1 scrollable: o.whiteSpace === "normal", element: this, - items: [this.text] + items: [this.text], }); + return; } - if (BI.isNumber(o.textWidth) && o.textWidth > 0) { // 1.6 + if (BI.isNumber(o.textWidth) && o.textWidth > 0) { // 1.6 json.maxWidth = o.textWidth; BI.createWidget({ type: "bi.center_adapt", @@ -163,10 +171,11 @@ element: this, items: [ { - el: (this.text = BI.createWidget(json)) + el: (this.text = BI.createWidget(json)), } - ] + ], }); + return; } if (o.whiteSpace === "normal") { // 1.7 @@ -176,7 +185,7 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, }); this.text = BI.createWidget(json); BI.createWidget({ @@ -184,13 +193,14 @@ columnSize: ["auto"], // important! 让文字在flex布局下shrink为1 scrollable: true, element: this, - items: [this.text] + items: [this.text], }); + return; } if (BI.isNumber(o.height) && o.height > 0) { // 1.8 this.element.css({ - "line-height": o.height / BI.pixRatio + BI.pixUnit + "line-height": o.height / BI.pixRatio + BI.pixUnit, }); json.textAlign = o.textAlign; delete json.maxWidth; @@ -201,8 +211,9 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, })); + return; } this.text = BI.createWidget(BI.extend(json, { @@ -211,13 +222,13 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, })); BI.createWidget({ type: "bi.center_adapt", columnSize: ["auto"], // important! 让文字在flex布局下shrink为1 element: this, - items: [this.text] + items: [this.text], }); }, @@ -238,10 +249,11 @@ element: this, items: [ { - el: (this.text = BI.createWidget(json)) + el: (this.text = BI.createWidget(json)), } - ] + ], }); + return; } BI.createWidget({ // 2.2 @@ -258,16 +270,17 @@ element: this, items: [ { - el: (this.text = BI.createWidget(json)) + el: (this.text = BI.createWidget(json)), } - ] + ], }); + return; } if (BI.isNumber(o.height) && o.height > 0) { // 2.3 if (o.whiteSpace !== "normal") { this.element.css({ - "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit + "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit, }); } delete json.maxWidth; @@ -278,8 +291,9 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, })); + return; } json.maxWidth = o.width - 2 * o.hgap - o.lgap - o.rgap; @@ -296,14 +310,15 @@ bgap: o.bgap, element: this, items: [{ - el: (this.text = BI.createWidget(json)) - }] + el: (this.text = BI.createWidget(json)), + }], }); + return; } if (BI.isNumber(o.textWidth) && o.textWidth > 0) { json.maxWidth = o.textWidth; - BI.createWidget({ // 2.5 + BI.createWidget({ // 2.5 type: adaptLayout, horizontalAlign: o.textAlign, columnSize: ["auto"], // important! 让文字在flex布局下shrink为1 @@ -317,16 +332,17 @@ element: this, items: [ { - el: (this.text = BI.createWidget(json)) + el: (this.text = BI.createWidget(json)), } - ] + ], }); + return; } if (BI.isNumber(o.height) && o.height > 0) { if (o.whiteSpace !== "normal") { this.element.css({ - "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit + "line-height": (o.height - (o.vgap * 2)) / BI.pixRatio + BI.pixUnit, }); } delete json.maxWidth; @@ -337,8 +353,9 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, })); + return; } this.text = BI.createWidget(BI.extend(json, { @@ -347,7 +364,7 @@ lgap: o.lgap, rgap: o.rgap, tgap: o.tgap, - bgap: o.bgap + bgap: o.bgap, })); BI.createWidget({ type: adaptLayout, @@ -355,7 +372,7 @@ columnSize: ["auto"], // important! 让文字在flex布局下shrink为1 element: this, scrollable: o.whiteSpace === "normal", - items: [this.text] + items: [this.text], }); }, @@ -394,6 +411,6 @@ this.options.text = v; this.text.setValue(v); } - } + }, }); }()); diff --git a/src/base/single/label/html.label.js b/src/base/single/label/html.label.js index 2ebe7815d..e1ac76b66 100644 --- a/src/base/single/label/html.label.js +++ b/src/base/single/label/html.label.js @@ -5,11 +5,12 @@ BI.HtmlLabel = BI.inherit(BI.AbstractLabel, { props: { - baseCls: "bi-html-label" + baseCls: "bi-html-label", }, _createJson: function () { var o = this.options; + return { type: "bi.html", textAlign: o.textAlign, @@ -17,9 +18,9 @@ BI.HtmlLabel = BI.inherit(BI.AbstractLabel, { lineHeight: o.textHeight, text: o.text, value: o.value, - handler: o.handler + handler: o.handler, }; - } + }, }); -BI.shortcut("bi.html_label", BI.HtmlLabel); \ No newline at end of file +BI.shortcut("bi.html_label", BI.HtmlLabel); diff --git a/src/base/single/label/icon.label.js b/src/base/single/label/icon.label.js index b5779c3e5..bff864f1d 100644 --- a/src/base/single/label/icon.label.js +++ b/src/base/single/label/icon.label.js @@ -21,12 +21,12 @@ BI.IconLabel = BI.inherit(BI.Single, { render: function () { var o = this.options; this.element.css({ - textAlign: "center" + textAlign: "center", }); this.icon = BI.createWidget({ type: "bi.icon", width: o.iconWidth, - height: o.iconHeight + height: o.iconHeight, }); if (BI.isNumber(o.height) && o.height > 0 && BI.isNull(o.iconWidth) && BI.isNull(o.iconHeight)) { this.element.css("lineHeight", (o.lineHeight || o.height) / BI.pixRatio + BI.pixUnit); @@ -39,7 +39,7 @@ BI.IconLabel = BI.inherit(BI.Single, { rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, - items: [this.icon] + items: [this.icon], }); } else { this.element.css("lineHeight", "1"); @@ -52,9 +52,9 @@ BI.IconLabel = BI.inherit(BI.Single, { rgap: o.rgap, tgap: o.tgap, bgap: o.bgap, - items: [this.icon] + items: [this.icon], }); } - } + }, }); BI.shortcut("bi.icon_label", BI.IconLabel); diff --git a/src/base/single/label/label.js b/src/base/single/label/label.js index 37129087c..98bfa3707 100644 --- a/src/base/single/label/label.js +++ b/src/base/single/label/label.js @@ -7,7 +7,7 @@ BI.Label = BI.inherit(BI.AbstractLabel, { props: { baseCls: "bi-label", py: "", - keyword: "" + keyword: "", }, doRedMark: function () { @@ -16,7 +16,7 @@ BI.Label = BI.inherit(BI.AbstractLabel, { unRedMark: function () { this.text.unRedMark.apply(this.text, arguments); - } + }, }); BI.shortcut("bi.label", BI.Label); diff --git a/src/base/single/link/__test__/link.test.js b/src/base/single/link/__test__/link.test.js index e425cb44b..630d1da71 100644 --- a/src/base/single/link/__test__/link.test.js +++ b/src/base/single/link/__test__/link.test.js @@ -5,15 +5,14 @@ */ describe("LinkTest", function () { - /** * test_author_windy */ it("link", function () { var a = BI.Test.createWidget({ - type: "bi.link" + type: "bi.link", }); - expect(a.element.is('a')).to.equal(true); + expect(a.element.is("a")).to.equal(true); a.destroy(); }); -}); \ No newline at end of file +}); diff --git a/src/base/single/link/link.js b/src/base/single/link/link.js index 680893537..176389af5 100644 --- a/src/base/single/link/link.js +++ b/src/base/single/link/link.js @@ -6,16 +6,18 @@ BI.Link = BI.inherit(BI.Label, { _defaultConfig: function () { var conf = BI.Link.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { baseCls: (conf.baseCls || "") + " bi-link display-block", tagName: "a", href: "", - target: "_blank" + target: "_blank", }); }, _createJson: function () { var o = this.options; + return { type: "bi.a", textAlign: o.textAlign, @@ -26,9 +28,9 @@ BI.Link = BI.inherit(BI.Label, { value: o.value, py: o.py, href: o.href, - target: o.target + target: o.target, }; - } + }, }); BI.shortcut("bi.link", BI.Link); diff --git a/src/base/single/text.pure.js b/src/base/single/text.pure.js index 7c4d93c0c..07a201369 100644 --- a/src/base/single/text.pure.js +++ b/src/base/single/text.pure.js @@ -5,7 +5,7 @@ BI.PureText = BI.inherit(BI.Widget, { props: { - tagName: null + tagName: null, }, render: function () { @@ -27,6 +27,7 @@ if (!BI.isKey(text)) { return ""; } + return BI.Text.formatText(text + ""); }, @@ -38,7 +39,7 @@ setText: function (text) { this.options.text = BI.isNotNull(text) ? text : ""; this.element.__textKeywordMarked__(this._getShowText()); - } + }, }); BI.shortcut("bi.pure_text", BI.PureText); }()); diff --git a/src/base/single/tip/0.tip.js b/src/base/single/tip/0.tip.js index c792b91b3..a13240d8b 100644 --- a/src/base/single/tip/0.tip.js +++ b/src/base/single/tip/0.tip.js @@ -9,14 +9,15 @@ BI.Tip = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Tip.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { _baseCls: (conf._baseCls || "") + " bi-tip", - zIndex: BI.zIndex_tip + zIndex: BI.zIndex_tip, }); }, _init: function () { BI.Tip.superclass._init.apply(this, arguments); - this.element.css({zIndex: this.options.zIndex}); - } -}); \ No newline at end of file + this.element.css({ zIndex: this.options.zIndex }); + }, +}); diff --git a/src/base/single/tip/tip.toast.js b/src/base/single/tip/tip.toast.js index 0440ee23d..4b59260c9 100644 --- a/src/base/single/tip/tip.toast.js +++ b/src/base/single/tip/tip.toast.js @@ -31,14 +31,15 @@ BI.Toast = BI.inherit(BI.Tip, { var self = this, o = this.options, c = this._const; this.element.css({ minWidth: (o.closable ? c.closableMinWidth : c.minWidth) / BI.pixRatio + BI.pixUnit, - maxWidth: (o.closable ? c.closableMaxWidth : c.maxWidth) / BI.pixRatio + BI.pixUnit + maxWidth: (o.closable ? c.closableMaxWidth : c.maxWidth) / BI.pixRatio + BI.pixUnit, }); this.element.addClass("toast-" + o.level); - var fn = function (e) { + function fn(e) { e.stopPropagation(); e.stopEvent(); + return false; - }; + } this.element.bind({ click: fn, mousedown: fn, @@ -46,7 +47,7 @@ BI.Toast = BI.inherit(BI.Tip, { mouseover: fn, mouseenter: fn, mouseleave: fn, - mousemove: fn + mousemove: fn, }); var cls; switch (o.level) { @@ -68,9 +69,9 @@ BI.Toast = BI.inherit(BI.Tip, { break; } - var hasCloseIcon = function () { + function hasCloseIcon() { return o.closable === true || (o.closable === null && o.autoClose === false); - }; + } var items = [{ type: "bi.icon_label", cls: cls + " toast-icon", @@ -81,7 +82,7 @@ BI.Toast = BI.inherit(BI.Tip, { whiteSpace: "normal", text: o.text, textHeight: o.textHeight, - textAlign: "left" + textAlign: "left", }, }]; @@ -106,13 +107,13 @@ BI.Toast = BI.inherit(BI.Tip, { hgap: o.hgap, vgap: o.vgap, innerHgap: o.innerHgap, - columnSize: columnSize + columnSize: columnSize, }; }, beforeDestroy: function () { this.fireEvent(BI.Toast.EVENT_DESTORY); - } + }, }); BI.Toast.EVENT_DESTORY = "EVENT_DESTORY"; BI.shortcut("bi.toast", BI.Toast); diff --git a/src/base/single/tip/tip.tooltip.js b/src/base/single/tip/tip.tooltip.js index 5499f05ac..70c710497 100644 --- a/src/base/single/tip/tip.tooltip.js +++ b/src/base/single/tip/tip.tooltip.js @@ -8,7 +8,7 @@ BI.Tooltip = BI.inherit(BI.Tip, { _const: { hgap: 8, - vgap: 4 + vgap: 4, }, _defaultConfig: function () { @@ -23,12 +23,12 @@ BI.Tooltip = BI.inherit(BI.Tip, { }, render: function () { - var self = this, o = this.options; + var o = this.options; this.element.addClass("tooltip-" + o.level); - var fn = function (e) { + function fn(e) { o.stopPropagation && e.stopPropagation(); o.stopEvent && e.stopEvent(); - }; + } this.element.bind({ click: fn, mousedown: fn, @@ -36,7 +36,7 @@ BI.Tooltip = BI.inherit(BI.Tip, { mouseover: fn, mouseenter: fn, mouseleave: fn, - mousemove: fn + mousemove: fn, }); var texts = (o.text + "").split("\n"); @@ -52,9 +52,9 @@ BI.Tooltip = BI.inherit(BI.Tip, { textAlign: o.textAlign, whiteSpace: "normal", text: text, - textHeight: 18 + textHeight: 18, }; - }) + }), }); } else { this.text = BI.createWidget({ @@ -81,7 +81,7 @@ BI.Tooltip = BI.inherit(BI.Tip, { setLevel: function (level) { this.element.removeClass("tooltip-success").removeClass("tooltip-warning"); this.element.addClass("tooltip-" + level); - } + }, }); BI.shortcut("bi.tooltip", BI.Tooltip); diff --git a/src/base/single/trigger/trigger.js b/src/base/single/trigger/trigger.js index 9e97d2226..486ae898f 100644 --- a/src/base/single/trigger/trigger.js +++ b/src/base/single/trigger/trigger.js @@ -7,9 +7,10 @@ BI.Trigger = BI.inherit(BI.Single, { _defaultConfig: function () { var conf = BI.Trigger.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { _baseCls: (conf._baseCls || "") + " bi-trigger cursor-pointer", - height: 24 + height: 24, }); }, diff --git a/src/base/tree/customtree.js b/src/base/tree/customtree.js index a72edba2a..c20af875a 100644 --- a/src/base/tree/customtree.js +++ b/src/base/tree/customtree.js @@ -13,8 +13,8 @@ BI.CustomTree = BI.inherit(BI.Widget, { expander: { el: {}, popup: { - type: "bi.custom_tree" - } + type: "bi.custom_tree", + }, }, items: [], @@ -24,9 +24,9 @@ BI.CustomTree = BI.inherit(BI.Widget, { type: "bi.button_tree", chooseType: 0, layouts: [{ - type: "bi.vertical" - }] - } + type: "bi.vertical", + }], + }, }); }, @@ -45,12 +45,12 @@ BI.CustomTree = BI.inherit(BI.Widget, { var item = BI.extend({ type: "bi.expander", el: { - value: node.value + value: node.value, }, - popup: {type: "bi.custom_tree"} + popup: { type: "bi.custom_tree" }, }, BI.deepClone(o.expander), { id: node.id, - pId: node.pId + pId: node.pId, }); var el = BI.stripEL(node); if (!BI.isWidget(el)) { @@ -68,6 +68,7 @@ BI.CustomTree = BI.inherit(BI.Widget, { } var args = Array.prototype.slice.call(arguments, 0); args[0].node = node; + return o.itemsCreator.apply(self, args); }; BI.isNull(item.popup.el) && (item.popup.el = BI.deepClone(o.el)); @@ -76,6 +77,7 @@ BI.CustomTree = BI.inherit(BI.Widget, { items.push(node); } }); + return items; }, @@ -92,7 +94,7 @@ BI.CustomTree = BI.inherit(BI.Widget, { callback.apply(null, args); }]); }, - value: o.value + value: o.value, }); this.tree.on(BI.Controller.EVENT_CHANGE, function (type, val, obj) { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); @@ -141,8 +143,8 @@ BI.CustomTree = BI.inherit(BI.Widget, { empty: function () { this.tree.empty(); - } + }, }); BI.CustomTree.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.custom_tree", BI.CustomTree); \ No newline at end of file +BI.shortcut("bi.custom_tree", BI.CustomTree); diff --git a/src/case/button/item.multiselect.js b/src/case/button/item.multiselect.js index 0d44b6da8..b90fafac5 100644 --- a/src/case/button/item.multiselect.js +++ b/src/case/button/item.multiselect.js @@ -20,11 +20,6 @@ BI.MultiSelectItem = BI.inherit(BI.BasicButton, { this.checkbox = BI.createWidget({ type: "bi.checkbox" }); - this.checkbox.on(BI.Controller.EVENT_CHANGE, function (type) { - if (type === BI.Events.CLICK) { - self.setSelected(self.isSelected()); - } - }); return { type: "bi.vertical_adapt", columnSize: [o.iconWrapperWidth || o.height, "fill"], @@ -74,7 +69,6 @@ BI.MultiSelectItem = BI.inherit(BI.BasicButton, { doClick: function () { BI.MultiSelectItem.superclass.doClick.apply(this, arguments); - this.checkbox.setSelected(this.isSelected()); if (this.isValid()) { this.fireEvent(BI.MultiSelectItem.EVENT_CHANGE, this.getValue(), this); } diff --git a/src/case/button/item.singleselect.radio.js b/src/case/button/item.singleselect.radio.js index a7c5fe04b..74ebe49c9 100644 --- a/src/case/button/item.singleselect.radio.js +++ b/src/case/button/item.singleselect.radio.js @@ -28,16 +28,6 @@ BI.SingleSelectRadioItem = BI.inherit(BI.BasicButton, { ref: function (_ref) { self.radio = _ref; }, - listeners: [ - { - eventName: BI.Controller.EVENT_CHANGE, - action: function (type) { - if (type === BI.Events.CLICK) { - self.setSelected(self.isSelected()); - } - } - } - ], }] }, { el: { @@ -82,7 +72,6 @@ BI.SingleSelectRadioItem = BI.inherit(BI.BasicButton, { doClick: function () { BI.SingleSelectRadioItem.superclass.doClick.apply(this, arguments); - this.radio.setSelected(this.isSelected()); if (this.isValid()) { this.fireEvent(BI.SingleSelectRadioItem.EVENT_CHANGE, this.isSelected(), this); } diff --git a/src/case/button/node/siwtcher.tree.node.js b/src/case/button/node/siwtcher.tree.node.js new file mode 100644 index 000000000..c118518d6 --- /dev/null +++ b/src/case/button/node/siwtcher.tree.node.js @@ -0,0 +1,59 @@ +BI.TreeNodeSwitcher = BI.inherit(BI.NodeButton, { + _defaultConfig: function () { + return BI.extend(BI.TreeNodeSwitcher.superclass._defaultConfig.apply(this, arguments), { + baseCls: "bi-tree-node-switcher", + iconWidth: 24, + iconHeight: 24, + isFirstNode: false, + isLastNode: false, + layer: 0 + }); + }, + + render: function () { + + const [collapse, expand] = this.getIconCls(); + + return { + type: "bi.icon_label", + iconWidth: this.options.iconWidth, + iconHeight: this.options.iconHeight, + cls: this.options.open ? expand : collapse, + }; + }, + + getIconCls: function () { + var options = this.options; + if (options.layer === 0 && options.isFirstNode && options.isLastNode) { + // 只有一层,并且是第一个节点,并且是最后一个节点 + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? ["tree-solid-collapse-icon-type1", "tree-solid-expand-icon-type1"] : ["tree-collapse-icon-type1", "tree-expand-icon-type1"]; + } else if (options.layer === 0 && options.isFirstNode) { + // 第一层,并且是第一个节点 + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? ["tree-solid-collapse-icon-type2", "tree-solid-expand-icon-type2"] : ["tree-collapse-icon-type2", "tree-expand-icon-type2"]; + } else if (options.isLastNode) { + // 最后一个节点 + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? ["tree-solid-collapse-icon-type4", "tree-solid-expand-icon-type4"] : ["tree-collapse-icon-type4", "tree-expand-icon-type4"]; + } else { + // 其他情况 + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? ["tree-solid-collapse-icon-type3", "tree-solid-expand-icon-type3"] : ["tree-collapse-icon-type3", "tree-expand-icon-type3"]; + } + }, + + setOpened: function (b) { + BI.TreeNodeSwitcher.superclass.setOpened.apply(this, arguments); + const [collapse, expand] = this.getIconCls(); + if (b) { + this.element.addClass(expand).removeClass(collapse); + } else { + this.element.addClass(collapse).removeClass(expand); + } + }, + + doClick: function () { + BI.TreeNodeSwitcher.superclass.doClick.apply(this, arguments); + this.fireEvent(BI.TreeNodeSwitcher.EVENT_CHANGE, this); + } +}); + +BI.TreeNodeSwitcher.EVENT_CHANGE = "EVENT_CHANGE"; +BI.shortcut("bi.tree_node_switcher", BI.TreeNodeSwitcher); diff --git a/src/case/button/node/treenode.js b/src/case/button/node/treenode.js new file mode 100644 index 000000000..c557f791c --- /dev/null +++ b/src/case/button/node/treenode.js @@ -0,0 +1,106 @@ +BI.BasicTreeNode = BI.inherit(BI.NodeButton, { + _defaultConfig: function (props) { + var conf = BI.BasicTreeNode.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { + baseCls: (conf.baseCls || "") + " bi-tree-node " + (props.selectable ? "bi-list-item-active" : "bi-list-item"), + id: "", + pId: "", + open: false, + height: 24, + readonly: true, + isFirstNode: false, + isLastNode: false, + switcherIcon: {}, + selectable: true, + disabled: false, // disabled不会影响展开收起功能 + }); + }, + + render: function () { + var self = this, o = this.options; + + const checkbox = { + type: "bi.tree_node_switcher", + __ref: function (_ref) { + self.switcher = _ref; + }, + iconHeight: o.height, + iconWidth: o.iconWrapperWidth || o.height, + open: o.open, + isFirstNode: o.isFirstNode, + isLastNode: o.isLastNode, + layer: o.layer, + ...o.switcherIcon, + stopPropagation: o.selectable, + mounted: function () { + this.setEnable(true); + }, + listeners: [ + { + eventName: "EVENT_CHANGE", + action: () => { + if (!this.isEnabled() || o.selectable) { + this.isOpened() ? this.triggerCollapse() : this.triggerExpand(); + } + } + } + ] + }; + + return { + type: "bi.vertical_adapt", + columnSize: [o.iconWrapperWidth || o.height, "fill"], + items: [ + { + el: checkbox, + lgap: o.layer * BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT / 2, // 偏移公式为每一层的偏移量为节点高度的一半 + }, { + el: { + type: "bi.label", + ref: function (_ref) { + self.text = _ref; + }, + textAlign: "left", + whiteSpace: "nowrap", + textHeight: o.height, + height: o.height, + hgap: o.hgap || o.textHgap, + vgap: o.textVgap, + lgap: o.textLgap, + rgap: o.textRgap, + text: o.text, + value: o.value, + keyword: o.keyword, + py: o.py + } + } + ] + }; + }, + + doRedMark: function () { + this.text.doRedMark.apply(this.text, arguments); + }, + + unRedMark: function () { + this.text.unRedMark.apply(this.text, arguments); + }, + + doClick: function () { + if (this.options.selectable) { + return; + } + BI.BasicTreeNode.superclass.doClick.apply(this, arguments); + }, + + setOpened: function (v) { + BI.BasicTreeNode.superclass.setOpened.apply(this, arguments); + this.switcher.setOpened(v); + }, + + setValue: function () { + BI.BasicTreeNode.superclass.setValue.apply(this, arguments); + } +}); + +BI.shortcut("bi.tree_node", BI.BasicTreeNode); diff --git a/src/case/button/treeitem/treeitem.js b/src/case/button/treeitem/treeitem.js new file mode 100644 index 000000000..dd7e008f6 --- /dev/null +++ b/src/case/button/treeitem/treeitem.js @@ -0,0 +1,86 @@ +BI.BasicTreeItem = BI.inherit(BI.NodeButton, { + _defaultConfig: function () { + var conf = BI.BasicTreeItem.superclass._defaultConfig.apply(this, arguments); + return BI.extend(conf, { + baseCls: (conf.baseCls || "") + " bi-tree-item bi-list-item-active", + id: "", + pId: "", + height: 24, + readonly: true, + isFirstNode: false, + isLastNode: false, + }); + }, + + render: function () { + var self = this, o = this.options; + + return { + type: "bi.vertical_adapt", + columnSize: ["", "fill"], + items: [ + { + el: { + type: "bi.layout", + height: o.height, + width: o.height, + cls: this.getLineCls(), + }, + lgap: o.layer * BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT / 2, // 偏移公式为每一层的偏移量为节点高度的一半 + }, + { + el: { + type: "bi.label", + ref: function (_ref) { + self.text = _ref; + }, + textAlign: "left", + whiteSpace: "nowrap", + textHeight: o.height, + height: o.height, + hgap: o.hgap || o.textHgap, + vgap: o.textVgap, + lgap: o.textLgap, + rgap: o.textRgap, + text: o.text, + value: o.value, + keyword: o.keyword, + py: o.py + }, + } + ] + }; + }, + + getLineCls: function () { + var options = this.options; + if (options.layer === 0 && options.isFirstNode && options.isLastNode) { + return ""; + } else if (options.layer === 0 && options.isFirstNode) { + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? "first-solid-line-conn-background" : "first-line-conn-background"; + } else if (options.isLastNode) { + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? "last-solid-line-conn-background" : "last-line-conn-background"; + } else { + return BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? "mid-solid-line-conn-background" : "mid-line-conn-background"; + } + }, + + doRedMark: function () { + this.text.doRedMark.apply(this.text, arguments); + }, + + unRedMark: function () { + this.text.unRedMark.apply(this.text, arguments); + }, + + getId: function () { + return this.options.id; + }, + + getPId: function () { + return this.options.pId; + } + +}); + +BI.shortcut("bi.tree_item", BI.BasicTreeItem); diff --git a/src/case/combo/bubblecombo/popup.bubble.js b/src/case/combo/bubblecombo/popup.bubble.js index 7bc1f500c..6826a99f5 100644 --- a/src/case/combo/bubblecombo/popup.bubble.js +++ b/src/case/combo/bubblecombo/popup.bubble.js @@ -36,7 +36,9 @@ BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, { }, { text: BI.i18nText(BI.i18nText("BI-Basic_OK")), value: true - }] + }], + innerVgap: 16, + innerHgap: 16, }); }, @@ -48,8 +50,7 @@ BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, { if (BI.isWidget(buttonOpt)) { items.push({ el: buttonOpt, - lgap: i === 0 ? 15 : 10, - rgap: i === o.buttons.length - 1 ? 15 : 0 + lgap: 12, }); } else { items.push({ @@ -60,14 +61,14 @@ BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, { self.fireEvent(BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON, v); } }, buttonOpt), - lgap: i === 0 ? 15 : 10, - rgap: i === o.buttons.length - 1 ? 15 : 0 + lgap: 12, }); } }); return BI.createWidget({ type: "bi.right_vertical_adapt", - height: 44, + innerVgap: o.innerVgap, + innerHgap: o.innerHgap, items: items }); }, @@ -79,20 +80,17 @@ BI.BubblePopupBarView = BI.inherit(BI.BubblePopupView, { _createView: function () { var o = this.options; - var button = BI.createWidget({ - type: "bi.button_group", + var view = BI.createWidget({ + type: "bi.vertical", items: [this._createContent()], - layouts: [{ - type: "bi.vertical", - cls: "bar-popup-container", - hgap: BI.SIZE_CONSANTS.H_GAP_SIZE, - tgap: BI.SIZE_CONSANTS.V_GAP_SIZE - }] + cls: "bar-popup-container", + hgap: o.innerHgap, + tgap: o.innerVgap, }); - button.element.css("min-height", o.minHeight - 44); + view.element.css("min-height", o.minHeight); - return button; + return view; } }); BI.BubblePopupBarView.EVENT_CLICK_TOOLBAR_BUTTON = "EVENT_CLICK_TOOLBAR_BUTTON"; diff --git a/src/case/combo/iconcombo/combo.icon.js b/src/case/combo/iconcombo/combo.icon.js index 81050859a..6c0f45c51 100644 --- a/src/case/combo/iconcombo/combo.icon.js +++ b/src/case/combo/iconcombo/combo.icon.js @@ -20,7 +20,9 @@ BI.IconCombo = BI.inherit(BI.Widget, { adjustXOffset: 0, adjustYOffset: 0, offsetStyle: "left", - chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE + chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, + isShowDown: true, + hideWhenAnotherComboOpen: false }); }, @@ -42,7 +44,8 @@ BI.IconCombo = BI.inherit(BI.Widget, { height: o.height, iconWidth: o.iconWidth, iconHeight: o.iconHeight, - value: o.value + value: o.value, + isShowDown: o.isShowDown }); this.popup = BI.createWidget(o.popup, { type: "bi.icon_combo_popup", @@ -69,6 +72,7 @@ BI.IconCombo = BI.inherit(BI.Widget, { adjustYOffset: o.adjustYOffset, offsetStyle: o.offsetStyle, el: this.trigger, + hideWhenAnotherComboOpen: o.hideWhenAnotherComboOpen, popup: { el: this.popup, maxWidth: o.maxWidth, diff --git a/src/case/combo/searchtextvaluecombo/combo.searchtextvalue.js b/src/case/combo/searchtextvaluecombo/combo.searchtextvalue.js index 8de574c76..09608dea9 100644 --- a/src/case/combo/searchtextvaluecombo/combo.searchtextvalue.js +++ b/src/case/combo/searchtextvaluecombo/combo.searchtextvalue.js @@ -33,7 +33,6 @@ BI.SearchTextValueCombo = BI.inherit(BI.Widget, { adjustLength: 2, height: height, width: width, - toggle: false, ref: function () { self.combo = this; }, diff --git a/src/case/combo/searchtextvaluecombo/trigger.searchtextvalue.js b/src/case/combo/searchtextvaluecombo/trigger.searchtextvalue.js index c61093b35..7f6f7925d 100644 --- a/src/case/combo/searchtextvaluecombo/trigger.searchtextvalue.js +++ b/src/case/combo/searchtextvaluecombo/trigger.searchtextvalue.js @@ -24,10 +24,6 @@ BI.SearchTextValueTrigger = BI.inherit(BI.Trigger, { }, width: o.height, height: o.height, - stopPropagation: true, - handler: function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.TOGGLE); - } }; var stateText = this._digest(o.value, o.items) || o.text; diff --git a/src/case/combo/textvaluecombo/combo.textvalue.js b/src/case/combo/textvaluecombo/combo.textvalue.js index 633656464..dc39d1b1e 100644 --- a/src/case/combo/textvaluecombo/combo.textvalue.js +++ b/src/case/combo/textvaluecombo/combo.textvalue.js @@ -12,7 +12,9 @@ BI.TextValueCombo = BI.inherit(BI.Widget, { chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, text: "", value: "", + defaultText: "", allowClear: false, + status: "success", // success | warning | error }); }, @@ -27,94 +29,137 @@ BI.TextValueCombo = BI.inherit(BI.Widget, { self.populate(newValue); }) : o.items; BI.TextValueCombo.superclass._init.apply(this, arguments); - this.trigger = BI.createWidget({ + }, + + render: function () { + + const o = this.options; + + const trigger = { type: "bi.select_text_trigger", + ref: ref => this.trigger = ref, cls: "text-value-trigger", items: o.items, height: o.height, text: o.text, value: o.value, - warningTitle: o.warningTitle, + title: () => { + if (this.options.status === "error") { + return { + level: "warning", + text: o.warningTitle, + }; + } + return { + level: "success", + }; + }, allowClear: o.allowClear, + defaultText: o.defaultText, listeners: [ { eventName: BI.SelectTextTrigger.EVENT_CLEAR, - action: function () { - self._clear(); - self.fireEvent(BI.TextValueCombo.EVENT_CHANGE); + action: () => { + this._clear(); + this.fireEvent(BI.TextValueCombo.EVENT_CHANGE); } } ], - }); - this.popup = BI.createWidget({ + }; + const popup = { type: "bi.text_value_combo_popup", + ref: ref => this.popup = ref, chooseType: o.chooseType, value: o.value, - items: o.items - }); - this.popup.on(BI.TextValueComboPopup.EVENT_CHANGE, function () { - self.setValue(self.popup.getValue()); - self.textIconCombo.hideView(); - self.fireEvent(BI.TextValueCombo.EVENT_CHANGE, arguments); - }); - this.popup.on(BI.Controller.EVENT_CHANGE, function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); - }); - this.textIconCombo = BI.createWidget({ + items: o.items, + listeners: [ + { + eventName: BI.TextValueComboPopup.EVENT_CHANGE, + action: (...args) => { + this.setValue(this.popup.getValue()); + this.combo.hideView(); + this.fireEvent(BI.TextValueCombo.EVENT_CHANGE, ...args); + } + }, { + eventName: BI.Controller.EVENT_CHANGE, + action: (...args) => { + this.fireEvent(BI.Controller.EVENT_CHANGE, ...args); + } + } + ] + }; + + return { type: "bi.combo", + ref: ref => this.combo = ref, container: o.container, direction: o.direction, - element: this, adjustLength: 2, - el: this.trigger, + el: trigger, popup: { - el: this.popup, + el: popup, + value: o.value, maxHeight: 240, minHeight: 25 } - }); + }; + }, + + mounted: function () { + const o = this.options; if (BI.isKey(o.value)) { this._checkError(o.value); } }, _clear: function () { - this.setValue(); + this.combo.setValue(); + this.setStatus("success"); }, _checkError: function (v) { - v = BI.isArray(v) ? v[0] : v; - var tipType = null; + + if (BI.isNull(v)) { + this.setStatus("success"); + return; + } + + var vals = BI.isArray(v) ? v : [v]; + var result = BI.find(this.options.items, function (idx, item) { - return v === item.value; + return BI.contains(vals, item.value); }); + if (BI.isNull(result)) { - if (this.isEnabled()) { - tipType = "warning"; - } - this.element.addClass("error"); - this.trigger.element.addClass("error"); + this.setStatus("error"); } else { - this.element.removeClass("error"); - this.trigger.element.removeClass("error"); + this.setStatus("success"); } - this.trigger.setTipType(tipType); + }, + + clear: function () { + this._clear(); }, setValue: function (v) { - this.trigger.setValue(v); - this.popup.setValue(v); + this.combo.setValue(v); this._checkError(v); }, + setStatus: function (status) { + this.element.removeClass(`bi-status-${this.options.status}`); + this.element.addClass(`bi-status-${status}`); + this.options.status = status; + }, + getValue: function () { - var value = this.popup.getValue(); + var value = this.combo.getValue(); return BI.isNull(value) ? [] : (BI.isArray(value) ? value : [value]); }, populate: function (items) { this.options.items = items; - this.textIconCombo.populate(items); + this.combo.populate(items); } }); BI.TextValueCombo.EVENT_CHANGE = "EVENT_CHANGE"; diff --git a/src/case/editor/editor.defaulttext.js b/src/case/editor/editor.defaulttext.js index 5c01c7a01..4cfaf59a5 100644 --- a/src/case/editor/editor.defaulttext.js +++ b/src/case/editor/editor.defaulttext.js @@ -46,12 +46,15 @@ BI.DefaultTextEditor = BI.inherit(BI.Widget, { errorText: o.errorText, invisible: true, }); + + var showText = BI.isFunction(o.text) ? o.text() : o.text; + this.text = BI.createWidget({ type: "bi.text_button", - cls: BI.isKey(o.text) ? "tip-text-style" : "bi-water-mark tip-text-style", + cls: BI.isKey(showText) ? "tip-text-style" : "bi-water-mark tip-text-style", textAlign: "left", height: o.height, - text: BI.isKey(o.text) ? o.text : o.defaultText, + text: showText || o.defaultText, hgap: o.hgap + 2, handler: function () { self._showInput(); diff --git a/src/case/editor/editor.state.js b/src/case/editor/editor.state.js index d1e11b20a..e9d3900bd 100644 --- a/src/case/editor/editor.state.js +++ b/src/case/editor/editor.state.js @@ -21,8 +21,8 @@ BI.StateEditor = BI.inherit(BI.Widget, { watermark: "", errorText: "", height: 24, - defaultText: "", // 默认显示值,默认显示值与显示值的区别是默认显示值标记灰色 - text: BI.i18nText("BI-Basic_Unrestricted"), // 显示值 + defaultText: BI.i18nText("BI-Basic_Unrestricted"), // 默认显示值,默认显示值与显示值的区别是默认显示值标记灰色 + text: "", // 显示值 el: {} }); }, diff --git a/src/case/editor/editor.state.simple.js b/src/case/editor/editor.state.simple.js index 81b815441..4d17ab30e 100644 --- a/src/case/editor/editor.state.simple.js +++ b/src/case/editor/editor.state.simple.js @@ -22,7 +22,8 @@ BI.SimpleStateEditor = BI.inherit(BI.Widget, { watermark: "", errorText: "", height: 24, - text: BI.i18nText("BI-Basic_Unrestricted") + text: "", + defaultText: BI.i18nText("BI-Basic_Unrestricted"), }); }, @@ -136,7 +137,7 @@ BI.SimpleStateEditor = BI.inherit(BI.Widget, { items: [this.editor] }); this._showHint(); - if(BI.isNotNull(o.text)){ + if (BI.isNotNull(o.text)) { this.setState(o.text); } }, @@ -232,6 +233,7 @@ BI.SimpleStateEditor = BI.inherit(BI.Widget, { setState: function (v) { var o = this.options; BI.SimpleStateEditor.superclass.setValue.apply(this, arguments); + var defaultText = BI.isFunction(o.defaultText) ? o.defaultText() : o.defaultText; if (BI.isNumber(v)) { if (v === BI.Selection.All) { this._setText(BI.i18nText("BI-Already_Selected")); @@ -240,7 +242,7 @@ BI.SimpleStateEditor = BI.inherit(BI.Widget, { this._setText(BI.i18nText("BI-Already_Selected")); this.text.element.removeClass("bi-water-mark"); } else { - this._setText(o.text); + this._setText(BI.isKey(defaultText) ? defaultText : o.text); this.text.element.addClass("bi-water-mark"); } return; @@ -280,4 +282,4 @@ BI.SimpleStateEditor.EVENT_RESTRICT = "EVENT_RESTRICT"; BI.SimpleStateEditor.EVENT_SPACE = "EVENT_SPACE"; BI.SimpleStateEditor.EVENT_EMPTY = "EVENT_EMPTY"; -BI.shortcut("bi.simple_state_editor", BI.SimpleStateEditor); \ No newline at end of file +BI.shortcut("bi.simple_state_editor", BI.SimpleStateEditor); diff --git a/src/case/layer/pane.list.js b/src/case/layer/pane.list.js index 26be09624..d4b774d00 100644 --- a/src/case/layer/pane.list.js +++ b/src/case/layer/pane.list.js @@ -38,6 +38,7 @@ BI.ListPane = BI.inherit(BI.Pane, { chooseType: BI.ButtonGroup.CHOOSE_TYPE_SINGLE, behaviors: {}, items: o.items, + value: o.value, itemsCreator: function (op, calback) { if (op.times === 1) { self.empty(); diff --git a/src/case/tree/tree.level.js b/src/case/tree/tree.level.js index baac6a94c..81609217e 100644 --- a/src/case/tree/tree.level.js +++ b/src/case/tree/tree.level.js @@ -26,33 +26,24 @@ BI.LevelTree = BI.inherit(BI.Widget, { _formatItems: function (nodes, layer, pNode) { var self = this; BI.each(nodes, function (i, node) { - var extend = { layer: layer, height: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT }; + var extend = { + layer: layer, + height: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, + isFirstNode: i === 0, + isLastNode: i === nodes.length - 1, + }; if (!BI.isKey(node.id)) { node.id = BI.UUID(); } extend.pNode = pNode; if (node.isParent === true || node.parent === true || BI.isNotEmptyArray(node.children)) { - extend.type = "bi.mid_plus_group_node"; - if (i === nodes.length - 1) { - extend.type = "bi.last_plus_group_node"; - extend.isLastNode = true; - } - if (i === 0 && !pNode) { - extend.type = "bi.first_plus_group_node"; - } - if (i === 0 && i === nodes.length - 1) { // 根 - extend.type = "bi.plus_group_node"; - } + extend.type = "bi.tree_node"; + extend.selectable = false; + BI.defaults(node, extend); self._formatItems(node.children, layer + 1, node); } else { - extend.type = "bi.mid_tree_leaf_item"; - if (i === 0 && !pNode) { - extend.type = "bi.first_tree_leaf_item"; - } - if (i === nodes.length - 1) { - extend.type = "bi.last_tree_leaf_item"; - } + extend.type = "bi.tree_item"; BI.defaults(node, extend); } }); @@ -76,12 +67,14 @@ BI.LevelTree = BI.inherit(BI.Widget, { type: "bi.custom_tree", element: this, expander: BI.extend({ + type: "bi.tree_expander", el: {}, + isDefaultInit: false, + selectable: false, popup: { type: "bi.custom_tree" } }, o.expander), - items: this._formatItems(BI.Tree.transformToTreeFormat(nodes), 0), value: o.value, @@ -97,6 +90,7 @@ BI.LevelTree = BI.inherit(BI.Widget, { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); if (type === BI.Events.CLICK) { self.fireEvent(BI.LevelTree.EVENT_CHANGE, value, ob); + self.setValue(value); } }); }, diff --git a/src/case/tree/treeexpander/tree.expander.js b/src/case/tree/treeexpander/tree.expander.js index 88f5dbf50..8dde0807b 100644 --- a/src/case/tree/treeexpander/tree.expander.js +++ b/src/case/tree/treeexpander/tree.expander.js @@ -6,6 +6,7 @@ isLastNode: false, // 是不是最后一个 isFirstNode: false, // 是不是第一个 selectable: false, + showLine: true, }, render: function () { @@ -33,6 +34,7 @@ layer: o.layer || o.el.layer, isLastNode: o.isLastNode || o.el.isLastNode, isFirstNode: o.isFirstNode || o.el.isFirstNode, + showLine: o.showLine, el: o.popup, }, value: o.value, @@ -59,7 +61,8 @@ getValue: function () { if (this.trigger.isSelected()) { - return [this.trigger.getValue()]; + var value = this.trigger.getValue(); + return BI.isArray(value) ? value : [value]; } return this.expander.getValue(); }, diff --git a/src/case/tree/treeexpander/tree.expander.popup.js b/src/case/tree/treeexpander/tree.expander.popup.js index 96f9fe259..c3f53e40c 100644 --- a/src/case/tree/treeexpander/tree.expander.popup.js +++ b/src/case/tree/treeexpander/tree.expander.popup.js @@ -6,6 +6,7 @@ layer: 0, // 第几层级 el: {}, isLastNode: false, + showLine: true, }; }, @@ -22,12 +23,15 @@ this.popupView.on(BI.Controller.EVENT_CHANGE, function () { self.fireEvent(BI.Controller.EVENT_CHANGE, arguments); }); - this.popupView.element.css("margin-left", -offset * (o.layer + 1)); - this.element.css("margin-left", offset * (o.layer + 1)); + + if (o.showLine) { + this.popupView.element.css("margin-left", -offset * (o.layer + 1)); + this.element.css("margin-left", offset * (o.layer + 1)); + } return { type: "bi.vertical", - cls: !o.isLastNode ? (BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? "line solid" : "line") : "", + cls: (o.showLine && !o.isLastNode) ? (BI.STYLE_CONSTANTS.LINK_LINE_TYPE === "solid" ? "line solid" : "line") : "", scrolly: null, items: [ this.popupView, @@ -40,11 +44,11 @@ }, getValue: function () { - return this.popupview.getValue(); + return this.popupView.getValue(); }, populate: function (items) { - this.popupview.populate(items); + this.popupView.populate(items); }, getAllLeaves: function () { diff --git a/src/case/trigger/trigger.text.js b/src/case/trigger/trigger.text.js index 8acee1c78..fe72fde60 100644 --- a/src/case/trigger/trigger.text.js +++ b/src/case/trigger/trigger.text.js @@ -17,21 +17,28 @@ BI.TextTrigger = BI.inherit(BI.Trigger, { allowClear: false, title: function () { return self.text.getText(); - } + }, + defaultText: "", + text: "", }; }, render: function () { var self = this, o = this.options, c = this._const; - var text = { + + var text = this.getText(); + + var defaultText = this.getDefaultText(); + + var label = { type: "bi.label", ref: function (_ref) { self.text = _ref; }, - cls: "select-text-label" + (BI.isKey(o.textCls) ? (" " + o.textCls) : ""), + cls: `select-text-label ${o.textCls} ${!BI.isNotEmptyString(text) && BI.isNotEmptyString(defaultText) ? "bi-tips" : ""}`, textAlign: "left", height: o.height, - text: o.text, + text: text || o.defaultText, tipType: o.tipType, warningTitle: o.warningTitle, hgap: o.textHgap, @@ -56,7 +63,7 @@ BI.TextTrigger = BI.inherit(BI.Trigger, { columnSize: ["fill", o.triggerWidth || o.height], items: [ { - el: text, + el: label, width: "fill" }, { el: o.allowClear ? { @@ -89,6 +96,16 @@ BI.TextTrigger = BI.inherit(BI.Trigger, { }); }, + getText: function () { + var o = this.options; + return BI.isFunction(o.text) ? o.text() : o.text; + }, + + getDefaultText: function () { + var o = this.options; + return BI.isFunction(o.defaultText) ? o.defaultText() : o.defaultText; + }, + getTextor: function () { return this.text; }, @@ -101,10 +118,19 @@ BI.TextTrigger = BI.inherit(BI.Trigger, { }, setText: function (text) { - this.text.setText(text); if (this.options.allowClear) { this.clearBtn.setVisible(BI.isNotEmptyString(text)); } + if (BI.isKey(text)) { + this.text.setText(text); + this.text.element.removeClass("bi-tips"); + } else if (BI.isKey(this.options.defaultText)) { + this.text.setText(this.options.defaultText); + this.text.element.addClass("bi-tips"); + } else { + this.text.setText(""); + this.text.element.removeClass("bi-tips"); + } }, setTipType: function (v) { diff --git a/src/case/trigger/trigger.text.select.js b/src/case/trigger/trigger.text.select.js index 4ec177764..3be2d7757 100644 --- a/src/case/trigger/trigger.text.select.js +++ b/src/case/trigger/trigger.text.select.js @@ -13,6 +13,7 @@ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { height: 24, allowClear: false, valueFormatter: BI.emptyFn, + defaultText: "", }); }, @@ -26,6 +27,7 @@ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { height: o.height, readonly: o.readonly, text: obj.text, + defaultText: o.defaultText, textCls: obj.textCls, textHgap: o.textHgap, textVgap: o.textVgap, @@ -34,7 +36,7 @@ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { textTgap: o.textTgap, textBgap: o.textBgap, tipType: o.tipType, - warningTitle: o.warningTitle, + title: null, allowClear: o.allowClear, listeners: [ { @@ -48,13 +50,22 @@ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { }); }, - _digest: function (vals, items) { + _digest: function (val, items) { var o = this.options; - vals = BI.isArray(vals) ? vals : [vals]; + val = BI.isArray(val) ? val[0] : val; + + // 提升valueFormatter的优先级 + if (o.valueFormatter !== BI.emptyFn && BI.isFunction(o.valueFormatter)) { + return { + text: o.valueFormatter(val), + }; + } + var result = []; + var formatItems = BI.Tree.transformToArrayFormat(items); BI.each(formatItems, function (i, item) { - if (BI.deepContains(vals, item.value) && !BI.contains(result, item.text || item.value)) { + if (val === item.value && !BI.contains(result, item.text || item.value)) { result.push(item.text || item.value); } }); @@ -62,12 +73,18 @@ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { if (result.length > 0) { return { textCls: "", - text: o.valueFormatter(vals[0]) || result.join(","), // 只保留单个value的场景,后续会把BI.isArray(vals) ? vals : [vals];这种都去掉 + text: result.join(","), }; } else { + var text = BI.isFunction(o.text) ? o.text() : o.text; + if (BI.isEmptyString(text)) { + return { + textCls: "bi-tips", + text: "" + }; + } return { - textCls: "bi-water-mark", - text: BI.isFunction(o.text) ? o.text() : o.text + text: o.text }; } }, @@ -77,8 +94,8 @@ BI.SelectTextTrigger = BI.inherit(BI.Trigger, { this.trigger.setText(text); }, - setValue: function (vals) { - var formatValue = this._digest(vals, this.options.items); + setValue: function (val) { + var formatValue = this._digest(val, this.options.items); this.trigger.setTextCls(formatValue.textCls); this.trigger.setText(formatValue.text); }, diff --git a/src/component/treevaluechooser/combo.listtreevaluechooser.js b/src/component/treevaluechooser/combo.listtreevaluechooser.js index fb6b3dfa8..0366a4bbc 100644 --- a/src/component/treevaluechooser/combo.listtreevaluechooser.js +++ b/src/component/treevaluechooser/combo.listtreevaluechooser.js @@ -30,6 +30,7 @@ BI.ListTreeValueChooserInsertCombo = BI.inherit(BI.AbstractListTreeValueChooser, isNeedAdjustWidth: o.isNeedAdjustWidth, element: this, text: o.text, + defaultText: o.defaultText, value: o.value, watermark: o.watermark, allowInsertValue: o.allowInsertValue, diff --git a/src/component/treevaluechooser/combo.treevaluechooser.insert.js b/src/component/treevaluechooser/combo.treevaluechooser.insert.js index ec60a0a4a..f9c6ebf4b 100644 --- a/src/component/treevaluechooser/combo.treevaluechooser.insert.js +++ b/src/component/treevaluechooser/combo.treevaluechooser.insert.js @@ -30,6 +30,7 @@ BI.TreeValueChooserInsertCombo = BI.inherit(BI.AbstractTreeValueChooser, { isNeedAdjustWidth: o.isNeedAdjustWidth, allowEdit: o.allowEdit, text: o.text, + defaultText: o.defaultText, value: o.value, watermark: o.watermark, element: this, diff --git a/src/component/treevaluechooser/combo.treevaluechooser.js b/src/component/treevaluechooser/combo.treevaluechooser.js index 4eec5d7c4..33cb4e520 100644 --- a/src/component/treevaluechooser/combo.treevaluechooser.js +++ b/src/component/treevaluechooser/combo.treevaluechooser.js @@ -28,6 +28,7 @@ BI.TreeValueChooserCombo = BI.inherit(BI.AbstractTreeValueChooser, { type: "bi.multi_tree_combo", simple: o.simple, text: o.text, + defaultText: o.defaultText, allowEdit: o.allowEdit, value: o.value, watermark: o.watermark, @@ -96,7 +97,7 @@ BI.TreeValueChooserCombo = BI.inherit(BI.AbstractTreeValueChooser, { return this.combo.getValue(); }, - getAllValue: function() { + getAllValue: function () { return this.buildCompleteTree(this.combo.getValue()); }, diff --git a/src/component/valuechooser/combo.valuechooser.js b/src/component/valuechooser/combo.valuechooser.js index 3da94a312..786dc1abd 100644 --- a/src/component/valuechooser/combo.valuechooser.js +++ b/src/component/valuechooser/combo.valuechooser.js @@ -31,6 +31,7 @@ BI.ValueChooserCombo = BI.inherit(BI.AbstractValueChooser, { element: this, allowEdit: o.allowEdit, text: o.text, + defaultText: o.defaultText, value: this._assertValue(o.value), itemsCreator: BI.bind(this._itemsCreator, this), valueFormatter: BI.bind(this._valueFormatter, this), @@ -82,7 +83,7 @@ BI.ValueChooserCombo = BI.inherit(BI.AbstractValueChooser, { }; }, - getAllValue: function() { + getAllValue: function () { var val = this.combo.getValue() || {}; if (val.type === BI.Selection.Multi) { return val.value || []; diff --git a/src/component/valuechooser/combo.valuechooser.nobar.js b/src/component/valuechooser/combo.valuechooser.nobar.js index 927f70f81..2910ea4fa 100644 --- a/src/component/valuechooser/combo.valuechooser.nobar.js +++ b/src/component/valuechooser/combo.valuechooser.nobar.js @@ -25,12 +25,13 @@ BI.ValueChooserNoBarCombo = BI.inherit(BI.AbstractValueChooser, { simple: o.simple, allowEdit: o.allowEdit, text: o.text, + defaultText: o.defaultText, value: this._assertValue(o.value), itemsCreator: BI.bind(this._itemsCreator, this), valueFormatter: BI.bind(this._valueFormatter, this), width: o.width, height: o.height, - ref: function(_ref) { + ref: function (_ref) { self.combo = _ref; }, listeners: [{ @@ -64,7 +65,7 @@ BI.ValueChooserNoBarCombo = BI.inherit(BI.AbstractValueChooser, { self.fireEvent(BI.ValueChooserNoBarCombo.EVENT_CONFIRM); } }] - } + }; }, setValue: function (v) { @@ -75,7 +76,7 @@ BI.ValueChooserNoBarCombo = BI.inherit(BI.AbstractValueChooser, { return this.combo.getValue(); }, - getAllValue: function() { + getAllValue: function () { return this.getValue(); }, diff --git a/src/core/1.lodash.js b/src/core/1.lodash.js index 8be57fe24..934448ac6 100644 --- a/src/core/1.lodash.js +++ b/src/core/1.lodash.js @@ -1,10275 +1,10357 @@ /** * @license * Lodash (Custom Build) - * Build: `lodash core plus="debounce,throttle,get,set,findIndex,findLastIndex,findKey,findLastKey,isArrayLike,invert,invertBy,uniq,uniqBy,omit,omitBy,zip,unzip,rest,range,random,reject,intersection,drop,countBy,union,zipObject,initial,cloneDeep,clamp,isPlainObject,take,takeRight,without,difference,defaultsDeep,trim,merge,groupBy,uniqBy,before,after,unescape"` + * Build: `lodash core plus="debounce,throttle,get,set,findIndex,findLastIndex,findKey,findLastKey,isArrayLike,invert,invertBy,uniq,uniqBy,omit,omitBy,zip,unzip,rest,range,random,reject,intersection,drop,countBy,union,zipObject,initial,cloneDeep,clamp,isPlainObject,take,takeRight,without,difference,defaultsDeep,trim,merge,groupBy,uniqBy,before,after,unescape,chunk"` * Copyright JS Foundation and other contributors * Released under MIT license * Based on Underscore.js 1.8.3 * Copyright Jeremy Ashkenas, DocumentCloud and Investigative Reporters & Editors */ -;(function() { - - /** Used as a safe reference for `undefined` in pre-ES5 environments. */ - var undefined; - - /** Used as the semantic version number. */ - var VERSION = '4.17.5'; - - /** Used as the size to enable large array optimizations. */ - var LARGE_ARRAY_SIZE = 200; - - /** Error message constants. */ - var FUNC_ERROR_TEXT = 'Expected a function'; - - /** Used to stand-in for `undefined` hash values. */ - var HASH_UNDEFINED = '__lodash_hash_undefined__'; - - /** Used as the maximum memoize cache size. */ - var MAX_MEMOIZE_SIZE = 500; - - /** Used as the internal argument placeholder. */ - var PLACEHOLDER = '__lodash_placeholder__'; - - /** Used to compose bitmasks for cloning. */ - var CLONE_DEEP_FLAG = 1, - CLONE_FLAT_FLAG = 2, - CLONE_SYMBOLS_FLAG = 4; - - /** Used to compose bitmasks for value comparisons. */ - var COMPARE_PARTIAL_FLAG = 1, - COMPARE_UNORDERED_FLAG = 2; - - /** Used to compose bitmasks for function metadata. */ - var WRAP_BIND_FLAG = 1, - WRAP_BIND_KEY_FLAG = 2, - WRAP_CURRY_BOUND_FLAG = 4, - WRAP_CURRY_FLAG = 8, - WRAP_CURRY_RIGHT_FLAG = 16, - WRAP_PARTIAL_FLAG = 32, - WRAP_PARTIAL_RIGHT_FLAG = 64, - WRAP_ARY_FLAG = 128, - WRAP_REARG_FLAG = 256, - WRAP_FLIP_FLAG = 512; - - /** Used to detect hot functions by number of calls within a span of milliseconds. */ - var HOT_COUNT = 800, - HOT_SPAN = 16; - - /** Used to indicate the type of lazy iteratees. */ - var LAZY_FILTER_FLAG = 1, - LAZY_MAP_FLAG = 2, - LAZY_WHILE_FLAG = 3; - - /** Used as references for various `Number` constants. */ - var INFINITY = 1 / 0, - MAX_SAFE_INTEGER = 9007199254740991, - MAX_INTEGER = 1.7976931348623157e+308, - NAN = 0 / 0; - - /** Used as references for the maximum length and index of an array. */ - var MAX_ARRAY_LENGTH = 4294967295; - - /** Used to associate wrap methods with their bit flags. */ - var wrapFlags = [ - ['ary', WRAP_ARY_FLAG], - ['bind', WRAP_BIND_FLAG], - ['bindKey', WRAP_BIND_KEY_FLAG], - ['curry', WRAP_CURRY_FLAG], - ['curryRight', WRAP_CURRY_RIGHT_FLAG], - ['flip', WRAP_FLIP_FLAG], - ['partial', WRAP_PARTIAL_FLAG], - ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], - ['rearg', WRAP_REARG_FLAG] - ]; - - /** `Object#toString` result references. */ - var argsTag = '[object Arguments]', - arrayTag = '[object Array]', - asyncTag = '[object AsyncFunction]', - boolTag = '[object Boolean]', - dateTag = '[object Date]', - errorTag = '[object Error]', - funcTag = '[object Function]', - genTag = '[object GeneratorFunction]', - mapTag = '[object Map]', - numberTag = '[object Number]', - nullTag = '[object Null]', - objectTag = '[object Object]', - promiseTag = '[object Promise]', - proxyTag = '[object Proxy]', - regexpTag = '[object RegExp]', - setTag = '[object Set]', - stringTag = '[object String]', - symbolTag = '[object Symbol]', - undefinedTag = '[object Undefined]', - weakMapTag = '[object WeakMap]'; - - var arrayBufferTag = '[object ArrayBuffer]', - dataViewTag = '[object DataView]', - float32Tag = '[object Float32Array]', - float64Tag = '[object Float64Array]', - int8Tag = '[object Int8Array]', - int16Tag = '[object Int16Array]', - int32Tag = '[object Int32Array]', - uint8Tag = '[object Uint8Array]', - uint8ClampedTag = '[object Uint8ClampedArray]', - uint16Tag = '[object Uint16Array]', - uint32Tag = '[object Uint32Array]'; - - /** Used to match HTML entities and HTML characters. */ - var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, - reUnescapedHtml = /[&<>"']/g, - reHasEscapedHtml = RegExp(reEscapedHtml.source), - reHasUnescapedHtml = RegExp(reUnescapedHtml.source); - - /** Used to match property names within property paths. */ - var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, - reIsPlainProp = /^\w*$/, - rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; - - /** - * Used to match `RegExp` - * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). - */ - var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; - - /** Used to match leading and trailing whitespace. */ - var reTrim = /^\s+|\s+$/g; - - /** Used to match wrap detail comments. */ - var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, - reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, - reSplitDetails = /,? & /; - - /** Used to match backslashes in property paths. */ - var reEscapeChar = /\\(\\)?/g; - - /** Used to match `RegExp` flags from their coerced string values. */ - var reFlags = /\w*$/; - - /** Used to detect bad signed hexadecimal string values. */ - var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; - - /** Used to detect binary string values. */ - var reIsBinary = /^0b[01]+$/i; - - /** Used to detect host constructors (Safari). */ - var reIsHostCtor = /^\[object .+?Constructor\]$/; - - /** Used to detect octal string values. */ - var reIsOctal = /^0o[0-7]+$/i; - - /** Used to detect unsigned integer values. */ - var reIsUint = /^(?:0|[1-9]\d*)$/; - - /** Used to compose unicode character classes. */ - var rsAstralRange = '\\ud800-\\udfff', - rsComboMarksRange = '\\u0300-\\u036f', - reComboHalfMarksRange = '\\ufe20-\\ufe2f', - rsComboSymbolsRange = '\\u20d0-\\u20ff', - rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, - rsVarRange = '\\ufe0e\\ufe0f'; - - /** Used to compose unicode capture groups. */ - var rsAstral = '[' + rsAstralRange + ']', - rsCombo = '[' + rsComboRange + ']', - rsFitz = '\\ud83c[\\udffb-\\udfff]', - rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', - rsNonAstral = '[^' + rsAstralRange + ']', - rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', - rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', - rsZWJ = '\\u200d'; - - /** Used to compose unicode regexes. */ - var reOptMod = rsModifier + '?', - rsOptVar = '[' + rsVarRange + ']?', - rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', - rsSeq = rsOptVar + reOptMod + rsOptJoin, - rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; - - /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ - var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); - - /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ - var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); - - /** Used to identify `toStringTag` values of typed arrays. */ - var typedArrayTags = {}; - typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = - typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = - typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = - typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = - typedArrayTags[uint32Tag] = true; - typedArrayTags[argsTag] = typedArrayTags[arrayTag] = - typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = - typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = - typedArrayTags[errorTag] = typedArrayTags[funcTag] = - typedArrayTags[mapTag] = typedArrayTags[numberTag] = - typedArrayTags[objectTag] = typedArrayTags[regexpTag] = - typedArrayTags[setTag] = typedArrayTags[stringTag] = - typedArrayTags[weakMapTag] = false; - - /** Used to identify `toStringTag` values supported by `_.clone`. */ - var cloneableTags = {}; - cloneableTags[argsTag] = cloneableTags[arrayTag] = - cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = - cloneableTags[boolTag] = cloneableTags[dateTag] = - cloneableTags[float32Tag] = cloneableTags[float64Tag] = - cloneableTags[int8Tag] = cloneableTags[int16Tag] = - cloneableTags[int32Tag] = cloneableTags[mapTag] = - cloneableTags[numberTag] = cloneableTags[objectTag] = - cloneableTags[regexpTag] = cloneableTags[setTag] = - cloneableTags[stringTag] = cloneableTags[symbolTag] = - cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = - cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; - cloneableTags[errorTag] = cloneableTags[funcTag] = - cloneableTags[weakMapTag] = false; - - /** Used to map characters to HTML entities. */ - var htmlEscapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - "'": ''' - }; - - /** Used to map HTML entities to characters. */ - var htmlUnescapes = { - '&': '&', - '<': '<', - '>': '>', - '"': '"', - ''': "'" - }; - - /** Built-in method references without a dependency on `root`. */ - var freeParseFloat = parseFloat, - freeParseInt = parseInt; - - /** Detect free variable `global` from Node.js. */ - var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; - - /** Detect free variable `self`. */ - var freeSelf = typeof self == 'object' && self && self.Object === Object && self; - - /** Used as a reference to the global object. */ - var root = freeGlobal || freeSelf || Function('return this')(); - - /** Detect free variable `exports`. */ - var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; - - /** Detect free variable `module`. */ - var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; - - /** Detect the popular CommonJS extension `module.exports`. */ - var moduleExports = freeModule && freeModule.exports === freeExports; - - /** Detect free variable `process` from Node.js. */ - var freeProcess = moduleExports && freeGlobal.process; - - /** Used to access faster Node.js helpers. */ - var nodeUtil = (function() { - try { - return freeProcess && freeProcess.binding && freeProcess.binding('util'); - } catch (e) {} - }()); - - /* Node.js helper references. */ - var nodeIsDate = nodeUtil && nodeUtil.isDate, - nodeIsMap = nodeUtil && nodeUtil.isMap, - nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, - nodeIsSet = nodeUtil && nodeUtil.isSet, - nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; - - /*--------------------------------------------------------------------------*/ - - /** - * A faster alternative to `Function#apply`, this function invokes `func` - * with the `this` binding of `thisArg` and the arguments of `args`. - * - * @private - * @param {Function} func The function to invoke. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} args The arguments to invoke `func` with. - * @returns {*} Returns the result of `func`. - */ - function apply(func, thisArg, args) { - switch (args.length) { - case 0: return func.call(thisArg); - case 1: return func.call(thisArg, args[0]); - case 2: return func.call(thisArg, args[0], args[1]); - case 3: return func.call(thisArg, args[0], args[1], args[2]); - } - return func.apply(thisArg, args); - } - - /** - * A specialized version of `baseAggregator` for arrays. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function arrayAggregator(array, setter, iteratee, accumulator) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - var value = array[index]; - setter(accumulator, value, iteratee(value), array); - } - return accumulator; - } - - /** - * A specialized version of `_.forEach` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns `array`. - */ - function arrayEach(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (iteratee(array[index], index, array) === false) { - break; - } - } - return array; - } - - /** - * A specialized version of `_.every` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - */ - function arrayEvery(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (!predicate(array[index], index, array)) { - return false; - } - } - return true; - } - - /** - * A specialized version of `_.filter` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function arrayFilter(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (predicate(value, index, array)) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * A specialized version of `_.includes` for arrays without support for - * specifying an index to search from. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludes(array, value) { - var length = array == null ? 0 : array.length; - return !!length && baseIndexOf(array, value, 0) > -1; - } - - /** - * This function is like `arrayIncludes` except that it accepts a comparator. - * - * @private - * @param {Array} [array] The array to inspect. - * @param {*} target The value to search for. - * @param {Function} comparator The comparator invoked per element. - * @returns {boolean} Returns `true` if `target` is found, else `false`. - */ - function arrayIncludesWith(array, value, comparator) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (comparator(value, array[index])) { - return true; - } - } - return false; - } - - /** - * A specialized version of `_.map` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function arrayMap(array, iteratee) { - var index = -1, - length = array == null ? 0 : array.length, - result = Array(length); - - while (++index < length) { - result[index] = iteratee(array[index], index, array); - } - return result; - } - - /** - * Appends the elements of `values` to `array`. - * - * @private - * @param {Array} array The array to modify. - * @param {Array} values The values to append. - * @returns {Array} Returns `array`. - */ - function arrayPush(array, values) { - var index = -1, - length = values.length, - offset = array.length; - - while (++index < length) { - array[offset + index] = values[index]; - } - return array; - } - - /** - * A specialized version of `_.reduce` for arrays without support for - * iteratee shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @param {boolean} [initAccum] Specify using the first element of `array` as - * the initial value. - * @returns {*} Returns the accumulated value. - */ - function arrayReduce(array, iteratee, accumulator, initAccum) { - var index = -1, - length = array == null ? 0 : array.length; - - if (initAccum && length) { - accumulator = array[++index]; - } - while (++index < length) { - accumulator = iteratee(accumulator, array[index], index, array); - } - return accumulator; - } - - /** - * A specialized version of `_.some` for arrays without support for iteratee - * shorthands. - * - * @private - * @param {Array} [array] The array to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function arraySome(array, predicate) { - var index = -1, - length = array == null ? 0 : array.length; - - while (++index < length) { - if (predicate(array[index], index, array)) { +;(function () { + + /** Used as a safe reference for `undefined` in pre-ES5 environments. */ + var undefined; + + /** Used as the semantic version number. */ + var VERSION = '4.17.5'; + + /** Used as the size to enable large array optimizations. */ + var LARGE_ARRAY_SIZE = 200; + + /** Error message constants. */ + var FUNC_ERROR_TEXT = 'Expected a function'; + + /** Used to stand-in for `undefined` hash values. */ + var HASH_UNDEFINED = '__lodash_hash_undefined__'; + + /** Used as the maximum memoize cache size. */ + var MAX_MEMOIZE_SIZE = 500; + + /** Used as the internal argument placeholder. */ + var PLACEHOLDER = '__lodash_placeholder__'; + + /** Used to compose bitmasks for cloning. */ + var CLONE_DEEP_FLAG = 1, + CLONE_FLAT_FLAG = 2, + CLONE_SYMBOLS_FLAG = 4; + + /** Used to compose bitmasks for value comparisons. */ + var COMPARE_PARTIAL_FLAG = 1, + COMPARE_UNORDERED_FLAG = 2; + + /** Used to compose bitmasks for function metadata. */ + var WRAP_BIND_FLAG = 1, + WRAP_BIND_KEY_FLAG = 2, + WRAP_CURRY_BOUND_FLAG = 4, + WRAP_CURRY_FLAG = 8, + WRAP_CURRY_RIGHT_FLAG = 16, + WRAP_PARTIAL_FLAG = 32, + WRAP_PARTIAL_RIGHT_FLAG = 64, + WRAP_ARY_FLAG = 128, + WRAP_REARG_FLAG = 256, + WRAP_FLIP_FLAG = 512; + + /** Used to detect hot functions by number of calls within a span of milliseconds. */ + var HOT_COUNT = 800, + HOT_SPAN = 16; + + /** Used to indicate the type of lazy iteratees. */ + var LAZY_FILTER_FLAG = 1, + LAZY_MAP_FLAG = 2, + LAZY_WHILE_FLAG = 3; + + /** Used as references for various `Number` constants. */ + var INFINITY = 1 / 0, + MAX_SAFE_INTEGER = 9007199254740991, + MAX_INTEGER = 1.7976931348623157e+308, + NAN = 0 / 0; + + /** Used as references for the maximum length and index of an array. */ + var MAX_ARRAY_LENGTH = 4294967295; + + /** Used to associate wrap methods with their bit flags. */ + var wrapFlags = [ + ['ary', WRAP_ARY_FLAG], + ['bind', WRAP_BIND_FLAG], + ['bindKey', WRAP_BIND_KEY_FLAG], + ['curry', WRAP_CURRY_FLAG], + ['curryRight', WRAP_CURRY_RIGHT_FLAG], + ['flip', WRAP_FLIP_FLAG], + ['partial', WRAP_PARTIAL_FLAG], + ['partialRight', WRAP_PARTIAL_RIGHT_FLAG], + ['rearg', WRAP_REARG_FLAG] + ]; + + /** `Object#toString` result references. */ + var argsTag = '[object Arguments]', + arrayTag = '[object Array]', + asyncTag = '[object AsyncFunction]', + boolTag = '[object Boolean]', + dateTag = '[object Date]', + errorTag = '[object Error]', + funcTag = '[object Function]', + genTag = '[object GeneratorFunction]', + mapTag = '[object Map]', + numberTag = '[object Number]', + nullTag = '[object Null]', + objectTag = '[object Object]', + promiseTag = '[object Promise]', + proxyTag = '[object Proxy]', + regexpTag = '[object RegExp]', + setTag = '[object Set]', + stringTag = '[object String]', + symbolTag = '[object Symbol]', + undefinedTag = '[object Undefined]', + weakMapTag = '[object WeakMap]'; + + var arrayBufferTag = '[object ArrayBuffer]', + dataViewTag = '[object DataView]', + float32Tag = '[object Float32Array]', + float64Tag = '[object Float64Array]', + int8Tag = '[object Int8Array]', + int16Tag = '[object Int16Array]', + int32Tag = '[object Int32Array]', + uint8Tag = '[object Uint8Array]', + uint8ClampedTag = '[object Uint8ClampedArray]', + uint16Tag = '[object Uint16Array]', + uint32Tag = '[object Uint32Array]'; + + /** Used to match HTML entities and HTML characters. */ + var reEscapedHtml = /&(?:amp|lt|gt|quot|#39);/g, + reUnescapedHtml = /[&<>"']/g, + reHasEscapedHtml = RegExp(reEscapedHtml.source), + reHasUnescapedHtml = RegExp(reUnescapedHtml.source); + + /** Used to match property names within property paths. */ + var reIsDeepProp = /\.|\[(?:[^[\]]*|(["'])(?:(?!\1)[^\\]|\\.)*?\1)\]/, + reIsPlainProp = /^\w*$/, + rePropName = /[^.[\]]+|\[(?:(-?\d+(?:\.\d+)?)|(["'])((?:(?!\2)[^\\]|\\.)*?)\2)\]|(?=(?:\.|\[\])(?:\.|\[\]|$))/g; + + /** + * Used to match `RegExp` + * [syntax characters](http://ecma-international.org/ecma-262/7.0/#sec-patterns). + */ + var reRegExpChar = /[\\^$.*+?()[\]{}|]/g; + + /** Used to match leading and trailing whitespace. */ + var reTrim = /^\s+|\s+$/g; + + /** Used to match wrap detail comments. */ + var reWrapComment = /\{(?:\n\/\* \[wrapped with .+\] \*\/)?\n?/, + reWrapDetails = /\{\n\/\* \[wrapped with (.+)\] \*/, + reSplitDetails = /,? & /; + + /** Used to match backslashes in property paths. */ + var reEscapeChar = /\\(\\)?/g; + + /** Used to match `RegExp` flags from their coerced string values. */ + var reFlags = /\w*$/; + + /** Used to detect bad signed hexadecimal string values. */ + var reIsBadHex = /^[-+]0x[0-9a-f]+$/i; + + /** Used to detect binary string values. */ + var reIsBinary = /^0b[01]+$/i; + + /** Used to detect host constructors (Safari). */ + var reIsHostCtor = /^\[object .+?Constructor\]$/; + + /** Used to detect octal string values. */ + var reIsOctal = /^0o[0-7]+$/i; + + /** Used to detect unsigned integer values. */ + var reIsUint = /^(?:0|[1-9]\d*)$/; + + /** Used to compose unicode character classes. */ + var rsAstralRange = '\\ud800-\\udfff', + rsComboMarksRange = '\\u0300-\\u036f', + reComboHalfMarksRange = '\\ufe20-\\ufe2f', + rsComboSymbolsRange = '\\u20d0-\\u20ff', + rsComboRange = rsComboMarksRange + reComboHalfMarksRange + rsComboSymbolsRange, + rsVarRange = '\\ufe0e\\ufe0f'; + + /** Used to compose unicode capture groups. */ + var rsAstral = '[' + rsAstralRange + ']', + rsCombo = '[' + rsComboRange + ']', + rsFitz = '\\ud83c[\\udffb-\\udfff]', + rsModifier = '(?:' + rsCombo + '|' + rsFitz + ')', + rsNonAstral = '[^' + rsAstralRange + ']', + rsRegional = '(?:\\ud83c[\\udde6-\\uddff]){2}', + rsSurrPair = '[\\ud800-\\udbff][\\udc00-\\udfff]', + rsZWJ = '\\u200d'; + + /** Used to compose unicode regexes. */ + var reOptMod = rsModifier + '?', + rsOptVar = '[' + rsVarRange + ']?', + rsOptJoin = '(?:' + rsZWJ + '(?:' + [rsNonAstral, rsRegional, rsSurrPair].join('|') + ')' + rsOptVar + reOptMod + ')*', + rsSeq = rsOptVar + reOptMod + rsOptJoin, + rsSymbol = '(?:' + [rsNonAstral + rsCombo + '?', rsCombo, rsRegional, rsSurrPair, rsAstral].join('|') + ')'; + + /** Used to match [string symbols](https://mathiasbynens.be/notes/javascript-unicode). */ + var reUnicode = RegExp(rsFitz + '(?=' + rsFitz + ')|' + rsSymbol + rsSeq, 'g'); + + /** Used to detect strings with [zero-width joiners or code points from the astral planes](http://eev.ee/blog/2015/09/12/dark-corners-of-unicode/). */ + var reHasUnicode = RegExp('[' + rsZWJ + rsAstralRange + rsComboRange + rsVarRange + ']'); + + /** Used to identify `toStringTag` values of typed arrays. */ + var typedArrayTags = {}; + typedArrayTags[float32Tag] = typedArrayTags[float64Tag] = + typedArrayTags[int8Tag] = typedArrayTags[int16Tag] = + typedArrayTags[int32Tag] = typedArrayTags[uint8Tag] = + typedArrayTags[uint8ClampedTag] = typedArrayTags[uint16Tag] = + typedArrayTags[uint32Tag] = true; + typedArrayTags[argsTag] = typedArrayTags[arrayTag] = + typedArrayTags[arrayBufferTag] = typedArrayTags[boolTag] = + typedArrayTags[dataViewTag] = typedArrayTags[dateTag] = + typedArrayTags[errorTag] = typedArrayTags[funcTag] = + typedArrayTags[mapTag] = typedArrayTags[numberTag] = + typedArrayTags[objectTag] = typedArrayTags[regexpTag] = + typedArrayTags[setTag] = typedArrayTags[stringTag] = + typedArrayTags[weakMapTag] = false; + + /** Used to identify `toStringTag` values supported by `_.clone`. */ + var cloneableTags = {}; + cloneableTags[argsTag] = cloneableTags[arrayTag] = + cloneableTags[arrayBufferTag] = cloneableTags[dataViewTag] = + cloneableTags[boolTag] = cloneableTags[dateTag] = + cloneableTags[float32Tag] = cloneableTags[float64Tag] = + cloneableTags[int8Tag] = cloneableTags[int16Tag] = + cloneableTags[int32Tag] = cloneableTags[mapTag] = + cloneableTags[numberTag] = cloneableTags[objectTag] = + cloneableTags[regexpTag] = cloneableTags[setTag] = + cloneableTags[stringTag] = cloneableTags[symbolTag] = + cloneableTags[uint8Tag] = cloneableTags[uint8ClampedTag] = + cloneableTags[uint16Tag] = cloneableTags[uint32Tag] = true; + cloneableTags[errorTag] = cloneableTags[funcTag] = + cloneableTags[weakMapTag] = false; + + /** Used to map characters to HTML entities. */ + var htmlEscapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + "'": ''' + }; + + /** Used to map HTML entities to characters. */ + var htmlUnescapes = { + '&': '&', + '<': '<', + '>': '>', + '"': '"', + ''': "'" + }; + + /** Built-in method references without a dependency on `root`. */ + var freeParseFloat = parseFloat, + freeParseInt = parseInt; + + /** Detect free variable `global` from Node.js. */ + var freeGlobal = typeof global == 'object' && global && global.Object === Object && global; + + /** Detect free variable `self`. */ + var freeSelf = typeof self == 'object' && self && self.Object === Object && self; + + /** Used as a reference to the global object. */ + var root = freeGlobal || freeSelf || Function('return this')(); + + /** Detect free variable `exports`. */ + var freeExports = typeof exports == 'object' && exports && !exports.nodeType && exports; + + /** Detect free variable `module`. */ + var freeModule = freeExports && typeof module == 'object' && module && !module.nodeType && module; + + /** Detect the popular CommonJS extension `module.exports`. */ + var moduleExports = freeModule && freeModule.exports === freeExports; + + /** Detect free variable `process` from Node.js. */ + var freeProcess = moduleExports && freeGlobal.process; + + /** Used to access faster Node.js helpers. */ + var nodeUtil = (function () { + try { + return freeProcess && freeProcess.binding && freeProcess.binding('util'); + } catch (e) { + } + }()); + + /* Node.js helper references. */ + var nodeIsDate = nodeUtil && nodeUtil.isDate, + nodeIsMap = nodeUtil && nodeUtil.isMap, + nodeIsRegExp = nodeUtil && nodeUtil.isRegExp, + nodeIsSet = nodeUtil && nodeUtil.isSet, + nodeIsTypedArray = nodeUtil && nodeUtil.isTypedArray; + + /*--------------------------------------------------------------------------*/ + + /** + * A faster alternative to `Function#apply`, this function invokes `func` + * with the `this` binding of `thisArg` and the arguments of `args`. + * + * @private + * @param {Function} func The function to invoke. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} args The arguments to invoke `func` with. + * @returns {*} Returns the result of `func`. + */ + function apply(func, thisArg, args) { + switch (args.length) { + case 0: + return func.call(thisArg); + case 1: + return func.call(thisArg, args[0]); + case 2: + return func.call(thisArg, args[0], args[1]); + case 3: + return func.call(thisArg, args[0], args[1], args[2]); + } + return func.apply(thisArg, args); + } + + /** + * A specialized version of `baseAggregator` for arrays. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function arrayAggregator(array, setter, iteratee, accumulator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + var value = array[index]; + setter(accumulator, value, iteratee(value), array); + } + return accumulator; + } + + /** + * A specialized version of `_.forEach` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns `array`. + */ + function arrayEach(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (iteratee(array[index], index, array) === false) { + break; + } + } + return array; + } + + /** + * A specialized version of `_.every` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + */ + function arrayEvery(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (!predicate(array[index], index, array)) { + return false; + } + } return true; - } - } - return false; - } - - /** - * Gets the size of an ASCII `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - var asciiSize = baseProperty('length'); - - /** - * Converts an ASCII `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function asciiToArray(string) { - return string.split(''); - } - - /** - * The base implementation of methods like `_.findKey` and `_.findLastKey`, - * without support for iteratee shorthands, which iterates over `collection` - * using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the found element or its key, else `undefined`. - */ - function baseFindKey(collection, predicate, eachFunc) { - var result; - eachFunc(collection, function(value, key, collection) { - if (predicate(value, key, collection)) { - result = key; + } + + /** + * A specialized version of `_.filter` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function arrayFilter(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (predicate(value, index, array)) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * A specialized version of `_.includes` for arrays without support for + * specifying an index to search from. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludes(array, value) { + var length = array == null ? 0 : array.length; + return !!length && baseIndexOf(array, value, 0) > -1; + } + + /** + * This function is like `arrayIncludes` except that it accepts a comparator. + * + * @private + * @param {Array} [array] The array to inspect. + * @param {*} target The value to search for. + * @param {Function} comparator The comparator invoked per element. + * @returns {boolean} Returns `true` if `target` is found, else `false`. + */ + function arrayIncludesWith(array, value, comparator) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (comparator(value, array[index])) { + return true; + } + } return false; - } - }); - return result; - } - - /** - * The base implementation of `_.findIndex` and `_.findLastIndex` without - * support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} predicate The function invoked per iteration. - * @param {number} fromIndex The index to search from. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseFindIndex(array, predicate, fromIndex, fromRight) { - var length = array.length, - index = fromIndex + (fromRight ? 1 : -1); - - while ((fromRight ? index-- : ++index < length)) { - if (predicate(array[index], index, array)) { + } + + /** + * A specialized version of `_.map` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function arrayMap(array, iteratee) { + var index = -1, + length = array == null ? 0 : array.length, + result = Array(length); + + while (++index < length) { + result[index] = iteratee(array[index], index, array); + } + return result; + } + + /** + * Appends the elements of `values` to `array`. + * + * @private + * @param {Array} array The array to modify. + * @param {Array} values The values to append. + * @returns {Array} Returns `array`. + */ + function arrayPush(array, values) { + var index = -1, + length = values.length, + offset = array.length; + + while (++index < length) { + array[offset + index] = values[index]; + } + return array; + } + + /** + * A specialized version of `_.reduce` for arrays without support for + * iteratee shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @param {boolean} [initAccum] Specify using the first element of `array` as + * the initial value. + * @returns {*} Returns the accumulated value. + */ + function arrayReduce(array, iteratee, accumulator, initAccum) { + var index = -1, + length = array == null ? 0 : array.length; + + if (initAccum && length) { + accumulator = array[++index]; + } + while (++index < length) { + accumulator = iteratee(accumulator, array[index], index, array); + } + return accumulator; + } + + /** + * A specialized version of `_.some` for arrays without support for iteratee + * shorthands. + * + * @private + * @param {Array} [array] The array to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function arraySome(array, predicate) { + var index = -1, + length = array == null ? 0 : array.length; + + while (++index < length) { + if (predicate(array[index], index, array)) { + return true; + } + } + return false; + } + + /** + * Gets the size of an ASCII `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + var asciiSize = baseProperty('length'); + + /** + * Converts an ASCII `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function asciiToArray(string) { + return string.split(''); + } + + /** + * The base implementation of methods like `_.findKey` and `_.findLastKey`, + * without support for iteratee shorthands, which iterates over `collection` + * using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the found element or its key, else `undefined`. + */ + function baseFindKey(collection, predicate, eachFunc) { + var result; + eachFunc(collection, function (value, key, collection) { + if (predicate(value, key, collection)) { + result = key; + return false; + } + }); + return result; + } + + /** + * The base implementation of `_.findIndex` and `_.findLastIndex` without + * support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} predicate The function invoked per iteration. + * @param {number} fromIndex The index to search from. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseFindIndex(array, predicate, fromIndex, fromRight) { + var length = array.length, + index = fromIndex + (fromRight ? 1 : -1); + + while ((fromRight ? index-- : ++index < length)) { + if (predicate(array[index], index, array)) { + return index; + } + } + return -1; + } + + /** + * The base implementation of `_.indexOf` without `fromIndex` bounds checks. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function baseIndexOf(array, value, fromIndex) { + return value === value + ? strictIndexOf(array, value, fromIndex) + : baseFindIndex(array, baseIsNaN, fromIndex); + } + + /** + * The base implementation of `_.isNaN` without support for number objects. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + */ + function baseIsNaN(value) { + return value !== value; + } + + /** + * The base implementation of `_.property` without support for deep paths. + * + * @private + * @param {string} key The key of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function baseProperty(key) { + return function (object) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.propertyOf` without support for deep paths. + * + * @private + * @param {Object} object The object to query. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyOf(object) { + return function (key) { + return object == null ? undefined : object[key]; + }; + } + + /** + * The base implementation of `_.reduce` and `_.reduceRight`, without support + * for iteratee shorthands, which iterates over `collection` using `eachFunc`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {*} accumulator The initial value. + * @param {boolean} initAccum Specify using the first or last element of + * `collection` as the initial value. + * @param {Function} eachFunc The function to iterate over `collection`. + * @returns {*} Returns the accumulated value. + */ + function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { + eachFunc(collection, function (value, index, collection) { + accumulator = initAccum + ? (initAccum = false, value) + : iteratee(accumulator, value, index, collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.sortBy` which uses `comparer` to define the + * sort order of `array` and replaces criteria objects with their corresponding + * values. + * + * @private + * @param {Array} array The array to sort. + * @param {Function} comparer The function to define sort order. + * @returns {Array} Returns `array`. + */ + function baseSortBy(array, comparer) { + var length = array.length; + + array.sort(comparer); + while (length--) { + array[length] = array[length].value; + } + return array; + } + + /** + * The base implementation of `_.times` without support for iteratee shorthands + * or max array length checks. + * + * @private + * @param {number} n The number of times to invoke `iteratee`. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the array of results. + */ + function baseTimes(n, iteratee) { + var index = -1, + result = Array(n); + + while (++index < n) { + result[index] = iteratee(index); + } + return result; + } + + /** + * The base implementation of `_.unary` without support for storing metadata. + * + * @private + * @param {Function} func The function to cap arguments for. + * @returns {Function} Returns the new capped function. + */ + function baseUnary(func) { + return function (value) { + return func(value); + }; + } + + /** + * The base implementation of `_.values` and `_.valuesIn` which creates an + * array of `object` property values corresponding to the property names + * of `props`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} props The property names to get values for. + * @returns {Object} Returns the array of property values. + */ + function baseValues(object, props) { + return arrayMap(props, function (key) { + return object[key]; + }); + } + + /** + * Checks if a `cache` value for `key` exists. + * + * @private + * @param {Object} cache The cache to query. + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function cacheHas(cache, key) { + return cache.has(key); + } + + /** + * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the first unmatched string symbol. + */ + function charsStartIndex(strSymbols, chrSymbols) { + var index = -1, + length = strSymbols.length; + + while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) { + } + return index; + } + + /** + * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol + * that is not found in the character symbols. + * + * @private + * @param {Array} strSymbols The string symbols to inspect. + * @param {Array} chrSymbols The character symbols to find. + * @returns {number} Returns the index of the last unmatched string symbol. + */ + function charsEndIndex(strSymbols, chrSymbols) { + var index = strSymbols.length; + + while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) { + } return index; - } - } - return -1; - } - - /** - * The base implementation of `_.indexOf` without `fromIndex` bounds checks. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function baseIndexOf(array, value, fromIndex) { - return value === value - ? strictIndexOf(array, value, fromIndex) - : baseFindIndex(array, baseIsNaN, fromIndex); - } - - /** - * The base implementation of `_.isNaN` without support for number objects. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - */ - function baseIsNaN(value) { - return value !== value; - } - - /** - * The base implementation of `_.property` without support for deep paths. - * - * @private - * @param {string} key The key of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function baseProperty(key) { - return function(object) { - return object == null ? undefined : object[key]; + } + + /** + * Gets the number of `placeholder` occurrences in `array`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} placeholder The placeholder to search for. + * @returns {number} Returns the placeholder count. + */ + function countHolders(array, placeholder) { + var length = array.length, + result = 0; + + while (length--) { + if (array[length] === placeholder) { + ++result; + } + } + return result; + } + + /** + * Used by `_.escape` to convert characters to HTML entities. + * + * @private + * @param {string} chr The matched character to escape. + * @returns {string} Returns the escaped character. + */ + var escapeHtmlChar = basePropertyOf(htmlEscapes); + + /** + * Gets the value at `key` of `object`. + * + * @private + * @param {Object} [object] The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function getValue(object, key) { + return object == null ? undefined : object[key]; + } + + /** + * Checks if `string` contains Unicode symbols. + * + * @private + * @param {string} string The string to inspect. + * @returns {boolean} Returns `true` if a symbol is found, else `false`. + */ + function hasUnicode(string) { + return reHasUnicode.test(string); + } + + /** + * Converts `iterator` to an array. + * + * @private + * @param {Object} iterator The iterator to convert. + * @returns {Array} Returns the converted array. + */ + function iteratorToArray(iterator) { + var data, + result = []; + + while (!(data = iterator.next()).done) { + result.push(data.value); + } + return result; + } + + /** + * Converts `map` to its key-value pairs. + * + * @private + * @param {Object} map The map to convert. + * @returns {Array} Returns the key-value pairs. + */ + function mapToArray(map) { + var index = -1, + result = Array(map.size); + + map.forEach(function (value, key) { + result[++index] = [key, value]; + }); + return result; + } + + /** + * Creates a unary function that invokes `func` with its argument transformed. + * + * @private + * @param {Function} func The function to wrap. + * @param {Function} transform The argument transform. + * @returns {Function} Returns the new function. + */ + function overArg(func, transform) { + return function (arg) { + return func(transform(arg)); + }; + } + + /** + * Replaces all `placeholder` elements in `array` with an internal placeholder + * and returns an array of their indexes. + * + * @private + * @param {Array} array The array to modify. + * @param {*} placeholder The placeholder to replace. + * @returns {Array} Returns the new array of placeholder indexes. + */ + function replaceHolders(array, placeholder) { + var index = -1, + length = array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value === placeholder || value === PLACEHOLDER) { + array[index] = PLACEHOLDER; + result[resIndex++] = index; + } + } + return result; + } + + /** + * Gets the value at `key`, unless `key` is "__proto__". + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the property to get. + * @returns {*} Returns the property value. + */ + function safeGet(object, key) { + return key == '__proto__' + ? undefined + : object[key]; + } + + /** + * Converts `set` to an array of its values. + * + * @private + * @param {Object} set The set to convert. + * @returns {Array} Returns the values. + */ + function setToArray(set) { + var index = -1, + result = Array(set.size); + + set.forEach(function (value) { + result[++index] = value; + }); + return result; + } + + /** + * A specialized version of `_.indexOf` which performs strict equality + * comparisons of values, i.e. `===`. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} fromIndex The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function strictIndexOf(array, value, fromIndex) { + var index = fromIndex - 1, + length = array.length; + + while (++index < length) { + if (array[index] === value) { + return index; + } + } + return -1; + } + + /** + * Gets the number of symbols in `string`. + * + * @private + * @param {string} string The string to inspect. + * @returns {number} Returns the string size. + */ + function stringSize(string) { + return hasUnicode(string) + ? unicodeSize(string) + : asciiSize(string); + } + + /** + * Converts `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function stringToArray(string) { + return hasUnicode(string) + ? unicodeToArray(string) + : asciiToArray(string); + } + + /** + * Used by `_.unescape` to convert HTML entities to characters. + * + * @private + * @param {string} chr The matched character to unescape. + * @returns {string} Returns the unescaped character. + */ + var unescapeHtmlChar = basePropertyOf(htmlUnescapes); + + /** + * Gets the size of a Unicode `string`. + * + * @private + * @param {string} string The string inspect. + * @returns {number} Returns the string size. + */ + function unicodeSize(string) { + var result = reUnicode.lastIndex = 0; + while (reUnicode.test(string)) { + ++result; + } + return result; + } + + /** + * Converts a Unicode `string` to an array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the converted array. + */ + function unicodeToArray(string) { + return string.match(reUnicode) || []; + } + + /*--------------------------------------------------------------------------*/ + + /** Used for built-in method references. */ + var arrayProto = Array.prototype, + funcProto = Function.prototype, + objectProto = Object.prototype; + + /** Used to detect overreaching core-js shims. */ + var coreJsData = root['__core-js_shared__']; + + /** Used to resolve the decompiled source of functions. */ + var funcToString = funcProto.toString; + + /** Used to check objects for own properties. */ + var hasOwnProperty = objectProto.hasOwnProperty; + + /** Used to generate unique IDs. */ + var idCounter = 0; + + /** Used to detect methods masquerading as native. */ + var maskSrcKey = (function () { + var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); + return uid ? ('Symbol(src)_1.' + uid) : ''; + }()); + + /** + * Used to resolve the + * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) + * of values. + */ + var nativeObjectToString = objectProto.toString; + + /** Used to infer the `Object` constructor. */ + var objectCtorString = funcToString.call(Object); + + /** Used to restore the original `_` reference in `_.noConflict`. */ + var oldDash = root._; + + /** Used to detect if a method is native. */ + var reIsNative = RegExp('^' + + funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') + .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' + ); + + /** Built-in value references. */ + var Buffer = moduleExports ? root.Buffer : undefined, + Symbol = root.Symbol, + Uint8Array = root.Uint8Array, + allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, + getPrototype = overArg(Object.getPrototypeOf, Object), + objectCreate = Object.create, + propertyIsEnumerable = objectProto.propertyIsEnumerable, + splice = arrayProto.splice, + spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, + symIterator = Symbol ? Symbol.iterator : undefined, + symToStringTag = Symbol ? Symbol.toStringTag : undefined; + + var defineProperty = (function () { + try { + var func = getNative(Object, 'defineProperty'); + func({}, '', {}); + return func; + } catch (e) { + } + }()); + + /* Built-in method references for those with the same name as other `lodash` methods. */ + var nativeCeil = Math.ceil, + nativeFloor = Math.floor, + nativeGetSymbols = Object.getOwnPropertySymbols, + nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, + nativeIsFinite = root.isFinite, + nativeKeys = overArg(Object.keys, Object), + nativeMax = Math.max, + nativeMin = Math.min, + nativeNow = Date.now, + nativeRandom = Math.random, + nativeReverse = arrayProto.reverse; + + /* Built-in method references that are verified to be native. */ + var DataView = getNative(root, 'DataView'), + Map = getNative(root, 'Map'), + Promise = getNative(root, 'Promise'), + Set = getNative(root, 'Set'), + WeakMap = getNative(root, 'WeakMap'), + nativeCreate = getNative(Object, 'create'); + + /** Used to store function metadata. */ + var metaMap = WeakMap && new WeakMap; + + /** Used to lookup unminified function names. */ + var realNames = {}; + + /** Used to detect maps, sets, and weakmaps. */ + var dataViewCtorString = toSource(DataView), + mapCtorString = toSource(Map), + promiseCtorString = toSource(Promise), + setCtorString = toSource(Set), + weakMapCtorString = toSource(WeakMap); + + /** Used to convert symbols to primitives and strings. */ + var symbolProto = Symbol ? Symbol.prototype : undefined, + symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, + symbolToString = symbolProto ? symbolProto.toString : undefined; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` object which wraps `value` to enable implicit method + * chain sequences. Methods that operate on and return arrays, collections, + * and functions can be chained together. Methods that retrieve a single value + * or may return a primitive value will automatically end the chain sequence + * and return the unwrapped value. Otherwise, the value must be unwrapped + * with `_#value`. + * + * Explicit chain sequences, which must be unwrapped with `_#value`, may be + * enabled using `_.chain`. + * + * The execution of chained methods is lazy, that is, it's deferred until + * `_#value` is implicitly or explicitly called. + * + * Lazy evaluation allows several methods to support shortcut fusion. + * Shortcut fusion is an optimization to merge iteratee calls; this avoids + * the creation of intermediate arrays and can greatly reduce the number of + * iteratee executions. Sections of a chain sequence qualify for shortcut + * fusion if the section is applied to an array and iteratees accept only + * one argument. The heuristic for whether a section qualifies for shortcut + * fusion is subject to change. + * + * Chaining is supported in custom builds as long as the `_#value` method is + * directly or indirectly included in the build. + * + * In addition to lodash methods, wrappers have `Array` and `String` methods. + * + * The wrapper `Array` methods are: + * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` + * + * The wrapper `String` methods are: + * `replace` and `split` + * + * The wrapper methods that support shortcut fusion are: + * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, + * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, + * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` + * + * The chainable wrapper methods are: + * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, + * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, + * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, + * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, + * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, + * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, + * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, + * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, + * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, + * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, + * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, + * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, + * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, + * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, + * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, + * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, + * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, + * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, + * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, + * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, + * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, + * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, + * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, + * `zipObject`, `zipObjectDeep`, and `zipWith` + * + * The wrapper methods that are **not** chainable by default are: + * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, + * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, + * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, + * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, + * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, + * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, + * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, + * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, + * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, + * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, + * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, + * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, + * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, + * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, + * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, + * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, + * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, + * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, + * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, + * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, + * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, + * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, + * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, + * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, + * `upperFirst`, `value`, and `words` + * + * @name _ + * @constructor + * @category Seq + * @param {*} value The value to wrap in a `lodash` instance. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2, 3]); + * + * // Returns an unwrapped value. + * wrapped.reduce(_.add); + * // => 6 + * + * // Returns a wrapped value. + * var squares = wrapped.map(square); + * + * _.isArray(squares); + * // => false + * + * _.isArray(squares.value()); + * // => true + */ + function lodash(value) { + if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { + if (value instanceof LodashWrapper) { + return value; + } + if (hasOwnProperty.call(value, '__wrapped__')) { + return wrapperClone(value); + } + } + return new LodashWrapper(value); + } + + /** + * The base implementation of `_.create` without support for assigning + * properties to the created object. + * + * @private + * @param {Object} proto The object to inherit from. + * @returns {Object} Returns the new object. + */ + var baseCreate = (function () { + function object() { + } + + return function (proto) { + if (!isObject(proto)) { + return {}; + } + if (objectCreate) { + return objectCreate(proto); + } + object.prototype = proto; + var result = new object; + object.prototype = undefined; + return result; + }; + }()); + + /** + * The function whose prototype chain sequence wrappers inherit from. + * + * @private + */ + function baseLodash() { + // No operation performed. + } + + /** + * The base constructor for creating `lodash` wrapper objects. + * + * @private + * @param {*} value The value to wrap. + * @param {boolean} [chainAll] Enable explicit method chain sequences. + */ + function LodashWrapper(value, chainAll) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__chain__ = !!chainAll; + this.__index__ = 0; + this.__values__ = undefined; + } + + // Ensure wrappers are instances of `baseLodash`. + lodash.prototype = baseLodash.prototype; + lodash.prototype.constructor = lodash; + + LodashWrapper.prototype = baseCreate(baseLodash.prototype); + LodashWrapper.prototype.constructor = LodashWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. + * + * @private + * @constructor + * @param {*} value The value to wrap. + */ + function LazyWrapper(value) { + this.__wrapped__ = value; + this.__actions__ = []; + this.__dir__ = 1; + this.__filtered__ = false; + this.__iteratees__ = []; + this.__takeCount__ = MAX_ARRAY_LENGTH; + this.__views__ = []; + } + + /** + * Creates a clone of the lazy wrapper object. + * + * @private + * @name clone + * @memberOf LazyWrapper + * @returns {Object} Returns the cloned `LazyWrapper` object. + */ + function lazyClone() { + var result = new LazyWrapper(this.__wrapped__); + result.__actions__ = copyArray(this.__actions__); + result.__dir__ = this.__dir__; + result.__filtered__ = this.__filtered__; + result.__iteratees__ = copyArray(this.__iteratees__); + result.__takeCount__ = this.__takeCount__; + result.__views__ = copyArray(this.__views__); + return result; + } + + /** + * Reverses the direction of lazy iteration. + * + * @private + * @name reverse + * @memberOf LazyWrapper + * @returns {Object} Returns the new reversed `LazyWrapper` object. + */ + function lazyReverse() { + if (this.__filtered__) { + var result = new LazyWrapper(this); + result.__dir__ = -1; + result.__filtered__ = true; + } else { + result = this.clone(); + result.__dir__ *= -1; + } + return result; + } + + /** + * Extracts the unwrapped value from its lazy wrapper. + * + * @private + * @name value + * @memberOf LazyWrapper + * @returns {*} Returns the unwrapped value. + */ + function lazyValue() { + var array = this.__wrapped__.value(), + dir = this.__dir__, + isArr = isArray(array), + isRight = dir < 0, + arrLength = isArr ? array.length : 0, + view = getView(0, arrLength, this.__views__), + start = view.start, + end = view.end, + length = end - start, + index = isRight ? end : (start - 1), + iteratees = this.__iteratees__, + iterLength = iteratees.length, + resIndex = 0, + takeCount = nativeMin(length, this.__takeCount__); + + if (!isArr || (!isRight && arrLength == length && takeCount == length)) { + return baseWrapperValue(array, this.__actions__); + } + var result = []; + + outer: + while (length-- && resIndex < takeCount) { + index += dir; + + var iterIndex = -1, + value = array[index]; + + while (++iterIndex < iterLength) { + var data = iteratees[iterIndex], + iteratee = data.iteratee, + type = data.type, + computed = iteratee(value); + + if (type == LAZY_MAP_FLAG) { + value = computed; + } else if (!computed) { + if (type == LAZY_FILTER_FLAG) { + continue outer; + } else { + break outer; + } + } + } + result[resIndex++] = value; + } + return result; + } + + // Ensure `LazyWrapper` is an instance of `baseLodash`. + LazyWrapper.prototype = baseCreate(baseLodash.prototype); + LazyWrapper.prototype.constructor = LazyWrapper; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a hash object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Hash(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the hash. + * + * @private + * @name clear + * @memberOf Hash + */ + function hashClear() { + this.__data__ = nativeCreate ? nativeCreate(null) : {}; + this.size = 0; + } + + /** + * Removes `key` and its value from the hash. + * + * @private + * @name delete + * @memberOf Hash + * @param {Object} hash The hash to modify. + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function hashDelete(key) { + var result = this.has(key) && delete this.__data__[key]; + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the hash value for `key`. + * + * @private + * @name get + * @memberOf Hash + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function hashGet(key) { + var data = this.__data__; + if (nativeCreate) { + var result = data[key]; + return result === HASH_UNDEFINED ? undefined : result; + } + return hasOwnProperty.call(data, key) ? data[key] : undefined; + } + + /** + * Checks if a hash value for `key` exists. + * + * @private + * @name has + * @memberOf Hash + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function hashHas(key) { + var data = this.__data__; + return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); + } + + /** + * Sets the hash `key` to `value`. + * + * @private + * @name set + * @memberOf Hash + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the hash instance. + */ + function hashSet(key, value) { + var data = this.__data__; + this.size += this.has(key) ? 0 : 1; + data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; + return this; + } + + // Add methods to `Hash`. + Hash.prototype.clear = hashClear; + Hash.prototype['delete'] = hashDelete; + Hash.prototype.get = hashGet; + Hash.prototype.has = hashHas; + Hash.prototype.set = hashSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an list cache object. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function ListCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the list cache. + * + * @private + * @name clear + * @memberOf ListCache + */ + function listCacheClear() { + this.__data__ = []; + this.size = 0; + } + + /** + * Removes `key` and its value from the list cache. + * + * @private + * @name delete + * @memberOf ListCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function listCacheDelete(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + return false; + } + var lastIndex = data.length - 1; + if (index == lastIndex) { + data.pop(); + } else { + splice.call(data, index, 1); + } + --this.size; + return true; + } + + /** + * Gets the list cache value for `key`. + * + * @private + * @name get + * @memberOf ListCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function listCacheGet(key) { + var data = this.__data__, + index = assocIndexOf(data, key); + + return index < 0 ? undefined : data[index][1]; + } + + /** + * Checks if a list cache value for `key` exists. + * + * @private + * @name has + * @memberOf ListCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function listCacheHas(key) { + return assocIndexOf(this.__data__, key) > -1; + } + + /** + * Sets the list cache `key` to `value`. + * + * @private + * @name set + * @memberOf ListCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the list cache instance. + */ + function listCacheSet(key, value) { + var data = this.__data__, + index = assocIndexOf(data, key); + + if (index < 0) { + ++this.size; + data.push([key, value]); + } else { + data[index][1] = value; + } + return this; + } + + // Add methods to `ListCache`. + ListCache.prototype.clear = listCacheClear; + ListCache.prototype['delete'] = listCacheDelete; + ListCache.prototype.get = listCacheGet; + ListCache.prototype.has = listCacheHas; + ListCache.prototype.set = listCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a map cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function MapCache(entries) { + var index = -1, + length = entries == null ? 0 : entries.length; + + this.clear(); + while (++index < length) { + var entry = entries[index]; + this.set(entry[0], entry[1]); + } + } + + /** + * Removes all key-value entries from the map. + * + * @private + * @name clear + * @memberOf MapCache + */ + function mapCacheClear() { + this.size = 0; + this.__data__ = { + 'hash': new Hash, + 'map': new (Map || ListCache), + 'string': new Hash + }; + } + + /** + * Removes `key` and its value from the map. + * + * @private + * @name delete + * @memberOf MapCache + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function mapCacheDelete(key) { + var result = getMapData(this, key)['delete'](key); + this.size -= result ? 1 : 0; + return result; + } + + /** + * Gets the map value for `key`. + * + * @private + * @name get + * @memberOf MapCache + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function mapCacheGet(key) { + return getMapData(this, key).get(key); + } + + /** + * Checks if a map value for `key` exists. + * + * @private + * @name has + * @memberOf MapCache + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function mapCacheHas(key) { + return getMapData(this, key).has(key); + } + + /** + * Sets the map `key` to `value`. + * + * @private + * @name set + * @memberOf MapCache + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the map cache instance. + */ + function mapCacheSet(key, value) { + var data = getMapData(this, key), + size = data.size; + + data.set(key, value); + this.size += data.size == size ? 0 : 1; + return this; + } + + // Add methods to `MapCache`. + MapCache.prototype.clear = mapCacheClear; + MapCache.prototype['delete'] = mapCacheDelete; + MapCache.prototype.get = mapCacheGet; + MapCache.prototype.has = mapCacheHas; + MapCache.prototype.set = mapCacheSet; + + /*------------------------------------------------------------------------*/ + + /** + * + * Creates an array cache object to store unique values. + * + * @private + * @constructor + * @param {Array} [values] The values to cache. + */ + function SetCache(values) { + var index = -1, + length = values == null ? 0 : values.length; + + this.__data__ = new MapCache; + while (++index < length) { + this.add(values[index]); + } + } + + /** + * Adds `value` to the array cache. + * + * @private + * @name add + * @memberOf SetCache + * @alias push + * @param {*} value The value to cache. + * @returns {Object} Returns the cache instance. + */ + function setCacheAdd(value) { + this.__data__.set(value, HASH_UNDEFINED); + return this; + } + + /** + * Checks if `value` is in the array cache. + * + * @private + * @name has + * @memberOf SetCache + * @param {*} value The value to search for. + * @returns {number} Returns `true` if `value` is found, else `false`. + */ + function setCacheHas(value) { + return this.__data__.has(value); + } + + // Add methods to `SetCache`. + SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; + SetCache.prototype.has = setCacheHas; + + /*------------------------------------------------------------------------*/ + + /** + * Creates a stack cache object to store key-value pairs. + * + * @private + * @constructor + * @param {Array} [entries] The key-value pairs to cache. + */ + function Stack(entries) { + var data = this.__data__ = new ListCache(entries); + this.size = data.size; + } + + /** + * Removes all key-value entries from the stack. + * + * @private + * @name clear + * @memberOf Stack + */ + function stackClear() { + this.__data__ = new ListCache; + this.size = 0; + } + + /** + * Removes `key` and its value from the stack. + * + * @private + * @name delete + * @memberOf Stack + * @param {string} key The key of the value to remove. + * @returns {boolean} Returns `true` if the entry was removed, else `false`. + */ + function stackDelete(key) { + var data = this.__data__, + result = data['delete'](key); + + this.size = data.size; + return result; + } + + /** + * Gets the stack value for `key`. + * + * @private + * @name get + * @memberOf Stack + * @param {string} key The key of the value to get. + * @returns {*} Returns the entry value. + */ + function stackGet(key) { + return this.__data__.get(key); + } + + /** + * Checks if a stack value for `key` exists. + * + * @private + * @name has + * @memberOf Stack + * @param {string} key The key of the entry to check. + * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. + */ + function stackHas(key) { + return this.__data__.has(key); + } + + /** + * Sets the stack `key` to `value`. + * + * @private + * @name set + * @memberOf Stack + * @param {string} key The key of the value to set. + * @param {*} value The value to set. + * @returns {Object} Returns the stack cache instance. + */ + function stackSet(key, value) { + var data = this.__data__; + if (data instanceof ListCache) { + var pairs = data.__data__; + if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { + pairs.push([key, value]); + this.size = ++data.size; + return this; + } + data = this.__data__ = new MapCache(pairs); + } + data.set(key, value); + this.size = data.size; + return this; + } + + // Add methods to `Stack`. + Stack.prototype.clear = stackClear; + Stack.prototype['delete'] = stackDelete; + Stack.prototype.get = stackGet; + Stack.prototype.has = stackHas; + Stack.prototype.set = stackSet; + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of the enumerable property names of the array-like `value`. + * + * @private + * @param {*} value The value to query. + * @param {boolean} inherited Specify returning inherited property names. + * @returns {Array} Returns the array of property names. + */ + function arrayLikeKeys(value, inherited) { + var isArr = isArray(value), + isArg = !isArr && isArguments(value), + isBuff = !isArr && !isArg && isBuffer(value), + isType = !isArr && !isArg && !isBuff && isTypedArray(value), + skipIndexes = isArr || isArg || isBuff || isType, + result = skipIndexes ? baseTimes(value.length, String) : [], + length = result.length; + + for (var key in value) { + if ((inherited || hasOwnProperty.call(value, key)) && + !(skipIndexes && ( + // Safari 9 has enumerable `arguments.length` in strict mode. + key == 'length' || + // Node.js 0.10 has enumerable non-index properties on buffers. + (isBuff && (key == 'offset' || key == 'parent')) || + // PhantomJS 2 has enumerable non-index properties on typed arrays. + (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || + // Skip index properties. + isIndex(key, length) + ))) { + result.push(key); + } + } + return result; + } + + /** + * This function is like `assignValue` except that it doesn't assign + * `undefined` values. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignMergeValue(object, key, value) { + if ((value !== undefined && !eq(object[key], value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Assigns `value` to `key` of `object` if the existing value is not equivalent + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function assignValue(object, key, value) { + var objValue = object[key]; + if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || + (value === undefined && !(key in object))) { + baseAssignValue(object, key, value); + } + } + + /** + * Gets the index at which the `key` is found in `array` of key-value pairs. + * + * @private + * @param {Array} array The array to inspect. + * @param {*} key The key to search for. + * @returns {number} Returns the index of the matched value, else `-1`. + */ + function assocIndexOf(array, key) { + var length = array.length; + while (length--) { + if (eq(array[length][0], key)) { + return length; + } + } + return -1; + } + + /** + * Aggregates elements of `collection` on `accumulator` with keys transformed + * by `iteratee` and values set by `setter`. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform keys. + * @param {Object} accumulator The initial aggregated object. + * @returns {Function} Returns `accumulator`. + */ + function baseAggregator(collection, setter, iteratee, accumulator) { + baseEach(collection, function (value, key, collection) { + setter(accumulator, value, iteratee(value), collection); + }); + return accumulator; + } + + /** + * The base implementation of `_.assign` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssign(object, source) { + return object && copyObject(source, keys(source), object); + } + + /** + * The base implementation of `_.assignIn` without support for multiple sources + * or `customizer` functions. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @returns {Object} Returns `object`. + */ + function baseAssignIn(object, source) { + return object && copyObject(source, keysIn(source), object); + } + + /** + * The base implementation of `assignValue` and `assignMergeValue` without + * value checks. + * + * @private + * @param {Object} object The object to modify. + * @param {string} key The key of the property to assign. + * @param {*} value The value to assign. + */ + function baseAssignValue(object, key, value) { + if (key == '__proto__' && defineProperty) { + defineProperty(object, key, { + 'configurable': true, + 'enumerable': true, + 'value': value, + 'writable': true + }); + } else { + object[key] = value; + } + } + + /** + * The base implementation of `_.at` without support for individual paths. + * + * @private + * @param {Object} object The object to iterate over. + * @param {string[]} paths The property paths to pick. + * @returns {Array} Returns the picked elements. + */ + function baseAt(object, paths) { + var index = -1, + length = paths.length, + result = Array(length), + skip = object == null; + + while (++index < length) { + result[index] = skip ? undefined : get(object, paths[index]); + } + return result; + } + + /** + * The base implementation of `_.clamp` which doesn't coerce arguments. + * + * @private + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + */ + function baseClamp(number, lower, upper) { + if (number === number) { + if (upper !== undefined) { + number = number <= upper ? number : upper; + } + if (lower !== undefined) { + number = number >= lower ? number : lower; + } + } + return number; + } + + /** + * The base implementation of `_.clone` and `_.cloneDeep` which tracks + * traversed objects. + * + * @private + * @param {*} value The value to clone. + * @param {boolean} bitmask The bitmask flags. + * 1 - Deep clone + * 2 - Flatten inherited properties + * 4 - Clone symbols + * @param {Function} [customizer] The function to customize cloning. + * @param {string} [key] The key of `value`. + * @param {Object} [object] The parent object of `value`. + * @param {Object} [stack] Tracks traversed objects and their clone counterparts. + * @returns {*} Returns the cloned value. + */ + function baseClone(value, bitmask, customizer, key, object, stack) { + var result, + isDeep = bitmask & CLONE_DEEP_FLAG, + isFlat = bitmask & CLONE_FLAT_FLAG, + isFull = bitmask & CLONE_SYMBOLS_FLAG; + + if (customizer) { + result = object ? customizer(value, key, object, stack) : customizer(value); + } + if (result !== undefined) { + return result; + } + if (!isObject(value)) { + return value; + } + var isArr = isArray(value); + if (isArr) { + result = initCloneArray(value); + if (!isDeep) { + return copyArray(value, result); + } + } else { + var tag = getTag(value), + isFunc = tag == funcTag || tag == genTag; + + if (isBuffer(value)) { + return cloneBuffer(value, isDeep); + } + if (tag == objectTag || tag == argsTag || (isFunc && !object)) { + result = (isFlat || isFunc) ? {} : initCloneObject(value); + if (!isDeep) { + return isFlat + ? copySymbolsIn(value, baseAssignIn(result, value)) + : copySymbols(value, baseAssign(result, value)); + } + } else { + if (!cloneableTags[tag]) { + return object ? value : {}; + } + result = initCloneByTag(value, tag, isDeep); + } + } + // Check for circular references and return its corresponding clone. + stack || (stack = new Stack); + var stacked = stack.get(value); + if (stacked) { + return stacked; + } + stack.set(value, result); + + if (isSet(value)) { + value.forEach(function (subValue) { + result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); + }); + + return result; + } + + if (isMap(value)) { + value.forEach(function (subValue, key) { + result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + + return result; + } + + var keysFunc = isFull + ? (isFlat ? getAllKeysIn : getAllKeys) + : (isFlat ? keysIn : keys); + + var props = isArr ? undefined : keysFunc(value); + arrayEach(props || value, function (subValue, key) { + if (props) { + key = subValue; + subValue = value[key]; + } + // Recursively populate clone (susceptible to call stack limits). + assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + }); + return result; + } + + /** + * The base implementation of `_.delay` and `_.defer` which accepts `args` + * to provide to `func`. + * + * @private + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {Array} args The arguments to provide to `func`. + * @returns {number|Object} Returns the timer id or timeout object. + */ + function baseDelay(func, wait, args) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return setTimeout(function () { + func.apply(undefined, args); + }, wait); + } + + /** + * The base implementation of methods like `_.difference` without support + * for excluding multiple arrays or iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Array} values The values to exclude. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of filtered values. + */ + function baseDifference(array, values, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + isCommon = true, + length = array.length, + result = [], + valuesLength = values.length; + + if (!length) { + return result; + } + if (iteratee) { + values = arrayMap(values, baseUnary(iteratee)); + } + if (comparator) { + includes = arrayIncludesWith; + isCommon = false; + } else if (values.length >= LARGE_ARRAY_SIZE) { + includes = cacheHas; + isCommon = false; + values = new SetCache(values); + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee == null ? value : iteratee(value); + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var valuesIndex = valuesLength; + while (valuesIndex--) { + if (values[valuesIndex] === computed) { + continue outer; + } + } + result.push(value); + } else if (!includes(values, computed, comparator)) { + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.forEach` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + */ + var baseEach = createBaseEach(baseForOwn); + + /** + * The base implementation of `_.every` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false` + */ + function baseEvery(collection, predicate) { + var result = true; + baseEach(collection, function (value, index, collection) { + result = !!predicate(value, index, collection); + return result; + }); + return result; + } + + /** + * The base implementation of methods like `_.max` and `_.min` which accepts a + * `comparator` to determine the extremum value. + * + * @private + * @param {Array} array The array to iterate over. + * @param {Function} iteratee The iteratee invoked per iteration. + * @param {Function} comparator The comparator used to compare values. + * @returns {*} Returns the extremum value. + */ + function baseExtremum(array, iteratee, comparator) { + var index = -1, + length = array.length; + + while (++index < length) { + var value = array[index], + current = iteratee(value); + + if (current != null && (computed === undefined + ? (current === current && !isSymbol(current)) + : comparator(current, computed) + )) { + var computed = current, + result = value; + } + } + return result; + } + + /** + * The base implementation of `_.filter` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + */ + function baseFilter(collection, predicate) { + var result = []; + baseEach(collection, function (value, index, collection) { + if (predicate(value, index, collection)) { + result.push(value); + } + }); + return result; + } + + /** + * The base implementation of `_.flatten` with support for restricting flattening. + * + * @private + * @param {Array} array The array to flatten. + * @param {number} depth The maximum recursion depth. + * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. + * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. + * @param {Array} [result=[]] The initial result value. + * @returns {Array} Returns the new flattened array. + */ + function baseFlatten(array, depth, predicate, isStrict, result) { + var index = -1, + length = array.length; + + predicate || (predicate = isFlattenable); + result || (result = []); + + while (++index < length) { + var value = array[index]; + if (depth > 0 && predicate(value)) { + if (depth > 1) { + // Recursively flatten arrays (susceptible to call stack limits). + baseFlatten(value, depth - 1, predicate, isStrict, result); + } else { + arrayPush(result, value); + } + } else if (!isStrict) { + result[result.length] = value; + } + } + return result; + } + + /** + * The base implementation of `baseForOwn` which iterates over `object` + * properties returned by `keysFunc` and invokes `iteratee` for each property. + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseFor = createBaseFor(); + + /** + * This function is like `baseFor` except that it iterates over properties + * in the opposite order. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @param {Function} keysFunc The function to get the keys of `object`. + * @returns {Object} Returns `object`. + */ + var baseForRight = createBaseFor(true); + + /** + * The base implementation of `_.forOwn` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwn(object, iteratee) { + return object && baseFor(object, iteratee, keys); + } + + /** + * The base implementation of `_.forOwnRight` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Object} Returns `object`. + */ + function baseForOwnRight(object, iteratee) { + return object && baseForRight(object, iteratee, keys); + } + + /** + * The base implementation of `_.functions` which creates an array of + * `object` function property names filtered from `props`. + * + * @private + * @param {Object} object The object to inspect. + * @param {Array} props The property names to filter. + * @returns {Array} Returns the function names. + */ + function baseFunctions(object, props) { + return arrayFilter(props, function (key) { + return isFunction(object[key]); + }); + } + + /** + * The base implementation of `_.get` without support for default values. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @returns {*} Returns the resolved value. + */ + function baseGet(object, path) { + path = castPath(path, object); + + var index = 0, + length = path.length; + + while (object != null && index < length) { + object = object[toKey(path[index++])]; + } + return (index && index == length) ? object : undefined; + } + + /** + * The base implementation of `getAllKeys` and `getAllKeysIn` which uses + * `keysFunc` and `symbolsFunc` to get the enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Function} keysFunc The function to get the keys of `object`. + * @param {Function} symbolsFunc The function to get the symbols of `object`. + * @returns {Array} Returns the array of property names and symbols. + */ + function baseGetAllKeys(object, keysFunc, symbolsFunc) { + var result = keysFunc(object); + return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); + } + + /** + * The base implementation of `getTag` without fallbacks for buggy environments. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + function baseGetTag(value) { + if (value == null) { + return value === undefined ? undefinedTag : nullTag; + } + return (symToStringTag && symToStringTag in Object(value)) + ? getRawTag(value) + : objectToString(value); + } + + /** + * The base implementation of `_.gt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is greater than `other`, + * else `false`. + */ + function baseGt(value, other) { + return value > other; + } + + /** + * The base implementation of `_.has` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHas(object, key) { + return object != null && hasOwnProperty.call(object, key); + } + + /** + * The base implementation of `_.hasIn` without support for deep paths. + * + * @private + * @param {Object} [object] The object to query. + * @param {Array|string} key The key to check. + * @returns {boolean} Returns `true` if `key` exists, else `false`. + */ + function baseHasIn(object, key) { + return object != null && key in Object(object); + } + + /** + * The base implementation of methods like `_.intersection`, without support + * for iteratee shorthands, that accepts an array of arrays to inspect. + * + * @private + * @param {Array} arrays The arrays to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new array of shared values. + */ + function baseIntersection(arrays, iteratee, comparator) { + var includes = comparator ? arrayIncludesWith : arrayIncludes, + length = arrays[0].length, + othLength = arrays.length, + othIndex = othLength, + caches = Array(othLength), + maxLength = Infinity, + result = []; + + while (othIndex--) { + var array = arrays[othIndex]; + if (othIndex && iteratee) { + array = arrayMap(array, baseUnary(iteratee)); + } + maxLength = nativeMin(array.length, maxLength); + caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) + ? new SetCache(othIndex && array) + : undefined; + } + array = arrays[0]; + + var index = -1, + seen = caches[0]; + + outer: + while (++index < length && result.length < maxLength) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (!(seen + ? cacheHas(seen, computed) + : includes(result, computed, comparator) + )) { + othIndex = othLength; + while (--othIndex) { + var cache = caches[othIndex]; + if (!(cache + ? cacheHas(cache, computed) + : includes(arrays[othIndex], computed, comparator)) + ) { + continue outer; + } + } + if (seen) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.invert` and `_.invertBy` which inverts + * `object` with values transformed by `iteratee` and set by `setter`. + * + * @private + * @param {Object} object The object to iterate over. + * @param {Function} setter The function to set `accumulator` values. + * @param {Function} iteratee The iteratee to transform values. + * @param {Object} accumulator The initial inverted object. + * @returns {Function} Returns `accumulator`. + */ + function baseInverter(object, setter, iteratee, accumulator) { + baseForOwn(object, function (value, key, object) { + setter(accumulator, iteratee(value), key, object); + }); + return accumulator; + } + + /** + * The base implementation of `_.invoke` without support for individual + * method arguments. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path of the method to invoke. + * @param {Array} args The arguments to invoke the method with. + * @returns {*} Returns the result of the invoked method. + */ + function baseInvoke(object, path, args) { + path = castPath(path, object); + object = parent(object, path); + var func = object == null ? object : object[toKey(last(path))]; + return func == null ? undefined : apply(func, object, args); + } + + /** + * The base implementation of `_.isArguments`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + */ + function baseIsArguments(value) { + return isObjectLike(value) && baseGetTag(value) == argsTag; + } + + /** + * The base implementation of `_.isDate` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + */ + function baseIsDate(value) { + return isObjectLike(value) && baseGetTag(value) == dateTag; + } + + /** + * The base implementation of `_.isEqual` which supports partial comparisons + * and tracks traversed objects. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @param {boolean} bitmask The bitmask flags. + * 1 - Unordered comparison + * 2 - Partial comparison + * @param {Function} [customizer] The function to customize comparisons. + * @param {Object} [stack] Tracks traversed `value` and `other` objects. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + */ + function baseIsEqual(value, other, bitmask, customizer, stack) { + if (value === other) { + return true; + } + if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { + return value !== value && other !== other; + } + return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); + } + + /** + * A specialized version of `baseIsEqual` for arrays and objects which performs + * deep comparisons and tracks traversed objects enabling objects with circular + * references to be compared. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} [stack] Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { + var objIsArr = isArray(object), + othIsArr = isArray(other), + objTag = objIsArr ? arrayTag : getTag(object), + othTag = othIsArr ? arrayTag : getTag(other); + + objTag = objTag == argsTag ? objectTag : objTag; + othTag = othTag == argsTag ? objectTag : othTag; + + var objIsObj = objTag == objectTag, + othIsObj = othTag == objectTag, + isSameTag = objTag == othTag; + + if (isSameTag && isBuffer(object)) { + if (!isBuffer(other)) { + return false; + } + objIsArr = true; + objIsObj = false; + } + if (isSameTag && !objIsObj) { + stack || (stack = new Stack); + return (objIsArr || isTypedArray(object)) + ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) + : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + } + if (!(bitmask & COMPARE_PARTIAL_FLAG)) { + var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), + othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); + + if (objIsWrapped || othIsWrapped) { + var objUnwrapped = objIsWrapped ? object.value() : object, + othUnwrapped = othIsWrapped ? other.value() : other; + + stack || (stack = new Stack); + return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); + } + } + if (!isSameTag) { + return false; + } + stack || (stack = new Stack); + return equalObjects(object, other, bitmask, customizer, equalFunc, stack); + } + + /** + * The base implementation of `_.isMap` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + */ + function baseIsMap(value) { + return isObjectLike(value) && getTag(value) == mapTag; + } + + /** + * The base implementation of `_.isMatch` without support for iteratee shorthands. + * + * @private + * @param {Object} object The object to inspect. + * @param {Object} source The object of property values to match. + * @param {Array} matchData The property names, values, and compare flags to match. + * @param {Function} [customizer] The function to customize comparisons. + * @returns {boolean} Returns `true` if `object` is a match, else `false`. + */ + function baseIsMatch(object, source, matchData, customizer) { + var index = matchData.length, + length = index, + noCustomizer = !customizer; + + if (object == null) { + return !length; + } + object = Object(object); + while (index--) { + var data = matchData[index]; + if ((noCustomizer && data[2]) + ? data[1] !== object[data[0]] + : !(data[0] in object) + ) { + return false; + } + } + while (++index < length) { + data = matchData[index]; + var key = data[0], + objValue = object[key], + srcValue = data[1]; + + if (noCustomizer && data[2]) { + if (objValue === undefined && !(key in object)) { + return false; + } + } else { + var stack = new Stack; + if (customizer) { + var result = customizer(objValue, srcValue, key, object, source, stack); + } + if (!(result === undefined + ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) + : result + )) { + return false; + } + } + } + return true; + } + + /** + * The base implementation of `_.isNative` without bad shim checks. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a native function, + * else `false`. + */ + function baseIsNative(value) { + if (!isObject(value) || isMasked(value)) { + return false; + } + var pattern = isFunction(value) ? reIsNative : reIsHostCtor; + return pattern.test(toSource(value)); + } + + /** + * The base implementation of `_.isRegExp` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + */ + function baseIsRegExp(value) { + return isObjectLike(value) && baseGetTag(value) == regexpTag; + } + + /** + * The base implementation of `_.isSet` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + */ + function baseIsSet(value) { + return isObjectLike(value) && getTag(value) == setTag; + } + + /** + * The base implementation of `_.isTypedArray` without Node.js optimizations. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + */ + function baseIsTypedArray(value) { + return isObjectLike(value) && + isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; + } + + /** + * The base implementation of `_.iteratee`. + * + * @private + * @param {*} [value=_.identity] The value to convert to an iteratee. + * @returns {Function} Returns the iteratee. + */ + function baseIteratee(value) { + // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. + // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. + if (typeof value == 'function') { + return value; + } + if (value == null) { + return identity; + } + if (typeof value == 'object') { + return isArray(value) + ? baseMatchesProperty(value[0], value[1]) + : baseMatches(value); + } + return property(value); + } + + /** + * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeys(object) { + if (!isPrototype(object)) { + return nativeKeys(object); + } + var result = []; + for (var key in Object(object)) { + if (hasOwnProperty.call(object, key) && key != 'constructor') { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function baseKeysIn(object) { + if (!isObject(object)) { + return nativeKeysIn(object); + } + var isProto = isPrototype(object), + result = []; + + for (var key in object) { + if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { + result.push(key); + } + } + return result; + } + + /** + * The base implementation of `_.lt` which doesn't coerce arguments. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if `value` is less than `other`, + * else `false`. + */ + function baseLt(value, other) { + return value < other; + } + + /** + * The base implementation of `_.map` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} iteratee The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + */ + function baseMap(collection, iteratee) { + var index = -1, + result = isArrayLike(collection) ? Array(collection.length) : []; + + baseEach(collection, function (value, key, collection) { + result[++index] = iteratee(value, key, collection); + }); + return result; + } + + /** + * The base implementation of `_.matches` which doesn't clone `source`. + * + * @private + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatches(source) { + var matchData = getMatchData(source); + if (matchData.length == 1 && matchData[0][2]) { + return matchesStrictComparable(matchData[0][0], matchData[0][1]); + } + return function (object) { + return object === source || baseIsMatch(object, source, matchData); + }; + } + + /** + * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. + * + * @private + * @param {string} path The path of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function baseMatchesProperty(path, srcValue) { + if (isKey(path) && isStrictComparable(srcValue)) { + return matchesStrictComparable(toKey(path), srcValue); + } + return function (object) { + var objValue = get(object, path); + return (objValue === undefined && objValue === srcValue) + ? hasIn(object, path) + : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); + }; + } + + /** + * The base implementation of `_.merge` without support for multiple sources. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {number} srcIndex The index of `source`. + * @param {Function} [customizer] The function to customize merged values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMerge(object, source, srcIndex, customizer, stack) { + if (object === source) { + return; + } + baseFor(source, function (srcValue, key) { + if (isObject(srcValue)) { + stack || (stack = new Stack); + baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); + } else { + var newValue = customizer + ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) + : undefined; + + if (newValue === undefined) { + newValue = srcValue; + } + assignMergeValue(object, key, newValue); + } + }, keysIn); + } + + /** + * A specialized version of `baseMerge` for arrays and objects which performs + * deep merges and tracks traversed objects enabling objects with circular + * references to be merged. + * + * @private + * @param {Object} object The destination object. + * @param {Object} source The source object. + * @param {string} key The key of the value to merge. + * @param {number} srcIndex The index of `source`. + * @param {Function} mergeFunc The function to merge values. + * @param {Function} [customizer] The function to customize assigned values. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + */ + function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { + var objValue = safeGet(object, key), + srcValue = safeGet(source, key), + stacked = stack.get(srcValue); + + if (stacked) { + assignMergeValue(object, key, stacked); + return; + } + var newValue = customizer + ? customizer(objValue, srcValue, (key + ''), object, source, stack) + : undefined; + + var isCommon = newValue === undefined; + + if (isCommon) { + var isArr = isArray(srcValue), + isBuff = !isArr && isBuffer(srcValue), + isTyped = !isArr && !isBuff && isTypedArray(srcValue); + + newValue = srcValue; + if (isArr || isBuff || isTyped) { + if (isArray(objValue)) { + newValue = objValue; + } else if (isArrayLikeObject(objValue)) { + newValue = copyArray(objValue); + } else if (isBuff) { + isCommon = false; + newValue = cloneBuffer(srcValue, true); + } else if (isTyped) { + isCommon = false; + newValue = cloneTypedArray(srcValue, true); + } else { + newValue = []; + } + } else if (isPlainObject(srcValue) || isArguments(srcValue)) { + newValue = objValue; + if (isArguments(objValue)) { + newValue = toPlainObject(objValue); + } else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { + newValue = initCloneObject(srcValue); + } + } else { + isCommon = false; + } + } + if (isCommon) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, newValue); + mergeFunc(newValue, srcValue, srcIndex, customizer, stack); + stack['delete'](srcValue); + } + assignMergeValue(object, key, newValue); + } + + /** + * The base implementation of `_.orderBy` without param guards. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. + * @param {string[]} orders The sort orders of `iteratees`. + * @returns {Array} Returns the new sorted array. + */ + function baseOrderBy(collection, iteratees, orders) { + var index = -1; + iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(baseIteratee)); + + var result = baseMap(collection, function (value, key, collection) { + var criteria = arrayMap(iteratees, function (iteratee) { + return iteratee(value); + }); + return { 'criteria': criteria, 'index': ++index, 'value': value }; + }); + + return baseSortBy(result, function (object, other) { + return compareMultiple(object, other, orders); + }); + } + + /** + * The base implementation of `_.pick` without support for individual + * property identifiers. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @returns {Object} Returns the new object. + */ + function basePick(object, paths) { + return basePickBy(object, paths, function (value, path) { + return hasIn(object, path); + }); + } + + /** + * The base implementation of `_.pickBy` without support for iteratee shorthands. + * + * @private + * @param {Object} object The source object. + * @param {string[]} paths The property paths to pick. + * @param {Function} predicate The function invoked per property. + * @returns {Object} Returns the new object. + */ + function basePickBy(object, paths, predicate) { + var index = -1, + length = paths.length, + result = {}; + + while (++index < length) { + var path = paths[index], + value = baseGet(object, path); + + if (predicate(value, path)) { + baseSet(result, castPath(path, object), value); + } + } + return result; + } + + /** + * A specialized version of `baseProperty` which supports deep paths. + * + * @private + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + */ + function basePropertyDeep(path) { + return function (object) { + return baseGet(object, path); + }; + } + + /** + * The base implementation of `_.random` without support for returning + * floating-point numbers. + * + * @private + * @param {number} lower The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the random number. + */ + function baseRandom(lower, upper) { + return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); + } + + /** + * The base implementation of `_.range` and `_.rangeRight` which doesn't + * coerce arguments. + * + * @private + * @param {number} start The start of the range. + * @param {number} end The end of the range. + * @param {number} step The value to increment or decrement by. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Array} Returns the range of numbers. + */ + function baseRange(start, end, step, fromRight) { + var index = -1, + length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), + result = Array(length); + + while (length--) { + result[fromRight ? length : ++index] = start; + start += step; + } + return result; + } + + /** + * The base implementation of `_.rest` which doesn't validate or coerce arguments. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + */ + function baseRest(func, start) { + return setToString(overRest(func, start, identity), func + ''); + } + + /** + * The base implementation of `_.set`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @param {Function} [customizer] The function to customize path creation. + * @returns {Object} Returns `object`. + */ + function baseSet(object, path, value, customizer) { + if (!isObject(object)) { + return object; + } + path = castPath(path, object); + + var index = -1, + length = path.length, + lastIndex = length - 1, + nested = object; + + while (nested != null && ++index < length) { + var key = toKey(path[index]), + newValue = value; + + if (index != lastIndex) { + var objValue = nested[key]; + newValue = customizer ? customizer(objValue, key, nested) : undefined; + if (newValue === undefined) { + newValue = isObject(objValue) + ? objValue + : (isIndex(path[index + 1]) ? [] : {}); + } + } + assignValue(nested, key, newValue); + nested = nested[key]; + } + return object; + } + + /** + * The base implementation of `setData` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var baseSetData = !metaMap ? identity : function (func, data) { + metaMap.set(func, data); + return func; }; - } - - /** - * The base implementation of `_.propertyOf` without support for deep paths. - * - * @private - * @param {Object} object The object to query. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyOf(object) { - return function(key) { - return object == null ? undefined : object[key]; + + /** + * The base implementation of `setToString` without support for hot loop shorting. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var baseSetToString = !defineProperty ? identity : function (func, string) { + return defineProperty(func, 'toString', { + 'configurable': true, + 'enumerable': false, + 'value': constant(string), + 'writable': true + }); }; - } - - /** - * The base implementation of `_.reduce` and `_.reduceRight`, without support - * for iteratee shorthands, which iterates over `collection` using `eachFunc`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {*} accumulator The initial value. - * @param {boolean} initAccum Specify using the first or last element of - * `collection` as the initial value. - * @param {Function} eachFunc The function to iterate over `collection`. - * @returns {*} Returns the accumulated value. - */ - function baseReduce(collection, iteratee, accumulator, initAccum, eachFunc) { - eachFunc(collection, function(value, index, collection) { - accumulator = initAccum - ? (initAccum = false, value) - : iteratee(accumulator, value, index, collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.sortBy` which uses `comparer` to define the - * sort order of `array` and replaces criteria objects with their corresponding - * values. - * - * @private - * @param {Array} array The array to sort. - * @param {Function} comparer The function to define sort order. - * @returns {Array} Returns `array`. - */ - function baseSortBy(array, comparer) { - var length = array.length; - - array.sort(comparer); - while (length--) { - array[length] = array[length].value; - } - return array; - } - - /** - * The base implementation of `_.times` without support for iteratee shorthands - * or max array length checks. - * - * @private - * @param {number} n The number of times to invoke `iteratee`. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the array of results. - */ - function baseTimes(n, iteratee) { - var index = -1, - result = Array(n); - - while (++index < n) { - result[index] = iteratee(index); - } - return result; - } - - /** - * The base implementation of `_.unary` without support for storing metadata. - * - * @private - * @param {Function} func The function to cap arguments for. - * @returns {Function} Returns the new capped function. - */ - function baseUnary(func) { - return function(value) { - return func(value); + + /** + * The base implementation of `_.slice` without an iteratee call guard. + * + * @private + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function baseSlice(array, start, end) { + var index = -1, + length = array.length; + + if (start < 0) { + start = -start > length ? 0 : (length + start); + } + end = end > length ? length : end; + if (end < 0) { + end += length; + } + length = start > end ? 0 : ((end - start) >>> 0); + start >>>= 0; + + var result = Array(length); + while (++index < length) { + result[index] = array[index + start]; + } + return result; + } + + /** + * The base implementation of `_.some` without support for iteratee shorthands. + * + * @private + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} predicate The function invoked per iteration. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + */ + function baseSome(collection, predicate) { + var result; + + baseEach(collection, function (value, index, collection) { + result = predicate(value, index, collection); + return !result; + }); + return !!result; + } + + /** + * The base implementation of `_.toString` which doesn't convert nullish + * values to empty strings. + * + * @private + * @param {*} value The value to process. + * @returns {string} Returns the string. + */ + function baseToString(value) { + // Exit early for strings to avoid a performance hit in some environments. + if (typeof value == 'string') { + return value; + } + if (isArray(value)) { + // Recursively convert values (susceptible to call stack limits). + return arrayMap(value, baseToString) + ''; + } + if (isSymbol(value)) { + return symbolToString ? symbolToString.call(value) : ''; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * The base implementation of `_.uniqBy` without support for iteratee shorthands. + * + * @private + * @param {Array} array The array to inspect. + * @param {Function} [iteratee] The iteratee invoked per element. + * @param {Function} [comparator] The comparator invoked per element. + * @returns {Array} Returns the new duplicate free array. + */ + function baseUniq(array, iteratee, comparator) { + var index = -1, + includes = arrayIncludes, + length = array.length, + isCommon = true, + result = [], + seen = result; + + if (comparator) { + isCommon = false; + includes = arrayIncludesWith; + } else if (length >= LARGE_ARRAY_SIZE) { + var set = iteratee ? null : createSet(array); + if (set) { + return setToArray(set); + } + isCommon = false; + includes = cacheHas; + seen = new SetCache; + } else { + seen = iteratee ? [] : result; + } + outer: + while (++index < length) { + var value = array[index], + computed = iteratee ? iteratee(value) : value; + + value = (comparator || value !== 0) ? value : 0; + if (isCommon && computed === computed) { + var seenIndex = seen.length; + while (seenIndex--) { + if (seen[seenIndex] === computed) { + continue outer; + } + } + if (iteratee) { + seen.push(computed); + } + result.push(value); + } else if (!includes(seen, computed, comparator)) { + if (seen !== result) { + seen.push(computed); + } + result.push(value); + } + } + return result; + } + + /** + * The base implementation of `_.unset`. + * + * @private + * @param {Object} object The object to modify. + * @param {Array|string} path The property path to unset. + * @returns {boolean} Returns `true` if the property is deleted, else `false`. + */ + function baseUnset(object, path) { + path = castPath(path, object); + object = parent(object, path); + return object == null || delete object[toKey(last(path))]; + } + + /** + * The base implementation of `wrapperValue` which returns the result of + * performing a sequence of actions on the unwrapped `value`, where each + * successive action is supplied the return value of the previous. + * + * @private + * @param {*} value The unwrapped value. + * @param {Array} actions Actions to perform to resolve the unwrapped value. + * @returns {*} Returns the resolved value. + */ + function baseWrapperValue(value, actions) { + var result = value; + if (result instanceof LazyWrapper) { + result = result.value(); + } + return arrayReduce(actions, function (result, action) { + return action.func.apply(action.thisArg, arrayPush([result], action.args)); + }, result); + } + + /** + * This base implementation of `_.zipObject` which assigns values using `assignFunc`. + * + * @private + * @param {Array} props The property identifiers. + * @param {Array} values The property values. + * @param {Function} assignFunc The function to assign values. + * @returns {Object} Returns the new object. + */ + function baseZipObject(props, values, assignFunc) { + var index = -1, + length = props.length, + valsLength = values.length, + result = {}; + + while (++index < length) { + var value = index < valsLength ? values[index] : undefined; + assignFunc(result, props[index], value); + } + return result; + } + + /** + * Casts `value` to an empty array if it's not an array like object. + * + * @private + * @param {*} value The value to inspect. + * @returns {Array|Object} Returns the cast array-like object. + */ + function castArrayLikeObject(value) { + return isArrayLikeObject(value) ? value : []; + } + + /** + * Casts `value` to a path array if it's not one. + * + * @private + * @param {*} value The value to inspect. + * @param {Object} [object] The object to query keys on. + * @returns {Array} Returns the cast property path array. + */ + function castPath(value, object) { + if (isArray(value)) { + return value; + } + return isKey(value, object) ? [value] : stringToPath(toString(value)); + } + + /** + * Casts `array` to a slice if it's needed. + * + * @private + * @param {Array} array The array to inspect. + * @param {number} start The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the cast slice. + */ + function castSlice(array, start, end) { + var length = array.length; + end = end === undefined ? length : end; + return (!start && end >= length) ? array : baseSlice(array, start, end); + } + + /** + * Creates a clone of `buffer`. + * + * @private + * @param {Buffer} buffer The buffer to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Buffer} Returns the cloned buffer. + */ + function cloneBuffer(buffer, isDeep) { + if (isDeep) { + return buffer.slice(); + } + var length = buffer.length, + result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); + + buffer.copy(result); + return result; + } + + /** + * Creates a clone of `arrayBuffer`. + * + * @private + * @param {ArrayBuffer} arrayBuffer The array buffer to clone. + * @returns {ArrayBuffer} Returns the cloned array buffer. + */ + function cloneArrayBuffer(arrayBuffer) { + var result = new arrayBuffer.constructor(arrayBuffer.byteLength); + new Uint8Array(result).set(new Uint8Array(arrayBuffer)); + return result; + } + + /** + * Creates a clone of `dataView`. + * + * @private + * @param {Object} dataView The data view to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned data view. + */ + function cloneDataView(dataView, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; + return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); + } + + /** + * Creates a clone of `regexp`. + * + * @private + * @param {Object} regexp The regexp to clone. + * @returns {Object} Returns the cloned regexp. + */ + function cloneRegExp(regexp) { + var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); + result.lastIndex = regexp.lastIndex; + return result; + } + + /** + * Creates a clone of the `symbol` object. + * + * @private + * @param {Object} symbol The symbol object to clone. + * @returns {Object} Returns the cloned symbol object. + */ + function cloneSymbol(symbol) { + return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; + } + + /** + * Creates a clone of `typedArray`. + * + * @private + * @param {Object} typedArray The typed array to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the cloned typed array. + */ + function cloneTypedArray(typedArray, isDeep) { + var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; + return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); + } + + /** + * Compares values to sort them in ascending order. + * + * @private + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {number} Returns the sort order indicator for `value`. + */ + function compareAscending(value, other) { + if (value !== other) { + var valIsDefined = value !== undefined, + valIsNull = value === null, + valIsReflexive = value === value, + valIsSymbol = isSymbol(value); + + var othIsDefined = other !== undefined, + othIsNull = other === null, + othIsReflexive = other === other, + othIsSymbol = isSymbol(other); + + if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || + (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || + (valIsNull && othIsDefined && othIsReflexive) || + (!valIsDefined && othIsReflexive) || + !valIsReflexive) { + return 1; + } + if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || + (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || + (othIsNull && valIsDefined && valIsReflexive) || + (!othIsDefined && valIsReflexive) || + !othIsReflexive) { + return -1; + } + } + return 0; + } + + /** + * Used by `_.orderBy` to compare multiple properties of a value to another + * and stable sort them. + * + * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, + * specify an order of "desc" for descending or "asc" for ascending sort order + * of corresponding values. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {boolean[]|string[]} orders The order to sort by for each property. + * @returns {number} Returns the sort order indicator for `object`. + */ + function compareMultiple(object, other, orders) { + var index = -1, + objCriteria = object.criteria, + othCriteria = other.criteria, + length = objCriteria.length, + ordersLength = orders.length; + + while (++index < length) { + var result = compareAscending(objCriteria[index], othCriteria[index]); + if (result) { + if (index >= ordersLength) { + return result; + } + var order = orders[index]; + return result * (order == 'desc' ? -1 : 1); + } + } + // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications + // that causes it, under certain circumstances, to provide the same value for + // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 + // for more details. + // + // This also ensures a stable sort in V8 and other engines. + // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. + return object.index - other.index; + } + + /** + * Creates an array that is the composition of partially applied arguments, + * placeholders, and provided arguments into a single array of arguments. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to prepend to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgs(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersLength = holders.length, + leftIndex = -1, + leftLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(leftLength + rangeLength), + isUncurried = !isCurried; + + while (++leftIndex < leftLength) { + result[leftIndex] = partials[leftIndex]; + } + while (++argsIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[holders[argsIndex]] = args[argsIndex]; + } + } + while (rangeLength--) { + result[leftIndex++] = args[argsIndex++]; + } + return result; + } + + /** + * This function is like `composeArgs` except that the arguments composition + * is tailored for `_.partialRight`. + * + * @private + * @param {Array} args The provided arguments. + * @param {Array} partials The arguments to append to those provided. + * @param {Array} holders The `partials` placeholder indexes. + * @params {boolean} [isCurried] Specify composing for a curried function. + * @returns {Array} Returns the new array of composed arguments. + */ + function composeArgsRight(args, partials, holders, isCurried) { + var argsIndex = -1, + argsLength = args.length, + holdersIndex = -1, + holdersLength = holders.length, + rightIndex = -1, + rightLength = partials.length, + rangeLength = nativeMax(argsLength - holdersLength, 0), + result = Array(rangeLength + rightLength), + isUncurried = !isCurried; + + while (++argsIndex < rangeLength) { + result[argsIndex] = args[argsIndex]; + } + var offset = argsIndex; + while (++rightIndex < rightLength) { + result[offset + rightIndex] = partials[rightIndex]; + } + while (++holdersIndex < holdersLength) { + if (isUncurried || argsIndex < argsLength) { + result[offset + holders[holdersIndex]] = args[argsIndex++]; + } + } + return result; + } + + /** + * Copies the values of `source` to `array`. + * + * @private + * @param {Array} source The array to copy values from. + * @param {Array} [array=[]] The array to copy values to. + * @returns {Array} Returns `array`. + */ + function copyArray(source, array) { + var index = -1, + length = source.length; + + array || (array = Array(length)); + while (++index < length) { + array[index] = source[index]; + } + return array; + } + + /** + * Copies properties of `source` to `object`. + * + * @private + * @param {Object} source The object to copy properties from. + * @param {Array} props The property identifiers to copy. + * @param {Object} [object={}] The object to copy properties to. + * @param {Function} [customizer] The function to customize copied values. + * @returns {Object} Returns `object`. + */ + function copyObject(source, props, object, customizer) { + var isNew = !object; + object || (object = {}); + + var index = -1, + length = props.length; + + while (++index < length) { + var key = props[index]; + + var newValue = customizer + ? customizer(object[key], source[key], key, object, source) + : undefined; + + if (newValue === undefined) { + newValue = source[key]; + } + if (isNew) { + baseAssignValue(object, key, newValue); + } else { + assignValue(object, key, newValue); + } + } + return object; + } + + /** + * Copies own symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbols(source, object) { + return copyObject(source, getSymbols(source), object); + } + + /** + * Copies own and inherited symbols of `source` to `object`. + * + * @private + * @param {Object} source The object to copy symbols from. + * @param {Object} [object={}] The object to copy symbols to. + * @returns {Object} Returns `object`. + */ + function copySymbolsIn(source, object) { + return copyObject(source, getSymbolsIn(source), object); + } + + /** + * Creates a function like `_.groupBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} [initializer] The accumulator object initializer. + * @returns {Function} Returns the new aggregator function. + */ + function createAggregator(setter, initializer) { + return function (collection, iteratee) { + var func = isArray(collection) ? arrayAggregator : baseAggregator, + accumulator = initializer ? initializer() : {}; + + return func(collection, setter, baseIteratee(iteratee, 2), accumulator); + }; + } + + /** + * Creates a function like `_.assign`. + * + * @private + * @param {Function} assigner The function to assign values. + * @returns {Function} Returns the new assigner function. + */ + function createAssigner(assigner) { + return baseRest(function (object, sources) { + var index = -1, + length = sources.length, + customizer = length > 1 ? sources[length - 1] : undefined, + guard = length > 2 ? sources[2] : undefined; + + customizer = (assigner.length > 3 && typeof customizer == 'function') + ? (length--, customizer) + : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + customizer = length < 3 ? undefined : customizer; + length = 1; + } + object = Object(object); + while (++index < length) { + var source = sources[index]; + if (source) { + assigner(object, source, index, customizer); + } + } + return object; + }); + } + + /** + * Creates a `baseEach` or `baseEachRight` function. + * + * @private + * @param {Function} eachFunc The function to iterate over a collection. + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseEach(eachFunc, fromRight) { + return function (collection, iteratee) { + if (collection == null) { + return collection; + } + if (!isArrayLike(collection)) { + return eachFunc(collection, iteratee); + } + var length = collection.length, + index = fromRight ? length : -1, + iterable = Object(collection); + + while ((fromRight ? index-- : ++index < length)) { + if (iteratee(iterable[index], index, iterable) === false) { + break; + } + } + return collection; + }; + } + + /** + * Creates a base function for methods like `_.forIn` and `_.forOwn`. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new base function. + */ + function createBaseFor(fromRight) { + return function (object, iteratee, keysFunc) { + var index = -1, + iterable = Object(object), + props = keysFunc(object), + length = props.length; + + while (length--) { + var key = props[fromRight ? length : ++index]; + if (iteratee(iterable[key], key, iterable) === false) { + break; + } + } + return object; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the optional `this` + * binding of `thisArg`. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createBind(func, bitmask, thisArg) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return fn.apply(isBind ? thisArg : this, arguments); + } + + return wrapper; + } + + /** + * Creates a function that produces an instance of `Ctor` regardless of + * whether it was invoked as part of a `new` expression or by `call` or `apply`. + * + * @private + * @param {Function} Ctor The constructor to wrap. + * @returns {Function} Returns the new wrapped function. + */ + function createCtor(Ctor) { + return function () { + // Use a `switch` statement to work with class constructors. See + // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist + // for more details. + var args = arguments; + switch (args.length) { + case 0: + return new Ctor; + case 1: + return new Ctor(args[0]); + case 2: + return new Ctor(args[0], args[1]); + case 3: + return new Ctor(args[0], args[1], args[2]); + case 4: + return new Ctor(args[0], args[1], args[2], args[3]); + case 5: + return new Ctor(args[0], args[1], args[2], args[3], args[4]); + case 6: + return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); + case 7: + return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); + } + var thisBinding = baseCreate(Ctor.prototype), + result = Ctor.apply(thisBinding, args); + + // Mimic the constructor's `return` behavior. + // See https://es5.github.io/#x13.2.2 for more details. + return isObject(result) ? result : thisBinding; + }; + } + + /** + * Creates a function that wraps `func` to enable currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {number} arity The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createCurry(func, bitmask, arity) { + var Ctor = createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length, + placeholder = getHolder(wrapper); + + while (index--) { + args[index] = arguments[index]; + } + var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) + ? [] + : replaceHolders(args, placeholder); + + length -= holders.length; + if (length < arity) { + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, undefined, + args, holders, undefined, undefined, arity - length); + } + var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + return apply(fn, this, args); + } + + return wrapper; + } + + /** + * Creates a `_.find` or `_.findLast` function. + * + * @private + * @param {Function} findIndexFunc The function to find the collection index. + * @returns {Function} Returns the new find function. + */ + function createFind(findIndexFunc) { + return function (collection, predicate, fromIndex) { + var iterable = Object(collection); + if (!isArrayLike(collection)) { + var iteratee = baseIteratee(predicate, 3); + collection = keys(collection); + predicate = function (key) { + return iteratee(iterable[key], key, iterable); + }; + } + var index = findIndexFunc(collection, predicate, fromIndex); + return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; + }; + } + + /** + * Creates a function that wraps `func` to invoke it with optional `this` + * binding of `thisArg`, partial application, and currying. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [partialsRight] The arguments to append to those provided + * to the new function. + * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { + var isAry = bitmask & WRAP_ARY_FLAG, + isBind = bitmask & WRAP_BIND_FLAG, + isBindKey = bitmask & WRAP_BIND_KEY_FLAG, + isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), + isFlip = bitmask & WRAP_FLIP_FLAG, + Ctor = isBindKey ? undefined : createCtor(func); + + function wrapper() { + var length = arguments.length, + args = Array(length), + index = length; + + while (index--) { + args[index] = arguments[index]; + } + if (isCurried) { + var placeholder = getHolder(wrapper), + holdersCount = countHolders(args, placeholder); + } + if (partials) { + args = composeArgs(args, partials, holders, isCurried); + } + if (partialsRight) { + args = composeArgsRight(args, partialsRight, holdersRight, isCurried); + } + length -= holdersCount; + if (isCurried && length < arity) { + var newHolders = replaceHolders(args, placeholder); + return createRecurry( + func, bitmask, createHybrid, wrapper.placeholder, thisArg, + args, newHolders, argPos, ary, arity - length + ); + } + var thisBinding = isBind ? thisArg : this, + fn = isBindKey ? thisBinding[func] : func; + + length = args.length; + if (argPos) { + args = reorder(args, argPos); + } else if (isFlip && length > 1) { + args.reverse(); + } + if (isAry && ary < length) { + args.length = ary; + } + if (this && this !== root && this instanceof wrapper) { + fn = Ctor || createCtor(fn); + } + return fn.apply(thisBinding, args); + } + + return wrapper; + } + + /** + * Creates a function like `_.invertBy`. + * + * @private + * @param {Function} setter The function to set accumulator values. + * @param {Function} toIteratee The function to resolve iteratees. + * @returns {Function} Returns the new inverter function. + */ + function createInverter(setter, toIteratee) { + return function (object, iteratee) { + return baseInverter(object, setter, toIteratee(iteratee), {}); + }; + } + + /** + * Creates a function that wraps `func` to invoke it with the `this` binding + * of `thisArg` and `partials` prepended to the arguments it receives. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {*} thisArg The `this` binding of `func`. + * @param {Array} partials The arguments to prepend to those provided to + * the new function. + * @returns {Function} Returns the new wrapped function. + */ + function createPartial(func, bitmask, thisArg, partials) { + var isBind = bitmask & WRAP_BIND_FLAG, + Ctor = createCtor(func); + + function wrapper() { + var argsIndex = -1, + argsLength = arguments.length, + leftIndex = -1, + leftLength = partials.length, + args = Array(leftLength + argsLength), + fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; + + while (++leftIndex < leftLength) { + args[leftIndex] = partials[leftIndex]; + } + while (argsLength--) { + args[leftIndex++] = arguments[++argsIndex]; + } + return apply(fn, isBind ? thisArg : this, args); + } + + return wrapper; + } + + /** + * Creates a `_.range` or `_.rangeRight` function. + * + * @private + * @param {boolean} [fromRight] Specify iterating from right to left. + * @returns {Function} Returns the new range function. + */ + function createRange(fromRight) { + return function (start, end, step) { + if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { + end = step = undefined; + } + // Ensure the sign of `-0` is preserved. + start = toFinite(start); + if (end === undefined) { + end = start; + start = 0; + } else { + end = toFinite(end); + } + step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); + return baseRange(start, end, step, fromRight); + }; + } + + /** + * Creates a function that wraps `func` to continue currying. + * + * @private + * @param {Function} func The function to wrap. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @param {Function} wrapFunc The function to create the `func` wrapper. + * @param {*} placeholder The placeholder value. + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to prepend to those provided to + * the new function. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { + var isCurry = bitmask & WRAP_CURRY_FLAG, + newHolders = isCurry ? holders : undefined, + newHoldersRight = isCurry ? undefined : holders, + newPartials = isCurry ? partials : undefined, + newPartialsRight = isCurry ? undefined : partials; + + bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); + bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); + + if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { + bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); + } + var newData = [ + func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, + newHoldersRight, argPos, ary, arity + ]; + + var result = wrapFunc.apply(undefined, newData); + if (isLaziable(func)) { + setData(result, newData); + } + result.placeholder = placeholder; + return setWrapToString(result, func, bitmask); + } + + /** + * Creates a set object of `values`. + * + * @private + * @param {Array} values The values to add to the set. + * @returns {Object} Returns the new set. + */ + var createSet = !(Set && (1 / setToArray(new Set([, -0]))[1]) == INFINITY) ? noop : function (values) { + return new Set(values); }; - } - - /** - * The base implementation of `_.values` and `_.valuesIn` which creates an - * array of `object` property values corresponding to the property names - * of `props`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} props The property names to get values for. - * @returns {Object} Returns the array of property values. - */ - function baseValues(object, props) { - return arrayMap(props, function(key) { - return object[key]; - }); - } - - /** - * Checks if a `cache` value for `key` exists. - * - * @private - * @param {Object} cache The cache to query. - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function cacheHas(cache, key) { - return cache.has(key); - } - - /** - * Used by `_.trim` and `_.trimStart` to get the index of the first string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the first unmatched string symbol. - */ - function charsStartIndex(strSymbols, chrSymbols) { - var index = -1, - length = strSymbols.length; - - while (++index < length && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Used by `_.trim` and `_.trimEnd` to get the index of the last string symbol - * that is not found in the character symbols. - * - * @private - * @param {Array} strSymbols The string symbols to inspect. - * @param {Array} chrSymbols The character symbols to find. - * @returns {number} Returns the index of the last unmatched string symbol. - */ - function charsEndIndex(strSymbols, chrSymbols) { - var index = strSymbols.length; - - while (index-- && baseIndexOf(chrSymbols, strSymbols[index], 0) > -1) {} - return index; - } - - /** - * Gets the number of `placeholder` occurrences in `array`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} placeholder The placeholder to search for. - * @returns {number} Returns the placeholder count. - */ - function countHolders(array, placeholder) { - var length = array.length, - result = 0; - - while (length--) { - if (array[length] === placeholder) { - ++result; - } - } - return result; - } - - /** - * Used by `_.escape` to convert characters to HTML entities. - * - * @private - * @param {string} chr The matched character to escape. - * @returns {string} Returns the escaped character. - */ - var escapeHtmlChar = basePropertyOf(htmlEscapes); - - /** - * Gets the value at `key` of `object`. - * - * @private - * @param {Object} [object] The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function getValue(object, key) { - return object == null ? undefined : object[key]; - } - - /** - * Checks if `string` contains Unicode symbols. - * - * @private - * @param {string} string The string to inspect. - * @returns {boolean} Returns `true` if a symbol is found, else `false`. - */ - function hasUnicode(string) { - return reHasUnicode.test(string); - } - - /** - * Converts `iterator` to an array. - * - * @private - * @param {Object} iterator The iterator to convert. - * @returns {Array} Returns the converted array. - */ - function iteratorToArray(iterator) { - var data, - result = []; - - while (!(data = iterator.next()).done) { - result.push(data.value); - } - return result; - } - - /** - * Converts `map` to its key-value pairs. - * - * @private - * @param {Object} map The map to convert. - * @returns {Array} Returns the key-value pairs. - */ - function mapToArray(map) { - var index = -1, - result = Array(map.size); - - map.forEach(function(value, key) { - result[++index] = [key, value]; - }); - return result; - } - - /** - * Creates a unary function that invokes `func` with its argument transformed. - * - * @private - * @param {Function} func The function to wrap. - * @param {Function} transform The argument transform. - * @returns {Function} Returns the new function. - */ - function overArg(func, transform) { - return function(arg) { - return func(transform(arg)); + + /** + * Creates a function that either curries or invokes `func` with optional + * `this` binding and partially applied arguments. + * + * @private + * @param {Function|string} func The function or method name to wrap. + * @param {number} bitmask The bitmask flags. + * 1 - `_.bind` + * 2 - `_.bindKey` + * 4 - `_.curry` or `_.curryRight` of a bound function + * 8 - `_.curry` + * 16 - `_.curryRight` + * 32 - `_.partial` + * 64 - `_.partialRight` + * 128 - `_.rearg` + * 256 - `_.ary` + * 512 - `_.flip` + * @param {*} [thisArg] The `this` binding of `func`. + * @param {Array} [partials] The arguments to be partially applied. + * @param {Array} [holders] The `partials` placeholder indexes. + * @param {Array} [argPos] The argument positions of the new function. + * @param {number} [ary] The arity cap of `func`. + * @param {number} [arity] The arity of `func`. + * @returns {Function} Returns the new wrapped function. + */ + function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { + var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; + if (!isBindKey && typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + var length = partials ? partials.length : 0; + if (!length) { + bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); + partials = holders = undefined; + } + ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); + arity = arity === undefined ? arity : toInteger(arity); + length -= holders ? holders.length : 0; + + if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { + var partialsRight = partials, + holdersRight = holders; + + partials = holders = undefined; + } + var data = isBindKey ? undefined : getData(func); + + var newData = [ + func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, + argPos, ary, arity + ]; + + if (data) { + mergeData(newData, data); + } + func = newData[0]; + bitmask = newData[1]; + thisArg = newData[2]; + partials = newData[3]; + holders = newData[4]; + arity = newData[9] = newData[9] === undefined + ? (isBindKey ? 0 : func.length) + : nativeMax(newData[9] - length, 0); + + if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { + bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); + } + if (!bitmask || bitmask == WRAP_BIND_FLAG) { + var result = createBind(func, bitmask, thisArg); + } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { + result = createCurry(func, bitmask, arity); + } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { + result = createPartial(func, bitmask, thisArg, partials); + } else { + result = createHybrid.apply(undefined, newData); + } + var setter = data ? baseSetData : setData; + return setWrapToString(setter(result, newData), func, bitmask); + } + + /** + * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source + * objects into destination objects that are passed thru. + * + * @private + * @param {*} objValue The destination value. + * @param {*} srcValue The source value. + * @param {string} key The key of the property to merge. + * @param {Object} object The parent object of `objValue`. + * @param {Object} source The parent object of `srcValue`. + * @param {Object} [stack] Tracks traversed source values and their merged + * counterparts. + * @returns {*} Returns the value to assign. + */ + function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { + if (isObject(objValue) && isObject(srcValue)) { + // Recursively merge objects and arrays (susceptible to call stack limits). + stack.set(srcValue, objValue); + baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); + stack['delete'](srcValue); + } + return objValue; + } + + /** + * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain + * objects. + * + * @private + * @param {*} value The value to inspect. + * @param {string} key The key of the property to inspect. + * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. + */ + function customOmitClone(value) { + return isPlainObject(value) ? undefined : value; + } + + /** + * A specialized version of `baseIsEqualDeep` for arrays with support for + * partial deep comparisons. + * + * @private + * @param {Array} array The array to compare. + * @param {Array} other The other array to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `array` and `other` objects. + * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. + */ + function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + arrLength = array.length, + othLength = other.length; + + if (arrLength != othLength && !(isPartial && othLength > arrLength)) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(array); + if (stacked && stack.get(other)) { + return stacked == other; + } + var index = -1, + result = true, + seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; + + stack.set(array, other); + stack.set(other, array); + + // Ignore non-index properties. + while (++index < arrLength) { + var arrValue = array[index], + othValue = other[index]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, arrValue, index, other, array, stack) + : customizer(arrValue, othValue, index, array, other, stack); + } + if (compared !== undefined) { + if (compared) { + continue; + } + result = false; + break; + } + // Recursively compare arrays (susceptible to call stack limits). + if (seen) { + if (!arraySome(other, function (othValue, othIndex) { + if (!cacheHas(seen, othIndex) && + (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { + return seen.push(othIndex); + } + })) { + result = false; + break; + } + } else if (!( + arrValue === othValue || + equalFunc(arrValue, othValue, bitmask, customizer, stack) + )) { + result = false; + break; + } + } + stack['delete'](array); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseIsEqualDeep` for comparing objects of + * the same `toStringTag`. + * + * **Note:** This function only supports comparing values with tags of + * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {string} tag The `toStringTag` of the objects to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { + switch (tag) { + case dataViewTag: + if ((object.byteLength != other.byteLength) || + (object.byteOffset != other.byteOffset)) { + return false; + } + object = object.buffer; + other = other.buffer; + + case arrayBufferTag: + if ((object.byteLength != other.byteLength) || + !equalFunc(new Uint8Array(object), new Uint8Array(other))) { + return false; + } + return true; + + case boolTag: + case dateTag: + case numberTag: + // Coerce booleans to `1` or `0` and dates to milliseconds. + // Invalid dates are coerced to `NaN`. + return eq(+object, +other); + + case errorTag: + return object.name == other.name && object.message == other.message; + + case regexpTag: + case stringTag: + // Coerce regexes to strings and treat strings, primitives and objects, + // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring + // for more details. + return object == (other + ''); + + case mapTag: + var convert = mapToArray; + + case setTag: + var isPartial = bitmask & COMPARE_PARTIAL_FLAG; + convert || (convert = setToArray); + + if (object.size != other.size && !isPartial) { + return false; + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked) { + return stacked == other; + } + bitmask |= COMPARE_UNORDERED_FLAG; + + // Recursively compare objects (susceptible to call stack limits). + stack.set(object, other); + var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); + stack['delete'](object); + return result; + + case symbolTag: + if (symbolValueOf) { + return symbolValueOf.call(object) == symbolValueOf.call(other); + } + } + return false; + } + + /** + * A specialized version of `baseIsEqualDeep` for objects with support for + * partial deep comparisons. + * + * @private + * @param {Object} object The object to compare. + * @param {Object} other The other object to compare. + * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. + * @param {Function} customizer The function to customize comparisons. + * @param {Function} equalFunc The function to determine equivalents of values. + * @param {Object} stack Tracks traversed `object` and `other` objects. + * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. + */ + function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { + var isPartial = bitmask & COMPARE_PARTIAL_FLAG, + objProps = getAllKeys(object), + objLength = objProps.length, + othProps = getAllKeys(other), + othLength = othProps.length; + + if (objLength != othLength && !isPartial) { + return false; + } + var index = objLength; + while (index--) { + var key = objProps[index]; + if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { + return false; + } + } + // Assume cyclic values are equal. + var stacked = stack.get(object); + if (stacked && stack.get(other)) { + return stacked == other; + } + var result = true; + stack.set(object, other); + stack.set(other, object); + + var skipCtor = isPartial; + while (++index < objLength) { + key = objProps[index]; + var objValue = object[key], + othValue = other[key]; + + if (customizer) { + var compared = isPartial + ? customizer(othValue, objValue, key, other, object, stack) + : customizer(objValue, othValue, key, object, other, stack); + } + // Recursively compare objects (susceptible to call stack limits). + if (!(compared === undefined + ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) + : compared + )) { + result = false; + break; + } + skipCtor || (skipCtor = key == 'constructor'); + } + if (result && !skipCtor) { + var objCtor = object.constructor, + othCtor = other.constructor; + + // Non `Object` object instances with different constructors are not equal. + if (objCtor != othCtor && + ('constructor' in object && 'constructor' in other) && + !(typeof objCtor == 'function' && objCtor instanceof objCtor && + typeof othCtor == 'function' && othCtor instanceof othCtor)) { + result = false; + } + } + stack['delete'](object); + stack['delete'](other); + return result; + } + + /** + * A specialized version of `baseRest` which flattens the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @returns {Function} Returns the new function. + */ + function flatRest(func) { + return setToString(overRest(func, undefined, flatten), func + ''); + } + + /** + * Creates an array of own enumerable property names and symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeys(object) { + return baseGetAllKeys(object, keys, getSymbols); + } + + /** + * Creates an array of own and inherited enumerable property names and + * symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names and symbols. + */ + function getAllKeysIn(object) { + return baseGetAllKeys(object, keysIn, getSymbolsIn); + } + + /** + * Gets metadata for `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {*} Returns the metadata for `func`. + */ + var getData = !metaMap ? noop : function (func) { + return metaMap.get(func); }; - } - - /** - * Replaces all `placeholder` elements in `array` with an internal placeholder - * and returns an array of their indexes. - * - * @private - * @param {Array} array The array to modify. - * @param {*} placeholder The placeholder to replace. - * @returns {Array} Returns the new array of placeholder indexes. - */ - function replaceHolders(array, placeholder) { - var index = -1, - length = array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value === placeholder || value === PLACEHOLDER) { - array[index] = PLACEHOLDER; - result[resIndex++] = index; - } - } - return result; - } - - /** - * Gets the value at `key`, unless `key` is "__proto__". - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the property to get. - * @returns {*} Returns the property value. - */ - function safeGet(object, key) { - return key == '__proto__' - ? undefined - : object[key]; - } - - /** - * Converts `set` to an array of its values. - * - * @private - * @param {Object} set The set to convert. - * @returns {Array} Returns the values. - */ - function setToArray(set) { - var index = -1, - result = Array(set.size); - - set.forEach(function(value) { - result[++index] = value; - }); - return result; - } - - /** - * A specialized version of `_.indexOf` which performs strict equality - * comparisons of values, i.e. `===`. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} fromIndex The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function strictIndexOf(array, value, fromIndex) { - var index = fromIndex - 1, - length = array.length; - - while (++index < length) { - if (array[index] === value) { - return index; - } - } - return -1; - } - - /** - * Gets the number of symbols in `string`. - * - * @private - * @param {string} string The string to inspect. - * @returns {number} Returns the string size. - */ - function stringSize(string) { - return hasUnicode(string) - ? unicodeSize(string) - : asciiSize(string); - } - - /** - * Converts `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function stringToArray(string) { - return hasUnicode(string) - ? unicodeToArray(string) - : asciiToArray(string); - } - - /** - * Used by `_.unescape` to convert HTML entities to characters. - * - * @private - * @param {string} chr The matched character to unescape. - * @returns {string} Returns the unescaped character. - */ - var unescapeHtmlChar = basePropertyOf(htmlUnescapes); - - /** - * Gets the size of a Unicode `string`. - * - * @private - * @param {string} string The string inspect. - * @returns {number} Returns the string size. - */ - function unicodeSize(string) { - var result = reUnicode.lastIndex = 0; - while (reUnicode.test(string)) { - ++result; - } - return result; - } - - /** - * Converts a Unicode `string` to an array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the converted array. - */ - function unicodeToArray(string) { - return string.match(reUnicode) || []; - } - - /*--------------------------------------------------------------------------*/ - - /** Used for built-in method references. */ - var arrayProto = Array.prototype, - funcProto = Function.prototype, - objectProto = Object.prototype; - - /** Used to detect overreaching core-js shims. */ - var coreJsData = root['__core-js_shared__']; - - /** Used to resolve the decompiled source of functions. */ - var funcToString = funcProto.toString; - - /** Used to check objects for own properties. */ - var hasOwnProperty = objectProto.hasOwnProperty; - - /** Used to generate unique IDs. */ - var idCounter = 0; - - /** Used to detect methods masquerading as native. */ - var maskSrcKey = (function() { - var uid = /[^.]+$/.exec(coreJsData && coreJsData.keys && coreJsData.keys.IE_PROTO || ''); - return uid ? ('Symbol(src)_1.' + uid) : ''; - }()); - - /** - * Used to resolve the - * [`toStringTag`](http://ecma-international.org/ecma-262/7.0/#sec-object.prototype.tostring) - * of values. - */ - var nativeObjectToString = objectProto.toString; - - /** Used to infer the `Object` constructor. */ - var objectCtorString = funcToString.call(Object); - - /** Used to restore the original `_` reference in `_.noConflict`. */ - var oldDash = root._; - - /** Used to detect if a method is native. */ - var reIsNative = RegExp('^' + - funcToString.call(hasOwnProperty).replace(reRegExpChar, '\\$&') - .replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, '$1.*?') + '$' - ); - - /** Built-in value references. */ - var Buffer = moduleExports ? root.Buffer : undefined, - Symbol = root.Symbol, - Uint8Array = root.Uint8Array, - allocUnsafe = Buffer ? Buffer.allocUnsafe : undefined, - getPrototype = overArg(Object.getPrototypeOf, Object), - objectCreate = Object.create, - propertyIsEnumerable = objectProto.propertyIsEnumerable, - splice = arrayProto.splice, - spreadableSymbol = Symbol ? Symbol.isConcatSpreadable : undefined, - symIterator = Symbol ? Symbol.iterator : undefined, - symToStringTag = Symbol ? Symbol.toStringTag : undefined; - - var defineProperty = (function() { - try { - var func = getNative(Object, 'defineProperty'); - func({}, '', {}); - return func; - } catch (e) {} - }()); - - /* Built-in method references for those with the same name as other `lodash` methods. */ - var nativeCeil = Math.ceil, - nativeFloor = Math.floor, - nativeGetSymbols = Object.getOwnPropertySymbols, - nativeIsBuffer = Buffer ? Buffer.isBuffer : undefined, - nativeIsFinite = root.isFinite, - nativeKeys = overArg(Object.keys, Object), - nativeMax = Math.max, - nativeMin = Math.min, - nativeNow = Date.now, - nativeRandom = Math.random, - nativeReverse = arrayProto.reverse; - - /* Built-in method references that are verified to be native. */ - var DataView = getNative(root, 'DataView'), - Map = getNative(root, 'Map'), - Promise = getNative(root, 'Promise'), - Set = getNative(root, 'Set'), - WeakMap = getNative(root, 'WeakMap'), - nativeCreate = getNative(Object, 'create'); - - /** Used to store function metadata. */ - var metaMap = WeakMap && new WeakMap; - - /** Used to lookup unminified function names. */ - var realNames = {}; - - /** Used to detect maps, sets, and weakmaps. */ - var dataViewCtorString = toSource(DataView), - mapCtorString = toSource(Map), - promiseCtorString = toSource(Promise), - setCtorString = toSource(Set), - weakMapCtorString = toSource(WeakMap); - - /** Used to convert symbols to primitives and strings. */ - var symbolProto = Symbol ? Symbol.prototype : undefined, - symbolValueOf = symbolProto ? symbolProto.valueOf : undefined, - symbolToString = symbolProto ? symbolProto.toString : undefined; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` object which wraps `value` to enable implicit method - * chain sequences. Methods that operate on and return arrays, collections, - * and functions can be chained together. Methods that retrieve a single value - * or may return a primitive value will automatically end the chain sequence - * and return the unwrapped value. Otherwise, the value must be unwrapped - * with `_#value`. - * - * Explicit chain sequences, which must be unwrapped with `_#value`, may be - * enabled using `_.chain`. - * - * The execution of chained methods is lazy, that is, it's deferred until - * `_#value` is implicitly or explicitly called. - * - * Lazy evaluation allows several methods to support shortcut fusion. - * Shortcut fusion is an optimization to merge iteratee calls; this avoids - * the creation of intermediate arrays and can greatly reduce the number of - * iteratee executions. Sections of a chain sequence qualify for shortcut - * fusion if the section is applied to an array and iteratees accept only - * one argument. The heuristic for whether a section qualifies for shortcut - * fusion is subject to change. - * - * Chaining is supported in custom builds as long as the `_#value` method is - * directly or indirectly included in the build. - * - * In addition to lodash methods, wrappers have `Array` and `String` methods. - * - * The wrapper `Array` methods are: - * `concat`, `join`, `pop`, `push`, `shift`, `sort`, `splice`, and `unshift` - * - * The wrapper `String` methods are: - * `replace` and `split` - * - * The wrapper methods that support shortcut fusion are: - * `at`, `compact`, `drop`, `dropRight`, `dropWhile`, `filter`, `find`, - * `findLast`, `head`, `initial`, `last`, `map`, `reject`, `reverse`, `slice`, - * `tail`, `take`, `takeRight`, `takeRightWhile`, `takeWhile`, and `toArray` - * - * The chainable wrapper methods are: - * `after`, `ary`, `assign`, `assignIn`, `assignInWith`, `assignWith`, `at`, - * `before`, `bind`, `bindAll`, `bindKey`, `castArray`, `chain`, `chunk`, - * `commit`, `compact`, `concat`, `conforms`, `constant`, `countBy`, `create`, - * `curry`, `debounce`, `defaults`, `defaultsDeep`, `defer`, `delay`, - * `difference`, `differenceBy`, `differenceWith`, `drop`, `dropRight`, - * `dropRightWhile`, `dropWhile`, `extend`, `extendWith`, `fill`, `filter`, - * `flatMap`, `flatMapDeep`, `flatMapDepth`, `flatten`, `flattenDeep`, - * `flattenDepth`, `flip`, `flow`, `flowRight`, `fromPairs`, `functions`, - * `functionsIn`, `groupBy`, `initial`, `intersection`, `intersectionBy`, - * `intersectionWith`, `invert`, `invertBy`, `invokeMap`, `iteratee`, `keyBy`, - * `keys`, `keysIn`, `map`, `mapKeys`, `mapValues`, `matches`, `matchesProperty`, - * `memoize`, `merge`, `mergeWith`, `method`, `methodOf`, `mixin`, `negate`, - * `nthArg`, `omit`, `omitBy`, `once`, `orderBy`, `over`, `overArgs`, - * `overEvery`, `overSome`, `partial`, `partialRight`, `partition`, `pick`, - * `pickBy`, `plant`, `property`, `propertyOf`, `pull`, `pullAll`, `pullAllBy`, - * `pullAllWith`, `pullAt`, `push`, `range`, `rangeRight`, `rearg`, `reject`, - * `remove`, `rest`, `reverse`, `sampleSize`, `set`, `setWith`, `shuffle`, - * `slice`, `sort`, `sortBy`, `splice`, `spread`, `tail`, `take`, `takeRight`, - * `takeRightWhile`, `takeWhile`, `tap`, `throttle`, `thru`, `toArray`, - * `toPairs`, `toPairsIn`, `toPath`, `toPlainObject`, `transform`, `unary`, - * `union`, `unionBy`, `unionWith`, `uniq`, `uniqBy`, `uniqWith`, `unset`, - * `unshift`, `unzip`, `unzipWith`, `update`, `updateWith`, `values`, - * `valuesIn`, `without`, `wrap`, `xor`, `xorBy`, `xorWith`, `zip`, - * `zipObject`, `zipObjectDeep`, and `zipWith` - * - * The wrapper methods that are **not** chainable by default are: - * `add`, `attempt`, `camelCase`, `capitalize`, `ceil`, `clamp`, `clone`, - * `cloneDeep`, `cloneDeepWith`, `cloneWith`, `conformsTo`, `deburr`, - * `defaultTo`, `divide`, `each`, `eachRight`, `endsWith`, `eq`, `escape`, - * `escapeRegExp`, `every`, `find`, `findIndex`, `findKey`, `findLast`, - * `findLastIndex`, `findLastKey`, `first`, `floor`, `forEach`, `forEachRight`, - * `forIn`, `forInRight`, `forOwn`, `forOwnRight`, `get`, `gt`, `gte`, `has`, - * `hasIn`, `head`, `identity`, `includes`, `indexOf`, `inRange`, `invoke`, - * `isArguments`, `isArray`, `isArrayBuffer`, `isArrayLike`, `isArrayLikeObject`, - * `isBoolean`, `isBuffer`, `isDate`, `isElement`, `isEmpty`, `isEqual`, - * `isEqualWith`, `isError`, `isFinite`, `isFunction`, `isInteger`, `isLength`, - * `isMap`, `isMatch`, `isMatchWith`, `isNaN`, `isNative`, `isNil`, `isNull`, - * `isNumber`, `isObject`, `isObjectLike`, `isPlainObject`, `isRegExp`, - * `isSafeInteger`, `isSet`, `isString`, `isUndefined`, `isTypedArray`, - * `isWeakMap`, `isWeakSet`, `join`, `kebabCase`, `last`, `lastIndexOf`, - * `lowerCase`, `lowerFirst`, `lt`, `lte`, `max`, `maxBy`, `mean`, `meanBy`, - * `min`, `minBy`, `multiply`, `noConflict`, `noop`, `now`, `nth`, `pad`, - * `padEnd`, `padStart`, `parseInt`, `pop`, `random`, `reduce`, `reduceRight`, - * `repeat`, `result`, `round`, `runInContext`, `sample`, `shift`, `size`, - * `snakeCase`, `some`, `sortedIndex`, `sortedIndexBy`, `sortedLastIndex`, - * `sortedLastIndexBy`, `startCase`, `startsWith`, `stubArray`, `stubFalse`, - * `stubObject`, `stubString`, `stubTrue`, `subtract`, `sum`, `sumBy`, - * `template`, `times`, `toFinite`, `toInteger`, `toJSON`, `toLength`, - * `toLower`, `toNumber`, `toSafeInteger`, `toString`, `toUpper`, `trim`, - * `trimEnd`, `trimStart`, `truncate`, `unescape`, `uniqueId`, `upperCase`, - * `upperFirst`, `value`, and `words` - * - * @name _ - * @constructor - * @category Seq - * @param {*} value The value to wrap in a `lodash` instance. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2, 3]); - * - * // Returns an unwrapped value. - * wrapped.reduce(_.add); - * // => 6 - * - * // Returns a wrapped value. - * var squares = wrapped.map(square); - * - * _.isArray(squares); - * // => false - * - * _.isArray(squares.value()); - * // => true - */ - function lodash(value) { - if (isObjectLike(value) && !isArray(value) && !(value instanceof LazyWrapper)) { - if (value instanceof LodashWrapper) { - return value; - } - if (hasOwnProperty.call(value, '__wrapped__')) { - return wrapperClone(value); - } - } - return new LodashWrapper(value); - } - - /** - * The base implementation of `_.create` without support for assigning - * properties to the created object. - * - * @private - * @param {Object} proto The object to inherit from. - * @returns {Object} Returns the new object. - */ - var baseCreate = (function() { - function object() {} - return function(proto) { - if (!isObject(proto)) { - return {}; - } - if (objectCreate) { - return objectCreate(proto); - } - object.prototype = proto; - var result = new object; - object.prototype = undefined; - return result; + + /** + * Gets the name of `func`. + * + * @private + * @param {Function} func The function to query. + * @returns {string} Returns the function name. + */ + function getFuncName(func) { + var result = (func.name + ''), + array = realNames[result], + length = hasOwnProperty.call(realNames, result) ? array.length : 0; + + while (length--) { + var data = array[length], + otherFunc = data.func; + if (otherFunc == null || otherFunc == func) { + return data.name; + } + } + return result; + } + + /** + * Gets the argument placeholder value for `func`. + * + * @private + * @param {Function} func The function to inspect. + * @returns {*} Returns the placeholder value. + */ + function getHolder(func) { + var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; + return object.placeholder; + } + + /** + * Gets the data for `map`. + * + * @private + * @param {Object} map The map to query. + * @param {string} key The reference key. + * @returns {*} Returns the map data. + */ + function getMapData(map, key) { + var data = map.__data__; + return isKeyable(key) + ? data[typeof key == 'string' ? 'string' : 'hash'] + : data.map; + } + + /** + * Gets the property names, values, and compare flags of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the match data of `object`. + */ + function getMatchData(object) { + var result = keys(object), + length = result.length; + + while (length--) { + var key = result[length], + value = object[key]; + + result[length] = [key, value, isStrictComparable(value)]; + } + return result; + } + + /** + * Gets the native function at `key` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {string} key The key of the method to get. + * @returns {*} Returns the function if it's native, else `undefined`. + */ + function getNative(object, key) { + var value = getValue(object, key); + return baseIsNative(value) ? value : undefined; + } + + /** + * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the raw `toStringTag`. + */ + function getRawTag(value) { + var isOwn = hasOwnProperty.call(value, symToStringTag), + tag = value[symToStringTag]; + + try { + value[symToStringTag] = undefined; + var unmasked = true; + } catch (e) { + } + + var result = nativeObjectToString.call(value); + if (unmasked) { + if (isOwn) { + value[symToStringTag] = tag; + } else { + delete value[symToStringTag]; + } + } + return result; + } + + /** + * Creates an array of the own enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbols = !nativeGetSymbols ? stubArray : function (object) { + if (object == null) { + return []; + } + object = Object(object); + return arrayFilter(nativeGetSymbols(object), function (symbol) { + return propertyIsEnumerable.call(object, symbol); + }); }; - }()); - - /** - * The function whose prototype chain sequence wrappers inherit from. - * - * @private - */ - function baseLodash() { - // No operation performed. - } - - /** - * The base constructor for creating `lodash` wrapper objects. - * - * @private - * @param {*} value The value to wrap. - * @param {boolean} [chainAll] Enable explicit method chain sequences. - */ - function LodashWrapper(value, chainAll) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__chain__ = !!chainAll; - this.__index__ = 0; - this.__values__ = undefined; - } - - // Ensure wrappers are instances of `baseLodash`. - lodash.prototype = baseLodash.prototype; - lodash.prototype.constructor = lodash; - - LodashWrapper.prototype = baseCreate(baseLodash.prototype); - LodashWrapper.prototype.constructor = LodashWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a lazy wrapper object which wraps `value` to enable lazy evaluation. - * - * @private - * @constructor - * @param {*} value The value to wrap. - */ - function LazyWrapper(value) { - this.__wrapped__ = value; - this.__actions__ = []; - this.__dir__ = 1; - this.__filtered__ = false; - this.__iteratees__ = []; - this.__takeCount__ = MAX_ARRAY_LENGTH; - this.__views__ = []; - } - - /** - * Creates a clone of the lazy wrapper object. - * - * @private - * @name clone - * @memberOf LazyWrapper - * @returns {Object} Returns the cloned `LazyWrapper` object. - */ - function lazyClone() { - var result = new LazyWrapper(this.__wrapped__); - result.__actions__ = copyArray(this.__actions__); - result.__dir__ = this.__dir__; - result.__filtered__ = this.__filtered__; - result.__iteratees__ = copyArray(this.__iteratees__); - result.__takeCount__ = this.__takeCount__; - result.__views__ = copyArray(this.__views__); - return result; - } - - /** - * Reverses the direction of lazy iteration. - * - * @private - * @name reverse - * @memberOf LazyWrapper - * @returns {Object} Returns the new reversed `LazyWrapper` object. - */ - function lazyReverse() { - if (this.__filtered__) { - var result = new LazyWrapper(this); - result.__dir__ = -1; - result.__filtered__ = true; - } else { - result = this.clone(); - result.__dir__ *= -1; - } - return result; - } - - /** - * Extracts the unwrapped value from its lazy wrapper. - * - * @private - * @name value - * @memberOf LazyWrapper - * @returns {*} Returns the unwrapped value. - */ - function lazyValue() { - var array = this.__wrapped__.value(), - dir = this.__dir__, - isArr = isArray(array), - isRight = dir < 0, - arrLength = isArr ? array.length : 0, - view = getView(0, arrLength, this.__views__), - start = view.start, - end = view.end, - length = end - start, - index = isRight ? end : (start - 1), - iteratees = this.__iteratees__, - iterLength = iteratees.length, - resIndex = 0, - takeCount = nativeMin(length, this.__takeCount__); - - if (!isArr || (!isRight && arrLength == length && takeCount == length)) { - return baseWrapperValue(array, this.__actions__); - } - var result = []; - - outer: - while (length-- && resIndex < takeCount) { - index += dir; - - var iterIndex = -1, - value = array[index]; - - while (++iterIndex < iterLength) { - var data = iteratees[iterIndex], - iteratee = data.iteratee, - type = data.type, - computed = iteratee(value); - - if (type == LAZY_MAP_FLAG) { - value = computed; - } else if (!computed) { - if (type == LAZY_FILTER_FLAG) { - continue outer; - } else { - break outer; - } - } - } - result[resIndex++] = value; - } - return result; - } - - // Ensure `LazyWrapper` is an instance of `baseLodash`. - LazyWrapper.prototype = baseCreate(baseLodash.prototype); - LazyWrapper.prototype.constructor = LazyWrapper; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a hash object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Hash(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the hash. - * - * @private - * @name clear - * @memberOf Hash - */ - function hashClear() { - this.__data__ = nativeCreate ? nativeCreate(null) : {}; - this.size = 0; - } - - /** - * Removes `key` and its value from the hash. - * - * @private - * @name delete - * @memberOf Hash - * @param {Object} hash The hash to modify. - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function hashDelete(key) { - var result = this.has(key) && delete this.__data__[key]; - this.size -= result ? 1 : 0; - return result; - } - - /** - * Gets the hash value for `key`. - * - * @private - * @name get - * @memberOf Hash - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function hashGet(key) { - var data = this.__data__; - if (nativeCreate) { - var result = data[key]; - return result === HASH_UNDEFINED ? undefined : result; - } - return hasOwnProperty.call(data, key) ? data[key] : undefined; - } - - /** - * Checks if a hash value for `key` exists. - * - * @private - * @name has - * @memberOf Hash - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function hashHas(key) { - var data = this.__data__; - return nativeCreate ? (data[key] !== undefined) : hasOwnProperty.call(data, key); - } - - /** - * Sets the hash `key` to `value`. - * - * @private - * @name set - * @memberOf Hash - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the hash instance. - */ - function hashSet(key, value) { - var data = this.__data__; - this.size += this.has(key) ? 0 : 1; - data[key] = (nativeCreate && value === undefined) ? HASH_UNDEFINED : value; - return this; - } - - // Add methods to `Hash`. - Hash.prototype.clear = hashClear; - Hash.prototype['delete'] = hashDelete; - Hash.prototype.get = hashGet; - Hash.prototype.has = hashHas; - Hash.prototype.set = hashSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an list cache object. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function ListCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the list cache. - * - * @private - * @name clear - * @memberOf ListCache - */ - function listCacheClear() { - this.__data__ = []; - this.size = 0; - } - - /** - * Removes `key` and its value from the list cache. - * - * @private - * @name delete - * @memberOf ListCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function listCacheDelete(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - return false; - } - var lastIndex = data.length - 1; - if (index == lastIndex) { - data.pop(); - } else { - splice.call(data, index, 1); - } - --this.size; - return true; - } - - /** - * Gets the list cache value for `key`. - * - * @private - * @name get - * @memberOf ListCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function listCacheGet(key) { - var data = this.__data__, - index = assocIndexOf(data, key); - - return index < 0 ? undefined : data[index][1]; - } - - /** - * Checks if a list cache value for `key` exists. - * - * @private - * @name has - * @memberOf ListCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function listCacheHas(key) { - return assocIndexOf(this.__data__, key) > -1; - } - - /** - * Sets the list cache `key` to `value`. - * - * @private - * @name set - * @memberOf ListCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the list cache instance. - */ - function listCacheSet(key, value) { - var data = this.__data__, - index = assocIndexOf(data, key); - - if (index < 0) { - ++this.size; - data.push([key, value]); - } else { - data[index][1] = value; - } - return this; - } - - // Add methods to `ListCache`. - ListCache.prototype.clear = listCacheClear; - ListCache.prototype['delete'] = listCacheDelete; - ListCache.prototype.get = listCacheGet; - ListCache.prototype.has = listCacheHas; - ListCache.prototype.set = listCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a map cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function MapCache(entries) { - var index = -1, - length = entries == null ? 0 : entries.length; - - this.clear(); - while (++index < length) { - var entry = entries[index]; - this.set(entry[0], entry[1]); - } - } - - /** - * Removes all key-value entries from the map. - * - * @private - * @name clear - * @memberOf MapCache - */ - function mapCacheClear() { - this.size = 0; - this.__data__ = { - 'hash': new Hash, - 'map': new (Map || ListCache), - 'string': new Hash + + /** + * Creates an array of the own and inherited enumerable symbols of `object`. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of symbols. + */ + var getSymbolsIn = !nativeGetSymbols ? stubArray : function (object) { + var result = []; + while (object) { + arrayPush(result, getSymbols(object)); + object = getPrototype(object); + } + return result; }; - } - - /** - * Removes `key` and its value from the map. - * - * @private - * @name delete - * @memberOf MapCache - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function mapCacheDelete(key) { - var result = getMapData(this, key)['delete'](key); - this.size -= result ? 1 : 0; - return result; - } - - /** - * Gets the map value for `key`. - * - * @private - * @name get - * @memberOf MapCache - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function mapCacheGet(key) { - return getMapData(this, key).get(key); - } - - /** - * Checks if a map value for `key` exists. - * - * @private - * @name has - * @memberOf MapCache - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function mapCacheHas(key) { - return getMapData(this, key).has(key); - } - - /** - * Sets the map `key` to `value`. - * - * @private - * @name set - * @memberOf MapCache - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the map cache instance. - */ - function mapCacheSet(key, value) { - var data = getMapData(this, key), - size = data.size; - - data.set(key, value); - this.size += data.size == size ? 0 : 1; - return this; - } - - // Add methods to `MapCache`. - MapCache.prototype.clear = mapCacheClear; - MapCache.prototype['delete'] = mapCacheDelete; - MapCache.prototype.get = mapCacheGet; - MapCache.prototype.has = mapCacheHas; - MapCache.prototype.set = mapCacheSet; - - /*------------------------------------------------------------------------*/ - - /** - * - * Creates an array cache object to store unique values. - * - * @private - * @constructor - * @param {Array} [values] The values to cache. - */ - function SetCache(values) { - var index = -1, - length = values == null ? 0 : values.length; - - this.__data__ = new MapCache; - while (++index < length) { - this.add(values[index]); - } - } - - /** - * Adds `value` to the array cache. - * - * @private - * @name add - * @memberOf SetCache - * @alias push - * @param {*} value The value to cache. - * @returns {Object} Returns the cache instance. - */ - function setCacheAdd(value) { - this.__data__.set(value, HASH_UNDEFINED); - return this; - } - - /** - * Checks if `value` is in the array cache. - * - * @private - * @name has - * @memberOf SetCache - * @param {*} value The value to search for. - * @returns {number} Returns `true` if `value` is found, else `false`. - */ - function setCacheHas(value) { - return this.__data__.has(value); - } - - // Add methods to `SetCache`. - SetCache.prototype.add = SetCache.prototype.push = setCacheAdd; - SetCache.prototype.has = setCacheHas; - - /*------------------------------------------------------------------------*/ - - /** - * Creates a stack cache object to store key-value pairs. - * - * @private - * @constructor - * @param {Array} [entries] The key-value pairs to cache. - */ - function Stack(entries) { - var data = this.__data__ = new ListCache(entries); - this.size = data.size; - } - - /** - * Removes all key-value entries from the stack. - * - * @private - * @name clear - * @memberOf Stack - */ - function stackClear() { - this.__data__ = new ListCache; - this.size = 0; - } - - /** - * Removes `key` and its value from the stack. - * - * @private - * @name delete - * @memberOf Stack - * @param {string} key The key of the value to remove. - * @returns {boolean} Returns `true` if the entry was removed, else `false`. - */ - function stackDelete(key) { - var data = this.__data__, - result = data['delete'](key); - - this.size = data.size; - return result; - } - - /** - * Gets the stack value for `key`. - * - * @private - * @name get - * @memberOf Stack - * @param {string} key The key of the value to get. - * @returns {*} Returns the entry value. - */ - function stackGet(key) { - return this.__data__.get(key); - } - - /** - * Checks if a stack value for `key` exists. - * - * @private - * @name has - * @memberOf Stack - * @param {string} key The key of the entry to check. - * @returns {boolean} Returns `true` if an entry for `key` exists, else `false`. - */ - function stackHas(key) { - return this.__data__.has(key); - } - - /** - * Sets the stack `key` to `value`. - * - * @private - * @name set - * @memberOf Stack - * @param {string} key The key of the value to set. - * @param {*} value The value to set. - * @returns {Object} Returns the stack cache instance. - */ - function stackSet(key, value) { - var data = this.__data__; - if (data instanceof ListCache) { - var pairs = data.__data__; - if (!Map || (pairs.length < LARGE_ARRAY_SIZE - 1)) { - pairs.push([key, value]); - this.size = ++data.size; - return this; - } - data = this.__data__ = new MapCache(pairs); - } - data.set(key, value); - this.size = data.size; - return this; - } - - // Add methods to `Stack`. - Stack.prototype.clear = stackClear; - Stack.prototype['delete'] = stackDelete; - Stack.prototype.get = stackGet; - Stack.prototype.has = stackHas; - Stack.prototype.set = stackSet; - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array of the enumerable property names of the array-like `value`. - * - * @private - * @param {*} value The value to query. - * @param {boolean} inherited Specify returning inherited property names. - * @returns {Array} Returns the array of property names. - */ - function arrayLikeKeys(value, inherited) { - var isArr = isArray(value), - isArg = !isArr && isArguments(value), - isBuff = !isArr && !isArg && isBuffer(value), - isType = !isArr && !isArg && !isBuff && isTypedArray(value), - skipIndexes = isArr || isArg || isBuff || isType, - result = skipIndexes ? baseTimes(value.length, String) : [], - length = result.length; - - for (var key in value) { - if ((inherited || hasOwnProperty.call(value, key)) && - !(skipIndexes && ( - // Safari 9 has enumerable `arguments.length` in strict mode. - key == 'length' || - // Node.js 0.10 has enumerable non-index properties on buffers. - (isBuff && (key == 'offset' || key == 'parent')) || - // PhantomJS 2 has enumerable non-index properties on typed arrays. - (isType && (key == 'buffer' || key == 'byteLength' || key == 'byteOffset')) || - // Skip index properties. - isIndex(key, length) - ))) { - result.push(key); - } - } - return result; - } - - /** - * This function is like `assignValue` except that it doesn't assign - * `undefined` values. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignMergeValue(object, key, value) { - if ((value !== undefined && !eq(object[key], value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } - - /** - * Assigns `value` to `key` of `object` if the existing value is not equivalent - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function assignValue(object, key, value) { - var objValue = object[key]; - if (!(hasOwnProperty.call(object, key) && eq(objValue, value)) || - (value === undefined && !(key in object))) { - baseAssignValue(object, key, value); - } - } - - /** - * Gets the index at which the `key` is found in `array` of key-value pairs. - * - * @private - * @param {Array} array The array to inspect. - * @param {*} key The key to search for. - * @returns {number} Returns the index of the matched value, else `-1`. - */ - function assocIndexOf(array, key) { - var length = array.length; - while (length--) { - if (eq(array[length][0], key)) { - return length; - } - } - return -1; - } - - /** - * Aggregates elements of `collection` on `accumulator` with keys transformed - * by `iteratee` and values set by `setter`. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform keys. - * @param {Object} accumulator The initial aggregated object. - * @returns {Function} Returns `accumulator`. - */ - function baseAggregator(collection, setter, iteratee, accumulator) { - baseEach(collection, function(value, key, collection) { - setter(accumulator, value, iteratee(value), collection); - }); - return accumulator; - } - - /** - * The base implementation of `_.assign` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssign(object, source) { - return object && copyObject(source, keys(source), object); - } - - /** - * The base implementation of `_.assignIn` without support for multiple sources - * or `customizer` functions. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @returns {Object} Returns `object`. - */ - function baseAssignIn(object, source) { - return object && copyObject(source, keysIn(source), object); - } - - /** - * The base implementation of `assignValue` and `assignMergeValue` without - * value checks. - * - * @private - * @param {Object} object The object to modify. - * @param {string} key The key of the property to assign. - * @param {*} value The value to assign. - */ - function baseAssignValue(object, key, value) { - if (key == '__proto__' && defineProperty) { - defineProperty(object, key, { - 'configurable': true, - 'enumerable': true, - 'value': value, - 'writable': true - }); - } else { - object[key] = value; - } - } - - /** - * The base implementation of `_.at` without support for individual paths. - * - * @private - * @param {Object} object The object to iterate over. - * @param {string[]} paths The property paths to pick. - * @returns {Array} Returns the picked elements. - */ - function baseAt(object, paths) { - var index = -1, - length = paths.length, - result = Array(length), - skip = object == null; - - while (++index < length) { - result[index] = skip ? undefined : get(object, paths[index]); - } - return result; - } - - /** - * The base implementation of `_.clamp` which doesn't coerce arguments. - * - * @private - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - */ - function baseClamp(number, lower, upper) { - if (number === number) { - if (upper !== undefined) { - number = number <= upper ? number : upper; - } - if (lower !== undefined) { - number = number >= lower ? number : lower; - } - } - return number; - } - - /** - * The base implementation of `_.clone` and `_.cloneDeep` which tracks - * traversed objects. - * - * @private - * @param {*} value The value to clone. - * @param {boolean} bitmask The bitmask flags. - * 1 - Deep clone - * 2 - Flatten inherited properties - * 4 - Clone symbols - * @param {Function} [customizer] The function to customize cloning. - * @param {string} [key] The key of `value`. - * @param {Object} [object] The parent object of `value`. - * @param {Object} [stack] Tracks traversed objects and their clone counterparts. - * @returns {*} Returns the cloned value. - */ - function baseClone(value, bitmask, customizer, key, object, stack) { - var result, - isDeep = bitmask & CLONE_DEEP_FLAG, - isFlat = bitmask & CLONE_FLAT_FLAG, - isFull = bitmask & CLONE_SYMBOLS_FLAG; - - if (customizer) { - result = object ? customizer(value, key, object, stack) : customizer(value); - } - if (result !== undefined) { - return result; - } - if (!isObject(value)) { - return value; - } - var isArr = isArray(value); - if (isArr) { - result = initCloneArray(value); - if (!isDeep) { - return copyArray(value, result); - } - } else { - var tag = getTag(value), - isFunc = tag == funcTag || tag == genTag; - - if (isBuffer(value)) { - return cloneBuffer(value, isDeep); - } - if (tag == objectTag || tag == argsTag || (isFunc && !object)) { - result = (isFlat || isFunc) ? {} : initCloneObject(value); - if (!isDeep) { - return isFlat - ? copySymbolsIn(value, baseAssignIn(result, value)) - : copySymbols(value, baseAssign(result, value)); - } - } else { - if (!cloneableTags[tag]) { - return object ? value : {}; - } - result = initCloneByTag(value, tag, isDeep); - } - } - // Check for circular references and return its corresponding clone. - stack || (stack = new Stack); - var stacked = stack.get(value); - if (stacked) { - return stacked; - } - stack.set(value, result); - - if (isSet(value)) { - value.forEach(function(subValue) { - result.add(baseClone(subValue, bitmask, customizer, subValue, value, stack)); - }); - - return result; - } - - if (isMap(value)) { - value.forEach(function(subValue, key) { - result.set(key, baseClone(subValue, bitmask, customizer, key, value, stack)); - }); - - return result; - } - - var keysFunc = isFull - ? (isFlat ? getAllKeysIn : getAllKeys) - : (isFlat ? keysIn : keys); - - var props = isArr ? undefined : keysFunc(value); - arrayEach(props || value, function(subValue, key) { - if (props) { - key = subValue; - subValue = value[key]; - } - // Recursively populate clone (susceptible to call stack limits). - assignValue(result, key, baseClone(subValue, bitmask, customizer, key, value, stack)); + + /** + * Gets the `toStringTag` of `value`. + * + * @private + * @param {*} value The value to query. + * @returns {string} Returns the `toStringTag`. + */ + var getTag = baseGetTag; + + // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. + if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || + (Map && getTag(new Map) != mapTag) || + (Promise && getTag(Promise.resolve()) != promiseTag) || + (Set && getTag(new Set) != setTag) || + (WeakMap && getTag(new WeakMap) != weakMapTag)) { + getTag = function (value) { + var result = baseGetTag(value), + Ctor = result == objectTag ? value.constructor : undefined, + ctorString = Ctor ? toSource(Ctor) : ''; + + if (ctorString) { + switch (ctorString) { + case dataViewCtorString: + return dataViewTag; + case mapCtorString: + return mapTag; + case promiseCtorString: + return promiseTag; + case setCtorString: + return setTag; + case weakMapCtorString: + return weakMapTag; + } + } + return result; + }; + } + + /** + * Gets the view, applying any `transforms` to the `start` and `end` positions. + * + * @private + * @param {number} start The start of the view. + * @param {number} end The end of the view. + * @param {Array} transforms The transformations to apply to the view. + * @returns {Object} Returns an object containing the `start` and `end` + * positions of the view. + */ + function getView(start, end, transforms) { + var index = -1, + length = transforms.length; + + while (++index < length) { + var data = transforms[index], + size = data.size; + + switch (data.type) { + case 'drop': + start += size; + break; + case 'dropRight': + end -= size; + break; + case 'take': + end = nativeMin(end, start + size); + break; + case 'takeRight': + start = nativeMax(start, end - size); + break; + } + } + return { 'start': start, 'end': end }; + } + + /** + * Extracts wrapper details from the `source` body comment. + * + * @private + * @param {string} source The source to inspect. + * @returns {Array} Returns the wrapper details. + */ + function getWrapDetails(source) { + var match = source.match(reWrapDetails); + return match ? match[1].split(reSplitDetails) : []; + } + + /** + * Checks if `path` exists on `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @param {Function} hasFunc The function to check properties. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + */ + function hasPath(object, path, hasFunc) { + path = castPath(path, object); + + var index = -1, + length = path.length, + result = false; + + while (++index < length) { + var key = toKey(path[index]); + if (!(result = object != null && hasFunc(object, key))) { + break; + } + object = object[key]; + } + if (result || ++index != length) { + return result; + } + length = object == null ? 0 : object.length; + return !!length && isLength(length) && isIndex(key, length) && + (isArray(object) || isArguments(object)); + } + + /** + * Initializes an array clone. + * + * @private + * @param {Array} array The array to clone. + * @returns {Array} Returns the initialized clone. + */ + function initCloneArray(array) { + var length = array.length, + result = new array.constructor(length); + + // Add properties assigned by `RegExp#exec`. + if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { + result.index = array.index; + result.input = array.input; + } + return result; + } + + /** + * Initializes an object clone. + * + * @private + * @param {Object} object The object to clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneObject(object) { + return (typeof object.constructor == 'function' && !isPrototype(object)) + ? baseCreate(getPrototype(object)) + : {}; + } + + /** + * Initializes an object clone based on its `toStringTag`. + * + * **Note:** This function only supports cloning values with tags of + * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. + * + * @private + * @param {Object} object The object to clone. + * @param {string} tag The `toStringTag` of the object to clone. + * @param {boolean} [isDeep] Specify a deep clone. + * @returns {Object} Returns the initialized clone. + */ + function initCloneByTag(object, tag, isDeep) { + var Ctor = object.constructor; + switch (tag) { + case arrayBufferTag: + return cloneArrayBuffer(object); + + case boolTag: + case dateTag: + return new Ctor(+object); + + case dataViewTag: + return cloneDataView(object, isDeep); + + case float32Tag: + case float64Tag: + case int8Tag: + case int16Tag: + case int32Tag: + case uint8Tag: + case uint8ClampedTag: + case uint16Tag: + case uint32Tag: + return cloneTypedArray(object, isDeep); + + case mapTag: + return new Ctor; + + case numberTag: + case stringTag: + return new Ctor(object); + + case regexpTag: + return cloneRegExp(object); + + case setTag: + return new Ctor; + + case symbolTag: + return cloneSymbol(object); + } + } + + /** + * Inserts wrapper `details` in a comment at the top of the `source` body. + * + * @private + * @param {string} source The source to modify. + * @returns {Array} details The details to insert. + * @returns {string} Returns the modified source. + */ + function insertWrapDetails(source, details) { + var length = details.length; + if (!length) { + return source; + } + var lastIndex = length - 1; + details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; + details = details.join(length > 2 ? ', ' : ' '); + return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); + } + + /** + * Checks if `value` is a flattenable `arguments` object or array. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. + */ + function isFlattenable(value) { + return isArray(value) || isArguments(value) || + !!(spreadableSymbol && value && value[spreadableSymbol]); + } + + /** + * Checks if `value` is a valid array-like index. + * + * @private + * @param {*} value The value to check. + * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. + * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. + */ + function isIndex(value, length) { + var type = typeof value; + length = length == null ? MAX_SAFE_INTEGER : length; + + return !!length && + (type == 'number' || + (type != 'symbol' && reIsUint.test(value))) && + (value > -1 && value % 1 == 0 && value < length); + } + + /** + * Checks if the given arguments are from an iteratee call. + * + * @private + * @param {*} value The potential iteratee value argument. + * @param {*} index The potential iteratee index or key argument. + * @param {*} object The potential iteratee object argument. + * @returns {boolean} Returns `true` if the arguments are from an iteratee call, + * else `false`. + */ + function isIterateeCall(value, index, object) { + if (!isObject(object)) { + return false; + } + var type = typeof index; + if (type == 'number' + ? (isArrayLike(object) && isIndex(index, object.length)) + : (type == 'string' && index in object) + ) { + return eq(object[index], value); + } + return false; + } + + /** + * Checks if `value` is a property name and not a property path. + * + * @private + * @param {*} value The value to check. + * @param {Object} [object] The object to query keys on. + * @returns {boolean} Returns `true` if `value` is a property name, else `false`. + */ + function isKey(value, object) { + if (isArray(value)) { + return false; + } + var type = typeof value; + if (type == 'number' || type == 'symbol' || type == 'boolean' || + value == null || isSymbol(value)) { + return true; + } + return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || + (object != null && value in Object(object)); + } + + /** + * Checks if `value` is suitable for use as unique object key. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is suitable, else `false`. + */ + function isKeyable(value) { + var type = typeof value; + return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') + ? (value !== '__proto__') + : (value === null); + } + + /** + * Checks if `func` has a lazy counterpart. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` has a lazy counterpart, + * else `false`. + */ + function isLaziable(func) { + var funcName = getFuncName(func), + other = lodash[funcName]; + + if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { + return false; + } + if (func === other) { + return true; + } + var data = getData(other); + return !!data && func === data[0]; + } + + /** + * Checks if `func` has its source masked. + * + * @private + * @param {Function} func The function to check. + * @returns {boolean} Returns `true` if `func` is masked, else `false`. + */ + function isMasked(func) { + return !!maskSrcKey && (maskSrcKey in func); + } + + /** + * Checks if `value` is likely a prototype object. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. + */ + function isPrototype(value) { + var Ctor = value && value.constructor, + proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; + + return value === proto; + } + + /** + * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. + * + * @private + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` if suitable for strict + * equality comparisons, else `false`. + */ + function isStrictComparable(value) { + return value === value && !isObject(value); + } + + /** + * A specialized version of `matchesProperty` for source values suitable + * for strict equality comparisons, i.e. `===`. + * + * @private + * @param {string} key The key of the property to get. + * @param {*} srcValue The value to match. + * @returns {Function} Returns the new spec function. + */ + function matchesStrictComparable(key, srcValue) { + return function (object) { + if (object == null) { + return false; + } + return object[key] === srcValue && + (srcValue !== undefined || (key in Object(object))); + }; + } + + /** + * A specialized version of `_.memoize` which clears the memoized function's + * cache when it exceeds `MAX_MEMOIZE_SIZE`. + * + * @private + * @param {Function} func The function to have its output memoized. + * @returns {Function} Returns the new memoized function. + */ + function memoizeCapped(func) { + var result = memoize(func, function (key) { + if (cache.size === MAX_MEMOIZE_SIZE) { + cache.clear(); + } + return key; + }); + + var cache = result.cache; + return result; + } + + /** + * Merges the function metadata of `source` into `data`. + * + * Merging metadata reduces the number of wrappers used to invoke a function. + * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` + * may be applied regardless of execution order. Methods like `_.ary` and + * `_.rearg` modify function arguments, making the order in which they are + * executed important, preventing the merging of metadata. However, we make + * an exception for a safe combined case where curried functions have `_.ary` + * and or `_.rearg` applied. + * + * @private + * @param {Array} data The destination metadata. + * @param {Array} source The source metadata. + * @returns {Array} Returns `data`. + */ + function mergeData(data, source) { + var bitmask = data[1], + srcBitmask = source[1], + newBitmask = bitmask | srcBitmask, + isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); + + var isCombo = + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || + ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || + ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); + + // Exit early if metadata can't be merged. + if (!(isCommon || isCombo)) { + return data; + } + // Use source `thisArg` if available. + if (srcBitmask & WRAP_BIND_FLAG) { + data[2] = source[2]; + // Set when currying a bound function. + newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; + } + // Compose partial arguments. + var value = source[3]; + if (value) { + var partials = data[3]; + data[3] = partials ? composeArgs(partials, value, source[4]) : value; + data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; + } + // Compose partial right arguments. + value = source[5]; + if (value) { + partials = data[5]; + data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; + data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; + } + // Use source `argPos` if available. + value = source[7]; + if (value) { + data[7] = value; + } + // Use source `ary` if it's smaller. + if (srcBitmask & WRAP_ARY_FLAG) { + data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); + } + // Use source `arity` if one is not provided. + if (data[9] == null) { + data[9] = source[9]; + } + // Use source `func` and merge bitmasks. + data[0] = source[0]; + data[1] = newBitmask; + + return data; + } + + /** + * This function is like + * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * except that it includes inherited enumerable properties. + * + * @private + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + */ + function nativeKeysIn(object) { + var result = []; + if (object != null) { + for (var key in Object(object)) { + result.push(key); + } + } + return result; + } + + /** + * Converts `value` to a string using `Object.prototype.toString`. + * + * @private + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + */ + function objectToString(value) { + return nativeObjectToString.call(value); + } + + /** + * A specialized version of `baseRest` which transforms the rest array. + * + * @private + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @param {Function} transform The rest array transform. + * @returns {Function} Returns the new function. + */ + function overRest(func, start, transform) { + start = nativeMax(start === undefined ? (func.length - 1) : start, 0); + return function () { + var args = arguments, + index = -1, + length = nativeMax(args.length - start, 0), + array = Array(length); + + while (++index < length) { + array[index] = args[start + index]; + } + index = -1; + var otherArgs = Array(start + 1); + while (++index < start) { + otherArgs[index] = args[index]; + } + otherArgs[start] = transform(array); + return apply(func, this, otherArgs); + }; + } + + /** + * Gets the parent value at `path` of `object`. + * + * @private + * @param {Object} object The object to query. + * @param {Array} path The path to get the parent value of. + * @returns {*} Returns the parent value. + */ + function parent(object, path) { + return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); + } + + /** + * Reorder `array` according to the specified indexes where the element at + * the first index is assigned as the first element, the element at + * the second index is assigned as the second element, and so on. + * + * @private + * @param {Array} array The array to reorder. + * @param {Array} indexes The arranged array indexes. + * @returns {Array} Returns `array`. + */ + function reorder(array, indexes) { + var arrLength = array.length, + length = nativeMin(indexes.length, arrLength), + oldArray = copyArray(array); + + while (length--) { + var index = indexes[length]; + array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; + } + return array; + } + + /** + * Sets metadata for `func`. + * + * **Note:** If this function becomes hot, i.e. is invoked a lot in a short + * period of time, it will trip its breaker and transition to an identity + * function to avoid garbage collection pauses in V8. See + * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) + * for more details. + * + * @private + * @param {Function} func The function to associate metadata with. + * @param {*} data The metadata. + * @returns {Function} Returns `func`. + */ + var setData = shortOut(baseSetData); + + /** + * Sets the `toString` method of `func` to return `string`. + * + * @private + * @param {Function} func The function to modify. + * @param {Function} string The `toString` result. + * @returns {Function} Returns `func`. + */ + var setToString = shortOut(baseSetToString); + + /** + * Sets the `toString` method of `wrapper` to mimic the source of `reference` + * with wrapper details in a comment at the top of the source body. + * + * @private + * @param {Function} wrapper The function to modify. + * @param {Function} reference The reference function. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Function} Returns `wrapper`. + */ + function setWrapToString(wrapper, reference, bitmask) { + var source = (reference + ''); + return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); + } + + /** + * Creates a function that'll short out and invoke `identity` instead + * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` + * milliseconds. + * + * @private + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new shortable function. + */ + function shortOut(func) { + var count = 0, + lastCalled = 0; + + return function () { + var stamp = nativeNow(), + remaining = HOT_SPAN - (stamp - lastCalled); + + lastCalled = stamp; + if (remaining > 0) { + if (++count >= HOT_COUNT) { + return arguments[0]; + } + } else { + count = 0; + } + return func.apply(undefined, arguments); + }; + } + + /** + * Converts `string` to a property path array. + * + * @private + * @param {string} string The string to convert. + * @returns {Array} Returns the property path array. + */ + var stringToPath = memoizeCapped(function (string) { + var result = []; + if (string.charCodeAt(0) === 46 /* . */) { + result.push(''); + } + string.replace(rePropName, function (match, number, quote, subString) { + result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); + }); + return result; }); - return result; - } - - /** - * The base implementation of `_.delay` and `_.defer` which accepts `args` - * to provide to `func`. - * - * @private - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {Array} args The arguments to provide to `func`. - * @returns {number|Object} Returns the timer id or timeout object. - */ - function baseDelay(func, wait, args) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return setTimeout(function() { func.apply(undefined, args); }, wait); - } - - /** - * The base implementation of methods like `_.difference` without support - * for excluding multiple arrays or iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Array} values The values to exclude. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of filtered values. - */ - function baseDifference(array, values, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - isCommon = true, - length = array.length, - result = [], - valuesLength = values.length; - - if (!length) { - return result; - } - if (iteratee) { - values = arrayMap(values, baseUnary(iteratee)); - } - if (comparator) { - includes = arrayIncludesWith; - isCommon = false; - } - else if (values.length >= LARGE_ARRAY_SIZE) { - includes = cacheHas; - isCommon = false; - values = new SetCache(values); - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee == null ? value : iteratee(value); - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var valuesIndex = valuesLength; - while (valuesIndex--) { - if (values[valuesIndex] === computed) { - continue outer; - } - } - result.push(value); - } - else if (!includes(values, computed, comparator)) { - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.forEach` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - */ - var baseEach = createBaseEach(baseForOwn); - - /** - * The base implementation of `_.every` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false` - */ - function baseEvery(collection, predicate) { - var result = true; - baseEach(collection, function(value, index, collection) { - result = !!predicate(value, index, collection); - return result; + + /** + * Converts `value` to a string key if it's not a string or symbol. + * + * @private + * @param {*} value The value to inspect. + * @returns {string|symbol} Returns the key. + */ + function toKey(value) { + if (typeof value == 'string' || isSymbol(value)) { + return value; + } + var result = (value + ''); + return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; + } + + /** + * Converts `func` to its source code. + * + * @private + * @param {Function} func The function to convert. + * @returns {string} Returns the source code. + */ + function toSource(func) { + if (func != null) { + try { + return funcToString.call(func); + } catch (e) { + } + try { + return (func + ''); + } catch (e) { + } + } + return ''; + } + + /** + * Updates wrapper `details` based on `bitmask` flags. + * + * @private + * @returns {Array} details The details to modify. + * @param {number} bitmask The bitmask flags. See `createWrap` for more details. + * @returns {Array} Returns `details`. + */ + function updateWrapDetails(details, bitmask) { + arrayEach(wrapFlags, function (pair) { + var value = '_.' + pair[0]; + if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { + details.push(value); + } + }); + return details.sort(); + } + + /** + * Creates a clone of `wrapper`. + * + * @private + * @param {Object} wrapper The wrapper to clone. + * @returns {Object} Returns the cloned wrapper. + */ + function wrapperClone(wrapper) { + if (wrapper instanceof LazyWrapper) { + return wrapper.clone(); + } + var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); + result.__actions__ = copyArray(wrapper.__actions__); + result.__index__ = wrapper.__index__; + result.__values__ = wrapper.__values__; + return result; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an array of elements split into groups the length of `size`. + * If `array` can't be split evenly, the final chunk will be the remaining + * elements. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to process. + * @param {number} [size=1] The length of each chunk + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the new array of chunks. + * @example + * + * _.chunk(['a', 'b', 'c', 'd'], 2); + * // => [['a', 'b'], ['c', 'd']] + * + * _.chunk(['a', 'b', 'c', 'd'], 3); + * // => [['a', 'b', 'c'], ['d']] + */ + function chunk(array, size, guard) { + if ((guard ? isIterateeCall(array, size, guard) : size === undefined)) { + size = 1; + } else { + size = nativeMax(toInteger(size), 0); + } + var length = array == null ? 0 : array.length; + if (!length || size < 1) { + return []; + } + var index = 0, + resIndex = 0, + result = Array(nativeCeil(length / size)); + + while (index < length) { + result[resIndex++] = baseSlice(array, index, (index += size)); + } + return result; + } + + /** + * Creates an array with all falsey values removed. The values `false`, `null`, + * `0`, `""`, `undefined`, and `NaN` are falsey. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to compact. + * @returns {Array} Returns the new array of filtered values. + * @example + * + * _.compact([0, 1, false, 2, '', 3]); + * // => [1, 2, 3] + */ + function compact(array) { + var index = -1, + length = array == null ? 0 : array.length, + resIndex = 0, + result = []; + + while (++index < length) { + var value = array[index]; + if (value) { + result[resIndex++] = value; + } + } + return result; + } + + /** + * Creates a new array concatenating `array` with any additional arrays + * and/or values. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to concatenate. + * @param {...*} [values] The values to concatenate. + * @returns {Array} Returns the new concatenated array. + * @example + * + * var array = [1]; + * var other = _.concat(array, 2, [3], [[4]]); + * + * console.log(other); + * // => [1, 2, 3, [4]] + * + * console.log(array); + * // => [1] + */ + function concat() { + var length = arguments.length; + if (!length) { + return []; + } + var args = Array(length - 1), + array = arguments[0], + index = length; + + while (index--) { + args[index - 1] = arguments[index]; + } + return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); + } + + /** + * Creates an array of `array` values not included in the other given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * **Note:** Unlike `_.pullAll`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...Array} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.without, _.xor + * @example + * + * _.difference([2, 1], [2, 3]); + * // => [1] + */ + var difference = baseRest(function (array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) + : []; }); - return result; - } - - /** - * The base implementation of methods like `_.max` and `_.min` which accepts a - * `comparator` to determine the extremum value. - * - * @private - * @param {Array} array The array to iterate over. - * @param {Function} iteratee The iteratee invoked per iteration. - * @param {Function} comparator The comparator used to compare values. - * @returns {*} Returns the extremum value. - */ - function baseExtremum(array, iteratee, comparator) { - var index = -1, - length = array.length; - - while (++index < length) { - var value = array[index], - current = iteratee(value); - - if (current != null && (computed === undefined - ? (current === current && !isSymbol(current)) - : comparator(current, computed) - )) { - var computed = current, - result = value; - } - } - return result; - } - - /** - * The base implementation of `_.filter` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - */ - function baseFilter(collection, predicate) { - var result = []; - baseEach(collection, function(value, index, collection) { - if (predicate(value, index, collection)) { - result.push(value); - } + + /** + * Creates a slice of `array` with `n` elements dropped from the beginning. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to drop. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.drop([1, 2, 3]); + * // => [2, 3] + * + * _.drop([1, 2, 3], 2); + * // => [3] + * + * _.drop([1, 2, 3], 5); + * // => [] + * + * _.drop([1, 2, 3], 0); + * // => [1, 2, 3] + */ + function drop(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * This method is like `_.find` except that it returns the index of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': false }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': true } + * ]; + * + * _.findIndex(users, function(o) { return o.user == 'barney'; }); + * // => 0 + * + * // The `_.matches` iteratee shorthand. + * _.findIndex(users, { 'user': 'fred', 'active': false }); + * // => 1 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findIndex(users, ['active', false]); + * // => 0 + * + * // The `_.property` iteratee shorthand. + * _.findIndex(users, 'active'); + * // => 2 + */ + function findIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseFindIndex(array, baseIteratee(predicate, 3), index); + } + + /** + * This method is like `_.findIndex` except that it iterates over elements + * of `collection` from right to left. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=array.length-1] The index to search from. + * @returns {number} Returns the index of the found element, else `-1`. + * @example + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false }, + * { 'user': 'pebbles', 'active': false } + * ]; + * + * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); + * // => 2 + * + * // The `_.matches` iteratee shorthand. + * _.findLastIndex(users, { 'user': 'barney', 'active': true }); + * // => 0 + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastIndex(users, ['active', false]); + * // => 2 + * + * // The `_.property` iteratee shorthand. + * _.findLastIndex(users, 'active'); + * // => 0 + */ + function findLastIndex(array, predicate, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = length - 1; + if (fromIndex !== undefined) { + index = toInteger(fromIndex); + index = fromIndex < 0 + ? nativeMax(length + index, 0) + : nativeMin(index, length - 1); + } + return baseFindIndex(array, baseIteratee(predicate, 3), index, true); + } + + /** + * Flattens `array` a single level deep. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flatten([1, [2, [3, [4]], 5]]); + * // => [1, 2, [3, [4]], 5] + */ + function flatten(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, 1) : []; + } + + /** + * Recursively flattens `array`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to flatten. + * @returns {Array} Returns the new flattened array. + * @example + * + * _.flattenDeep([1, [2, [3, [4]], 5]]); + * // => [1, 2, 3, 4, 5] + */ + function flattenDeep(array) { + var length = array == null ? 0 : array.length; + return length ? baseFlatten(array, INFINITY) : []; + } + + /** + * Gets the first element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias first + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the first element of `array`. + * @example + * + * _.head([1, 2, 3]); + * // => 1 + * + * _.head([]); + * // => undefined + */ + function head(array) { + return (array && array.length) ? array[0] : undefined; + } + + /** + * Gets the index at which the first occurrence of `value` is found in `array` + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. If `fromIndex` is negative, it's used as the + * offset from the end of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {*} value The value to search for. + * @param {number} [fromIndex=0] The index to search from. + * @returns {number} Returns the index of the matched value, else `-1`. + * @example + * + * _.indexOf([1, 2, 1, 2], 2); + * // => 1 + * + * // Search from the `fromIndex`. + * _.indexOf([1, 2, 1, 2], 2, 2); + * // => 3 + */ + function indexOf(array, value, fromIndex) { + var length = array == null ? 0 : array.length; + if (!length) { + return -1; + } + var index = fromIndex == null ? 0 : toInteger(fromIndex); + if (index < 0) { + index = nativeMax(length + index, 0); + } + return baseIndexOf(array, value, index); + } + + /** + * Gets all but the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.initial([1, 2, 3]); + * // => [1, 2] + */ + function initial(array) { + var length = array == null ? 0 : array.length; + return length ? baseSlice(array, 0, -1) : []; + } + + /** + * Creates an array of unique values that are included in all given arrays + * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. The order and references of result values are + * determined by the first array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of intersecting values. + * @example + * + * _.intersection([2, 1], [2, 3]); + * // => [2] + */ + var intersection = baseRest(function (arrays) { + var mapped = arrayMap(arrays, castArrayLikeObject); + return (mapped.length && mapped[0] === arrays[0]) + ? baseIntersection(mapped) + : []; }); - return result; - } - - /** - * The base implementation of `_.flatten` with support for restricting flattening. - * - * @private - * @param {Array} array The array to flatten. - * @param {number} depth The maximum recursion depth. - * @param {boolean} [predicate=isFlattenable] The function invoked per iteration. - * @param {boolean} [isStrict] Restrict to values that pass `predicate` checks. - * @param {Array} [result=[]] The initial result value. - * @returns {Array} Returns the new flattened array. - */ - function baseFlatten(array, depth, predicate, isStrict, result) { - var index = -1, - length = array.length; - - predicate || (predicate = isFlattenable); - result || (result = []); - - while (++index < length) { - var value = array[index]; - if (depth > 0 && predicate(value)) { - if (depth > 1) { - // Recursively flatten arrays (susceptible to call stack limits). - baseFlatten(value, depth - 1, predicate, isStrict, result); + + /** + * Gets the last element of `array`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @returns {*} Returns the last element of `array`. + * @example + * + * _.last([1, 2, 3]); + * // => 3 + */ + function last(array) { + var length = array == null ? 0 : array.length; + return length ? array[length - 1] : undefined; + } + + /** + * Reverses `array` so that the first element becomes the last, the second + * element becomes the second to last, and so on. + * + * **Note:** This method mutates `array` and is based on + * [`Array#reverse`](https://mdn.io/Array/reverse). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to modify. + * @returns {Array} Returns `array`. + * @example + * + * var array = [1, 2, 3]; + * + * _.reverse(array); + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function reverse(array) { + return array == null ? array : nativeReverse.call(array); + } + + /** + * Creates a slice of `array` from `start` up to, but not including, `end`. + * + * **Note:** This method is used instead of + * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are + * returned. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to slice. + * @param {number} [start=0] The start position. + * @param {number} [end=array.length] The end position. + * @returns {Array} Returns the slice of `array`. + */ + function slice(array, start, end) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { + start = 0; + end = length; } else { - arrayPush(result, value); - } - } else if (!isStrict) { - result[result.length] = value; - } - } - return result; - } - - /** - * The base implementation of `baseForOwn` which iterates over `object` - * properties returned by `keysFunc` and invokes `iteratee` for each property. - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseFor = createBaseFor(); - - /** - * This function is like `baseFor` except that it iterates over properties - * in the opposite order. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @param {Function} keysFunc The function to get the keys of `object`. - * @returns {Object} Returns `object`. - */ - var baseForRight = createBaseFor(true); - - /** - * The base implementation of `_.forOwn` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwn(object, iteratee) { - return object && baseFor(object, iteratee, keys); - } - - /** - * The base implementation of `_.forOwnRight` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Object} Returns `object`. - */ - function baseForOwnRight(object, iteratee) { - return object && baseForRight(object, iteratee, keys); - } - - /** - * The base implementation of `_.functions` which creates an array of - * `object` function property names filtered from `props`. - * - * @private - * @param {Object} object The object to inspect. - * @param {Array} props The property names to filter. - * @returns {Array} Returns the function names. - */ - function baseFunctions(object, props) { - return arrayFilter(props, function(key) { - return isFunction(object[key]); + start = start == null ? 0 : toInteger(start); + end = end === undefined ? length : toInteger(end); + } + return baseSlice(array, start, end); + } + + /** + * Creates a slice of `array` with `n` elements taken from the beginning. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.take([1, 2, 3]); + * // => [1] + * + * _.take([1, 2, 3], 2); + * // => [1, 2] + * + * _.take([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.take([1, 2, 3], 0); + * // => [] + */ + function take(array, n, guard) { + if (!(array && array.length)) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + return baseSlice(array, 0, n < 0 ? 0 : n); + } + + /** + * Creates a slice of `array` with `n` elements taken from the end. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Array + * @param {Array} array The array to query. + * @param {number} [n=1] The number of elements to take. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {Array} Returns the slice of `array`. + * @example + * + * _.takeRight([1, 2, 3]); + * // => [3] + * + * _.takeRight([1, 2, 3], 2); + * // => [2, 3] + * + * _.takeRight([1, 2, 3], 5); + * // => [1, 2, 3] + * + * _.takeRight([1, 2, 3], 0); + * // => [] + */ + function takeRight(array, n, guard) { + var length = array == null ? 0 : array.length; + if (!length) { + return []; + } + n = (guard || n === undefined) ? 1 : toInteger(n); + n = length - n; + return baseSlice(array, n < 0 ? 0 : n, length); + } + + /** + * Creates an array of unique values, in order, from all given arrays using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to inspect. + * @returns {Array} Returns the new array of combined values. + * @example + * + * _.union([2], [1, 2]); + * // => [2, 1] + */ + var union = baseRest(function (arrays) { + return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); }); - } - - /** - * The base implementation of `_.get` without support for default values. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @returns {*} Returns the resolved value. - */ - function baseGet(object, path) { - path = castPath(path, object); - - var index = 0, - length = path.length; - - while (object != null && index < length) { - object = object[toKey(path[index++])]; - } - return (index && index == length) ? object : undefined; - } - - /** - * The base implementation of `getAllKeys` and `getAllKeysIn` which uses - * `keysFunc` and `symbolsFunc` to get the enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Function} keysFunc The function to get the keys of `object`. - * @param {Function} symbolsFunc The function to get the symbols of `object`. - * @returns {Array} Returns the array of property names and symbols. - */ - function baseGetAllKeys(object, keysFunc, symbolsFunc) { - var result = keysFunc(object); - return isArray(object) ? result : arrayPush(result, symbolsFunc(object)); - } - - /** - * The base implementation of `getTag` without fallbacks for buggy environments. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - function baseGetTag(value) { - if (value == null) { - return value === undefined ? undefinedTag : nullTag; - } - return (symToStringTag && symToStringTag in Object(value)) - ? getRawTag(value) - : objectToString(value); - } - - /** - * The base implementation of `_.gt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is greater than `other`, - * else `false`. - */ - function baseGt(value, other) { - return value > other; - } - - /** - * The base implementation of `_.has` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHas(object, key) { - return object != null && hasOwnProperty.call(object, key); - } - - /** - * The base implementation of `_.hasIn` without support for deep paths. - * - * @private - * @param {Object} [object] The object to query. - * @param {Array|string} key The key to check. - * @returns {boolean} Returns `true` if `key` exists, else `false`. - */ - function baseHasIn(object, key) { - return object != null && key in Object(object); - } - - /** - * The base implementation of methods like `_.intersection`, without support - * for iteratee shorthands, that accepts an array of arrays to inspect. - * - * @private - * @param {Array} arrays The arrays to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new array of shared values. - */ - function baseIntersection(arrays, iteratee, comparator) { - var includes = comparator ? arrayIncludesWith : arrayIncludes, - length = arrays[0].length, - othLength = arrays.length, - othIndex = othLength, - caches = Array(othLength), - maxLength = Infinity, - result = []; - - while (othIndex--) { - var array = arrays[othIndex]; - if (othIndex && iteratee) { - array = arrayMap(array, baseUnary(iteratee)); - } - maxLength = nativeMin(array.length, maxLength); - caches[othIndex] = !comparator && (iteratee || (length >= 120 && array.length >= 120)) - ? new SetCache(othIndex && array) - : undefined; - } - array = arrays[0]; - - var index = -1, - seen = caches[0]; - - outer: - while (++index < length && result.length < maxLength) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (!(seen - ? cacheHas(seen, computed) - : includes(result, computed, comparator) - )) { - othIndex = othLength; - while (--othIndex) { - var cache = caches[othIndex]; - if (!(cache - ? cacheHas(cache, computed) - : includes(arrays[othIndex], computed, comparator)) - ) { - continue outer; - } - } - if (seen) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.invert` and `_.invertBy` which inverts - * `object` with values transformed by `iteratee` and set by `setter`. - * - * @private - * @param {Object} object The object to iterate over. - * @param {Function} setter The function to set `accumulator` values. - * @param {Function} iteratee The iteratee to transform values. - * @param {Object} accumulator The initial inverted object. - * @returns {Function} Returns `accumulator`. - */ - function baseInverter(object, setter, iteratee, accumulator) { - baseForOwn(object, function(value, key, object) { - setter(accumulator, iteratee(value), key, object); + + /** + * Creates a duplicate-free version of an array, using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons, in which only the first occurrence of each element + * is kept. The order of result values is determined by the order they occur + * in the array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniq([2, 1, 2]); + * // => [2, 1] + */ + function uniq(array) { + return (array && array.length) ? baseUniq(array) : []; + } + + /** + * This method is like `_.uniq` except that it accepts `iteratee` which is + * invoked for each element in `array` to generate the criterion by which + * uniqueness is computed. The order of result values is determined by the + * order they occur in the array. The iteratee is invoked with one argument: + * (value). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Array} Returns the new duplicate free array. + * @example + * + * _.uniqBy([2.1, 1.2, 2.3], Math.floor); + * // => [2.1, 1.2] + * + * // The `_.property` iteratee shorthand. + * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); + * // => [{ 'x': 1 }, { 'x': 2 }] + */ + function uniqBy(array, iteratee) { + return (array && array.length) ? baseUniq(array, baseIteratee(iteratee, 2)) : []; + } + + /** + * This method is like `_.zip` except that it accepts an array of grouped + * elements and creates an array regrouping the elements to their pre-zip + * configuration. + * + * @static + * @memberOf _ + * @since 1.2.0 + * @category Array + * @param {Array} array The array of grouped elements to process. + * @returns {Array} Returns the new array of regrouped elements. + * @example + * + * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + * + * _.unzip(zipped); + * // => [['a', 'b'], [1, 2], [true, false]] + */ + function unzip(array) { + if (!(array && array.length)) { + return []; + } + var length = 0; + array = arrayFilter(array, function (group) { + if (isArrayLikeObject(group)) { + length = nativeMax(group.length, length); + return true; + } + }); + return baseTimes(length, function (index) { + return arrayMap(array, baseProperty(index)); + }); + } + + /** + * Creates an array excluding all given values using + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * for equality comparisons. + * + * **Note:** Unlike `_.pull`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {Array} array The array to inspect. + * @param {...*} [values] The values to exclude. + * @returns {Array} Returns the new array of filtered values. + * @see _.difference, _.xor + * @example + * + * _.without([2, 1, 2, 3], 1, 2); + * // => [3] + */ + var without = baseRest(function (array, values) { + return isArrayLikeObject(array) + ? baseDifference(array, values) + : []; }); - return accumulator; - } - - /** - * The base implementation of `_.invoke` without support for individual - * method arguments. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path of the method to invoke. - * @param {Array} args The arguments to invoke the method with. - * @returns {*} Returns the result of the invoked method. - */ - function baseInvoke(object, path, args) { - path = castPath(path, object); - object = parent(object, path); - var func = object == null ? object : object[toKey(last(path))]; - return func == null ? undefined : apply(func, object, args); - } - - /** - * The base implementation of `_.isArguments`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - */ - function baseIsArguments(value) { - return isObjectLike(value) && baseGetTag(value) == argsTag; - } - - /** - * The base implementation of `_.isDate` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - */ - function baseIsDate(value) { - return isObjectLike(value) && baseGetTag(value) == dateTag; - } - - /** - * The base implementation of `_.isEqual` which supports partial comparisons - * and tracks traversed objects. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @param {boolean} bitmask The bitmask flags. - * 1 - Unordered comparison - * 2 - Partial comparison - * @param {Function} [customizer] The function to customize comparisons. - * @param {Object} [stack] Tracks traversed `value` and `other` objects. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - */ - function baseIsEqual(value, other, bitmask, customizer, stack) { - if (value === other) { - return true; - } - if (value == null || other == null || (!isObjectLike(value) && !isObjectLike(other))) { - return value !== value && other !== other; - } - return baseIsEqualDeep(value, other, bitmask, customizer, baseIsEqual, stack); - } - - /** - * A specialized version of `baseIsEqual` for arrays and objects which performs - * deep comparisons and tracks traversed objects enabling objects with circular - * references to be compared. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} [stack] Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function baseIsEqualDeep(object, other, bitmask, customizer, equalFunc, stack) { - var objIsArr = isArray(object), - othIsArr = isArray(other), - objTag = objIsArr ? arrayTag : getTag(object), - othTag = othIsArr ? arrayTag : getTag(other); - - objTag = objTag == argsTag ? objectTag : objTag; - othTag = othTag == argsTag ? objectTag : othTag; - - var objIsObj = objTag == objectTag, - othIsObj = othTag == objectTag, - isSameTag = objTag == othTag; - - if (isSameTag && isBuffer(object)) { - if (!isBuffer(other)) { - return false; - } - objIsArr = true; - objIsObj = false; + + /** + * Creates an array of grouped elements, the first of which contains the + * first elements of the given arrays, the second of which contains the + * second elements of the given arrays, and so on. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Array + * @param {...Array} [arrays] The arrays to process. + * @returns {Array} Returns the new array of grouped elements. + * @example + * + * _.zip(['a', 'b'], [1, 2], [true, false]); + * // => [['a', 1, true], ['b', 2, false]] + */ + var zip = baseRest(unzip); + + /** + * This method is like `_.fromPairs` except that it accepts two arrays, + * one of property identifiers and one of corresponding values. + * + * @static + * @memberOf _ + * @since 0.4.0 + * @category Array + * @param {Array} [props=[]] The property identifiers. + * @param {Array} [values=[]] The property values. + * @returns {Object} Returns the new object. + * @example + * + * _.zipObject(['a', 'b'], [1, 2]); + * // => { 'a': 1, 'b': 2 } + */ + function zipObject(props, values) { + return baseZipObject(props || [], values || [], assignValue); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a `lodash` wrapper instance that wraps `value` with explicit method + * chain sequences enabled. The result of such sequences must be unwrapped + * with `_#value`. + * + * @static + * @memberOf _ + * @since 1.3.0 + * @category Seq + * @param {*} value The value to wrap. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'pebbles', 'age': 1 } + * ]; + * + * var youngest = _ + * .chain(users) + * .sortBy('age') + * .map(function(o) { + * return o.user + ' is ' + o.age; + * }) + * .head() + * .value(); + * // => 'pebbles is 1' + */ + function chain(value) { + var result = lodash(value); + result.__chain__ = true; + return result; } - if (isSameTag && !objIsObj) { - stack || (stack = new Stack); - return (objIsArr || isTypedArray(object)) - ? equalArrays(object, other, bitmask, customizer, equalFunc, stack) - : equalByTag(object, other, objTag, bitmask, customizer, equalFunc, stack); + + /** + * This method invokes `interceptor` and returns `value`. The interceptor + * is invoked with one argument; (value). The purpose of this method is to + * "tap into" a method chain sequence in order to modify intermediate results. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns `value`. + * @example + * + * _([1, 2, 3]) + * .tap(function(array) { + * // Mutate input array. + * array.pop(); + * }) + * .reverse() + * .value(); + * // => [2, 1] + */ + function tap(value, interceptor) { + interceptor(value); + return value; } - if (!(bitmask & COMPARE_PARTIAL_FLAG)) { - var objIsWrapped = objIsObj && hasOwnProperty.call(object, '__wrapped__'), - othIsWrapped = othIsObj && hasOwnProperty.call(other, '__wrapped__'); - if (objIsWrapped || othIsWrapped) { - var objUnwrapped = objIsWrapped ? object.value() : object, - othUnwrapped = othIsWrapped ? other.value() : other; + /** + * This method is like `_.tap` except that it returns the result of `interceptor`. + * The purpose of this method is to "pass thru" values replacing intermediate + * results in a method chain sequence. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Seq + * @param {*} value The value to provide to `interceptor`. + * @param {Function} interceptor The function to invoke. + * @returns {*} Returns the result of `interceptor`. + * @example + * + * _(' abc ') + * .chain() + * .trim() + * .thru(function(value) { + * return [value]; + * }) + * .value(); + * // => ['abc'] + */ + function thru(value, interceptor) { + return interceptor(value); + } + + /** + * This method is the wrapper version of `_.at`. + * + * @name at + * @memberOf _ + * @since 1.0.0 + * @category Seq + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; + * + * _(object).at(['a[0].b.c', 'a[1]']).value(); + * // => [3, 4] + */ + var wrapperAt = flatRest(function (paths) { + var length = paths.length, + start = length ? paths[0] : 0, + value = this.__wrapped__, + interceptor = function (object) { + return baseAt(object, paths); + }; + + if (length > 1 || this.__actions__.length || + !(value instanceof LazyWrapper) || !isIndex(start)) { + return this.thru(interceptor); + } + value = value.slice(start, +start + (length ? 1 : 0)); + value.__actions__.push({ + 'func': thru, + 'args': [interceptor], + 'thisArg': undefined + }); + return new LodashWrapper(value, this.__chain__).thru(function (array) { + if (length && !array.length) { + array.push(undefined); + } + return array; + }); + }); - stack || (stack = new Stack); - return equalFunc(objUnwrapped, othUnwrapped, bitmask, customizer, stack); - } - } - if (!isSameTag) { - return false; - } - stack || (stack = new Stack); - return equalObjects(object, other, bitmask, customizer, equalFunc, stack); - } - - /** - * The base implementation of `_.isMap` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - */ - function baseIsMap(value) { - return isObjectLike(value) && getTag(value) == mapTag; - } - - /** - * The base implementation of `_.isMatch` without support for iteratee shorthands. - * - * @private - * @param {Object} object The object to inspect. - * @param {Object} source The object of property values to match. - * @param {Array} matchData The property names, values, and compare flags to match. - * @param {Function} [customizer] The function to customize comparisons. - * @returns {boolean} Returns `true` if `object` is a match, else `false`. - */ - function baseIsMatch(object, source, matchData, customizer) { - var index = matchData.length, - length = index, - noCustomizer = !customizer; - - if (object == null) { - return !length; - } - object = Object(object); - while (index--) { - var data = matchData[index]; - if ((noCustomizer && data[2]) - ? data[1] !== object[data[0]] - : !(data[0] in object) - ) { - return false; - } + /** + * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. + * + * @name chain + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 } + * ]; + * + * // A sequence without explicit chaining. + * _(users).head(); + * // => { 'user': 'barney', 'age': 36 } + * + * // A sequence with explicit chaining. + * _(users) + * .chain() + * .head() + * .pick('user') + * .value(); + * // => { 'user': 'barney' } + */ + function wrapperChain() { + return chain(this); + } + + /** + * Executes the chain sequence and returns the wrapped result. + * + * @name commit + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2]; + * var wrapped = _(array).push(3); + * + * console.log(array); + * // => [1, 2] + * + * wrapped = wrapped.commit(); + * console.log(array); + * // => [1, 2, 3] + * + * wrapped.last(); + * // => 3 + * + * console.log(array); + * // => [1, 2, 3] + */ + function wrapperCommit() { + return new LodashWrapper(this.value(), this.__chain__); + } + + /** + * Gets the next value on a wrapped object following the + * [iterator protocol](https://mdn.io/iteration_protocols#iterator). + * + * @name next + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the next iterator value. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped.next(); + * // => { 'done': false, 'value': 1 } + * + * wrapped.next(); + * // => { 'done': false, 'value': 2 } + * + * wrapped.next(); + * // => { 'done': true, 'value': undefined } + */ + function wrapperNext() { + if (this.__values__ === undefined) { + this.__values__ = toArray(this.value()); + } + var done = this.__index__ >= this.__values__.length, + value = done ? undefined : this.__values__[this.__index__++]; + + return { 'done': done, 'value': value }; + } + + /** + * Enables the wrapper to be iterable. + * + * @name Symbol.iterator + * @memberOf _ + * @since 4.0.0 + * @category Seq + * @returns {Object} Returns the wrapper object. + * @example + * + * var wrapped = _([1, 2]); + * + * wrapped[Symbol.iterator]() === wrapped; + * // => true + * + * Array.from(wrapped); + * // => [1, 2] + */ + function wrapperToIterator() { + return this; } - while (++index < length) { - data = matchData[index]; - var key = data[0], - objValue = object[key], - srcValue = data[1]; - if (noCustomizer && data[2]) { - if (objValue === undefined && !(key in object)) { - return false; + /** + * Creates a clone of the chain sequence planting `value` as the wrapped value. + * + * @name plant + * @memberOf _ + * @since 3.2.0 + * @category Seq + * @param {*} value The value to plant. + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * function square(n) { + * return n * n; + * } + * + * var wrapped = _([1, 2]).map(square); + * var other = wrapped.plant([3, 4]); + * + * other.value(); + * // => [9, 16] + * + * wrapped.value(); + * // => [1, 4] + */ + function wrapperPlant(value) { + var result, + parent = this; + + while (parent instanceof baseLodash) { + var clone = wrapperClone(parent); + clone.__index__ = 0; + clone.__values__ = undefined; + if (result) { + previous.__wrapped__ = clone; + } else { + result = clone; + } + var previous = clone; + parent = parent.__wrapped__; } - } else { - var stack = new Stack; - if (customizer) { - var result = customizer(objValue, srcValue, key, object, source, stack); + previous.__wrapped__ = value; + return result; + } + + /** + * This method is the wrapper version of `_.reverse`. + * + * **Note:** This method mutates the wrapped array. + * + * @name reverse + * @memberOf _ + * @since 0.1.0 + * @category Seq + * @returns {Object} Returns the new `lodash` wrapper instance. + * @example + * + * var array = [1, 2, 3]; + * + * _(array).reverse().value() + * // => [3, 2, 1] + * + * console.log(array); + * // => [3, 2, 1] + */ + function wrapperReverse() { + var value = this.__wrapped__; + if (value instanceof LazyWrapper) { + var wrapped = value; + if (this.__actions__.length) { + wrapped = new LazyWrapper(this); + } + wrapped = wrapped.reverse(); + wrapped.__actions__.push({ + 'func': thru, + 'args': [reverse], + 'thisArg': undefined + }); + return new LodashWrapper(wrapped, this.__chain__); + } + return this.thru(reverse); + } + + /** + * Executes the chain sequence to resolve the unwrapped value. + * + * @name value + * @memberOf _ + * @since 0.1.0 + * @alias toJSON, valueOf + * @category Seq + * @returns {*} Returns the resolved unwrapped value. + * @example + * + * _([1, 2, 3]).value(); + * // => [1, 2, 3] + */ + function wrapperValue() { + return baseWrapperValue(this.__wrapped__, this.__actions__); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The corresponding value of + * each key is the number of times the key was returned by `iteratee`. The + * iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.countBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': 1, '6': 2 } + * + * // The `_.property` iteratee shorthand. + * _.countBy(['one', 'two', 'three'], 'length'); + * // => { '3': 2, '5': 1 } + */ + var countBy = createAggregator(function (result, value, key) { + if (hasOwnProperty.call(result, key)) { + ++result[key]; + } else { + baseAssignValue(result, key, 1); } - if (!(result === undefined - ? baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG, customizer, stack) - : result - )) { - return false; - } - } - } - return true; - } - - /** - * The base implementation of `_.isNative` without bad shim checks. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a native function, - * else `false`. - */ - function baseIsNative(value) { - if (!isObject(value) || isMasked(value)) { - return false; - } - var pattern = isFunction(value) ? reIsNative : reIsHostCtor; - return pattern.test(toSource(value)); - } - - /** - * The base implementation of `_.isRegExp` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - */ - function baseIsRegExp(value) { - return isObjectLike(value) && baseGetTag(value) == regexpTag; - } - - /** - * The base implementation of `_.isSet` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - */ - function baseIsSet(value) { - return isObjectLike(value) && getTag(value) == setTag; - } - - /** - * The base implementation of `_.isTypedArray` without Node.js optimizations. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - */ - function baseIsTypedArray(value) { - return isObjectLike(value) && - isLength(value.length) && !!typedArrayTags[baseGetTag(value)]; - } - - /** - * The base implementation of `_.iteratee`. - * - * @private - * @param {*} [value=_.identity] The value to convert to an iteratee. - * @returns {Function} Returns the iteratee. - */ - function baseIteratee(value) { - // Don't store the `typeof` result in a variable to avoid a JIT bug in Safari 9. - // See https://bugs.webkit.org/show_bug.cgi?id=156034 for more details. - if (typeof value == 'function') { - return value; - } - if (value == null) { - return identity; - } - if (typeof value == 'object') { - return isArray(value) - ? baseMatchesProperty(value[0], value[1]) - : baseMatches(value); - } - return property(value); - } - - /** - * The base implementation of `_.keys` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeys(object) { - if (!isPrototype(object)) { - return nativeKeys(object); - } - var result = []; - for (var key in Object(object)) { - if (hasOwnProperty.call(object, key) && key != 'constructor') { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.keysIn` which doesn't treat sparse arrays as dense. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function baseKeysIn(object) { - if (!isObject(object)) { - return nativeKeysIn(object); - } - var isProto = isPrototype(object), - result = []; - - for (var key in object) { - if (!(key == 'constructor' && (isProto || !hasOwnProperty.call(object, key)))) { - result.push(key); - } - } - return result; - } - - /** - * The base implementation of `_.lt` which doesn't coerce arguments. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if `value` is less than `other`, - * else `false`. - */ - function baseLt(value, other) { - return value < other; - } - - /** - * The base implementation of `_.map` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} iteratee The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - */ - function baseMap(collection, iteratee) { - var index = -1, - result = isArrayLike(collection) ? Array(collection.length) : []; - - baseEach(collection, function(value, key, collection) { - result[++index] = iteratee(value, key, collection); }); - return result; - } - - /** - * The base implementation of `_.matches` which doesn't clone `source`. - * - * @private - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatches(source) { - var matchData = getMatchData(source); - if (matchData.length == 1 && matchData[0][2]) { - return matchesStrictComparable(matchData[0][0], matchData[0][1]); - } - return function(object) { - return object === source || baseIsMatch(object, source, matchData); - }; - } - - /** - * The base implementation of `_.matchesProperty` which doesn't clone `srcValue`. - * - * @private - * @param {string} path The path of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function baseMatchesProperty(path, srcValue) { - if (isKey(path) && isStrictComparable(srcValue)) { - return matchesStrictComparable(toKey(path), srcValue); - } - return function(object) { - var objValue = get(object, path); - return (objValue === undefined && objValue === srcValue) - ? hasIn(object, path) - : baseIsEqual(srcValue, objValue, COMPARE_PARTIAL_FLAG | COMPARE_UNORDERED_FLAG); - }; - } - - /** - * The base implementation of `_.merge` without support for multiple sources. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {number} srcIndex The index of `source`. - * @param {Function} [customizer] The function to customize merged values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMerge(object, source, srcIndex, customizer, stack) { - if (object === source) { - return; - } - baseFor(source, function(srcValue, key) { - if (isObject(srcValue)) { - stack || (stack = new Stack); - baseMergeDeep(object, source, key, srcIndex, baseMerge, customizer, stack); - } - else { - var newValue = customizer - ? customizer(safeGet(object, key), srcValue, (key + ''), object, source, stack) - : undefined; - if (newValue === undefined) { - newValue = srcValue; + /** + * Checks if `predicate` returns truthy for **all** elements of `collection`. + * Iteration is stopped once `predicate` returns falsey. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * **Note:** This method returns `true` for + * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because + * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of + * elements of empty collections. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if all elements pass the predicate check, + * else `false`. + * @example + * + * _.every([true, 1, null, 'yes'], Boolean); + * // => false + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.every(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.every(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.every(users, 'active'); + * // => false + */ + function every(collection, predicate, guard) { + var func = isArray(collection) ? arrayEvery : baseEvery; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, baseIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning an array of all elements + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * **Note:** Unlike `_.remove`, this method returns a new array. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.reject + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * _.filter(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, { 'age': 36, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.filter(users, 'active'); + * // => objects for ['barney'] + */ + function filter(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, baseIteratee(predicate, 3)); + } + + /** + * Iterates over elements of `collection`, returning the first element + * `predicate` returns truthy for. The predicate is invoked with three + * arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param {number} [fromIndex=0] The index to search from. + * @returns {*} Returns the matched element, else `undefined`. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false }, + * { 'user': 'pebbles', 'age': 1, 'active': true } + * ]; + * + * _.find(users, function(o) { return o.age < 40; }); + * // => object for 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.find(users, { 'age': 1, 'active': true }); + * // => object for 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.find(users, ['active', false]); + * // => object for 'fred' + * + * // The `_.property` iteratee shorthand. + * _.find(users, 'active'); + * // => object for 'barney' + */ + var find = createFind(findIndex); + + /** + * Iterates over elements of `collection` and invokes `iteratee` for each element. + * The iteratee is invoked with three arguments: (value, index|key, collection). + * Iteratee functions may exit iteration early by explicitly returning `false`. + * + * **Note:** As with other "Collections" methods, objects with a "length" + * property are iterated like arrays. To avoid this behavior use `_.forIn` + * or `_.forOwn` for object iteration. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @alias each + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array|Object} Returns `collection`. + * @see _.forEachRight + * @example + * + * _.forEach([1, 2], function(value) { + * console.log(value); + * }); + * // => Logs `1` then `2`. + * + * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { + * console.log(key); + * }); + * // => Logs 'a' then 'b' (iteration order is not guaranteed). + */ + function forEach(collection, iteratee) { + var func = isArray(collection) ? arrayEach : baseEach; + return func(collection, baseIteratee(iteratee, 3)); + } + + /** + * Creates an object composed of keys generated from the results of running + * each element of `collection` thru `iteratee`. The order of grouped values + * is determined by the order they occur in `collection`. The corresponding + * value of each key is an array of elements responsible for generating the + * key. The iteratee is invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The iteratee to transform keys. + * @returns {Object} Returns the composed aggregate object. + * @example + * + * _.groupBy([6.1, 4.2, 6.3], Math.floor); + * // => { '4': [4.2], '6': [6.1, 6.3] } + * + * // The `_.property` iteratee shorthand. + * _.groupBy(['one', 'two', 'three'], 'length'); + * // => { '3': ['one', 'two'], '5': ['three'] } + */ + var groupBy = createAggregator(function (result, value, key) { + if (hasOwnProperty.call(result, key)) { + result[key].push(value); + } else { + baseAssignValue(result, key, [value]); } - assignMergeValue(object, key, newValue); - } - }, keysIn); - } - - /** - * A specialized version of `baseMerge` for arrays and objects which performs - * deep merges and tracks traversed objects enabling objects with circular - * references to be merged. - * - * @private - * @param {Object} object The destination object. - * @param {Object} source The source object. - * @param {string} key The key of the value to merge. - * @param {number} srcIndex The index of `source`. - * @param {Function} mergeFunc The function to merge values. - * @param {Function} [customizer] The function to customize assigned values. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - */ - function baseMergeDeep(object, source, key, srcIndex, mergeFunc, customizer, stack) { - var objValue = safeGet(object, key), - srcValue = safeGet(source, key), - stacked = stack.get(srcValue); - - if (stacked) { - assignMergeValue(object, key, stacked); - return; - } - var newValue = customizer - ? customizer(objValue, srcValue, (key + ''), object, source, stack) - : undefined; - - var isCommon = newValue === undefined; - - if (isCommon) { - var isArr = isArray(srcValue), - isBuff = !isArr && isBuffer(srcValue), - isTyped = !isArr && !isBuff && isTypedArray(srcValue); - - newValue = srcValue; - if (isArr || isBuff || isTyped) { - if (isArray(objValue)) { - newValue = objValue; - } - else if (isArrayLikeObject(objValue)) { - newValue = copyArray(objValue); - } - else if (isBuff) { - isCommon = false; - newValue = cloneBuffer(srcValue, true); - } - else if (isTyped) { - isCommon = false; - newValue = cloneTypedArray(srcValue, true); - } - else { - newValue = []; - } - } - else if (isPlainObject(srcValue) || isArguments(srcValue)) { - newValue = objValue; - if (isArguments(objValue)) { - newValue = toPlainObject(objValue); - } - else if (!isObject(objValue) || (srcIndex && isFunction(objValue))) { - newValue = initCloneObject(srcValue); - } - } - else { - isCommon = false; - } - } - if (isCommon) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, newValue); - mergeFunc(newValue, srcValue, srcIndex, customizer, stack); - stack['delete'](srcValue); - } - assignMergeValue(object, key, newValue); - } - - /** - * The base implementation of `_.orderBy` without param guards. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function[]|Object[]|string[]} iteratees The iteratees to sort by. - * @param {string[]} orders The sort orders of `iteratees`. - * @returns {Array} Returns the new sorted array. - */ - function baseOrderBy(collection, iteratees, orders) { - var index = -1; - iteratees = arrayMap(iteratees.length ? iteratees : [identity], baseUnary(baseIteratee)); - - var result = baseMap(collection, function(value, key, collection) { - var criteria = arrayMap(iteratees, function(iteratee) { - return iteratee(value); - }); - return { 'criteria': criteria, 'index': ++index, 'value': value }; }); - return baseSortBy(result, function(object, other) { - return compareMultiple(object, other, orders); - }); - } - - /** - * The base implementation of `_.pick` without support for individual - * property identifiers. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @returns {Object} Returns the new object. - */ - function basePick(object, paths) { - return basePickBy(object, paths, function(value, path) { - return hasIn(object, path); + /** + * Creates an array of values by running each element in `collection` thru + * `iteratee`. The iteratee is invoked with three arguments: + * (value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. + * + * The guarded methods are: + * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, + * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, + * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, + * `template`, `trim`, `trimEnd`, `trimStart`, and `words` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new mapped array. + * @example + * + * function square(n) { + * return n * n; + * } + * + * _.map([4, 8], square); + * // => [16, 64] + * + * _.map({ 'a': 4, 'b': 8 }, square); + * // => [16, 64] (iteration order is not guaranteed) + * + * var users = [ + * { 'user': 'barney' }, + * { 'user': 'fred' } + * ]; + * + * // The `_.property` iteratee shorthand. + * _.map(users, 'user'); + * // => ['barney', 'fred'] + */ + function map(collection, iteratee) { + var func = isArray(collection) ? arrayMap : baseMap; + return func(collection, baseIteratee(iteratee, 3)); + } + + /** + * Reduces `collection` to a value which is the accumulated result of running + * each element in `collection` thru `iteratee`, where each successive + * invocation is supplied the return value of the previous. If `accumulator` + * is not given, the first element of `collection` is used as the initial + * value. The iteratee is invoked with four arguments: + * (accumulator, value, index|key, collection). + * + * Many lodash methods are guarded to work as iteratees for methods like + * `_.reduce`, `_.reduceRight`, and `_.transform`. + * + * The guarded methods are: + * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, + * and `sortBy` + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [iteratee=_.identity] The function invoked per iteration. + * @param {*} [accumulator] The initial value. + * @returns {*} Returns the accumulated value. + * @see _.reduceRight + * @example + * + * _.reduce([1, 2], function(sum, n) { + * return sum + n; + * }, 0); + * // => 3 + * + * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { + * (result[value] || (result[value] = [])).push(key); + * return result; + * }, {}); + * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) + */ + function reduce(collection, iteratee, accumulator) { + var func = isArray(collection) ? arrayReduce : baseReduce, + initAccum = arguments.length < 3; + + return func(collection, baseIteratee(iteratee, 4), accumulator, initAccum, baseEach); + } + + /** + * The opposite of `_.filter`; this method returns the elements of `collection` + * that `predicate` does **not** return truthy for. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {Array} Returns the new filtered array. + * @see _.filter + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': false }, + * { 'user': 'fred', 'age': 40, 'active': true } + * ]; + * + * _.reject(users, function(o) { return !o.active; }); + * // => objects for ['fred'] + * + * // The `_.matches` iteratee shorthand. + * _.reject(users, { 'age': 40, 'active': true }); + * // => objects for ['barney'] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.reject(users, ['active', false]); + * // => objects for ['fred'] + * + * // The `_.property` iteratee shorthand. + * _.reject(users, 'active'); + * // => objects for ['barney'] + */ + function reject(collection, predicate) { + var func = isArray(collection) ? arrayFilter : baseFilter; + return func(collection, negate(baseIteratee(predicate, 3))); + } + + /** + * Gets the size of `collection` by returning its length for array-like + * values or the number of own enumerable string keyed properties for objects. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object|string} collection The collection to inspect. + * @returns {number} Returns the collection size. + * @example + * + * _.size([1, 2, 3]); + * // => 3 + * + * _.size({ 'a': 1, 'b': 2 }); + * // => 2 + * + * _.size('pebbles'); + * // => 7 + */ + function size(collection) { + if (collection == null) { + return 0; + } + if (isArrayLike(collection)) { + return isString(collection) ? stringSize(collection) : collection.length; + } + var tag = getTag(collection); + if (tag == mapTag || tag == setTag) { + return collection.size; + } + return baseKeys(collection).length; + } + + /** + * Checks if `predicate` returns truthy for **any** element of `collection`. + * Iteration is stopped once `predicate` returns truthy. The predicate is + * invoked with three arguments: (value, index|key, collection). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {boolean} Returns `true` if any element passes the predicate check, + * else `false`. + * @example + * + * _.some([null, 0, 'yes', false], Boolean); + * // => true + * + * var users = [ + * { 'user': 'barney', 'active': true }, + * { 'user': 'fred', 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.some(users, { 'user': 'barney', 'active': false }); + * // => false + * + * // The `_.matchesProperty` iteratee shorthand. + * _.some(users, ['active', false]); + * // => true + * + * // The `_.property` iteratee shorthand. + * _.some(users, 'active'); + * // => true + */ + function some(collection, predicate, guard) { + var func = isArray(collection) ? arraySome : baseSome; + if (guard && isIterateeCall(collection, predicate, guard)) { + predicate = undefined; + } + return func(collection, baseIteratee(predicate, 3)); + } + + /** + * Creates an array of elements, sorted in ascending order by the results of + * running each element in a collection thru each iteratee. This method + * performs a stable sort, that is, it preserves the original sort order of + * equal elements. The iteratees are invoked with one argument: (value). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Collection + * @param {Array|Object} collection The collection to iterate over. + * @param {...(Function|Function[])} [iteratees=[_.identity]] + * The iteratees to sort by. + * @returns {Array} Returns the new sorted array. + * @example + * + * var users = [ + * { 'user': 'fred', 'age': 48 }, + * { 'user': 'barney', 'age': 36 }, + * { 'user': 'fred', 'age': 40 }, + * { 'user': 'barney', 'age': 34 } + * ]; + * + * _.sortBy(users, [function(o) { return o.user; }]); + * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] + * + * _.sortBy(users, ['user', 'age']); + * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] + */ + var sortBy = baseRest(function (collection, iteratees) { + if (collection == null) { + return []; + } + var length = iteratees.length; + if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { + iteratees = []; + } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { + iteratees = [iteratees[0]]; + } + return baseOrderBy(collection, baseFlatten(iteratees, 1), []); }); - } - - /** - * The base implementation of `_.pickBy` without support for iteratee shorthands. - * - * @private - * @param {Object} object The source object. - * @param {string[]} paths The property paths to pick. - * @param {Function} predicate The function invoked per property. - * @returns {Object} Returns the new object. - */ - function basePickBy(object, paths, predicate) { - var index = -1, - length = paths.length, - result = {}; - - while (++index < length) { - var path = paths[index], - value = baseGet(object, path); - - if (predicate(value, path)) { - baseSet(result, castPath(path, object), value); - } - } - return result; - } - - /** - * A specialized version of `baseProperty` which supports deep paths. - * - * @private - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. - */ - function basePropertyDeep(path) { - return function(object) { - return baseGet(object, path); + + /*------------------------------------------------------------------------*/ + + /** + * Gets the timestamp of the number of milliseconds that have elapsed since + * the Unix epoch (1 January 1970 00:00:00 UTC). + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Date + * @returns {number} Returns the timestamp. + * @example + * + * _.defer(function(stamp) { + * console.log(_.now() - stamp); + * }, _.now()); + * // => Logs the number of milliseconds it took for the deferred invocation. + */ + var now = function () { + return root.Date.now(); }; - } - - /** - * The base implementation of `_.random` without support for returning - * floating-point numbers. - * - * @private - * @param {number} lower The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the random number. - */ - function baseRandom(lower, upper) { - return lower + nativeFloor(nativeRandom() * (upper - lower + 1)); - } - - /** - * The base implementation of `_.range` and `_.rangeRight` which doesn't - * coerce arguments. - * - * @private - * @param {number} start The start of the range. - * @param {number} end The end of the range. - * @param {number} step The value to increment or decrement by. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Array} Returns the range of numbers. - */ - function baseRange(start, end, step, fromRight) { - var index = -1, - length = nativeMax(nativeCeil((end - start) / (step || 1)), 0), - result = Array(length); - - while (length--) { - result[fromRight ? length : ++index] = start; - start += step; - } - return result; - } - - /** - * The base implementation of `_.rest` which doesn't validate or coerce arguments. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - */ - function baseRest(func, start) { - return setToString(overRest(func, start, identity), func + ''); - } - - /** - * The base implementation of `_.set`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @param {Function} [customizer] The function to customize path creation. - * @returns {Object} Returns `object`. - */ - function baseSet(object, path, value, customizer) { - if (!isObject(object)) { - return object; - } - path = castPath(path, object); - - var index = -1, - length = path.length, - lastIndex = length - 1, - nested = object; - - while (nested != null && ++index < length) { - var key = toKey(path[index]), - newValue = value; - - if (index != lastIndex) { - var objValue = nested[key]; - newValue = customizer ? customizer(objValue, key, nested) : undefined; - if (newValue === undefined) { - newValue = isObject(objValue) - ? objValue - : (isIndex(path[index + 1]) ? [] : {}); - } - } - assignValue(nested, key, newValue); - nested = nested[key]; - } - return object; - } - - /** - * The base implementation of `setData` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var baseSetData = !metaMap ? identity : function(func, data) { - metaMap.set(func, data); - return func; - }; - - /** - * The base implementation of `setToString` without support for hot loop shorting. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var baseSetToString = !defineProperty ? identity : function(func, string) { - return defineProperty(func, 'toString', { - 'configurable': true, - 'enumerable': false, - 'value': constant(string), - 'writable': true - }); - }; - - /** - * The base implementation of `_.slice` without an iteratee call guard. - * - * @private - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function baseSlice(array, start, end) { - var index = -1, - length = array.length; - - if (start < 0) { - start = -start > length ? 0 : (length + start); - } - end = end > length ? length : end; - if (end < 0) { - end += length; - } - length = start > end ? 0 : ((end - start) >>> 0); - start >>>= 0; - - var result = Array(length); - while (++index < length) { - result[index] = array[index + start]; - } - return result; - } - - /** - * The base implementation of `_.some` without support for iteratee shorthands. - * - * @private - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} predicate The function invoked per iteration. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - */ - function baseSome(collection, predicate) { - var result; - - baseEach(collection, function(value, index, collection) { - result = predicate(value, index, collection); - return !result; - }); - return !!result; - } - - /** - * The base implementation of `_.toString` which doesn't convert nullish - * values to empty strings. - * - * @private - * @param {*} value The value to process. - * @returns {string} Returns the string. - */ - function baseToString(value) { - // Exit early for strings to avoid a performance hit in some environments. - if (typeof value == 'string') { - return value; - } - if (isArray(value)) { - // Recursively convert values (susceptible to call stack limits). - return arrayMap(value, baseToString) + ''; - } - if (isSymbol(value)) { - return symbolToString ? symbolToString.call(value) : ''; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * The base implementation of `_.uniqBy` without support for iteratee shorthands. - * - * @private - * @param {Array} array The array to inspect. - * @param {Function} [iteratee] The iteratee invoked per element. - * @param {Function} [comparator] The comparator invoked per element. - * @returns {Array} Returns the new duplicate free array. - */ - function baseUniq(array, iteratee, comparator) { - var index = -1, - includes = arrayIncludes, - length = array.length, - isCommon = true, - result = [], - seen = result; - - if (comparator) { - isCommon = false; - includes = arrayIncludesWith; - } - else if (length >= LARGE_ARRAY_SIZE) { - var set = iteratee ? null : createSet(array); - if (set) { - return setToArray(set); - } - isCommon = false; - includes = cacheHas; - seen = new SetCache; - } - else { - seen = iteratee ? [] : result; - } - outer: - while (++index < length) { - var value = array[index], - computed = iteratee ? iteratee(value) : value; - - value = (comparator || value !== 0) ? value : 0; - if (isCommon && computed === computed) { - var seenIndex = seen.length; - while (seenIndex--) { - if (seen[seenIndex] === computed) { - continue outer; - } + + /*------------------------------------------------------------------------*/ + + /** + * The opposite of `_.before`; this method creates a function that invokes + * `func` once it's called `n` or more times. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {number} n The number of calls before `func` is invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var saves = ['profile', 'settings']; + * + * var done = _.after(saves.length, function() { + * console.log('done saving!'); + * }); + * + * _.forEach(saves, function(type) { + * asyncSave({ 'type': type, 'complete': done }); + * }); + * // => Logs 'done saving!' after the two async saves have completed. + */ + function after(n, func) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); } - if (iteratee) { - seen.push(computed); - } - result.push(value); - } - else if (!includes(seen, computed, comparator)) { - if (seen !== result) { - seen.push(computed); - } - result.push(value); - } - } - return result; - } - - /** - * The base implementation of `_.unset`. - * - * @private - * @param {Object} object The object to modify. - * @param {Array|string} path The property path to unset. - * @returns {boolean} Returns `true` if the property is deleted, else `false`. - */ - function baseUnset(object, path) { - path = castPath(path, object); - object = parent(object, path); - return object == null || delete object[toKey(last(path))]; - } - - /** - * The base implementation of `wrapperValue` which returns the result of - * performing a sequence of actions on the unwrapped `value`, where each - * successive action is supplied the return value of the previous. - * - * @private - * @param {*} value The unwrapped value. - * @param {Array} actions Actions to perform to resolve the unwrapped value. - * @returns {*} Returns the resolved value. - */ - function baseWrapperValue(value, actions) { - var result = value; - if (result instanceof LazyWrapper) { - result = result.value(); - } - return arrayReduce(actions, function(result, action) { - return action.func.apply(action.thisArg, arrayPush([result], action.args)); - }, result); - } - - /** - * This base implementation of `_.zipObject` which assigns values using `assignFunc`. - * - * @private - * @param {Array} props The property identifiers. - * @param {Array} values The property values. - * @param {Function} assignFunc The function to assign values. - * @returns {Object} Returns the new object. - */ - function baseZipObject(props, values, assignFunc) { - var index = -1, - length = props.length, - valsLength = values.length, - result = {}; - - while (++index < length) { - var value = index < valsLength ? values[index] : undefined; - assignFunc(result, props[index], value); - } - return result; - } - - /** - * Casts `value` to an empty array if it's not an array like object. - * - * @private - * @param {*} value The value to inspect. - * @returns {Array|Object} Returns the cast array-like object. - */ - function castArrayLikeObject(value) { - return isArrayLikeObject(value) ? value : []; - } - - /** - * Casts `value` to a path array if it's not one. - * - * @private - * @param {*} value The value to inspect. - * @param {Object} [object] The object to query keys on. - * @returns {Array} Returns the cast property path array. - */ - function castPath(value, object) { - if (isArray(value)) { - return value; - } - return isKey(value, object) ? [value] : stringToPath(toString(value)); - } - - /** - * Casts `array` to a slice if it's needed. - * - * @private - * @param {Array} array The array to inspect. - * @param {number} start The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the cast slice. - */ - function castSlice(array, start, end) { - var length = array.length; - end = end === undefined ? length : end; - return (!start && end >= length) ? array : baseSlice(array, start, end); - } - - /** - * Creates a clone of `buffer`. - * - * @private - * @param {Buffer} buffer The buffer to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Buffer} Returns the cloned buffer. - */ - function cloneBuffer(buffer, isDeep) { - if (isDeep) { - return buffer.slice(); - } - var length = buffer.length, - result = allocUnsafe ? allocUnsafe(length) : new buffer.constructor(length); - - buffer.copy(result); - return result; - } - - /** - * Creates a clone of `arrayBuffer`. - * - * @private - * @param {ArrayBuffer} arrayBuffer The array buffer to clone. - * @returns {ArrayBuffer} Returns the cloned array buffer. - */ - function cloneArrayBuffer(arrayBuffer) { - var result = new arrayBuffer.constructor(arrayBuffer.byteLength); - new Uint8Array(result).set(new Uint8Array(arrayBuffer)); - return result; - } - - /** - * Creates a clone of `dataView`. - * - * @private - * @param {Object} dataView The data view to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned data view. - */ - function cloneDataView(dataView, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(dataView.buffer) : dataView.buffer; - return new dataView.constructor(buffer, dataView.byteOffset, dataView.byteLength); - } - - /** - * Creates a clone of `regexp`. - * - * @private - * @param {Object} regexp The regexp to clone. - * @returns {Object} Returns the cloned regexp. - */ - function cloneRegExp(regexp) { - var result = new regexp.constructor(regexp.source, reFlags.exec(regexp)); - result.lastIndex = regexp.lastIndex; - return result; - } - - /** - * Creates a clone of the `symbol` object. - * - * @private - * @param {Object} symbol The symbol object to clone. - * @returns {Object} Returns the cloned symbol object. - */ - function cloneSymbol(symbol) { - return symbolValueOf ? Object(symbolValueOf.call(symbol)) : {}; - } - - /** - * Creates a clone of `typedArray`. - * - * @private - * @param {Object} typedArray The typed array to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the cloned typed array. - */ - function cloneTypedArray(typedArray, isDeep) { - var buffer = isDeep ? cloneArrayBuffer(typedArray.buffer) : typedArray.buffer; - return new typedArray.constructor(buffer, typedArray.byteOffset, typedArray.length); - } - - /** - * Compares values to sort them in ascending order. - * - * @private - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {number} Returns the sort order indicator for `value`. - */ - function compareAscending(value, other) { - if (value !== other) { - var valIsDefined = value !== undefined, - valIsNull = value === null, - valIsReflexive = value === value, - valIsSymbol = isSymbol(value); - - var othIsDefined = other !== undefined, - othIsNull = other === null, - othIsReflexive = other === other, - othIsSymbol = isSymbol(other); - - if ((!othIsNull && !othIsSymbol && !valIsSymbol && value > other) || - (valIsSymbol && othIsDefined && othIsReflexive && !othIsNull && !othIsSymbol) || - (valIsNull && othIsDefined && othIsReflexive) || - (!valIsDefined && othIsReflexive) || - !valIsReflexive) { - return 1; - } - if ((!valIsNull && !valIsSymbol && !othIsSymbol && value < other) || - (othIsSymbol && valIsDefined && valIsReflexive && !valIsNull && !valIsSymbol) || - (othIsNull && valIsDefined && valIsReflexive) || - (!othIsDefined && valIsReflexive) || - !othIsReflexive) { - return -1; - } - } - return 0; - } - - /** - * Used by `_.orderBy` to compare multiple properties of a value to another - * and stable sort them. - * - * If `orders` is unspecified, all values are sorted in ascending order. Otherwise, - * specify an order of "desc" for descending or "asc" for ascending sort order - * of corresponding values. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {boolean[]|string[]} orders The order to sort by for each property. - * @returns {number} Returns the sort order indicator for `object`. - */ - function compareMultiple(object, other, orders) { - var index = -1, - objCriteria = object.criteria, - othCriteria = other.criteria, - length = objCriteria.length, - ordersLength = orders.length; - - while (++index < length) { - var result = compareAscending(objCriteria[index], othCriteria[index]); - if (result) { - if (index >= ordersLength) { - return result; - } - var order = orders[index]; - return result * (order == 'desc' ? -1 : 1); - } - } - // Fixes an `Array#sort` bug in the JS engine embedded in Adobe applications - // that causes it, under certain circumstances, to provide the same value for - // `object` and `other`. See https://github.com/jashkenas/underscore/pull/1247 - // for more details. - // - // This also ensures a stable sort in V8 and other engines. - // See https://bugs.chromium.org/p/v8/issues/detail?id=90 for more details. - return object.index - other.index; - } - - /** - * Creates an array that is the composition of partially applied arguments, - * placeholders, and provided arguments into a single array of arguments. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to prepend to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgs(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersLength = holders.length, - leftIndex = -1, - leftLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(leftLength + rangeLength), - isUncurried = !isCurried; - - while (++leftIndex < leftLength) { - result[leftIndex] = partials[leftIndex]; - } - while (++argsIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[holders[argsIndex]] = args[argsIndex]; - } - } - while (rangeLength--) { - result[leftIndex++] = args[argsIndex++]; - } - return result; - } - - /** - * This function is like `composeArgs` except that the arguments composition - * is tailored for `_.partialRight`. - * - * @private - * @param {Array} args The provided arguments. - * @param {Array} partials The arguments to append to those provided. - * @param {Array} holders The `partials` placeholder indexes. - * @params {boolean} [isCurried] Specify composing for a curried function. - * @returns {Array} Returns the new array of composed arguments. - */ - function composeArgsRight(args, partials, holders, isCurried) { - var argsIndex = -1, - argsLength = args.length, - holdersIndex = -1, - holdersLength = holders.length, - rightIndex = -1, - rightLength = partials.length, - rangeLength = nativeMax(argsLength - holdersLength, 0), - result = Array(rangeLength + rightLength), - isUncurried = !isCurried; - - while (++argsIndex < rangeLength) { - result[argsIndex] = args[argsIndex]; - } - var offset = argsIndex; - while (++rightIndex < rightLength) { - result[offset + rightIndex] = partials[rightIndex]; - } - while (++holdersIndex < holdersLength) { - if (isUncurried || argsIndex < argsLength) { - result[offset + holders[holdersIndex]] = args[argsIndex++]; - } - } - return result; - } - - /** - * Copies the values of `source` to `array`. - * - * @private - * @param {Array} source The array to copy values from. - * @param {Array} [array=[]] The array to copy values to. - * @returns {Array} Returns `array`. - */ - function copyArray(source, array) { - var index = -1, - length = source.length; - - array || (array = Array(length)); - while (++index < length) { - array[index] = source[index]; - } - return array; - } - - /** - * Copies properties of `source` to `object`. - * - * @private - * @param {Object} source The object to copy properties from. - * @param {Array} props The property identifiers to copy. - * @param {Object} [object={}] The object to copy properties to. - * @param {Function} [customizer] The function to customize copied values. - * @returns {Object} Returns `object`. - */ - function copyObject(source, props, object, customizer) { - var isNew = !object; - object || (object = {}); - - var index = -1, - length = props.length; - - while (++index < length) { - var key = props[index]; - - var newValue = customizer - ? customizer(object[key], source[key], key, object, source) - : undefined; - - if (newValue === undefined) { - newValue = source[key]; - } - if (isNew) { - baseAssignValue(object, key, newValue); - } else { - assignValue(object, key, newValue); - } - } - return object; - } - - /** - * Copies own symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbols(source, object) { - return copyObject(source, getSymbols(source), object); - } - - /** - * Copies own and inherited symbols of `source` to `object`. - * - * @private - * @param {Object} source The object to copy symbols from. - * @param {Object} [object={}] The object to copy symbols to. - * @returns {Object} Returns `object`. - */ - function copySymbolsIn(source, object) { - return copyObject(source, getSymbolsIn(source), object); - } - - /** - * Creates a function like `_.groupBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} [initializer] The accumulator object initializer. - * @returns {Function} Returns the new aggregator function. - */ - function createAggregator(setter, initializer) { - return function(collection, iteratee) { - var func = isArray(collection) ? arrayAggregator : baseAggregator, - accumulator = initializer ? initializer() : {}; - - return func(collection, setter, baseIteratee(iteratee, 2), accumulator); - }; - } - - /** - * Creates a function like `_.assign`. - * - * @private - * @param {Function} assigner The function to assign values. - * @returns {Function} Returns the new assigner function. - */ - function createAssigner(assigner) { - return baseRest(function(object, sources) { - var index = -1, - length = sources.length, - customizer = length > 1 ? sources[length - 1] : undefined, - guard = length > 2 ? sources[2] : undefined; - - customizer = (assigner.length > 3 && typeof customizer == 'function') - ? (length--, customizer) - : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - customizer = length < 3 ? undefined : customizer; - length = 1; - } - object = Object(object); - while (++index < length) { - var source = sources[index]; - if (source) { - assigner(object, source, index, customizer); - } - } - return object; + n = toInteger(n); + return function () { + if (--n < 1) { + return func.apply(this, arguments); + } + }; + } + + /** + * Creates a function that invokes `func`, with the `this` binding and arguments + * of the created function, while it's called less than `n` times. Subsequent + * calls to the created function return the result of the last `func` invocation. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {number} n The number of calls at which `func` is no longer invoked. + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * jQuery(element).on('click', _.before(5, addContactToList)); + * // => Allows adding up to 4 contacts to the list. + */ + function before(n, func) { + var result; + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + n = toInteger(n); + return function () { + if (--n > 0) { + result = func.apply(this, arguments); + } + if (n <= 1) { + func = undefined; + } + return result; + }; + } + + /** + * Creates a function that invokes `func` with the `this` binding of `thisArg` + * and `partials` prepended to the arguments it receives. + * + * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, + * may be used as a placeholder for partially applied arguments. + * + * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" + * property of bound functions. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to bind. + * @param {*} thisArg The `this` binding of `func`. + * @param {...*} [partials] The arguments to be partially applied. + * @returns {Function} Returns the new bound function. + * @example + * + * function greet(greeting, punctuation) { + * return greeting + ' ' + this.user + punctuation; + * } + * + * var object = { 'user': 'fred' }; + * + * var bound = _.bind(greet, object, 'hi'); + * bound('!'); + * // => 'hi fred!' + * + * // Bound with placeholders. + * var bound = _.bind(greet, object, _, '!'); + * bound('hi'); + * // => 'hi fred!' + */ + var bind = baseRest(function (func, thisArg, partials) { + var bitmask = WRAP_BIND_FLAG; + if (partials.length) { + var holders = replaceHolders(partials, getHolder(bind)); + bitmask |= WRAP_PARTIAL_FLAG; + } + return createWrap(func, bitmask, thisArg, partials, holders); }); - } - - /** - * Creates a `baseEach` or `baseEachRight` function. - * - * @private - * @param {Function} eachFunc The function to iterate over a collection. - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseEach(eachFunc, fromRight) { - return function(collection, iteratee) { - if (collection == null) { - return collection; - } - if (!isArrayLike(collection)) { - return eachFunc(collection, iteratee); - } - var length = collection.length, - index = fromRight ? length : -1, - iterable = Object(collection); - - while ((fromRight ? index-- : ++index < length)) { - if (iteratee(iterable[index], index, iterable) === false) { - break; - } - } - return collection; - }; - } - - /** - * Creates a base function for methods like `_.forIn` and `_.forOwn`. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new base function. - */ - function createBaseFor(fromRight) { - return function(object, iteratee, keysFunc) { - var index = -1, - iterable = Object(object), - props = keysFunc(object), - length = props.length; - - while (length--) { - var key = props[fromRight ? length : ++index]; - if (iteratee(iterable[key], key, iterable) === false) { - break; - } - } - return object; - }; - } - - /** - * Creates a function that wraps `func` to invoke it with the optional `this` - * binding of `thisArg`. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createBind(func, bitmask, thisArg) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return fn.apply(isBind ? thisArg : this, arguments); - } - return wrapper; - } - - /** - * Creates a function that produces an instance of `Ctor` regardless of - * whether it was invoked as part of a `new` expression or by `call` or `apply`. - * - * @private - * @param {Function} Ctor The constructor to wrap. - * @returns {Function} Returns the new wrapped function. - */ - function createCtor(Ctor) { - return function() { - // Use a `switch` statement to work with class constructors. See - // http://ecma-international.org/ecma-262/7.0/#sec-ecmascript-function-objects-call-thisargument-argumentslist - // for more details. - var args = arguments; - switch (args.length) { - case 0: return new Ctor; - case 1: return new Ctor(args[0]); - case 2: return new Ctor(args[0], args[1]); - case 3: return new Ctor(args[0], args[1], args[2]); - case 4: return new Ctor(args[0], args[1], args[2], args[3]); - case 5: return new Ctor(args[0], args[1], args[2], args[3], args[4]); - case 6: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5]); - case 7: return new Ctor(args[0], args[1], args[2], args[3], args[4], args[5], args[6]); - } - var thisBinding = baseCreate(Ctor.prototype), - result = Ctor.apply(thisBinding, args); - - // Mimic the constructor's `return` behavior. - // See https://es5.github.io/#x13.2.2 for more details. - return isObject(result) ? result : thisBinding; - }; - } - - /** - * Creates a function that wraps `func` to enable currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {number} arity The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createCurry(func, bitmask, arity) { - var Ctor = createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length, - placeholder = getHolder(wrapper); - - while (index--) { - args[index] = arguments[index]; - } - var holders = (length < 3 && args[0] !== placeholder && args[length - 1] !== placeholder) - ? [] - : replaceHolders(args, placeholder); - - length -= holders.length; - if (length < arity) { - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, undefined, - args, holders, undefined, undefined, arity - length); - } - var fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - return apply(fn, this, args); - } - return wrapper; - } - - /** - * Creates a `_.find` or `_.findLast` function. - * - * @private - * @param {Function} findIndexFunc The function to find the collection index. - * @returns {Function} Returns the new find function. - */ - function createFind(findIndexFunc) { - return function(collection, predicate, fromIndex) { - var iterable = Object(collection); - if (!isArrayLike(collection)) { - var iteratee = baseIteratee(predicate, 3); - collection = keys(collection); - predicate = function(key) { return iteratee(iterable[key], key, iterable); }; - } - var index = findIndexFunc(collection, predicate, fromIndex); - return index > -1 ? iterable[iteratee ? collection[index] : index] : undefined; - }; - } - - /** - * Creates a function that wraps `func` to invoke it with optional `this` - * binding of `thisArg`, partial application, and currying. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [partialsRight] The arguments to append to those provided - * to the new function. - * @param {Array} [holdersRight] The `partialsRight` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createHybrid(func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, argPos, ary, arity) { - var isAry = bitmask & WRAP_ARY_FLAG, - isBind = bitmask & WRAP_BIND_FLAG, - isBindKey = bitmask & WRAP_BIND_KEY_FLAG, - isCurried = bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG), - isFlip = bitmask & WRAP_FLIP_FLAG, - Ctor = isBindKey ? undefined : createCtor(func); - - function wrapper() { - var length = arguments.length, - args = Array(length), - index = length; - - while (index--) { - args[index] = arguments[index]; - } - if (isCurried) { - var placeholder = getHolder(wrapper), - holdersCount = countHolders(args, placeholder); - } - if (partials) { - args = composeArgs(args, partials, holders, isCurried); - } - if (partialsRight) { - args = composeArgsRight(args, partialsRight, holdersRight, isCurried); - } - length -= holdersCount; - if (isCurried && length < arity) { - var newHolders = replaceHolders(args, placeholder); - return createRecurry( - func, bitmask, createHybrid, wrapper.placeholder, thisArg, - args, newHolders, argPos, ary, arity - length - ); - } - var thisBinding = isBind ? thisArg : this, - fn = isBindKey ? thisBinding[func] : func; - - length = args.length; - if (argPos) { - args = reorder(args, argPos); - } else if (isFlip && length > 1) { - args.reverse(); - } - if (isAry && ary < length) { - args.length = ary; - } - if (this && this !== root && this instanceof wrapper) { - fn = Ctor || createCtor(fn); - } - return fn.apply(thisBinding, args); - } - return wrapper; - } - - /** - * Creates a function like `_.invertBy`. - * - * @private - * @param {Function} setter The function to set accumulator values. - * @param {Function} toIteratee The function to resolve iteratees. - * @returns {Function} Returns the new inverter function. - */ - function createInverter(setter, toIteratee) { - return function(object, iteratee) { - return baseInverter(object, setter, toIteratee(iteratee), {}); - }; - } - - /** - * Creates a function that wraps `func` to invoke it with the `this` binding - * of `thisArg` and `partials` prepended to the arguments it receives. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {*} thisArg The `this` binding of `func`. - * @param {Array} partials The arguments to prepend to those provided to - * the new function. - * @returns {Function} Returns the new wrapped function. - */ - function createPartial(func, bitmask, thisArg, partials) { - var isBind = bitmask & WRAP_BIND_FLAG, - Ctor = createCtor(func); - - function wrapper() { - var argsIndex = -1, - argsLength = arguments.length, - leftIndex = -1, - leftLength = partials.length, - args = Array(leftLength + argsLength), - fn = (this && this !== root && this instanceof wrapper) ? Ctor : func; - - while (++leftIndex < leftLength) { - args[leftIndex] = partials[leftIndex]; - } - while (argsLength--) { - args[leftIndex++] = arguments[++argsIndex]; - } - return apply(fn, isBind ? thisArg : this, args); - } - return wrapper; - } - - /** - * Creates a `_.range` or `_.rangeRight` function. - * - * @private - * @param {boolean} [fromRight] Specify iterating from right to left. - * @returns {Function} Returns the new range function. - */ - function createRange(fromRight) { - return function(start, end, step) { - if (step && typeof step != 'number' && isIterateeCall(start, end, step)) { - end = step = undefined; - } - // Ensure the sign of `-0` is preserved. - start = toFinite(start); - if (end === undefined) { - end = start; - start = 0; - } else { - end = toFinite(end); - } - step = step === undefined ? (start < end ? 1 : -1) : toFinite(step); - return baseRange(start, end, step, fromRight); - }; - } - - /** - * Creates a function that wraps `func` to continue currying. - * - * @private - * @param {Function} func The function to wrap. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @param {Function} wrapFunc The function to create the `func` wrapper. - * @param {*} placeholder The placeholder value. - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to prepend to those provided to - * the new function. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createRecurry(func, bitmask, wrapFunc, placeholder, thisArg, partials, holders, argPos, ary, arity) { - var isCurry = bitmask & WRAP_CURRY_FLAG, - newHolders = isCurry ? holders : undefined, - newHoldersRight = isCurry ? undefined : holders, - newPartials = isCurry ? partials : undefined, - newPartialsRight = isCurry ? undefined : partials; - - bitmask |= (isCurry ? WRAP_PARTIAL_FLAG : WRAP_PARTIAL_RIGHT_FLAG); - bitmask &= ~(isCurry ? WRAP_PARTIAL_RIGHT_FLAG : WRAP_PARTIAL_FLAG); - - if (!(bitmask & WRAP_CURRY_BOUND_FLAG)) { - bitmask &= ~(WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG); - } - var newData = [ - func, bitmask, thisArg, newPartials, newHolders, newPartialsRight, - newHoldersRight, argPos, ary, arity - ]; - var result = wrapFunc.apply(undefined, newData); - if (isLaziable(func)) { - setData(result, newData); - } - result.placeholder = placeholder; - return setWrapToString(result, func, bitmask); - } - - /** - * Creates a set object of `values`. - * - * @private - * @param {Array} values The values to add to the set. - * @returns {Object} Returns the new set. - */ - var createSet = !(Set && (1 / setToArray(new Set([,-0]))[1]) == INFINITY) ? noop : function(values) { - return new Set(values); - }; - - /** - * Creates a function that either curries or invokes `func` with optional - * `this` binding and partially applied arguments. - * - * @private - * @param {Function|string} func The function or method name to wrap. - * @param {number} bitmask The bitmask flags. - * 1 - `_.bind` - * 2 - `_.bindKey` - * 4 - `_.curry` or `_.curryRight` of a bound function - * 8 - `_.curry` - * 16 - `_.curryRight` - * 32 - `_.partial` - * 64 - `_.partialRight` - * 128 - `_.rearg` - * 256 - `_.ary` - * 512 - `_.flip` - * @param {*} [thisArg] The `this` binding of `func`. - * @param {Array} [partials] The arguments to be partially applied. - * @param {Array} [holders] The `partials` placeholder indexes. - * @param {Array} [argPos] The argument positions of the new function. - * @param {number} [ary] The arity cap of `func`. - * @param {number} [arity] The arity of `func`. - * @returns {Function} Returns the new wrapped function. - */ - function createWrap(func, bitmask, thisArg, partials, holders, argPos, ary, arity) { - var isBindKey = bitmask & WRAP_BIND_KEY_FLAG; - if (!isBindKey && typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - var length = partials ? partials.length : 0; - if (!length) { - bitmask &= ~(WRAP_PARTIAL_FLAG | WRAP_PARTIAL_RIGHT_FLAG); - partials = holders = undefined; - } - ary = ary === undefined ? ary : nativeMax(toInteger(ary), 0); - arity = arity === undefined ? arity : toInteger(arity); - length -= holders ? holders.length : 0; - - if (bitmask & WRAP_PARTIAL_RIGHT_FLAG) { - var partialsRight = partials, - holdersRight = holders; - - partials = holders = undefined; - } - var data = isBindKey ? undefined : getData(func); - - var newData = [ - func, bitmask, thisArg, partials, holders, partialsRight, holdersRight, - argPos, ary, arity - ]; + /** + * Creates a debounced function that delays invoking `func` until after `wait` + * milliseconds have elapsed since the last time the debounced function was + * invoked. The debounced function comes with a `cancel` method to cancel + * delayed `func` invocations and a `flush` method to immediately invoke them. + * Provide `options` to indicate whether `func` should be invoked on the + * leading and/or trailing edge of the `wait` timeout. The `func` is invoked + * with the last arguments provided to the debounced function. Subsequent + * calls to the debounced function return the result of the last `func` + * invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the debounced function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.debounce` and `_.throttle`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to debounce. + * @param {number} [wait=0] The number of milliseconds to delay. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=false] + * Specify invoking on the leading edge of the timeout. + * @param {number} [options.maxWait] + * The maximum time `func` is allowed to be delayed before it's invoked. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new debounced function. + * @example + * + * // Avoid costly calculations while the window size is in flux. + * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); + * + * // Invoke `sendMail` when clicked, debouncing subsequent calls. + * jQuery(element).on('click', _.debounce(sendMail, 300, { + * 'leading': true, + * 'trailing': false + * })); + * + * // Ensure `batchLog` is invoked once after 1 second of debounced calls. + * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); + * var source = new EventSource('/stream'); + * jQuery(source).on('message', debounced); + * + * // Cancel the trailing debounced invocation. + * jQuery(window).on('popstate', debounced.cancel); + */ + function debounce(func, wait, options) { + var lastArgs, + lastThis, + maxWait, + result, + timerId, + lastCallTime, + lastInvokeTime = 0, + leading = false, + maxing = false, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + wait = toNumber(wait) || 0; + if (isObject(options)) { + leading = !!options.leading; + maxing = 'maxWait' in options; + maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } - if (data) { - mergeData(newData, data); - } - func = newData[0]; - bitmask = newData[1]; - thisArg = newData[2]; - partials = newData[3]; - holders = newData[4]; - arity = newData[9] = newData[9] === undefined - ? (isBindKey ? 0 : func.length) - : nativeMax(newData[9] - length, 0); - - if (!arity && bitmask & (WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG)) { - bitmask &= ~(WRAP_CURRY_FLAG | WRAP_CURRY_RIGHT_FLAG); - } - if (!bitmask || bitmask == WRAP_BIND_FLAG) { - var result = createBind(func, bitmask, thisArg); - } else if (bitmask == WRAP_CURRY_FLAG || bitmask == WRAP_CURRY_RIGHT_FLAG) { - result = createCurry(func, bitmask, arity); - } else if ((bitmask == WRAP_PARTIAL_FLAG || bitmask == (WRAP_BIND_FLAG | WRAP_PARTIAL_FLAG)) && !holders.length) { - result = createPartial(func, bitmask, thisArg, partials); - } else { - result = createHybrid.apply(undefined, newData); - } - var setter = data ? baseSetData : setData; - return setWrapToString(setter(result, newData), func, bitmask); - } - - /** - * Used by `_.defaultsDeep` to customize its `_.merge` use to merge source - * objects into destination objects that are passed thru. - * - * @private - * @param {*} objValue The destination value. - * @param {*} srcValue The source value. - * @param {string} key The key of the property to merge. - * @param {Object} object The parent object of `objValue`. - * @param {Object} source The parent object of `srcValue`. - * @param {Object} [stack] Tracks traversed source values and their merged - * counterparts. - * @returns {*} Returns the value to assign. - */ - function customDefaultsMerge(objValue, srcValue, key, object, source, stack) { - if (isObject(objValue) && isObject(srcValue)) { - // Recursively merge objects and arrays (susceptible to call stack limits). - stack.set(srcValue, objValue); - baseMerge(objValue, srcValue, undefined, customDefaultsMerge, stack); - stack['delete'](srcValue); - } - return objValue; - } - - /** - * Used by `_.omit` to customize its `_.cloneDeep` use to only clone plain - * objects. - * - * @private - * @param {*} value The value to inspect. - * @param {string} key The key of the property to inspect. - * @returns {*} Returns the uncloned value or `undefined` to defer cloning to `_.cloneDeep`. - */ - function customOmitClone(value) { - return isPlainObject(value) ? undefined : value; - } - - /** - * A specialized version of `baseIsEqualDeep` for arrays with support for - * partial deep comparisons. - * - * @private - * @param {Array} array The array to compare. - * @param {Array} other The other array to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `array` and `other` objects. - * @returns {boolean} Returns `true` if the arrays are equivalent, else `false`. - */ - function equalArrays(array, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - arrLength = array.length, - othLength = other.length; - - if (arrLength != othLength && !(isPartial && othLength > arrLength)) { - return false; - } - // Assume cyclic values are equal. - var stacked = stack.get(array); - if (stacked && stack.get(other)) { - return stacked == other; - } - var index = -1, - result = true, - seen = (bitmask & COMPARE_UNORDERED_FLAG) ? new SetCache : undefined; - - stack.set(array, other); - stack.set(other, array); - - // Ignore non-index properties. - while (++index < arrLength) { - var arrValue = array[index], - othValue = other[index]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, arrValue, index, other, array, stack) - : customizer(arrValue, othValue, index, array, other, stack); - } - if (compared !== undefined) { - if (compared) { - continue; - } - result = false; - break; - } - // Recursively compare arrays (susceptible to call stack limits). - if (seen) { - if (!arraySome(other, function(othValue, othIndex) { - if (!cacheHas(seen, othIndex) && - (arrValue === othValue || equalFunc(arrValue, othValue, bitmask, customizer, stack))) { - return seen.push(othIndex); - } - })) { - result = false; - break; - } - } else if (!( - arrValue === othValue || - equalFunc(arrValue, othValue, bitmask, customizer, stack) - )) { - result = false; - break; - } - } - stack['delete'](array); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseIsEqualDeep` for comparing objects of - * the same `toStringTag`. - * - * **Note:** This function only supports comparing values with tags of - * `Boolean`, `Date`, `Error`, `Number`, `RegExp`, or `String`. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {string} tag The `toStringTag` of the objects to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalByTag(object, other, tag, bitmask, customizer, equalFunc, stack) { - switch (tag) { - case dataViewTag: - if ((object.byteLength != other.byteLength) || - (object.byteOffset != other.byteOffset)) { - return false; - } - object = object.buffer; - other = other.buffer; - - case arrayBufferTag: - if ((object.byteLength != other.byteLength) || - !equalFunc(new Uint8Array(object), new Uint8Array(other))) { - return false; + function invokeFunc(time) { + var args = lastArgs, + thisArg = lastThis; + + lastArgs = lastThis = undefined; + lastInvokeTime = time; + result = func.apply(thisArg, args); + return result; } - return true; - case boolTag: - case dateTag: - case numberTag: - // Coerce booleans to `1` or `0` and dates to milliseconds. - // Invalid dates are coerced to `NaN`. - return eq(+object, +other); + function leadingEdge(time) { + // Reset any `maxWait` timer. + lastInvokeTime = time; + // Start the timer for the trailing edge. + timerId = setTimeout(timerExpired, wait); + // Invoke the leading edge. + return leading ? invokeFunc(time) : result; + } - case errorTag: - return object.name == other.name && object.message == other.message; + function remainingWait(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime, + timeWaiting = wait - timeSinceLastCall; - case regexpTag: - case stringTag: - // Coerce regexes to strings and treat strings, primitives and objects, - // as equal. See http://www.ecma-international.org/ecma-262/7.0/#sec-regexp.prototype.tostring - // for more details. - return object == (other + ''); + return maxing + ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) + : timeWaiting; + } - case mapTag: - var convert = mapToArray; + function shouldInvoke(time) { + var timeSinceLastCall = time - lastCallTime, + timeSinceLastInvoke = time - lastInvokeTime; - case setTag: - var isPartial = bitmask & COMPARE_PARTIAL_FLAG; - convert || (convert = setToArray); + // Either this is the first call, activity has stopped and we're at the + // trailing edge, the system time has gone backwards and we're treating + // it as the trailing edge, or we've hit the `maxWait` limit. + return (lastCallTime === undefined || (timeSinceLastCall >= wait) || + (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); + } - if (object.size != other.size && !isPartial) { - return false; + function timerExpired() { + var time = now(); + if (shouldInvoke(time)) { + return trailingEdge(time); + } + // Restart the timer. + timerId = setTimeout(timerExpired, remainingWait(time)); } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked) { - return stacked == other; + + function trailingEdge(time) { + timerId = undefined; + + // Only invoke if we have `lastArgs` which means `func` has been + // debounced at least once. + if (trailing && lastArgs) { + return invokeFunc(time); + } + lastArgs = lastThis = undefined; + return result; } - bitmask |= COMPARE_UNORDERED_FLAG; - // Recursively compare objects (susceptible to call stack limits). - stack.set(object, other); - var result = equalArrays(convert(object), convert(other), bitmask, customizer, equalFunc, stack); - stack['delete'](object); - return result; + function cancel() { + if (timerId !== undefined) { + clearTimeout(timerId); + } + lastInvokeTime = 0; + lastArgs = lastCallTime = lastThis = timerId = undefined; + } - case symbolTag: - if (symbolValueOf) { - return symbolValueOf.call(object) == symbolValueOf.call(other); - } - } - return false; - } - - /** - * A specialized version of `baseIsEqualDeep` for objects with support for - * partial deep comparisons. - * - * @private - * @param {Object} object The object to compare. - * @param {Object} other The other object to compare. - * @param {number} bitmask The bitmask flags. See `baseIsEqual` for more details. - * @param {Function} customizer The function to customize comparisons. - * @param {Function} equalFunc The function to determine equivalents of values. - * @param {Object} stack Tracks traversed `object` and `other` objects. - * @returns {boolean} Returns `true` if the objects are equivalent, else `false`. - */ - function equalObjects(object, other, bitmask, customizer, equalFunc, stack) { - var isPartial = bitmask & COMPARE_PARTIAL_FLAG, - objProps = getAllKeys(object), - objLength = objProps.length, - othProps = getAllKeys(other), - othLength = othProps.length; - - if (objLength != othLength && !isPartial) { - return false; - } - var index = objLength; - while (index--) { - var key = objProps[index]; - if (!(isPartial ? key in other : hasOwnProperty.call(other, key))) { - return false; - } - } - // Assume cyclic values are equal. - var stacked = stack.get(object); - if (stacked && stack.get(other)) { - return stacked == other; - } - var result = true; - stack.set(object, other); - stack.set(other, object); - - var skipCtor = isPartial; - while (++index < objLength) { - key = objProps[index]; - var objValue = object[key], - othValue = other[key]; - - if (customizer) { - var compared = isPartial - ? customizer(othValue, objValue, key, other, object, stack) - : customizer(objValue, othValue, key, object, other, stack); - } - // Recursively compare objects (susceptible to call stack limits). - if (!(compared === undefined - ? (objValue === othValue || equalFunc(objValue, othValue, bitmask, customizer, stack)) - : compared - )) { - result = false; - break; - } - skipCtor || (skipCtor = key == 'constructor'); - } - if (result && !skipCtor) { - var objCtor = object.constructor, - othCtor = other.constructor; - - // Non `Object` object instances with different constructors are not equal. - if (objCtor != othCtor && - ('constructor' in object && 'constructor' in other) && - !(typeof objCtor == 'function' && objCtor instanceof objCtor && - typeof othCtor == 'function' && othCtor instanceof othCtor)) { - result = false; - } - } - stack['delete'](object); - stack['delete'](other); - return result; - } - - /** - * A specialized version of `baseRest` which flattens the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @returns {Function} Returns the new function. - */ - function flatRest(func) { - return setToString(overRest(func, undefined, flatten), func + ''); - } - - /** - * Creates an array of own enumerable property names and symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeys(object) { - return baseGetAllKeys(object, keys, getSymbols); - } - - /** - * Creates an array of own and inherited enumerable property names and - * symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names and symbols. - */ - function getAllKeysIn(object) { - return baseGetAllKeys(object, keysIn, getSymbolsIn); - } - - /** - * Gets metadata for `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {*} Returns the metadata for `func`. - */ - var getData = !metaMap ? noop : function(func) { - return metaMap.get(func); - }; - - /** - * Gets the name of `func`. - * - * @private - * @param {Function} func The function to query. - * @returns {string} Returns the function name. - */ - function getFuncName(func) { - var result = (func.name + ''), - array = realNames[result], - length = hasOwnProperty.call(realNames, result) ? array.length : 0; - - while (length--) { - var data = array[length], - otherFunc = data.func; - if (otherFunc == null || otherFunc == func) { - return data.name; - } - } - return result; - } - - /** - * Gets the argument placeholder value for `func`. - * - * @private - * @param {Function} func The function to inspect. - * @returns {*} Returns the placeholder value. - */ - function getHolder(func) { - var object = hasOwnProperty.call(lodash, 'placeholder') ? lodash : func; - return object.placeholder; - } - - /** - * Gets the data for `map`. - * - * @private - * @param {Object} map The map to query. - * @param {string} key The reference key. - * @returns {*} Returns the map data. - */ - function getMapData(map, key) { - var data = map.__data__; - return isKeyable(key) - ? data[typeof key == 'string' ? 'string' : 'hash'] - : data.map; - } - - /** - * Gets the property names, values, and compare flags of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the match data of `object`. - */ - function getMatchData(object) { - var result = keys(object), - length = result.length; - - while (length--) { - var key = result[length], - value = object[key]; - - result[length] = [key, value, isStrictComparable(value)]; - } - return result; - } - - /** - * Gets the native function at `key` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {string} key The key of the method to get. - * @returns {*} Returns the function if it's native, else `undefined`. - */ - function getNative(object, key) { - var value = getValue(object, key); - return baseIsNative(value) ? value : undefined; - } - - /** - * A specialized version of `baseGetTag` which ignores `Symbol.toStringTag` values. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the raw `toStringTag`. - */ - function getRawTag(value) { - var isOwn = hasOwnProperty.call(value, symToStringTag), - tag = value[symToStringTag]; - - try { - value[symToStringTag] = undefined; - var unmasked = true; - } catch (e) {} - - var result = nativeObjectToString.call(value); - if (unmasked) { - if (isOwn) { - value[symToStringTag] = tag; - } else { - delete value[symToStringTag]; - } - } - return result; - } - - /** - * Creates an array of the own enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbols = !nativeGetSymbols ? stubArray : function(object) { - if (object == null) { - return []; - } - object = Object(object); - return arrayFilter(nativeGetSymbols(object), function(symbol) { - return propertyIsEnumerable.call(object, symbol); + function flush() { + return timerId === undefined ? result : trailingEdge(now()); + } + + function debounced() { + var time = now(), + isInvoking = shouldInvoke(time); + + lastArgs = arguments; + lastThis = this; + lastCallTime = time; + + if (isInvoking) { + if (timerId === undefined) { + return leadingEdge(lastCallTime); + } + if (maxing) { + // Handle invocations in a tight loop. + timerId = setTimeout(timerExpired, wait); + return invokeFunc(lastCallTime); + } + } + if (timerId === undefined) { + timerId = setTimeout(timerExpired, wait); + } + return result; + } + + debounced.cancel = cancel; + debounced.flush = flush; + return debounced; + } + + /** + * Defers invoking the `func` until the current call stack has cleared. Any + * additional arguments are provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to defer. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.defer(function(text) { + * console.log(text); + * }, 'deferred'); + * // => Logs 'deferred' after one millisecond. + */ + var defer = baseRest(function (func, args) { + return baseDelay(func, 1, args); }); - }; - - /** - * Creates an array of the own and inherited enumerable symbols of `object`. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of symbols. - */ - var getSymbolsIn = !nativeGetSymbols ? stubArray : function(object) { - var result = []; - while (object) { - arrayPush(result, getSymbols(object)); - object = getPrototype(object); - } - return result; - }; - - /** - * Gets the `toStringTag` of `value`. - * - * @private - * @param {*} value The value to query. - * @returns {string} Returns the `toStringTag`. - */ - var getTag = baseGetTag; - - // Fallback for data views, maps, sets, and weak maps in IE 11 and promises in Node.js < 6. - if ((DataView && getTag(new DataView(new ArrayBuffer(1))) != dataViewTag) || - (Map && getTag(new Map) != mapTag) || - (Promise && getTag(Promise.resolve()) != promiseTag) || - (Set && getTag(new Set) != setTag) || - (WeakMap && getTag(new WeakMap) != weakMapTag)) { - getTag = function(value) { - var result = baseGetTag(value), - Ctor = result == objectTag ? value.constructor : undefined, - ctorString = Ctor ? toSource(Ctor) : ''; - - if (ctorString) { - switch (ctorString) { - case dataViewCtorString: return dataViewTag; - case mapCtorString: return mapTag; - case promiseCtorString: return promiseTag; - case setCtorString: return setTag; - case weakMapCtorString: return weakMapTag; - } - } - return result; - }; - } - - /** - * Gets the view, applying any `transforms` to the `start` and `end` positions. - * - * @private - * @param {number} start The start of the view. - * @param {number} end The end of the view. - * @param {Array} transforms The transformations to apply to the view. - * @returns {Object} Returns an object containing the `start` and `end` - * positions of the view. - */ - function getView(start, end, transforms) { - var index = -1, - length = transforms.length; - - while (++index < length) { - var data = transforms[index], - size = data.size; - - switch (data.type) { - case 'drop': start += size; break; - case 'dropRight': end -= size; break; - case 'take': end = nativeMin(end, start + size); break; - case 'takeRight': start = nativeMax(start, end - size); break; - } - } - return { 'start': start, 'end': end }; - } - - /** - * Extracts wrapper details from the `source` body comment. - * - * @private - * @param {string} source The source to inspect. - * @returns {Array} Returns the wrapper details. - */ - function getWrapDetails(source) { - var match = source.match(reWrapDetails); - return match ? match[1].split(reSplitDetails) : []; - } - - /** - * Checks if `path` exists on `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @param {Function} hasFunc The function to check properties. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - */ - function hasPath(object, path, hasFunc) { - path = castPath(path, object); - - var index = -1, - length = path.length, - result = false; - - while (++index < length) { - var key = toKey(path[index]); - if (!(result = object != null && hasFunc(object, key))) { - break; - } - object = object[key]; - } - if (result || ++index != length) { - return result; - } - length = object == null ? 0 : object.length; - return !!length && isLength(length) && isIndex(key, length) && - (isArray(object) || isArguments(object)); - } - - /** - * Initializes an array clone. - * - * @private - * @param {Array} array The array to clone. - * @returns {Array} Returns the initialized clone. - */ - function initCloneArray(array) { - var length = array.length, - result = new array.constructor(length); - - // Add properties assigned by `RegExp#exec`. - if (length && typeof array[0] == 'string' && hasOwnProperty.call(array, 'index')) { - result.index = array.index; - result.input = array.input; - } - return result; - } - - /** - * Initializes an object clone. - * - * @private - * @param {Object} object The object to clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneObject(object) { - return (typeof object.constructor == 'function' && !isPrototype(object)) - ? baseCreate(getPrototype(object)) - : {}; - } - - /** - * Initializes an object clone based on its `toStringTag`. - * - * **Note:** This function only supports cloning values with tags of - * `Boolean`, `Date`, `Error`, `Map`, `Number`, `RegExp`, `Set`, or `String`. - * - * @private - * @param {Object} object The object to clone. - * @param {string} tag The `toStringTag` of the object to clone. - * @param {boolean} [isDeep] Specify a deep clone. - * @returns {Object} Returns the initialized clone. - */ - function initCloneByTag(object, tag, isDeep) { - var Ctor = object.constructor; - switch (tag) { - case arrayBufferTag: - return cloneArrayBuffer(object); - - case boolTag: - case dateTag: - return new Ctor(+object); - - case dataViewTag: - return cloneDataView(object, isDeep); - - case float32Tag: case float64Tag: - case int8Tag: case int16Tag: case int32Tag: - case uint8Tag: case uint8ClampedTag: case uint16Tag: case uint32Tag: - return cloneTypedArray(object, isDeep); - - case mapTag: - return new Ctor; - - case numberTag: - case stringTag: - return new Ctor(object); - - case regexpTag: - return cloneRegExp(object); - - case setTag: - return new Ctor; - - case symbolTag: - return cloneSymbol(object); - } - } - - /** - * Inserts wrapper `details` in a comment at the top of the `source` body. - * - * @private - * @param {string} source The source to modify. - * @returns {Array} details The details to insert. - * @returns {string} Returns the modified source. - */ - function insertWrapDetails(source, details) { - var length = details.length; - if (!length) { - return source; - } - var lastIndex = length - 1; - details[lastIndex] = (length > 1 ? '& ' : '') + details[lastIndex]; - details = details.join(length > 2 ? ', ' : ' '); - return source.replace(reWrapComment, '{\n/* [wrapped with ' + details + '] */\n'); - } - - /** - * Checks if `value` is a flattenable `arguments` object or array. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is flattenable, else `false`. - */ - function isFlattenable(value) { - return isArray(value) || isArguments(value) || - !!(spreadableSymbol && value && value[spreadableSymbol]); - } - - /** - * Checks if `value` is a valid array-like index. - * - * @private - * @param {*} value The value to check. - * @param {number} [length=MAX_SAFE_INTEGER] The upper bounds of a valid index. - * @returns {boolean} Returns `true` if `value` is a valid index, else `false`. - */ - function isIndex(value, length) { - var type = typeof value; - length = length == null ? MAX_SAFE_INTEGER : length; - - return !!length && - (type == 'number' || - (type != 'symbol' && reIsUint.test(value))) && - (value > -1 && value % 1 == 0 && value < length); - } - - /** - * Checks if the given arguments are from an iteratee call. - * - * @private - * @param {*} value The potential iteratee value argument. - * @param {*} index The potential iteratee index or key argument. - * @param {*} object The potential iteratee object argument. - * @returns {boolean} Returns `true` if the arguments are from an iteratee call, - * else `false`. - */ - function isIterateeCall(value, index, object) { - if (!isObject(object)) { - return false; - } - var type = typeof index; - if (type == 'number' - ? (isArrayLike(object) && isIndex(index, object.length)) - : (type == 'string' && index in object) - ) { - return eq(object[index], value); - } - return false; - } - - /** - * Checks if `value` is a property name and not a property path. - * - * @private - * @param {*} value The value to check. - * @param {Object} [object] The object to query keys on. - * @returns {boolean} Returns `true` if `value` is a property name, else `false`. - */ - function isKey(value, object) { - if (isArray(value)) { - return false; - } - var type = typeof value; - if (type == 'number' || type == 'symbol' || type == 'boolean' || - value == null || isSymbol(value)) { - return true; - } - return reIsPlainProp.test(value) || !reIsDeepProp.test(value) || - (object != null && value in Object(object)); - } - - /** - * Checks if `value` is suitable for use as unique object key. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is suitable, else `false`. - */ - function isKeyable(value) { - var type = typeof value; - return (type == 'string' || type == 'number' || type == 'symbol' || type == 'boolean') - ? (value !== '__proto__') - : (value === null); - } - - /** - * Checks if `func` has a lazy counterpart. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` has a lazy counterpart, - * else `false`. - */ - function isLaziable(func) { - var funcName = getFuncName(func), - other = lodash[funcName]; - - if (typeof other != 'function' || !(funcName in LazyWrapper.prototype)) { - return false; - } - if (func === other) { - return true; - } - var data = getData(other); - return !!data && func === data[0]; - } - - /** - * Checks if `func` has its source masked. - * - * @private - * @param {Function} func The function to check. - * @returns {boolean} Returns `true` if `func` is masked, else `false`. - */ - function isMasked(func) { - return !!maskSrcKey && (maskSrcKey in func); - } - - /** - * Checks if `value` is likely a prototype object. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a prototype, else `false`. - */ - function isPrototype(value) { - var Ctor = value && value.constructor, - proto = (typeof Ctor == 'function' && Ctor.prototype) || objectProto; - - return value === proto; - } - - /** - * Checks if `value` is suitable for strict equality comparisons, i.e. `===`. - * - * @private - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` if suitable for strict - * equality comparisons, else `false`. - */ - function isStrictComparable(value) { - return value === value && !isObject(value); - } - - /** - * A specialized version of `matchesProperty` for source values suitable - * for strict equality comparisons, i.e. `===`. - * - * @private - * @param {string} key The key of the property to get. - * @param {*} srcValue The value to match. - * @returns {Function} Returns the new spec function. - */ - function matchesStrictComparable(key, srcValue) { - return function(object) { - if (object == null) { - return false; - } - return object[key] === srcValue && - (srcValue !== undefined || (key in Object(object))); - }; - } - - /** - * A specialized version of `_.memoize` which clears the memoized function's - * cache when it exceeds `MAX_MEMOIZE_SIZE`. - * - * @private - * @param {Function} func The function to have its output memoized. - * @returns {Function} Returns the new memoized function. - */ - function memoizeCapped(func) { - var result = memoize(func, function(key) { - if (cache.size === MAX_MEMOIZE_SIZE) { - cache.clear(); - } - return key; + + /** + * Invokes `func` after `wait` milliseconds. Any additional arguments are + * provided to `func` when it's invoked. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to delay. + * @param {number} wait The number of milliseconds to delay invocation. + * @param {...*} [args] The arguments to invoke `func` with. + * @returns {number} Returns the timer id. + * @example + * + * _.delay(function(text) { + * console.log(text); + * }, 1000, 'later'); + * // => Logs 'later' after one second. + */ + var delay = baseRest(function (func, wait, args) { + return baseDelay(func, toNumber(wait) || 0, args); }); - var cache = result.cache; - return result; - } - - /** - * Merges the function metadata of `source` into `data`. - * - * Merging metadata reduces the number of wrappers used to invoke a function. - * This is possible because methods like `_.bind`, `_.curry`, and `_.partial` - * may be applied regardless of execution order. Methods like `_.ary` and - * `_.rearg` modify function arguments, making the order in which they are - * executed important, preventing the merging of metadata. However, we make - * an exception for a safe combined case where curried functions have `_.ary` - * and or `_.rearg` applied. - * - * @private - * @param {Array} data The destination metadata. - * @param {Array} source The source metadata. - * @returns {Array} Returns `data`. - */ - function mergeData(data, source) { - var bitmask = data[1], - srcBitmask = source[1], - newBitmask = bitmask | srcBitmask, - isCommon = newBitmask < (WRAP_BIND_FLAG | WRAP_BIND_KEY_FLAG | WRAP_ARY_FLAG); - - var isCombo = - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_CURRY_FLAG)) || - ((srcBitmask == WRAP_ARY_FLAG) && (bitmask == WRAP_REARG_FLAG) && (data[7].length <= source[8])) || - ((srcBitmask == (WRAP_ARY_FLAG | WRAP_REARG_FLAG)) && (source[7].length <= source[8]) && (bitmask == WRAP_CURRY_FLAG)); - - // Exit early if metadata can't be merged. - if (!(isCommon || isCombo)) { - return data; - } - // Use source `thisArg` if available. - if (srcBitmask & WRAP_BIND_FLAG) { - data[2] = source[2]; - // Set when currying a bound function. - newBitmask |= bitmask & WRAP_BIND_FLAG ? 0 : WRAP_CURRY_BOUND_FLAG; - } - // Compose partial arguments. - var value = source[3]; - if (value) { - var partials = data[3]; - data[3] = partials ? composeArgs(partials, value, source[4]) : value; - data[4] = partials ? replaceHolders(data[3], PLACEHOLDER) : source[4]; - } - // Compose partial right arguments. - value = source[5]; - if (value) { - partials = data[5]; - data[5] = partials ? composeArgsRight(partials, value, source[6]) : value; - data[6] = partials ? replaceHolders(data[5], PLACEHOLDER) : source[6]; - } - // Use source `argPos` if available. - value = source[7]; - if (value) { - data[7] = value; - } - // Use source `ary` if it's smaller. - if (srcBitmask & WRAP_ARY_FLAG) { - data[8] = data[8] == null ? source[8] : nativeMin(data[8], source[8]); - } - // Use source `arity` if one is not provided. - if (data[9] == null) { - data[9] = source[9]; - } - // Use source `func` and merge bitmasks. - data[0] = source[0]; - data[1] = newBitmask; - - return data; - } - - /** - * This function is like - * [`Object.keys`](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * except that it includes inherited enumerable properties. - * - * @private - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - */ - function nativeKeysIn(object) { - var result = []; - if (object != null) { - for (var key in Object(object)) { - result.push(key); - } - } - return result; - } - - /** - * Converts `value` to a string using `Object.prototype.toString`. - * - * @private - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - */ - function objectToString(value) { - return nativeObjectToString.call(value); - } - - /** - * A specialized version of `baseRest` which transforms the rest array. - * - * @private - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @param {Function} transform The rest array transform. - * @returns {Function} Returns the new function. - */ - function overRest(func, start, transform) { - start = nativeMax(start === undefined ? (func.length - 1) : start, 0); - return function() { - var args = arguments, - index = -1, - length = nativeMax(args.length - start, 0), - array = Array(length); - - while (++index < length) { - array[index] = args[start + index]; - } - index = -1; - var otherArgs = Array(start + 1); - while (++index < start) { - otherArgs[index] = args[index]; - } - otherArgs[start] = transform(array); - return apply(func, this, otherArgs); - }; - } - - /** - * Gets the parent value at `path` of `object`. - * - * @private - * @param {Object} object The object to query. - * @param {Array} path The path to get the parent value of. - * @returns {*} Returns the parent value. - */ - function parent(object, path) { - return path.length < 2 ? object : baseGet(object, baseSlice(path, 0, -1)); - } - - /** - * Reorder `array` according to the specified indexes where the element at - * the first index is assigned as the first element, the element at - * the second index is assigned as the second element, and so on. - * - * @private - * @param {Array} array The array to reorder. - * @param {Array} indexes The arranged array indexes. - * @returns {Array} Returns `array`. - */ - function reorder(array, indexes) { - var arrLength = array.length, - length = nativeMin(indexes.length, arrLength), - oldArray = copyArray(array); - - while (length--) { - var index = indexes[length]; - array[length] = isIndex(index, arrLength) ? oldArray[index] : undefined; - } - return array; - } - - /** - * Sets metadata for `func`. - * - * **Note:** If this function becomes hot, i.e. is invoked a lot in a short - * period of time, it will trip its breaker and transition to an identity - * function to avoid garbage collection pauses in V8. See - * [V8 issue 2070](https://bugs.chromium.org/p/v8/issues/detail?id=2070) - * for more details. - * - * @private - * @param {Function} func The function to associate metadata with. - * @param {*} data The metadata. - * @returns {Function} Returns `func`. - */ - var setData = shortOut(baseSetData); - - /** - * Sets the `toString` method of `func` to return `string`. - * - * @private - * @param {Function} func The function to modify. - * @param {Function} string The `toString` result. - * @returns {Function} Returns `func`. - */ - var setToString = shortOut(baseSetToString); - - /** - * Sets the `toString` method of `wrapper` to mimic the source of `reference` - * with wrapper details in a comment at the top of the source body. - * - * @private - * @param {Function} wrapper The function to modify. - * @param {Function} reference The reference function. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Function} Returns `wrapper`. - */ - function setWrapToString(wrapper, reference, bitmask) { - var source = (reference + ''); - return setToString(wrapper, insertWrapDetails(source, updateWrapDetails(getWrapDetails(source), bitmask))); - } - - /** - * Creates a function that'll short out and invoke `identity` instead - * of `func` when it's called `HOT_COUNT` or more times in `HOT_SPAN` - * milliseconds. - * - * @private - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new shortable function. - */ - function shortOut(func) { - var count = 0, - lastCalled = 0; - - return function() { - var stamp = nativeNow(), - remaining = HOT_SPAN - (stamp - lastCalled); - - lastCalled = stamp; - if (remaining > 0) { - if (++count >= HOT_COUNT) { - return arguments[0]; - } - } else { - count = 0; - } - return func.apply(undefined, arguments); + /** + * Creates a function that memoizes the result of `func`. If `resolver` is + * provided, it determines the cache key for storing the result based on the + * arguments provided to the memoized function. By default, the first argument + * provided to the memoized function is used as the map cache key. The `func` + * is invoked with the `this` binding of the memoized function. + * + * **Note:** The cache is exposed as the `cache` property on the memoized + * function. Its creation may be customized by replacing the `_.memoize.Cache` + * constructor with one whose instances implement the + * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) + * method interface of `clear`, `delete`, `get`, `has`, and `set`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to have its output memoized. + * @param {Function} [resolver] The function to resolve the cache key. + * @returns {Function} Returns the new memoized function. + * @example + * + * var object = { 'a': 1, 'b': 2 }; + * var other = { 'c': 3, 'd': 4 }; + * + * var values = _.memoize(_.values); + * values(object); + * // => [1, 2] + * + * values(other); + * // => [3, 4] + * + * object.a = 2; + * values(object); + * // => [1, 2] + * + * // Modify the result cache. + * values.cache.set(object, ['a', 'b']); + * values(object); + * // => ['a', 'b'] + * + * // Replace `_.memoize.Cache`. + * _.memoize.Cache = WeakMap; + */ + function memoize(func, resolver) { + if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { + throw new TypeError(FUNC_ERROR_TEXT); + } + var memoized = function () { + var args = arguments, + key = resolver ? resolver.apply(this, args) : args[0], + cache = memoized.cache; + + if (cache.has(key)) { + return cache.get(key); + } + var result = func.apply(this, args); + memoized.cache = cache.set(key, result) || cache; + return result; + }; + memoized.cache = new (memoize.Cache || MapCache); + return memoized; + } + + // Expose `MapCache`. + memoize.Cache = MapCache; + + /** + * Creates a function that negates the result of the predicate `func`. The + * `func` predicate is invoked with the `this` binding and arguments of the + * created function. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Function + * @param {Function} predicate The predicate to negate. + * @returns {Function} Returns the new negated function. + * @example + * + * function isEven(n) { + * return n % 2 == 0; + * } + * + * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); + * // => [1, 3, 5] + */ + function negate(predicate) { + if (typeof predicate != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + return function () { + var args = arguments; + switch (args.length) { + case 0: + return !predicate.call(this); + case 1: + return !predicate.call(this, args[0]); + case 2: + return !predicate.call(this, args[0], args[1]); + case 3: + return !predicate.call(this, args[0], args[1], args[2]); + } + return !predicate.apply(this, args); + }; + } + + /** + * Creates a function that is restricted to invoking `func` once. Repeat calls + * to the function return the value of the first invocation. The `func` is + * invoked with the `this` binding and arguments of the created function. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to restrict. + * @returns {Function} Returns the new restricted function. + * @example + * + * var initialize = _.once(createApplication); + * initialize(); + * initialize(); + * // => `createApplication` is invoked once + */ + function once(func) { + return before(2, func); + } + + /** + * Creates a function that invokes `func` with the `this` binding of the + * created function and arguments from `start` and beyond provided as + * an array. + * + * **Note:** This method is based on the + * [rest parameter](https://mdn.io/rest_parameters). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Function + * @param {Function} func The function to apply a rest parameter to. + * @param {number} [start=func.length-1] The start position of the rest parameter. + * @returns {Function} Returns the new function. + * @example + * + * var say = _.rest(function(what, names) { + * return what + ' ' + _.initial(names).join(', ') + + * (_.size(names) > 1 ? ', & ' : '') + _.last(names); + * }); + * + * say('hello', 'fred', 'barney', 'pebbles'); + * // => 'hello fred, barney, & pebbles' + */ + function rest(func, start) { + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + start = start === undefined ? start : toInteger(start); + return baseRest(func, start); + } + + /** + * Creates a throttled function that only invokes `func` at most once per + * every `wait` milliseconds. The throttled function comes with a `cancel` + * method to cancel delayed `func` invocations and a `flush` method to + * immediately invoke them. Provide `options` to indicate whether `func` + * should be invoked on the leading and/or trailing edge of the `wait` + * timeout. The `func` is invoked with the last arguments provided to the + * throttled function. Subsequent calls to the throttled function return the + * result of the last `func` invocation. + * + * **Note:** If `leading` and `trailing` options are `true`, `func` is + * invoked on the trailing edge of the timeout only if the throttled function + * is invoked more than once during the `wait` timeout. + * + * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred + * until to the next tick, similar to `setTimeout` with a timeout of `0`. + * + * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) + * for details over the differences between `_.throttle` and `_.debounce`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Function + * @param {Function} func The function to throttle. + * @param {number} [wait=0] The number of milliseconds to throttle invocations to. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.leading=true] + * Specify invoking on the leading edge of the timeout. + * @param {boolean} [options.trailing=true] + * Specify invoking on the trailing edge of the timeout. + * @returns {Function} Returns the new throttled function. + * @example + * + * // Avoid excessively updating the position while scrolling. + * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); + * + * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. + * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); + * jQuery(element).on('click', throttled); + * + * // Cancel the trailing throttled invocation. + * jQuery(window).on('popstate', throttled.cancel); + */ + function throttle(func, wait, options) { + var leading = true, + trailing = true; + + if (typeof func != 'function') { + throw new TypeError(FUNC_ERROR_TEXT); + } + if (isObject(options)) { + leading = 'leading' in options ? !!options.leading : leading; + trailing = 'trailing' in options ? !!options.trailing : trailing; + } + return debounce(func, wait, { + 'leading': leading, + 'maxWait': wait, + 'trailing': trailing + }); + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a shallow clone of `value`. + * + * **Note:** This method is loosely based on the + * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) + * and supports cloning arrays, array buffers, booleans, date objects, maps, + * numbers, `Object` objects, regexes, sets, strings, symbols, and typed + * arrays. The own enumerable properties of `arguments` objects are cloned + * as plain objects. An empty object is returned for uncloneable values such + * as error objects, functions, DOM nodes, and WeakMaps. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to clone. + * @returns {*} Returns the cloned value. + * @see _.cloneDeep + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var shallow = _.clone(objects); + * console.log(shallow[0] === objects[0]); + * // => true + */ + function clone(value) { + return baseClone(value, CLONE_SYMBOLS_FLAG); + } + + /** + * This method is like `_.clone` except that it recursively clones `value`. + * + * @static + * @memberOf _ + * @since 1.0.0 + * @category Lang + * @param {*} value The value to recursively clone. + * @returns {*} Returns the deep cloned value. + * @see _.clone + * @example + * + * var objects = [{ 'a': 1 }, { 'b': 2 }]; + * + * var deep = _.cloneDeep(objects); + * console.log(deep[0] === objects[0]); + * // => false + */ + function cloneDeep(value) { + return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); + } + + /** + * Performs a + * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) + * comparison between two values to determine if they are equivalent. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.eq(object, object); + * // => true + * + * _.eq(object, other); + * // => false + * + * _.eq('a', 'a'); + * // => true + * + * _.eq('a', Object('a')); + * // => false + * + * _.eq(NaN, NaN); + * // => true + */ + function eq(value, other) { + return value === other || (value !== value && other !== other); + } + + /** + * Checks if `value` is likely an `arguments` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an `arguments` object, + * else `false`. + * @example + * + * _.isArguments(function() { return arguments; }()); + * // => true + * + * _.isArguments([1, 2, 3]); + * // => false + */ + var isArguments = baseIsArguments(function () { + return arguments; + }()) ? baseIsArguments : function (value) { + return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && + !propertyIsEnumerable.call(value, 'callee'); }; - } - - /** - * Converts `string` to a property path array. - * - * @private - * @param {string} string The string to convert. - * @returns {Array} Returns the property path array. - */ - var stringToPath = memoizeCapped(function(string) { - var result = []; - if (string.charCodeAt(0) === 46 /* . */) { - result.push(''); - } - string.replace(rePropName, function(match, number, quote, subString) { - result.push(quote ? subString.replace(reEscapeChar, '$1') : (number || match)); - }); - return result; - }); - - /** - * Converts `value` to a string key if it's not a string or symbol. - * - * @private - * @param {*} value The value to inspect. - * @returns {string|symbol} Returns the key. - */ - function toKey(value) { - if (typeof value == 'string' || isSymbol(value)) { - return value; - } - var result = (value + ''); - return (result == '0' && (1 / value) == -INFINITY) ? '-0' : result; - } - - /** - * Converts `func` to its source code. - * - * @private - * @param {Function} func The function to convert. - * @returns {string} Returns the source code. - */ - function toSource(func) { - if (func != null) { - try { - return funcToString.call(func); - } catch (e) {} - try { - return (func + ''); - } catch (e) {} - } - return ''; - } - - /** - * Updates wrapper `details` based on `bitmask` flags. - * - * @private - * @returns {Array} details The details to modify. - * @param {number} bitmask The bitmask flags. See `createWrap` for more details. - * @returns {Array} Returns `details`. - */ - function updateWrapDetails(details, bitmask) { - arrayEach(wrapFlags, function(pair) { - var value = '_.' + pair[0]; - if ((bitmask & pair[1]) && !arrayIncludes(details, value)) { - details.push(value); - } - }); - return details.sort(); - } - - /** - * Creates a clone of `wrapper`. - * - * @private - * @param {Object} wrapper The wrapper to clone. - * @returns {Object} Returns the cloned wrapper. - */ - function wrapperClone(wrapper) { - if (wrapper instanceof LazyWrapper) { - return wrapper.clone(); - } - var result = new LodashWrapper(wrapper.__wrapped__, wrapper.__chain__); - result.__actions__ = copyArray(wrapper.__actions__); - result.__index__ = wrapper.__index__; - result.__values__ = wrapper.__values__; - return result; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an array with all falsey values removed. The values `false`, `null`, - * `0`, `""`, `undefined`, and `NaN` are falsey. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to compact. - * @returns {Array} Returns the new array of filtered values. - * @example - * - * _.compact([0, 1, false, 2, '', 3]); - * // => [1, 2, 3] - */ - function compact(array) { - var index = -1, - length = array == null ? 0 : array.length, - resIndex = 0, - result = []; - - while (++index < length) { - var value = array[index]; - if (value) { - result[resIndex++] = value; - } - } - return result; - } - - /** - * Creates a new array concatenating `array` with any additional arrays - * and/or values. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to concatenate. - * @param {...*} [values] The values to concatenate. - * @returns {Array} Returns the new concatenated array. - * @example - * - * var array = [1]; - * var other = _.concat(array, 2, [3], [[4]]); - * - * console.log(other); - * // => [1, 2, 3, [4]] - * - * console.log(array); - * // => [1] - */ - function concat() { - var length = arguments.length; - if (!length) { - return []; - } - var args = Array(length - 1), - array = arguments[0], - index = length; - - while (index--) { - args[index - 1] = arguments[index]; - } - return arrayPush(isArray(array) ? copyArray(array) : [array], baseFlatten(args, 1)); - } - - /** - * Creates an array of `array` values not included in the other given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * **Note:** Unlike `_.pullAll`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...Array} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.without, _.xor - * @example - * - * _.difference([2, 1], [2, 3]); - * // => [1] - */ - var difference = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, baseFlatten(values, 1, isArrayLikeObject, true)) - : []; - }); - - /** - * Creates a slice of `array` with `n` elements dropped from the beginning. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to drop. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.drop([1, 2, 3]); - * // => [2, 3] - * - * _.drop([1, 2, 3], 2); - * // => [3] - * - * _.drop([1, 2, 3], 5); - * // => [] - * - * _.drop([1, 2, 3], 0); - * // => [1, 2, 3] - */ - function drop(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * This method is like `_.find` except that it returns the index of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': false }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': true } - * ]; - * - * _.findIndex(users, function(o) { return o.user == 'barney'; }); - * // => 0 - * - * // The `_.matches` iteratee shorthand. - * _.findIndex(users, { 'user': 'fred', 'active': false }); - * // => 1 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findIndex(users, ['active', false]); - * // => 0 - * - * // The `_.property` iteratee shorthand. - * _.findIndex(users, 'active'); - * // => 2 - */ - function findIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseFindIndex(array, baseIteratee(predicate, 3), index); - } - - /** - * This method is like `_.findIndex` except that it iterates over elements - * of `collection` from right to left. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=array.length-1] The index to search from. - * @returns {number} Returns the index of the found element, else `-1`. - * @example - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false }, - * { 'user': 'pebbles', 'active': false } - * ]; - * - * _.findLastIndex(users, function(o) { return o.user == 'pebbles'; }); - * // => 2 - * - * // The `_.matches` iteratee shorthand. - * _.findLastIndex(users, { 'user': 'barney', 'active': true }); - * // => 0 - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastIndex(users, ['active', false]); - * // => 2 - * - * // The `_.property` iteratee shorthand. - * _.findLastIndex(users, 'active'); - * // => 0 - */ - function findLastIndex(array, predicate, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = length - 1; - if (fromIndex !== undefined) { - index = toInteger(fromIndex); - index = fromIndex < 0 - ? nativeMax(length + index, 0) - : nativeMin(index, length - 1); - } - return baseFindIndex(array, baseIteratee(predicate, 3), index, true); - } - - /** - * Flattens `array` a single level deep. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flatten([1, [2, [3, [4]], 5]]); - * // => [1, 2, [3, [4]], 5] - */ - function flatten(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, 1) : []; - } - - /** - * Recursively flattens `array`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to flatten. - * @returns {Array} Returns the new flattened array. - * @example - * - * _.flattenDeep([1, [2, [3, [4]], 5]]); - * // => [1, 2, 3, 4, 5] - */ - function flattenDeep(array) { - var length = array == null ? 0 : array.length; - return length ? baseFlatten(array, INFINITY) : []; - } - - /** - * Gets the first element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias first - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the first element of `array`. - * @example - * - * _.head([1, 2, 3]); - * // => 1 - * - * _.head([]); - * // => undefined - */ - function head(array) { - return (array && array.length) ? array[0] : undefined; - } - - /** - * Gets the index at which the first occurrence of `value` is found in `array` - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. If `fromIndex` is negative, it's used as the - * offset from the end of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {*} value The value to search for. - * @param {number} [fromIndex=0] The index to search from. - * @returns {number} Returns the index of the matched value, else `-1`. - * @example - * - * _.indexOf([1, 2, 1, 2], 2); - * // => 1 - * - * // Search from the `fromIndex`. - * _.indexOf([1, 2, 1, 2], 2, 2); - * // => 3 - */ - function indexOf(array, value, fromIndex) { - var length = array == null ? 0 : array.length; - if (!length) { - return -1; - } - var index = fromIndex == null ? 0 : toInteger(fromIndex); - if (index < 0) { - index = nativeMax(length + index, 0); - } - return baseIndexOf(array, value, index); - } - - /** - * Gets all but the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.initial([1, 2, 3]); - * // => [1, 2] - */ - function initial(array) { - var length = array == null ? 0 : array.length; - return length ? baseSlice(array, 0, -1) : []; - } - - /** - * Creates an array of unique values that are included in all given arrays - * using [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. The order and references of result values are - * determined by the first array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of intersecting values. - * @example - * - * _.intersection([2, 1], [2, 3]); - * // => [2] - */ - var intersection = baseRest(function(arrays) { - var mapped = arrayMap(arrays, castArrayLikeObject); - return (mapped.length && mapped[0] === arrays[0]) - ? baseIntersection(mapped) - : []; - }); - - /** - * Gets the last element of `array`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @returns {*} Returns the last element of `array`. - * @example - * - * _.last([1, 2, 3]); - * // => 3 - */ - function last(array) { - var length = array == null ? 0 : array.length; - return length ? array[length - 1] : undefined; - } - - /** - * Reverses `array` so that the first element becomes the last, the second - * element becomes the second to last, and so on. - * - * **Note:** This method mutates `array` and is based on - * [`Array#reverse`](https://mdn.io/Array/reverse). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to modify. - * @returns {Array} Returns `array`. - * @example - * - * var array = [1, 2, 3]; - * - * _.reverse(array); - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function reverse(array) { - return array == null ? array : nativeReverse.call(array); - } - - /** - * Creates a slice of `array` from `start` up to, but not including, `end`. - * - * **Note:** This method is used instead of - * [`Array#slice`](https://mdn.io/Array/slice) to ensure dense arrays are - * returned. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to slice. - * @param {number} [start=0] The start position. - * @param {number} [end=array.length] The end position. - * @returns {Array} Returns the slice of `array`. - */ - function slice(array, start, end) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - if (end && typeof end != 'number' && isIterateeCall(array, start, end)) { - start = 0; - end = length; - } - else { - start = start == null ? 0 : toInteger(start); - end = end === undefined ? length : toInteger(end); - } - return baseSlice(array, start, end); - } - - /** - * Creates a slice of `array` with `n` elements taken from the beginning. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.take([1, 2, 3]); - * // => [1] - * - * _.take([1, 2, 3], 2); - * // => [1, 2] - * - * _.take([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.take([1, 2, 3], 0); - * // => [] - */ - function take(array, n, guard) { - if (!(array && array.length)) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - return baseSlice(array, 0, n < 0 ? 0 : n); - } - - /** - * Creates a slice of `array` with `n` elements taken from the end. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Array - * @param {Array} array The array to query. - * @param {number} [n=1] The number of elements to take. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {Array} Returns the slice of `array`. - * @example - * - * _.takeRight([1, 2, 3]); - * // => [3] - * - * _.takeRight([1, 2, 3], 2); - * // => [2, 3] - * - * _.takeRight([1, 2, 3], 5); - * // => [1, 2, 3] - * - * _.takeRight([1, 2, 3], 0); - * // => [] - */ - function takeRight(array, n, guard) { - var length = array == null ? 0 : array.length; - if (!length) { - return []; - } - n = (guard || n === undefined) ? 1 : toInteger(n); - n = length - n; - return baseSlice(array, n < 0 ? 0 : n, length); - } - - /** - * Creates an array of unique values, in order, from all given arrays using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to inspect. - * @returns {Array} Returns the new array of combined values. - * @example - * - * _.union([2], [1, 2]); - * // => [2, 1] - */ - var union = baseRest(function(arrays) { - return baseUniq(baseFlatten(arrays, 1, isArrayLikeObject, true)); - }); - - /** - * Creates a duplicate-free version of an array, using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons, in which only the first occurrence of each element - * is kept. The order of result values is determined by the order they occur - * in the array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniq([2, 1, 2]); - * // => [2, 1] - */ - function uniq(array) { - return (array && array.length) ? baseUniq(array) : []; - } - - /** - * This method is like `_.uniq` except that it accepts `iteratee` which is - * invoked for each element in `array` to generate the criterion by which - * uniqueness is computed. The order of result values is determined by the - * order they occur in the array. The iteratee is invoked with one argument: - * (value). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Array} Returns the new duplicate free array. - * @example - * - * _.uniqBy([2.1, 1.2, 2.3], Math.floor); - * // => [2.1, 1.2] - * - * // The `_.property` iteratee shorthand. - * _.uniqBy([{ 'x': 1 }, { 'x': 2 }, { 'x': 1 }], 'x'); - * // => [{ 'x': 1 }, { 'x': 2 }] - */ - function uniqBy(array, iteratee) { - return (array && array.length) ? baseUniq(array, baseIteratee(iteratee, 2)) : []; - } - - /** - * This method is like `_.zip` except that it accepts an array of grouped - * elements and creates an array regrouping the elements to their pre-zip - * configuration. - * - * @static - * @memberOf _ - * @since 1.2.0 - * @category Array - * @param {Array} array The array of grouped elements to process. - * @returns {Array} Returns the new array of regrouped elements. - * @example - * - * var zipped = _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - * - * _.unzip(zipped); - * // => [['a', 'b'], [1, 2], [true, false]] - */ - function unzip(array) { - if (!(array && array.length)) { - return []; - } - var length = 0; - array = arrayFilter(array, function(group) { - if (isArrayLikeObject(group)) { - length = nativeMax(group.length, length); + + /** + * Checks if `value` is classified as an `Array` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array, else `false`. + * @example + * + * _.isArray([1, 2, 3]); + * // => true + * + * _.isArray(document.body.children); + * // => false + * + * _.isArray('abc'); + * // => false + * + * _.isArray(_.noop); + * // => false + */ + var isArray = Array.isArray; + + /** + * Checks if `value` is array-like. A value is considered array-like if it's + * not a function and has a `value.length` that's an integer greater than or + * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is array-like, else `false`. + * @example + * + * _.isArrayLike([1, 2, 3]); + * // => true + * + * _.isArrayLike(document.body.children); + * // => true + * + * _.isArrayLike('abc'); + * // => true + * + * _.isArrayLike(_.noop); + * // => false + */ + function isArrayLike(value) { + return value != null && isLength(value.length) && !isFunction(value); + } + + /** + * This method is like `_.isArrayLike` except that it also checks if `value` + * is an object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an array-like object, + * else `false`. + * @example + * + * _.isArrayLikeObject([1, 2, 3]); + * // => true + * + * _.isArrayLikeObject(document.body.children); + * // => true + * + * _.isArrayLikeObject('abc'); + * // => false + * + * _.isArrayLikeObject(_.noop); + * // => false + */ + function isArrayLikeObject(value) { + return isObjectLike(value) && isArrayLike(value); + } + + /** + * Checks if `value` is classified as a boolean primitive or object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. + * @example + * + * _.isBoolean(false); + * // => true + * + * _.isBoolean(null); + * // => false + */ + function isBoolean(value) { + return value === true || value === false || + (isObjectLike(value) && baseGetTag(value) == boolTag); + } + + /** + * Checks if `value` is a buffer. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. + * @example + * + * _.isBuffer(new Buffer(2)); + * // => true + * + * _.isBuffer(new Uint8Array(2)); + * // => false + */ + var isBuffer = nativeIsBuffer || stubFalse; + + /** + * Checks if `value` is classified as a `Date` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a date object, else `false`. + * @example + * + * _.isDate(new Date); + * // => true + * + * _.isDate('Mon April 23 2012'); + * // => false + */ + var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; + + /** + * Checks if `value` is an empty object, collection, map, or set. + * + * Objects are considered empty if they have no own enumerable string keyed + * properties. + * + * Array-like values such as `arguments` objects, arrays, buffers, strings, or + * jQuery-like collections are considered empty if they have a `length` of `0`. + * Similarly, maps and sets are considered empty if they have a `size` of `0`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is empty, else `false`. + * @example + * + * _.isEmpty(null); + * // => true + * + * _.isEmpty(true); + * // => true + * + * _.isEmpty(1); + * // => true + * + * _.isEmpty([1, 2, 3]); + * // => false + * + * _.isEmpty({ 'a': 1 }); + * // => false + */ + function isEmpty(value) { + if (value == null) { + return true; + } + if (isArrayLike(value) && + (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || + isBuffer(value) || isTypedArray(value) || isArguments(value))) { + return !value.length; + } + var tag = getTag(value); + if (tag == mapTag || tag == setTag) { + return !value.size; + } + if (isPrototype(value)) { + return !baseKeys(value).length; + } + for (var key in value) { + if (hasOwnProperty.call(value, key)) { + return false; + } + } return true; - } + } + + /** + * Performs a deep comparison between two values to determine if they are + * equivalent. + * + * **Note:** This method supports comparing arrays, array buffers, booleans, + * date objects, error objects, maps, numbers, `Object` objects, regexes, + * sets, strings, symbols, and typed arrays. `Object` objects are compared + * by their own, not inherited, enumerable properties. Functions and DOM + * nodes are compared by strict equality, i.e. `===`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to compare. + * @param {*} other The other value to compare. + * @returns {boolean} Returns `true` if the values are equivalent, else `false`. + * @example + * + * var object = { 'a': 1 }; + * var other = { 'a': 1 }; + * + * _.isEqual(object, other); + * // => true + * + * object === other; + * // => false + */ + function isEqual(value, other) { + return baseIsEqual(value, other); + } + + /** + * Checks if `value` is a finite primitive number. + * + * **Note:** This method is based on + * [`Number.isFinite`](https://mdn.io/Number/isFinite). + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. + * @example + * + * _.isFinite(3); + * // => true + * + * _.isFinite(Number.MIN_VALUE); + * // => true + * + * _.isFinite(Infinity); + * // => false + * + * _.isFinite('3'); + * // => false + */ + function isFinite(value) { + return typeof value == 'number' && nativeIsFinite(value); + } + + /** + * Checks if `value` is classified as a `Function` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a function, else `false`. + * @example + * + * _.isFunction(_); + * // => true + * + * _.isFunction(/abc/); + * // => false + */ + function isFunction(value) { + if (!isObject(value)) { + return false; + } + // The use of `Object#toString` avoids issues with the `typeof` operator + // in Safari 9 which returns 'object' for typed arrays and other constructors. + var tag = baseGetTag(value); + return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; + } + + /** + * Checks if `value` is a valid array-like length. + * + * **Note:** This method is loosely based on + * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. + * @example + * + * _.isLength(3); + * // => true + * + * _.isLength(Number.MIN_VALUE); + * // => false + * + * _.isLength(Infinity); + * // => false + * + * _.isLength('3'); + * // => false + */ + function isLength(value) { + return typeof value == 'number' && + value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; + } + + /** + * Checks if `value` is the + * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) + * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is an object, else `false`. + * @example + * + * _.isObject({}); + * // => true + * + * _.isObject([1, 2, 3]); + * // => true + * + * _.isObject(_.noop); + * // => true + * + * _.isObject(null); + * // => false + */ + function isObject(value) { + var type = typeof value; + return value != null && (type == 'object' || type == 'function'); + } + + /** + * Checks if `value` is object-like. A value is object-like if it's not `null` + * and has a `typeof` result of "object". + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is object-like, else `false`. + * @example + * + * _.isObjectLike({}); + * // => true + * + * _.isObjectLike([1, 2, 3]); + * // => true + * + * _.isObjectLike(_.noop); + * // => false + * + * _.isObjectLike(null); + * // => false + */ + function isObjectLike(value) { + return value != null && typeof value == 'object'; + } + + /** + * Checks if `value` is classified as a `Map` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a map, else `false`. + * @example + * + * _.isMap(new Map); + * // => true + * + * _.isMap(new WeakMap); + * // => false + */ + var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; + + /** + * Checks if `value` is `NaN`. + * + * **Note:** This method is based on + * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as + * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for + * `undefined` and other non-number values. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. + * @example + * + * _.isNaN(NaN); + * // => true + * + * _.isNaN(new Number(NaN)); + * // => true + * + * isNaN(undefined); + * // => true + * + * _.isNaN(undefined); + * // => false + */ + function isNaN(value) { + // An `NaN` primitive is the only value that is not equal to itself. + // Perform the `toStringTag` check first to avoid errors with some + // ActiveX objects in IE. + return isNumber(value) && value != +value; + } + + /** + * Checks if `value` is `null`. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `null`, else `false`. + * @example + * + * _.isNull(null); + * // => true + * + * _.isNull(void 0); + * // => false + */ + function isNull(value) { + return value === null; + } + + /** + * Checks if `value` is classified as a `Number` primitive or object. + * + * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are + * classified as numbers, use the `_.isFinite` method. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a number, else `false`. + * @example + * + * _.isNumber(3); + * // => true + * + * _.isNumber(Number.MIN_VALUE); + * // => true + * + * _.isNumber(Infinity); + * // => true + * + * _.isNumber('3'); + * // => false + */ + function isNumber(value) { + return typeof value == 'number' || + (isObjectLike(value) && baseGetTag(value) == numberTag); + } + + /** + * Checks if `value` is a plain object, that is, an object created by the + * `Object` constructor or one with a `[[Prototype]]` of `null`. + * + * @static + * @memberOf _ + * @since 0.8.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * _.isPlainObject(new Foo); + * // => false + * + * _.isPlainObject([1, 2, 3]); + * // => false + * + * _.isPlainObject({ 'x': 0, 'y': 0 }); + * // => true + * + * _.isPlainObject(Object.create(null)); + * // => true + */ + function isPlainObject(value) { + if (!isObjectLike(value) || baseGetTag(value) != objectTag) { + return false; + } + var proto = getPrototype(value); + if (proto === null) { + return true; + } + var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; + return typeof Ctor == 'function' && Ctor instanceof Ctor && + funcToString.call(Ctor) == objectCtorString; + } + + /** + * Checks if `value` is classified as a `RegExp` object. + * + * @static + * @memberOf _ + * @since 0.1.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. + * @example + * + * _.isRegExp(/abc/); + * // => true + * + * _.isRegExp('/abc/'); + * // => false + */ + var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; + + /** + * Checks if `value` is classified as a `Set` object. + * + * @static + * @memberOf _ + * @since 4.3.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a set, else `false`. + * @example + * + * _.isSet(new Set); + * // => true + * + * _.isSet(new WeakSet); + * // => false + */ + var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; + + /** + * Checks if `value` is classified as a `String` primitive or object. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a string, else `false`. + * @example + * + * _.isString('abc'); + * // => true + * + * _.isString(1); + * // => false + */ + function isString(value) { + return typeof value == 'string' || + (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); + } + + /** + * Checks if `value` is classified as a `Symbol` primitive or object. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. + * @example + * + * _.isSymbol(Symbol.iterator); + * // => true + * + * _.isSymbol('abc'); + * // => false + */ + function isSymbol(value) { + return typeof value == 'symbol' || + (isObjectLike(value) && baseGetTag(value) == symbolTag); + } + + /** + * Checks if `value` is classified as a typed array. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. + * @example + * + * _.isTypedArray(new Uint8Array); + * // => true + * + * _.isTypedArray([]); + * // => false + */ + var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; + + /** + * Checks if `value` is `undefined`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to check. + * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. + * @example + * + * _.isUndefined(void 0); + * // => true + * + * _.isUndefined(null); + * // => false + */ + function isUndefined(value) { + return value === undefined; + } + + /** + * Converts `value` to an array. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Lang + * @param {*} value The value to convert. + * @returns {Array} Returns the converted array. + * @example + * + * _.toArray({ 'a': 1, 'b': 2 }); + * // => [1, 2] + * + * _.toArray('abc'); + * // => ['a', 'b', 'c'] + * + * _.toArray(1); + * // => [] + * + * _.toArray(null); + * // => [] + */ + function toArray(value) { + if (!value) { + return []; + } + if (isArrayLike(value)) { + return isString(value) ? stringToArray(value) : copyArray(value); + } + if (symIterator && value[symIterator]) { + return iteratorToArray(value[symIterator]()); + } + var tag = getTag(value), + func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); + + return func(value); + } + + /** + * Converts `value` to a finite number. + * + * @static + * @memberOf _ + * @since 4.12.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted number. + * @example + * + * _.toFinite(3.2); + * // => 3.2 + * + * _.toFinite(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toFinite(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toFinite('3.2'); + * // => 3.2 + */ + function toFinite(value) { + if (!value) { + return value === 0 ? value : 0; + } + value = toNumber(value); + if (value === INFINITY || value === -INFINITY) { + var sign = (value < 0 ? -1 : 1); + return sign * MAX_INTEGER; + } + return value === value ? value : 0; + } + + /** + * Converts `value` to an integer. + * + * **Note:** This method is loosely based on + * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {number} Returns the converted integer. + * @example + * + * _.toInteger(3.2); + * // => 3 + * + * _.toInteger(Number.MIN_VALUE); + * // => 0 + * + * _.toInteger(Infinity); + * // => 1.7976931348623157e+308 + * + * _.toInteger('3.2'); + * // => 3 + */ + function toInteger(value) { + var result = toFinite(value), + remainder = result % 1; + + return result === result ? (remainder ? result - remainder : result) : 0; + } + + /** + * Converts `value` to a number. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to process. + * @returns {number} Returns the number. + * @example + * + * _.toNumber(3.2); + * // => 3.2 + * + * _.toNumber(Number.MIN_VALUE); + * // => 5e-324 + * + * _.toNumber(Infinity); + * // => Infinity + * + * _.toNumber('3.2'); + * // => 3.2 + */ + function toNumber(value) { + if (typeof value == 'number') { + return value; + } + if (isSymbol(value)) { + return NAN; + } + if (isObject(value)) { + var other = typeof value.valueOf == 'function' ? value.valueOf() : value; + value = isObject(other) ? (other + '') : other; + } + if (typeof value != 'string') { + return value === 0 ? value : +value; + } + value = value.replace(reTrim, ''); + var isBinary = reIsBinary.test(value); + return (isBinary || reIsOctal.test(value)) + ? freeParseInt(value.slice(2), isBinary ? 2 : 8) + : (reIsBadHex.test(value) ? NAN : +value); + } + + /** + * Converts `value` to a plain object flattening inherited enumerable string + * keyed properties of `value` to own properties of the plain object. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {Object} Returns the converted plain object. + * @example + * + * function Foo() { + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.assign({ 'a': 1 }, new Foo); + * // => { 'a': 1, 'b': 2 } + * + * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); + * // => { 'a': 1, 'b': 2, 'c': 3 } + */ + function toPlainObject(value) { + return copyObject(value, keysIn(value)); + } + + /** + * Converts `value` to a string. An empty string is returned for `null` + * and `undefined` values. The sign of `-0` is preserved. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Lang + * @param {*} value The value to convert. + * @returns {string} Returns the converted string. + * @example + * + * _.toString(null); + * // => '' + * + * _.toString(-0); + * // => '-0' + * + * _.toString([1, 2, 3]); + * // => '1,2,3' + */ + function toString(value) { + return value == null ? '' : baseToString(value); + } + + /*------------------------------------------------------------------------*/ + + /** + * This method is like `_.assign` except that it iterates over own and + * inherited source properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @alias extend + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.assign + * @example + * + * function Foo() { + * this.a = 1; + * } + * + * function Bar() { + * this.c = 3; + * } + * + * Foo.prototype.b = 2; + * Bar.prototype.d = 4; + * + * _.assignIn({ 'a': 0 }, new Foo, new Bar); + * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } + */ + var assignIn = createAssigner(function (object, source) { + copyObject(source, keysIn(source), object); }); - return baseTimes(length, function(index) { - return arrayMap(array, baseProperty(index)); + + /** + * Creates an object that inherits from the `prototype` object. If a + * `properties` object is given, its own enumerable string keyed properties + * are assigned to the created object. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Object + * @param {Object} prototype The object to inherit from. + * @param {Object} [properties] The properties to assign to the object. + * @returns {Object} Returns the new object. + * @example + * + * function Shape() { + * this.x = 0; + * this.y = 0; + * } + * + * function Circle() { + * Shape.call(this); + * } + * + * Circle.prototype = _.create(Shape.prototype, { + * 'constructor': Circle + * }); + * + * var circle = new Circle; + * circle instanceof Circle; + * // => true + * + * circle instanceof Shape; + * // => true + */ + function create(prototype, properties) { + var result = baseCreate(prototype); + return properties == null ? result : baseAssign(result, properties); + } + + /** + * Assigns own and inherited enumerable string keyed properties of source + * objects to the destination object for all destination properties that + * resolve to `undefined`. Source objects are applied from left to right. + * Once a property is set, additional values of the same property are ignored. + * + * **Note:** This method mutates `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaultsDeep + * @example + * + * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); + * // => { 'a': 1, 'b': 2 } + */ + var defaults = baseRest(function (object, sources) { + object = Object(object); + + var index = -1; + var length = sources.length; + var guard = length > 2 ? sources[2] : undefined; + + if (guard && isIterateeCall(sources[0], sources[1], guard)) { + length = 1; + } + + while (++index < length) { + var source = sources[index]; + var props = keysIn(source); + var propsIndex = -1; + var propsLength = props.length; + + while (++propsIndex < propsLength) { + var key = props[propsIndex]; + var value = object[key]; + + if (value === undefined || + (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { + object[key] = source[key]; + } + } + } + + return object; }); - } - - /** - * Creates an array excluding all given values using - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * for equality comparisons. - * - * **Note:** Unlike `_.pull`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {Array} array The array to inspect. - * @param {...*} [values] The values to exclude. - * @returns {Array} Returns the new array of filtered values. - * @see _.difference, _.xor - * @example - * - * _.without([2, 1, 2, 3], 1, 2); - * // => [3] - */ - var without = baseRest(function(array, values) { - return isArrayLikeObject(array) - ? baseDifference(array, values) - : []; - }); - - /** - * Creates an array of grouped elements, the first of which contains the - * first elements of the given arrays, the second of which contains the - * second elements of the given arrays, and so on. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Array - * @param {...Array} [arrays] The arrays to process. - * @returns {Array} Returns the new array of grouped elements. - * @example - * - * _.zip(['a', 'b'], [1, 2], [true, false]); - * // => [['a', 1, true], ['b', 2, false]] - */ - var zip = baseRest(unzip); - - /** - * This method is like `_.fromPairs` except that it accepts two arrays, - * one of property identifiers and one of corresponding values. - * - * @static - * @memberOf _ - * @since 0.4.0 - * @category Array - * @param {Array} [props=[]] The property identifiers. - * @param {Array} [values=[]] The property values. - * @returns {Object} Returns the new object. - * @example - * - * _.zipObject(['a', 'b'], [1, 2]); - * // => { 'a': 1, 'b': 2 } - */ - function zipObject(props, values) { - return baseZipObject(props || [], values || [], assignValue); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a `lodash` wrapper instance that wraps `value` with explicit method - * chain sequences enabled. The result of such sequences must be unwrapped - * with `_#value`. - * - * @static - * @memberOf _ - * @since 1.3.0 - * @category Seq - * @param {*} value The value to wrap. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'pebbles', 'age': 1 } - * ]; - * - * var youngest = _ - * .chain(users) - * .sortBy('age') - * .map(function(o) { - * return o.user + ' is ' + o.age; - * }) - * .head() - * .value(); - * // => 'pebbles is 1' - */ - function chain(value) { - var result = lodash(value); - result.__chain__ = true; - return result; - } - - /** - * This method invokes `interceptor` and returns `value`. The interceptor - * is invoked with one argument; (value). The purpose of this method is to - * "tap into" a method chain sequence in order to modify intermediate results. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns `value`. - * @example - * - * _([1, 2, 3]) - * .tap(function(array) { - * // Mutate input array. - * array.pop(); - * }) - * .reverse() - * .value(); - * // => [2, 1] - */ - function tap(value, interceptor) { - interceptor(value); - return value; - } - - /** - * This method is like `_.tap` except that it returns the result of `interceptor`. - * The purpose of this method is to "pass thru" values replacing intermediate - * results in a method chain sequence. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Seq - * @param {*} value The value to provide to `interceptor`. - * @param {Function} interceptor The function to invoke. - * @returns {*} Returns the result of `interceptor`. - * @example - * - * _(' abc ') - * .chain() - * .trim() - * .thru(function(value) { - * return [value]; - * }) - * .value(); - * // => ['abc'] - */ - function thru(value, interceptor) { - return interceptor(value); - } - - /** - * This method is the wrapper version of `_.at`. - * - * @name at - * @memberOf _ - * @since 1.0.0 - * @category Seq - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }, 4] }; - * - * _(object).at(['a[0].b.c', 'a[1]']).value(); - * // => [3, 4] - */ - var wrapperAt = flatRest(function(paths) { - var length = paths.length, - start = length ? paths[0] : 0, - value = this.__wrapped__, - interceptor = function(object) { return baseAt(object, paths); }; - - if (length > 1 || this.__actions__.length || - !(value instanceof LazyWrapper) || !isIndex(start)) { - return this.thru(interceptor); - } - value = value.slice(start, +start + (length ? 1 : 0)); - value.__actions__.push({ - 'func': thru, - 'args': [interceptor], - 'thisArg': undefined + + /** + * This method is like `_.defaults` except that it recursively assigns + * default properties. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.10.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @see _.defaults + * @example + * + * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); + * // => { 'a': { 'b': 2, 'c': 3 } } + */ + var defaultsDeep = baseRest(function (args) { + args.push(undefined, customDefaultsMerge); + return apply(mergeWith, undefined, args); }); - return new LodashWrapper(value, this.__chain__).thru(function(array) { - if (length && !array.length) { - array.push(undefined); - } - return array; + + /** + * This method is like `_.find` except that it returns the key of the first + * element `predicate` returns truthy for instead of the element itself. + * + * @static + * @memberOf _ + * @since 1.1.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findKey(users, function(o) { return o.age < 40; }); + * // => 'barney' (iteration order is not guaranteed) + * + * // The `_.matches` iteratee shorthand. + * _.findKey(users, { 'age': 1, 'active': true }); + * // => 'pebbles' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findKey(users, 'active'); + * // => 'barney' + */ + function findKey(object, predicate) { + return baseFindKey(object, baseIteratee(predicate, 3), baseForOwn); + } + + /** + * This method is like `_.findKey` except that it iterates over elements of + * a collection in the opposite order. + * + * @static + * @memberOf _ + * @since 2.0.0 + * @category Object + * @param {Object} object The object to inspect. + * @param {Function} [predicate=_.identity] The function invoked per iteration. + * @returns {string|undefined} Returns the key of the matched element, + * else `undefined`. + * @example + * + * var users = { + * 'barney': { 'age': 36, 'active': true }, + * 'fred': { 'age': 40, 'active': false }, + * 'pebbles': { 'age': 1, 'active': true } + * }; + * + * _.findLastKey(users, function(o) { return o.age < 40; }); + * // => returns 'pebbles' assuming `_.findKey` returns 'barney' + * + * // The `_.matches` iteratee shorthand. + * _.findLastKey(users, { 'age': 36, 'active': true }); + * // => 'barney' + * + * // The `_.matchesProperty` iteratee shorthand. + * _.findLastKey(users, ['active', false]); + * // => 'fred' + * + * // The `_.property` iteratee shorthand. + * _.findLastKey(users, 'active'); + * // => 'pebbles' + */ + function findLastKey(object, predicate) { + return baseFindKey(object, baseIteratee(predicate, 3), baseForOwnRight); + } + + /** + * Gets the value at `path` of `object`. If the resolved value is + * `undefined`, the `defaultValue` is returned in its place. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to get. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.get(object, 'a[0].b.c'); + * // => 3 + * + * _.get(object, ['a', '0', 'b', 'c']); + * // => 3 + * + * _.get(object, 'a.b.c', 'default'); + * // => 'default' + */ + function get(object, path, defaultValue) { + var result = object == null ? undefined : baseGet(object, path); + return result === undefined ? defaultValue : result; + } + + /** + * Checks if `path` is a direct property of `object`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = { 'a': { 'b': 2 } }; + * var other = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.has(object, 'a'); + * // => true + * + * _.has(object, 'a.b'); + * // => true + * + * _.has(object, ['a', 'b']); + * // => true + * + * _.has(other, 'a'); + * // => false + */ + function has(object, path) { + return object != null && hasPath(object, path, baseHas); + } + + /** + * Checks if `path` is a direct or inherited property of `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path to check. + * @returns {boolean} Returns `true` if `path` exists, else `false`. + * @example + * + * var object = _.create({ 'a': _.create({ 'b': 2 }) }); + * + * _.hasIn(object, 'a'); + * // => true + * + * _.hasIn(object, 'a.b'); + * // => true + * + * _.hasIn(object, ['a', 'b']); + * // => true + * + * _.hasIn(object, 'b'); + * // => false + */ + function hasIn(object, path) { + return object != null && hasPath(object, path, baseHasIn); + } + + /** + * Creates an object composed of the inverted keys and values of `object`. + * If `object` contains duplicate values, subsequent values overwrite + * property assignments of previous values. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Object + * @param {Object} object The object to invert. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invert(object); + * // => { '1': 'c', '2': 'b' } + */ + var invert = createInverter(function (result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + result[value] = key; + }, constant(identity)); + + /** + * This method is like `_.invert` except that the inverted object is generated + * from the results of running each element of `object` thru `iteratee`. The + * corresponding inverted value of each inverted key is an array of keys + * responsible for generating the inverted value. The iteratee is invoked + * with one argument: (value). + * + * @static + * @memberOf _ + * @since 4.1.0 + * @category Object + * @param {Object} object The object to invert. + * @param {Function} [iteratee=_.identity] The iteratee invoked per element. + * @returns {Object} Returns the new inverted object. + * @example + * + * var object = { 'a': 1, 'b': 2, 'c': 1 }; + * + * _.invertBy(object); + * // => { '1': ['a', 'c'], '2': ['b'] } + * + * _.invertBy(object, function(value) { + * return 'group' + value; + * }); + * // => { 'group1': ['a', 'c'], 'group2': ['b'] } + */ + var invertBy = createInverter(function (result, value, key) { + if (value != null && + typeof value.toString != 'function') { + value = nativeObjectToString.call(value); + } + + if (hasOwnProperty.call(result, value)) { + result[value].push(key); + } else { + result[value] = [key]; + } + }, baseIteratee); + + /** + * Creates an array of the own enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. See the + * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) + * for more details. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keys(new Foo); + * // => ['a', 'b'] (iteration order is not guaranteed) + * + * _.keys('hi'); + * // => ['0', '1'] + */ + function keys(object) { + return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); + } + + /** + * Creates an array of the own and inherited enumerable property names of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property names. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.keysIn(new Foo); + * // => ['a', 'b', 'c'] (iteration order is not guaranteed) + */ + function keysIn(object) { + return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); + } + + /** + * This method is like `_.assign` except that it recursively merges own and + * inherited enumerable string keyed properties of source objects into the + * destination object. Source properties that resolve to `undefined` are + * skipped if a destination value exists. Array and plain object properties + * are merged recursively. Other objects and value types are overridden by + * assignment. Source objects are applied from left to right. Subsequent + * sources overwrite property assignments of previous sources. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 0.5.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} [sources] The source objects. + * @returns {Object} Returns `object`. + * @example + * + * var object = { + * 'a': [{ 'b': 2 }, { 'd': 4 }] + * }; + * + * var other = { + * 'a': [{ 'c': 3 }, { 'e': 5 }] + * }; + * + * _.merge(object, other); + * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } + */ + var merge = createAssigner(function (object, source, srcIndex) { + baseMerge(object, source, srcIndex); }); - }); - - /** - * Creates a `lodash` wrapper instance with explicit method chain sequences enabled. - * - * @name chain - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 } - * ]; - * - * // A sequence without explicit chaining. - * _(users).head(); - * // => { 'user': 'barney', 'age': 36 } - * - * // A sequence with explicit chaining. - * _(users) - * .chain() - * .head() - * .pick('user') - * .value(); - * // => { 'user': 'barney' } - */ - function wrapperChain() { - return chain(this); - } - - /** - * Executes the chain sequence and returns the wrapped result. - * - * @name commit - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2]; - * var wrapped = _(array).push(3); - * - * console.log(array); - * // => [1, 2] - * - * wrapped = wrapped.commit(); - * console.log(array); - * // => [1, 2, 3] - * - * wrapped.last(); - * // => 3 - * - * console.log(array); - * // => [1, 2, 3] - */ - function wrapperCommit() { - return new LodashWrapper(this.value(), this.__chain__); - } - - /** - * Gets the next value on a wrapped object following the - * [iterator protocol](https://mdn.io/iteration_protocols#iterator). - * - * @name next - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the next iterator value. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped.next(); - * // => { 'done': false, 'value': 1 } - * - * wrapped.next(); - * // => { 'done': false, 'value': 2 } - * - * wrapped.next(); - * // => { 'done': true, 'value': undefined } - */ - function wrapperNext() { - if (this.__values__ === undefined) { - this.__values__ = toArray(this.value()); - } - var done = this.__index__ >= this.__values__.length, - value = done ? undefined : this.__values__[this.__index__++]; - - return { 'done': done, 'value': value }; - } - - /** - * Enables the wrapper to be iterable. - * - * @name Symbol.iterator - * @memberOf _ - * @since 4.0.0 - * @category Seq - * @returns {Object} Returns the wrapper object. - * @example - * - * var wrapped = _([1, 2]); - * - * wrapped[Symbol.iterator]() === wrapped; - * // => true - * - * Array.from(wrapped); - * // => [1, 2] - */ - function wrapperToIterator() { - return this; - } - - /** - * Creates a clone of the chain sequence planting `value` as the wrapped value. - * - * @name plant - * @memberOf _ - * @since 3.2.0 - * @category Seq - * @param {*} value The value to plant. - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * function square(n) { - * return n * n; - * } - * - * var wrapped = _([1, 2]).map(square); - * var other = wrapped.plant([3, 4]); - * - * other.value(); - * // => [9, 16] - * - * wrapped.value(); - * // => [1, 4] - */ - function wrapperPlant(value) { - var result, - parent = this; - - while (parent instanceof baseLodash) { - var clone = wrapperClone(parent); - clone.__index__ = 0; - clone.__values__ = undefined; - if (result) { - previous.__wrapped__ = clone; - } else { - result = clone; - } - var previous = clone; - parent = parent.__wrapped__; - } - previous.__wrapped__ = value; - return result; - } - - /** - * This method is the wrapper version of `_.reverse`. - * - * **Note:** This method mutates the wrapped array. - * - * @name reverse - * @memberOf _ - * @since 0.1.0 - * @category Seq - * @returns {Object} Returns the new `lodash` wrapper instance. - * @example - * - * var array = [1, 2, 3]; - * - * _(array).reverse().value() - * // => [3, 2, 1] - * - * console.log(array); - * // => [3, 2, 1] - */ - function wrapperReverse() { - var value = this.__wrapped__; - if (value instanceof LazyWrapper) { - var wrapped = value; - if (this.__actions__.length) { - wrapped = new LazyWrapper(this); - } - wrapped = wrapped.reverse(); - wrapped.__actions__.push({ - 'func': thru, - 'args': [reverse], - 'thisArg': undefined - }); - return new LodashWrapper(wrapped, this.__chain__); - } - return this.thru(reverse); - } - - /** - * Executes the chain sequence to resolve the unwrapped value. - * - * @name value - * @memberOf _ - * @since 0.1.0 - * @alias toJSON, valueOf - * @category Seq - * @returns {*} Returns the resolved unwrapped value. - * @example - * - * _([1, 2, 3]).value(); - * // => [1, 2, 3] - */ - function wrapperValue() { - return baseWrapperValue(this.__wrapped__, this.__actions__); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The corresponding value of - * each key is the number of times the key was returned by `iteratee`. The - * iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.countBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': 1, '6': 2 } - * - * // The `_.property` iteratee shorthand. - * _.countBy(['one', 'two', 'three'], 'length'); - * // => { '3': 2, '5': 1 } - */ - var countBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - ++result[key]; - } else { - baseAssignValue(result, key, 1); - } - }); - - /** - * Checks if `predicate` returns truthy for **all** elements of `collection`. - * Iteration is stopped once `predicate` returns falsey. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * **Note:** This method returns `true` for - * [empty collections](https://en.wikipedia.org/wiki/Empty_set) because - * [everything is true](https://en.wikipedia.org/wiki/Vacuous_truth) of - * elements of empty collections. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if all elements pass the predicate check, - * else `false`. - * @example - * - * _.every([true, 1, null, 'yes'], Boolean); - * // => false - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.every(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.every(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.every(users, 'active'); - * // => false - */ - function every(collection, predicate, guard) { - var func = isArray(collection) ? arrayEvery : baseEvery; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, baseIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning an array of all elements - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * **Note:** Unlike `_.remove`, this method returns a new array. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.reject - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * _.filter(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, { 'age': 36, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.filter(users, 'active'); - * // => objects for ['barney'] - */ - function filter(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, baseIteratee(predicate, 3)); - } - - /** - * Iterates over elements of `collection`, returning the first element - * `predicate` returns truthy for. The predicate is invoked with three - * arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param {number} [fromIndex=0] The index to search from. - * @returns {*} Returns the matched element, else `undefined`. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false }, - * { 'user': 'pebbles', 'age': 1, 'active': true } - * ]; - * - * _.find(users, function(o) { return o.age < 40; }); - * // => object for 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.find(users, { 'age': 1, 'active': true }); - * // => object for 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.find(users, ['active', false]); - * // => object for 'fred' - * - * // The `_.property` iteratee shorthand. - * _.find(users, 'active'); - * // => object for 'barney' - */ - var find = createFind(findIndex); - - /** - * Iterates over elements of `collection` and invokes `iteratee` for each element. - * The iteratee is invoked with three arguments: (value, index|key, collection). - * Iteratee functions may exit iteration early by explicitly returning `false`. - * - * **Note:** As with other "Collections" methods, objects with a "length" - * property are iterated like arrays. To avoid this behavior use `_.forIn` - * or `_.forOwn` for object iteration. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @alias each - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array|Object} Returns `collection`. - * @see _.forEachRight - * @example - * - * _.forEach([1, 2], function(value) { - * console.log(value); - * }); - * // => Logs `1` then `2`. - * - * _.forEach({ 'a': 1, 'b': 2 }, function(value, key) { - * console.log(key); - * }); - * // => Logs 'a' then 'b' (iteration order is not guaranteed). - */ - function forEach(collection, iteratee) { - var func = isArray(collection) ? arrayEach : baseEach; - return func(collection, baseIteratee(iteratee, 3)); - } - - /** - * Creates an object composed of keys generated from the results of running - * each element of `collection` thru `iteratee`. The order of grouped values - * is determined by the order they occur in `collection`. The corresponding - * value of each key is an array of elements responsible for generating the - * key. The iteratee is invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The iteratee to transform keys. - * @returns {Object} Returns the composed aggregate object. - * @example - * - * _.groupBy([6.1, 4.2, 6.3], Math.floor); - * // => { '4': [4.2], '6': [6.1, 6.3] } - * - * // The `_.property` iteratee shorthand. - * _.groupBy(['one', 'two', 'three'], 'length'); - * // => { '3': ['one', 'two'], '5': ['three'] } - */ - var groupBy = createAggregator(function(result, value, key) { - if (hasOwnProperty.call(result, key)) { - result[key].push(value); - } else { - baseAssignValue(result, key, [value]); - } - }); - - /** - * Creates an array of values by running each element in `collection` thru - * `iteratee`. The iteratee is invoked with three arguments: - * (value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.every`, `_.filter`, `_.map`, `_.mapValues`, `_.reject`, and `_.some`. - * - * The guarded methods are: - * `ary`, `chunk`, `curry`, `curryRight`, `drop`, `dropRight`, `every`, - * `fill`, `invert`, `parseInt`, `random`, `range`, `rangeRight`, `repeat`, - * `sampleSize`, `slice`, `some`, `sortBy`, `split`, `take`, `takeRight`, - * `template`, `trim`, `trimEnd`, `trimStart`, and `words` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new mapped array. - * @example - * - * function square(n) { - * return n * n; - * } - * - * _.map([4, 8], square); - * // => [16, 64] - * - * _.map({ 'a': 4, 'b': 8 }, square); - * // => [16, 64] (iteration order is not guaranteed) - * - * var users = [ - * { 'user': 'barney' }, - * { 'user': 'fred' } - * ]; - * - * // The `_.property` iteratee shorthand. - * _.map(users, 'user'); - * // => ['barney', 'fred'] - */ - function map(collection, iteratee) { - var func = isArray(collection) ? arrayMap : baseMap; - return func(collection, baseIteratee(iteratee, 3)); - } - - /** - * Reduces `collection` to a value which is the accumulated result of running - * each element in `collection` thru `iteratee`, where each successive - * invocation is supplied the return value of the previous. If `accumulator` - * is not given, the first element of `collection` is used as the initial - * value. The iteratee is invoked with four arguments: - * (accumulator, value, index|key, collection). - * - * Many lodash methods are guarded to work as iteratees for methods like - * `_.reduce`, `_.reduceRight`, and `_.transform`. - * - * The guarded methods are: - * `assign`, `defaults`, `defaultsDeep`, `includes`, `merge`, `orderBy`, - * and `sortBy` - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [iteratee=_.identity] The function invoked per iteration. - * @param {*} [accumulator] The initial value. - * @returns {*} Returns the accumulated value. - * @see _.reduceRight - * @example - * - * _.reduce([1, 2], function(sum, n) { - * return sum + n; - * }, 0); - * // => 3 - * - * _.reduce({ 'a': 1, 'b': 2, 'c': 1 }, function(result, value, key) { - * (result[value] || (result[value] = [])).push(key); - * return result; - * }, {}); - * // => { '1': ['a', 'c'], '2': ['b'] } (iteration order is not guaranteed) - */ - function reduce(collection, iteratee, accumulator) { - var func = isArray(collection) ? arrayReduce : baseReduce, - initAccum = arguments.length < 3; - - return func(collection, baseIteratee(iteratee, 4), accumulator, initAccum, baseEach); - } - - /** - * The opposite of `_.filter`; this method returns the elements of `collection` - * that `predicate` does **not** return truthy for. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {Array} Returns the new filtered array. - * @see _.filter - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': false }, - * { 'user': 'fred', 'age': 40, 'active': true } - * ]; - * - * _.reject(users, function(o) { return !o.active; }); - * // => objects for ['fred'] - * - * // The `_.matches` iteratee shorthand. - * _.reject(users, { 'age': 40, 'active': true }); - * // => objects for ['barney'] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.reject(users, ['active', false]); - * // => objects for ['fred'] - * - * // The `_.property` iteratee shorthand. - * _.reject(users, 'active'); - * // => objects for ['barney'] - */ - function reject(collection, predicate) { - var func = isArray(collection) ? arrayFilter : baseFilter; - return func(collection, negate(baseIteratee(predicate, 3))); - } - - /** - * Gets the size of `collection` by returning its length for array-like - * values or the number of own enumerable string keyed properties for objects. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object|string} collection The collection to inspect. - * @returns {number} Returns the collection size. - * @example - * - * _.size([1, 2, 3]); - * // => 3 - * - * _.size({ 'a': 1, 'b': 2 }); - * // => 2 - * - * _.size('pebbles'); - * // => 7 - */ - function size(collection) { - if (collection == null) { - return 0; - } - if (isArrayLike(collection)) { - return isString(collection) ? stringSize(collection) : collection.length; - } - var tag = getTag(collection); - if (tag == mapTag || tag == setTag) { - return collection.size; - } - return baseKeys(collection).length; - } - - /** - * Checks if `predicate` returns truthy for **any** element of `collection`. - * Iteration is stopped once `predicate` returns truthy. The predicate is - * invoked with three arguments: (value, index|key, collection). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {boolean} Returns `true` if any element passes the predicate check, - * else `false`. - * @example - * - * _.some([null, 0, 'yes', false], Boolean); - * // => true - * - * var users = [ - * { 'user': 'barney', 'active': true }, - * { 'user': 'fred', 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.some(users, { 'user': 'barney', 'active': false }); - * // => false - * - * // The `_.matchesProperty` iteratee shorthand. - * _.some(users, ['active', false]); - * // => true - * - * // The `_.property` iteratee shorthand. - * _.some(users, 'active'); - * // => true - */ - function some(collection, predicate, guard) { - var func = isArray(collection) ? arraySome : baseSome; - if (guard && isIterateeCall(collection, predicate, guard)) { - predicate = undefined; - } - return func(collection, baseIteratee(predicate, 3)); - } - - /** - * Creates an array of elements, sorted in ascending order by the results of - * running each element in a collection thru each iteratee. This method - * performs a stable sort, that is, it preserves the original sort order of - * equal elements. The iteratees are invoked with one argument: (value). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Collection - * @param {Array|Object} collection The collection to iterate over. - * @param {...(Function|Function[])} [iteratees=[_.identity]] - * The iteratees to sort by. - * @returns {Array} Returns the new sorted array. - * @example - * - * var users = [ - * { 'user': 'fred', 'age': 48 }, - * { 'user': 'barney', 'age': 36 }, - * { 'user': 'fred', 'age': 40 }, - * { 'user': 'barney', 'age': 34 } - * ]; - * - * _.sortBy(users, [function(o) { return o.user; }]); - * // => objects for [['barney', 36], ['barney', 34], ['fred', 48], ['fred', 40]] - * - * _.sortBy(users, ['user', 'age']); - * // => objects for [['barney', 34], ['barney', 36], ['fred', 40], ['fred', 48]] - */ - var sortBy = baseRest(function(collection, iteratees) { - if (collection == null) { - return []; - } - var length = iteratees.length; - if (length > 1 && isIterateeCall(collection, iteratees[0], iteratees[1])) { - iteratees = []; - } else if (length > 2 && isIterateeCall(iteratees[0], iteratees[1], iteratees[2])) { - iteratees = [iteratees[0]]; - } - return baseOrderBy(collection, baseFlatten(iteratees, 1), []); - }); - - /*------------------------------------------------------------------------*/ - - /** - * Gets the timestamp of the number of milliseconds that have elapsed since - * the Unix epoch (1 January 1970 00:00:00 UTC). - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Date - * @returns {number} Returns the timestamp. - * @example - * - * _.defer(function(stamp) { - * console.log(_.now() - stamp); - * }, _.now()); - * // => Logs the number of milliseconds it took for the deferred invocation. - */ - var now = function() { - return root.Date.now(); - }; - - /*------------------------------------------------------------------------*/ - - /** - * The opposite of `_.before`; this method creates a function that invokes - * `func` once it's called `n` or more times. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {number} n The number of calls before `func` is invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var saves = ['profile', 'settings']; - * - * var done = _.after(saves.length, function() { - * console.log('done saving!'); - * }); - * - * _.forEach(saves, function(type) { - * asyncSave({ 'type': type, 'complete': done }); - * }); - * // => Logs 'done saving!' after the two async saves have completed. - */ - function after(n, func) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n < 1) { - return func.apply(this, arguments); - } - }; - } - - /** - * Creates a function that invokes `func`, with the `this` binding and arguments - * of the created function, while it's called less than `n` times. Subsequent - * calls to the created function return the result of the last `func` invocation. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {number} n The number of calls at which `func` is no longer invoked. - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * jQuery(element).on('click', _.before(5, addContactToList)); - * // => Allows adding up to 4 contacts to the list. - */ - function before(n, func) { - var result; - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - n = toInteger(n); - return function() { - if (--n > 0) { - result = func.apply(this, arguments); - } - if (n <= 1) { - func = undefined; - } - return result; - }; - } - - /** - * Creates a function that invokes `func` with the `this` binding of `thisArg` - * and `partials` prepended to the arguments it receives. - * - * The `_.bind.placeholder` value, which defaults to `_` in monolithic builds, - * may be used as a placeholder for partially applied arguments. - * - * **Note:** Unlike native `Function#bind`, this method doesn't set the "length" - * property of bound functions. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to bind. - * @param {*} thisArg The `this` binding of `func`. - * @param {...*} [partials] The arguments to be partially applied. - * @returns {Function} Returns the new bound function. - * @example - * - * function greet(greeting, punctuation) { - * return greeting + ' ' + this.user + punctuation; - * } - * - * var object = { 'user': 'fred' }; - * - * var bound = _.bind(greet, object, 'hi'); - * bound('!'); - * // => 'hi fred!' - * - * // Bound with placeholders. - * var bound = _.bind(greet, object, _, '!'); - * bound('hi'); - * // => 'hi fred!' - */ - var bind = baseRest(function(func, thisArg, partials) { - var bitmask = WRAP_BIND_FLAG; - if (partials.length) { - var holders = replaceHolders(partials, getHolder(bind)); - bitmask |= WRAP_PARTIAL_FLAG; - } - return createWrap(func, bitmask, thisArg, partials, holders); - }); - - /** - * Creates a debounced function that delays invoking `func` until after `wait` - * milliseconds have elapsed since the last time the debounced function was - * invoked. The debounced function comes with a `cancel` method to cancel - * delayed `func` invocations and a `flush` method to immediately invoke them. - * Provide `options` to indicate whether `func` should be invoked on the - * leading and/or trailing edge of the `wait` timeout. The `func` is invoked - * with the last arguments provided to the debounced function. Subsequent - * calls to the debounced function return the result of the last `func` - * invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the debounced function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.debounce` and `_.throttle`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to debounce. - * @param {number} [wait=0] The number of milliseconds to delay. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=false] - * Specify invoking on the leading edge of the timeout. - * @param {number} [options.maxWait] - * The maximum time `func` is allowed to be delayed before it's invoked. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new debounced function. - * @example - * - * // Avoid costly calculations while the window size is in flux. - * jQuery(window).on('resize', _.debounce(calculateLayout, 150)); - * - * // Invoke `sendMail` when clicked, debouncing subsequent calls. - * jQuery(element).on('click', _.debounce(sendMail, 300, { - * 'leading': true, - * 'trailing': false - * })); - * - * // Ensure `batchLog` is invoked once after 1 second of debounced calls. - * var debounced = _.debounce(batchLog, 250, { 'maxWait': 1000 }); - * var source = new EventSource('/stream'); - * jQuery(source).on('message', debounced); - * - * // Cancel the trailing debounced invocation. - * jQuery(window).on('popstate', debounced.cancel); - */ - function debounce(func, wait, options) { - var lastArgs, - lastThis, - maxWait, - result, - timerId, - lastCallTime, - lastInvokeTime = 0, - leading = false, - maxing = false, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - wait = toNumber(wait) || 0; - if (isObject(options)) { - leading = !!options.leading; - maxing = 'maxWait' in options; - maxWait = maxing ? nativeMax(toNumber(options.maxWait) || 0, wait) : maxWait; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - - function invokeFunc(time) { - var args = lastArgs, - thisArg = lastThis; - - lastArgs = lastThis = undefined; - lastInvokeTime = time; - result = func.apply(thisArg, args); - return result; - } - - function leadingEdge(time) { - // Reset any `maxWait` timer. - lastInvokeTime = time; - // Start the timer for the trailing edge. - timerId = setTimeout(timerExpired, wait); - // Invoke the leading edge. - return leading ? invokeFunc(time) : result; - } - - function remainingWait(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime, - timeWaiting = wait - timeSinceLastCall; - - return maxing - ? nativeMin(timeWaiting, maxWait - timeSinceLastInvoke) - : timeWaiting; - } - - function shouldInvoke(time) { - var timeSinceLastCall = time - lastCallTime, - timeSinceLastInvoke = time - lastInvokeTime; - - // Either this is the first call, activity has stopped and we're at the - // trailing edge, the system time has gone backwards and we're treating - // it as the trailing edge, or we've hit the `maxWait` limit. - return (lastCallTime === undefined || (timeSinceLastCall >= wait) || - (timeSinceLastCall < 0) || (maxing && timeSinceLastInvoke >= maxWait)); - } - - function timerExpired() { - var time = now(); - if (shouldInvoke(time)) { - return trailingEdge(time); - } - // Restart the timer. - timerId = setTimeout(timerExpired, remainingWait(time)); - } - - function trailingEdge(time) { - timerId = undefined; - - // Only invoke if we have `lastArgs` which means `func` has been - // debounced at least once. - if (trailing && lastArgs) { - return invokeFunc(time); - } - lastArgs = lastThis = undefined; - return result; - } - - function cancel() { - if (timerId !== undefined) { - clearTimeout(timerId); - } - lastInvokeTime = 0; - lastArgs = lastCallTime = lastThis = timerId = undefined; - } - - function flush() { - return timerId === undefined ? result : trailingEdge(now()); - } - - function debounced() { - var time = now(), - isInvoking = shouldInvoke(time); - - lastArgs = arguments; - lastThis = this; - lastCallTime = time; - - if (isInvoking) { - if (timerId === undefined) { - return leadingEdge(lastCallTime); - } - if (maxing) { - // Handle invocations in a tight loop. - timerId = setTimeout(timerExpired, wait); - return invokeFunc(lastCallTime); - } - } - if (timerId === undefined) { - timerId = setTimeout(timerExpired, wait); - } - return result; - } - debounced.cancel = cancel; - debounced.flush = flush; - return debounced; - } - - /** - * Defers invoking the `func` until the current call stack has cleared. Any - * additional arguments are provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to defer. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.defer(function(text) { - * console.log(text); - * }, 'deferred'); - * // => Logs 'deferred' after one millisecond. - */ - var defer = baseRest(function(func, args) { - return baseDelay(func, 1, args); - }); - - /** - * Invokes `func` after `wait` milliseconds. Any additional arguments are - * provided to `func` when it's invoked. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to delay. - * @param {number} wait The number of milliseconds to delay invocation. - * @param {...*} [args] The arguments to invoke `func` with. - * @returns {number} Returns the timer id. - * @example - * - * _.delay(function(text) { - * console.log(text); - * }, 1000, 'later'); - * // => Logs 'later' after one second. - */ - var delay = baseRest(function(func, wait, args) { - return baseDelay(func, toNumber(wait) || 0, args); - }); - - /** - * Creates a function that memoizes the result of `func`. If `resolver` is - * provided, it determines the cache key for storing the result based on the - * arguments provided to the memoized function. By default, the first argument - * provided to the memoized function is used as the map cache key. The `func` - * is invoked with the `this` binding of the memoized function. - * - * **Note:** The cache is exposed as the `cache` property on the memoized - * function. Its creation may be customized by replacing the `_.memoize.Cache` - * constructor with one whose instances implement the - * [`Map`](http://ecma-international.org/ecma-262/7.0/#sec-properties-of-the-map-prototype-object) - * method interface of `clear`, `delete`, `get`, `has`, and `set`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to have its output memoized. - * @param {Function} [resolver] The function to resolve the cache key. - * @returns {Function} Returns the new memoized function. - * @example - * - * var object = { 'a': 1, 'b': 2 }; - * var other = { 'c': 3, 'd': 4 }; - * - * var values = _.memoize(_.values); - * values(object); - * // => [1, 2] - * - * values(other); - * // => [3, 4] - * - * object.a = 2; - * values(object); - * // => [1, 2] - * - * // Modify the result cache. - * values.cache.set(object, ['a', 'b']); - * values(object); - * // => ['a', 'b'] - * - * // Replace `_.memoize.Cache`. - * _.memoize.Cache = WeakMap; - */ - function memoize(func, resolver) { - if (typeof func != 'function' || (resolver != null && typeof resolver != 'function')) { - throw new TypeError(FUNC_ERROR_TEXT); - } - var memoized = function() { - var args = arguments, - key = resolver ? resolver.apply(this, args) : args[0], - cache = memoized.cache; - - if (cache.has(key)) { - return cache.get(key); - } - var result = func.apply(this, args); - memoized.cache = cache.set(key, result) || cache; - return result; - }; - memoized.cache = new (memoize.Cache || MapCache); - return memoized; - } - - // Expose `MapCache`. - memoize.Cache = MapCache; - - /** - * Creates a function that negates the result of the predicate `func`. The - * `func` predicate is invoked with the `this` binding and arguments of the - * created function. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Function - * @param {Function} predicate The predicate to negate. - * @returns {Function} Returns the new negated function. - * @example - * - * function isEven(n) { - * return n % 2 == 0; - * } - * - * _.filter([1, 2, 3, 4, 5, 6], _.negate(isEven)); - * // => [1, 3, 5] - */ - function negate(predicate) { - if (typeof predicate != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - return function() { - var args = arguments; - switch (args.length) { - case 0: return !predicate.call(this); - case 1: return !predicate.call(this, args[0]); - case 2: return !predicate.call(this, args[0], args[1]); - case 3: return !predicate.call(this, args[0], args[1], args[2]); - } - return !predicate.apply(this, args); - }; - } - - /** - * Creates a function that is restricted to invoking `func` once. Repeat calls - * to the function return the value of the first invocation. The `func` is - * invoked with the `this` binding and arguments of the created function. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to restrict. - * @returns {Function} Returns the new restricted function. - * @example - * - * var initialize = _.once(createApplication); - * initialize(); - * initialize(); - * // => `createApplication` is invoked once - */ - function once(func) { - return before(2, func); - } - - /** - * Creates a function that invokes `func` with the `this` binding of the - * created function and arguments from `start` and beyond provided as - * an array. - * - * **Note:** This method is based on the - * [rest parameter](https://mdn.io/rest_parameters). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Function - * @param {Function} func The function to apply a rest parameter to. - * @param {number} [start=func.length-1] The start position of the rest parameter. - * @returns {Function} Returns the new function. - * @example - * - * var say = _.rest(function(what, names) { - * return what + ' ' + _.initial(names).join(', ') + - * (_.size(names) > 1 ? ', & ' : '') + _.last(names); - * }); - * - * say('hello', 'fred', 'barney', 'pebbles'); - * // => 'hello fred, barney, & pebbles' - */ - function rest(func, start) { - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - start = start === undefined ? start : toInteger(start); - return baseRest(func, start); - } - - /** - * Creates a throttled function that only invokes `func` at most once per - * every `wait` milliseconds. The throttled function comes with a `cancel` - * method to cancel delayed `func` invocations and a `flush` method to - * immediately invoke them. Provide `options` to indicate whether `func` - * should be invoked on the leading and/or trailing edge of the `wait` - * timeout. The `func` is invoked with the last arguments provided to the - * throttled function. Subsequent calls to the throttled function return the - * result of the last `func` invocation. - * - * **Note:** If `leading` and `trailing` options are `true`, `func` is - * invoked on the trailing edge of the timeout only if the throttled function - * is invoked more than once during the `wait` timeout. - * - * If `wait` is `0` and `leading` is `false`, `func` invocation is deferred - * until to the next tick, similar to `setTimeout` with a timeout of `0`. - * - * See [David Corbacho's article](https://css-tricks.com/debouncing-throttling-explained-examples/) - * for details over the differences between `_.throttle` and `_.debounce`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Function - * @param {Function} func The function to throttle. - * @param {number} [wait=0] The number of milliseconds to throttle invocations to. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.leading=true] - * Specify invoking on the leading edge of the timeout. - * @param {boolean} [options.trailing=true] - * Specify invoking on the trailing edge of the timeout. - * @returns {Function} Returns the new throttled function. - * @example - * - * // Avoid excessively updating the position while scrolling. - * jQuery(window).on('scroll', _.throttle(updatePosition, 100)); - * - * // Invoke `renewToken` when the click event is fired, but not more than once every 5 minutes. - * var throttled = _.throttle(renewToken, 300000, { 'trailing': false }); - * jQuery(element).on('click', throttled); - * - * // Cancel the trailing throttled invocation. - * jQuery(window).on('popstate', throttled.cancel); - */ - function throttle(func, wait, options) { - var leading = true, - trailing = true; - - if (typeof func != 'function') { - throw new TypeError(FUNC_ERROR_TEXT); - } - if (isObject(options)) { - leading = 'leading' in options ? !!options.leading : leading; - trailing = 'trailing' in options ? !!options.trailing : trailing; - } - return debounce(func, wait, { - 'leading': leading, - 'maxWait': wait, - 'trailing': trailing + + /** + * This method is like `_.merge` except that it accepts `customizer` which + * is invoked to produce the merged values of the destination and source + * properties. If `customizer` returns `undefined`, merging is handled by the + * method instead. The `customizer` is invoked with six arguments: + * (objValue, srcValue, key, object, source, stack). + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The destination object. + * @param {...Object} sources The source objects. + * @param {Function} customizer The function to customize assigned values. + * @returns {Object} Returns `object`. + * @example + * + * function customizer(objValue, srcValue) { + * if (_.isArray(objValue)) { + * return objValue.concat(srcValue); + * } + * } + * + * var object = { 'a': [1], 'b': [2] }; + * var other = { 'a': [3], 'b': [4] }; + * + * _.mergeWith(object, other, customizer); + * // => { 'a': [1, 3], 'b': [2, 4] } + */ + var mergeWith = createAssigner(function (object, source, srcIndex, customizer) { + baseMerge(object, source, srcIndex, customizer); }); - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a shallow clone of `value`. - * - * **Note:** This method is loosely based on the - * [structured clone algorithm](https://mdn.io/Structured_clone_algorithm) - * and supports cloning arrays, array buffers, booleans, date objects, maps, - * numbers, `Object` objects, regexes, sets, strings, symbols, and typed - * arrays. The own enumerable properties of `arguments` objects are cloned - * as plain objects. An empty object is returned for uncloneable values such - * as error objects, functions, DOM nodes, and WeakMaps. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to clone. - * @returns {*} Returns the cloned value. - * @see _.cloneDeep - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var shallow = _.clone(objects); - * console.log(shallow[0] === objects[0]); - * // => true - */ - function clone(value) { - return baseClone(value, CLONE_SYMBOLS_FLAG); - } - - /** - * This method is like `_.clone` except that it recursively clones `value`. - * - * @static - * @memberOf _ - * @since 1.0.0 - * @category Lang - * @param {*} value The value to recursively clone. - * @returns {*} Returns the deep cloned value. - * @see _.clone - * @example - * - * var objects = [{ 'a': 1 }, { 'b': 2 }]; - * - * var deep = _.cloneDeep(objects); - * console.log(deep[0] === objects[0]); - * // => false - */ - function cloneDeep(value) { - return baseClone(value, CLONE_DEEP_FLAG | CLONE_SYMBOLS_FLAG); - } - - /** - * Performs a - * [`SameValueZero`](http://ecma-international.org/ecma-262/7.0/#sec-samevaluezero) - * comparison between two values to determine if they are equivalent. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.eq(object, object); - * // => true - * - * _.eq(object, other); - * // => false - * - * _.eq('a', 'a'); - * // => true - * - * _.eq('a', Object('a')); - * // => false - * - * _.eq(NaN, NaN); - * // => true - */ - function eq(value, other) { - return value === other || (value !== value && other !== other); - } - - /** - * Checks if `value` is likely an `arguments` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an `arguments` object, - * else `false`. - * @example - * - * _.isArguments(function() { return arguments; }()); - * // => true - * - * _.isArguments([1, 2, 3]); - * // => false - */ - var isArguments = baseIsArguments(function() { return arguments; }()) ? baseIsArguments : function(value) { - return isObjectLike(value) && hasOwnProperty.call(value, 'callee') && - !propertyIsEnumerable.call(value, 'callee'); - }; - - /** - * Checks if `value` is classified as an `Array` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array, else `false`. - * @example - * - * _.isArray([1, 2, 3]); - * // => true - * - * _.isArray(document.body.children); - * // => false - * - * _.isArray('abc'); - * // => false - * - * _.isArray(_.noop); - * // => false - */ - var isArray = Array.isArray; - - /** - * Checks if `value` is array-like. A value is considered array-like if it's - * not a function and has a `value.length` that's an integer greater than or - * equal to `0` and less than or equal to `Number.MAX_SAFE_INTEGER`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is array-like, else `false`. - * @example - * - * _.isArrayLike([1, 2, 3]); - * // => true - * - * _.isArrayLike(document.body.children); - * // => true - * - * _.isArrayLike('abc'); - * // => true - * - * _.isArrayLike(_.noop); - * // => false - */ - function isArrayLike(value) { - return value != null && isLength(value.length) && !isFunction(value); - } - - /** - * This method is like `_.isArrayLike` except that it also checks if `value` - * is an object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an array-like object, - * else `false`. - * @example - * - * _.isArrayLikeObject([1, 2, 3]); - * // => true - * - * _.isArrayLikeObject(document.body.children); - * // => true - * - * _.isArrayLikeObject('abc'); - * // => false - * - * _.isArrayLikeObject(_.noop); - * // => false - */ - function isArrayLikeObject(value) { - return isObjectLike(value) && isArrayLike(value); - } - - /** - * Checks if `value` is classified as a boolean primitive or object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a boolean, else `false`. - * @example - * - * _.isBoolean(false); - * // => true - * - * _.isBoolean(null); - * // => false - */ - function isBoolean(value) { - return value === true || value === false || - (isObjectLike(value) && baseGetTag(value) == boolTag); - } - - /** - * Checks if `value` is a buffer. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a buffer, else `false`. - * @example - * - * _.isBuffer(new Buffer(2)); - * // => true - * - * _.isBuffer(new Uint8Array(2)); - * // => false - */ - var isBuffer = nativeIsBuffer || stubFalse; - - /** - * Checks if `value` is classified as a `Date` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a date object, else `false`. - * @example - * - * _.isDate(new Date); - * // => true - * - * _.isDate('Mon April 23 2012'); - * // => false - */ - var isDate = nodeIsDate ? baseUnary(nodeIsDate) : baseIsDate; - - /** - * Checks if `value` is an empty object, collection, map, or set. - * - * Objects are considered empty if they have no own enumerable string keyed - * properties. - * - * Array-like values such as `arguments` objects, arrays, buffers, strings, or - * jQuery-like collections are considered empty if they have a `length` of `0`. - * Similarly, maps and sets are considered empty if they have a `size` of `0`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is empty, else `false`. - * @example - * - * _.isEmpty(null); - * // => true - * - * _.isEmpty(true); - * // => true - * - * _.isEmpty(1); - * // => true - * - * _.isEmpty([1, 2, 3]); - * // => false - * - * _.isEmpty({ 'a': 1 }); - * // => false - */ - function isEmpty(value) { - if (value == null) { - return true; - } - if (isArrayLike(value) && - (isArray(value) || typeof value == 'string' || typeof value.splice == 'function' || - isBuffer(value) || isTypedArray(value) || isArguments(value))) { - return !value.length; - } - var tag = getTag(value); - if (tag == mapTag || tag == setTag) { - return !value.size; - } - if (isPrototype(value)) { - return !baseKeys(value).length; - } - for (var key in value) { - if (hasOwnProperty.call(value, key)) { - return false; - } - } - return true; - } - - /** - * Performs a deep comparison between two values to determine if they are - * equivalent. - * - * **Note:** This method supports comparing arrays, array buffers, booleans, - * date objects, error objects, maps, numbers, `Object` objects, regexes, - * sets, strings, symbols, and typed arrays. `Object` objects are compared - * by their own, not inherited, enumerable properties. Functions and DOM - * nodes are compared by strict equality, i.e. `===`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to compare. - * @param {*} other The other value to compare. - * @returns {boolean} Returns `true` if the values are equivalent, else `false`. - * @example - * - * var object = { 'a': 1 }; - * var other = { 'a': 1 }; - * - * _.isEqual(object, other); - * // => true - * - * object === other; - * // => false - */ - function isEqual(value, other) { - return baseIsEqual(value, other); - } - - /** - * Checks if `value` is a finite primitive number. - * - * **Note:** This method is based on - * [`Number.isFinite`](https://mdn.io/Number/isFinite). - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a finite number, else `false`. - * @example - * - * _.isFinite(3); - * // => true - * - * _.isFinite(Number.MIN_VALUE); - * // => true - * - * _.isFinite(Infinity); - * // => false - * - * _.isFinite('3'); - * // => false - */ - function isFinite(value) { - return typeof value == 'number' && nativeIsFinite(value); - } - - /** - * Checks if `value` is classified as a `Function` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a function, else `false`. - * @example - * - * _.isFunction(_); - * // => true - * - * _.isFunction(/abc/); - * // => false - */ - function isFunction(value) { - if (!isObject(value)) { - return false; - } - // The use of `Object#toString` avoids issues with the `typeof` operator - // in Safari 9 which returns 'object' for typed arrays and other constructors. - var tag = baseGetTag(value); - return tag == funcTag || tag == genTag || tag == asyncTag || tag == proxyTag; - } - - /** - * Checks if `value` is a valid array-like length. - * - * **Note:** This method is loosely based on - * [`ToLength`](http://ecma-international.org/ecma-262/7.0/#sec-tolength). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a valid length, else `false`. - * @example - * - * _.isLength(3); - * // => true - * - * _.isLength(Number.MIN_VALUE); - * // => false - * - * _.isLength(Infinity); - * // => false - * - * _.isLength('3'); - * // => false - */ - function isLength(value) { - return typeof value == 'number' && - value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER; - } - - /** - * Checks if `value` is the - * [language type](http://www.ecma-international.org/ecma-262/7.0/#sec-ecmascript-language-types) - * of `Object`. (e.g. arrays, functions, objects, regexes, `new Number(0)`, and `new String('')`) - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is an object, else `false`. - * @example - * - * _.isObject({}); - * // => true - * - * _.isObject([1, 2, 3]); - * // => true - * - * _.isObject(_.noop); - * // => true - * - * _.isObject(null); - * // => false - */ - function isObject(value) { - var type = typeof value; - return value != null && (type == 'object' || type == 'function'); - } - - /** - * Checks if `value` is object-like. A value is object-like if it's not `null` - * and has a `typeof` result of "object". - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is object-like, else `false`. - * @example - * - * _.isObjectLike({}); - * // => true - * - * _.isObjectLike([1, 2, 3]); - * // => true - * - * _.isObjectLike(_.noop); - * // => false - * - * _.isObjectLike(null); - * // => false - */ - function isObjectLike(value) { - return value != null && typeof value == 'object'; - } - - /** - * Checks if `value` is classified as a `Map` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a map, else `false`. - * @example - * - * _.isMap(new Map); - * // => true - * - * _.isMap(new WeakMap); - * // => false - */ - var isMap = nodeIsMap ? baseUnary(nodeIsMap) : baseIsMap; - - /** - * Checks if `value` is `NaN`. - * - * **Note:** This method is based on - * [`Number.isNaN`](https://mdn.io/Number/isNaN) and is not the same as - * global [`isNaN`](https://mdn.io/isNaN) which returns `true` for - * `undefined` and other non-number values. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `NaN`, else `false`. - * @example - * - * _.isNaN(NaN); - * // => true - * - * _.isNaN(new Number(NaN)); - * // => true - * - * isNaN(undefined); - * // => true - * - * _.isNaN(undefined); - * // => false - */ - function isNaN(value) { - // An `NaN` primitive is the only value that is not equal to itself. - // Perform the `toStringTag` check first to avoid errors with some - // ActiveX objects in IE. - return isNumber(value) && value != +value; - } - - /** - * Checks if `value` is `null`. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `null`, else `false`. - * @example - * - * _.isNull(null); - * // => true - * - * _.isNull(void 0); - * // => false - */ - function isNull(value) { - return value === null; - } - - /** - * Checks if `value` is classified as a `Number` primitive or object. - * - * **Note:** To exclude `Infinity`, `-Infinity`, and `NaN`, which are - * classified as numbers, use the `_.isFinite` method. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a number, else `false`. - * @example - * - * _.isNumber(3); - * // => true - * - * _.isNumber(Number.MIN_VALUE); - * // => true - * - * _.isNumber(Infinity); - * // => true - * - * _.isNumber('3'); - * // => false - */ - function isNumber(value) { - return typeof value == 'number' || - (isObjectLike(value) && baseGetTag(value) == numberTag); - } - - /** - * Checks if `value` is a plain object, that is, an object created by the - * `Object` constructor or one with a `[[Prototype]]` of `null`. - * - * @static - * @memberOf _ - * @since 0.8.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a plain object, else `false`. - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * _.isPlainObject(new Foo); - * // => false - * - * _.isPlainObject([1, 2, 3]); - * // => false - * - * _.isPlainObject({ 'x': 0, 'y': 0 }); - * // => true - * - * _.isPlainObject(Object.create(null)); - * // => true - */ - function isPlainObject(value) { - if (!isObjectLike(value) || baseGetTag(value) != objectTag) { - return false; - } - var proto = getPrototype(value); - if (proto === null) { - return true; - } - var Ctor = hasOwnProperty.call(proto, 'constructor') && proto.constructor; - return typeof Ctor == 'function' && Ctor instanceof Ctor && - funcToString.call(Ctor) == objectCtorString; - } - - /** - * Checks if `value` is classified as a `RegExp` object. - * - * @static - * @memberOf _ - * @since 0.1.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a regexp, else `false`. - * @example - * - * _.isRegExp(/abc/); - * // => true - * - * _.isRegExp('/abc/'); - * // => false - */ - var isRegExp = nodeIsRegExp ? baseUnary(nodeIsRegExp) : baseIsRegExp; - - /** - * Checks if `value` is classified as a `Set` object. - * - * @static - * @memberOf _ - * @since 4.3.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a set, else `false`. - * @example - * - * _.isSet(new Set); - * // => true - * - * _.isSet(new WeakSet); - * // => false - */ - var isSet = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet; - - /** - * Checks if `value` is classified as a `String` primitive or object. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a string, else `false`. - * @example - * - * _.isString('abc'); - * // => true - * - * _.isString(1); - * // => false - */ - function isString(value) { - return typeof value == 'string' || - (!isArray(value) && isObjectLike(value) && baseGetTag(value) == stringTag); - } - - /** - * Checks if `value` is classified as a `Symbol` primitive or object. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a symbol, else `false`. - * @example - * - * _.isSymbol(Symbol.iterator); - * // => true - * - * _.isSymbol('abc'); - * // => false - */ - function isSymbol(value) { - return typeof value == 'symbol' || - (isObjectLike(value) && baseGetTag(value) == symbolTag); - } - - /** - * Checks if `value` is classified as a typed array. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is a typed array, else `false`. - * @example - * - * _.isTypedArray(new Uint8Array); - * // => true - * - * _.isTypedArray([]); - * // => false - */ - var isTypedArray = nodeIsTypedArray ? baseUnary(nodeIsTypedArray) : baseIsTypedArray; - - /** - * Checks if `value` is `undefined`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to check. - * @returns {boolean} Returns `true` if `value` is `undefined`, else `false`. - * @example - * - * _.isUndefined(void 0); - * // => true - * - * _.isUndefined(null); - * // => false - */ - function isUndefined(value) { - return value === undefined; - } - - /** - * Converts `value` to an array. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Lang - * @param {*} value The value to convert. - * @returns {Array} Returns the converted array. - * @example - * - * _.toArray({ 'a': 1, 'b': 2 }); - * // => [1, 2] - * - * _.toArray('abc'); - * // => ['a', 'b', 'c'] - * - * _.toArray(1); - * // => [] - * - * _.toArray(null); - * // => [] - */ - function toArray(value) { - if (!value) { - return []; - } - if (isArrayLike(value)) { - return isString(value) ? stringToArray(value) : copyArray(value); - } - if (symIterator && value[symIterator]) { - return iteratorToArray(value[symIterator]()); - } - var tag = getTag(value), - func = tag == mapTag ? mapToArray : (tag == setTag ? setToArray : values); - - return func(value); - } - - /** - * Converts `value` to a finite number. - * - * @static - * @memberOf _ - * @since 4.12.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted number. - * @example - * - * _.toFinite(3.2); - * // => 3.2 - * - * _.toFinite(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toFinite(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toFinite('3.2'); - * // => 3.2 - */ - function toFinite(value) { - if (!value) { - return value === 0 ? value : 0; - } - value = toNumber(value); - if (value === INFINITY || value === -INFINITY) { - var sign = (value < 0 ? -1 : 1); - return sign * MAX_INTEGER; - } - return value === value ? value : 0; - } - - /** - * Converts `value` to an integer. - * - * **Note:** This method is loosely based on - * [`ToInteger`](http://www.ecma-international.org/ecma-262/7.0/#sec-tointeger). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {number} Returns the converted integer. - * @example - * - * _.toInteger(3.2); - * // => 3 - * - * _.toInteger(Number.MIN_VALUE); - * // => 0 - * - * _.toInteger(Infinity); - * // => 1.7976931348623157e+308 - * - * _.toInteger('3.2'); - * // => 3 - */ - function toInteger(value) { - var result = toFinite(value), - remainder = result % 1; - - return result === result ? (remainder ? result - remainder : result) : 0; - } - - /** - * Converts `value` to a number. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to process. - * @returns {number} Returns the number. - * @example - * - * _.toNumber(3.2); - * // => 3.2 - * - * _.toNumber(Number.MIN_VALUE); - * // => 5e-324 - * - * _.toNumber(Infinity); - * // => Infinity - * - * _.toNumber('3.2'); - * // => 3.2 - */ - function toNumber(value) { - if (typeof value == 'number') { - return value; - } - if (isSymbol(value)) { - return NAN; - } - if (isObject(value)) { - var other = typeof value.valueOf == 'function' ? value.valueOf() : value; - value = isObject(other) ? (other + '') : other; - } - if (typeof value != 'string') { - return value === 0 ? value : +value; - } - value = value.replace(reTrim, ''); - var isBinary = reIsBinary.test(value); - return (isBinary || reIsOctal.test(value)) - ? freeParseInt(value.slice(2), isBinary ? 2 : 8) - : (reIsBadHex.test(value) ? NAN : +value); - } - - /** - * Converts `value` to a plain object flattening inherited enumerable string - * keyed properties of `value` to own properties of the plain object. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {Object} Returns the converted plain object. - * @example - * - * function Foo() { - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.assign({ 'a': 1 }, new Foo); - * // => { 'a': 1, 'b': 2 } - * - * _.assign({ 'a': 1 }, _.toPlainObject(new Foo)); - * // => { 'a': 1, 'b': 2, 'c': 3 } - */ - function toPlainObject(value) { - return copyObject(value, keysIn(value)); - } - - /** - * Converts `value` to a string. An empty string is returned for `null` - * and `undefined` values. The sign of `-0` is preserved. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Lang - * @param {*} value The value to convert. - * @returns {string} Returns the converted string. - * @example - * - * _.toString(null); - * // => '' - * - * _.toString(-0); - * // => '-0' - * - * _.toString([1, 2, 3]); - * // => '1,2,3' - */ - function toString(value) { - return value == null ? '' : baseToString(value); - } - - /*------------------------------------------------------------------------*/ - - /** - * This method is like `_.assign` except that it iterates over own and - * inherited source properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @alias extend - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.assign - * @example - * - * function Foo() { - * this.a = 1; - * } - * - * function Bar() { - * this.c = 3; - * } - * - * Foo.prototype.b = 2; - * Bar.prototype.d = 4; - * - * _.assignIn({ 'a': 0 }, new Foo, new Bar); - * // => { 'a': 1, 'b': 2, 'c': 3, 'd': 4 } - */ - var assignIn = createAssigner(function(object, source) { - copyObject(source, keysIn(source), object); - }); - - /** - * Creates an object that inherits from the `prototype` object. If a - * `properties` object is given, its own enumerable string keyed properties - * are assigned to the created object. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Object - * @param {Object} prototype The object to inherit from. - * @param {Object} [properties] The properties to assign to the object. - * @returns {Object} Returns the new object. - * @example - * - * function Shape() { - * this.x = 0; - * this.y = 0; - * } - * - * function Circle() { - * Shape.call(this); - * } - * - * Circle.prototype = _.create(Shape.prototype, { - * 'constructor': Circle - * }); - * - * var circle = new Circle; - * circle instanceof Circle; - * // => true - * - * circle instanceof Shape; - * // => true - */ - function create(prototype, properties) { - var result = baseCreate(prototype); - return properties == null ? result : baseAssign(result, properties); - } - - /** - * Assigns own and inherited enumerable string keyed properties of source - * objects to the destination object for all destination properties that - * resolve to `undefined`. Source objects are applied from left to right. - * Once a property is set, additional values of the same property are ignored. - * - * **Note:** This method mutates `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaultsDeep - * @example - * - * _.defaults({ 'a': 1 }, { 'b': 2 }, { 'a': 3 }); - * // => { 'a': 1, 'b': 2 } - */ - var defaults = baseRest(function(object, sources) { - object = Object(object); - - var index = -1; - var length = sources.length; - var guard = length > 2 ? sources[2] : undefined; - - if (guard && isIterateeCall(sources[0], sources[1], guard)) { - length = 1; - } - - while (++index < length) { - var source = sources[index]; - var props = keysIn(source); - var propsIndex = -1; - var propsLength = props.length; - - while (++propsIndex < propsLength) { - var key = props[propsIndex]; - var value = object[key]; - - if (value === undefined || - (eq(value, objectProto[key]) && !hasOwnProperty.call(object, key))) { - object[key] = source[key]; - } - } - } - - return object; - }); - - /** - * This method is like `_.defaults` except that it recursively assigns - * default properties. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.10.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @see _.defaults - * @example - * - * _.defaultsDeep({ 'a': { 'b': 2 } }, { 'a': { 'b': 1, 'c': 3 } }); - * // => { 'a': { 'b': 2, 'c': 3 } } - */ - var defaultsDeep = baseRest(function(args) { - args.push(undefined, customDefaultsMerge); - return apply(mergeWith, undefined, args); - }); - - /** - * This method is like `_.find` except that it returns the key of the first - * element `predicate` returns truthy for instead of the element itself. - * - * @static - * @memberOf _ - * @since 1.1.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findKey(users, function(o) { return o.age < 40; }); - * // => 'barney' (iteration order is not guaranteed) - * - * // The `_.matches` iteratee shorthand. - * _.findKey(users, { 'age': 1, 'active': true }); - * // => 'pebbles' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findKey(users, 'active'); - * // => 'barney' - */ - function findKey(object, predicate) { - return baseFindKey(object, baseIteratee(predicate, 3), baseForOwn); - } - - /** - * This method is like `_.findKey` except that it iterates over elements of - * a collection in the opposite order. - * - * @static - * @memberOf _ - * @since 2.0.0 - * @category Object - * @param {Object} object The object to inspect. - * @param {Function} [predicate=_.identity] The function invoked per iteration. - * @returns {string|undefined} Returns the key of the matched element, - * else `undefined`. - * @example - * - * var users = { - * 'barney': { 'age': 36, 'active': true }, - * 'fred': { 'age': 40, 'active': false }, - * 'pebbles': { 'age': 1, 'active': true } - * }; - * - * _.findLastKey(users, function(o) { return o.age < 40; }); - * // => returns 'pebbles' assuming `_.findKey` returns 'barney' - * - * // The `_.matches` iteratee shorthand. - * _.findLastKey(users, { 'age': 36, 'active': true }); - * // => 'barney' - * - * // The `_.matchesProperty` iteratee shorthand. - * _.findLastKey(users, ['active', false]); - * // => 'fred' - * - * // The `_.property` iteratee shorthand. - * _.findLastKey(users, 'active'); - * // => 'pebbles' - */ - function findLastKey(object, predicate) { - return baseFindKey(object, baseIteratee(predicate, 3), baseForOwnRight); - } - - /** - * Gets the value at `path` of `object`. If the resolved value is - * `undefined`, the `defaultValue` is returned in its place. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to get. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.get(object, 'a[0].b.c'); - * // => 3 - * - * _.get(object, ['a', '0', 'b', 'c']); - * // => 3 - * - * _.get(object, 'a.b.c', 'default'); - * // => 'default' - */ - function get(object, path, defaultValue) { - var result = object == null ? undefined : baseGet(object, path); - return result === undefined ? defaultValue : result; - } - - /** - * Checks if `path` is a direct property of `object`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = { 'a': { 'b': 2 } }; - * var other = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.has(object, 'a'); - * // => true - * - * _.has(object, 'a.b'); - * // => true - * - * _.has(object, ['a', 'b']); - * // => true - * - * _.has(other, 'a'); - * // => false - */ - function has(object, path) { - return object != null && hasPath(object, path, baseHas); - } - - /** - * Checks if `path` is a direct or inherited property of `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path to check. - * @returns {boolean} Returns `true` if `path` exists, else `false`. - * @example - * - * var object = _.create({ 'a': _.create({ 'b': 2 }) }); - * - * _.hasIn(object, 'a'); - * // => true - * - * _.hasIn(object, 'a.b'); - * // => true - * - * _.hasIn(object, ['a', 'b']); - * // => true - * - * _.hasIn(object, 'b'); - * // => false - */ - function hasIn(object, path) { - return object != null && hasPath(object, path, baseHasIn); - } - - /** - * Creates an object composed of the inverted keys and values of `object`. - * If `object` contains duplicate values, subsequent values overwrite - * property assignments of previous values. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Object - * @param {Object} object The object to invert. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invert(object); - * // => { '1': 'c', '2': 'b' } - */ - var invert = createInverter(function(result, value, key) { - if (value != null && - typeof value.toString != 'function') { - value = nativeObjectToString.call(value); - } - - result[value] = key; - }, constant(identity)); - - /** - * This method is like `_.invert` except that the inverted object is generated - * from the results of running each element of `object` thru `iteratee`. The - * corresponding inverted value of each inverted key is an array of keys - * responsible for generating the inverted value. The iteratee is invoked - * with one argument: (value). - * - * @static - * @memberOf _ - * @since 4.1.0 - * @category Object - * @param {Object} object The object to invert. - * @param {Function} [iteratee=_.identity] The iteratee invoked per element. - * @returns {Object} Returns the new inverted object. - * @example - * - * var object = { 'a': 1, 'b': 2, 'c': 1 }; - * - * _.invertBy(object); - * // => { '1': ['a', 'c'], '2': ['b'] } - * - * _.invertBy(object, function(value) { - * return 'group' + value; - * }); - * // => { 'group1': ['a', 'c'], 'group2': ['b'] } - */ - var invertBy = createInverter(function(result, value, key) { - if (value != null && - typeof value.toString != 'function') { - value = nativeObjectToString.call(value); - } - - if (hasOwnProperty.call(result, value)) { - result[value].push(key); - } else { - result[value] = [key]; - } - }, baseIteratee); - - /** - * Creates an array of the own enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. See the - * [ES spec](http://ecma-international.org/ecma-262/7.0/#sec-object.keys) - * for more details. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keys(new Foo); - * // => ['a', 'b'] (iteration order is not guaranteed) - * - * _.keys('hi'); - * // => ['0', '1'] - */ - function keys(object) { - return isArrayLike(object) ? arrayLikeKeys(object) : baseKeys(object); - } - - /** - * Creates an array of the own and inherited enumerable property names of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property names. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.keysIn(new Foo); - * // => ['a', 'b', 'c'] (iteration order is not guaranteed) - */ - function keysIn(object) { - return isArrayLike(object) ? arrayLikeKeys(object, true) : baseKeysIn(object); - } - - /** - * This method is like `_.assign` except that it recursively merges own and - * inherited enumerable string keyed properties of source objects into the - * destination object. Source properties that resolve to `undefined` are - * skipped if a destination value exists. Array and plain object properties - * are merged recursively. Other objects and value types are overridden by - * assignment. Source objects are applied from left to right. Subsequent - * sources overwrite property assignments of previous sources. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 0.5.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} [sources] The source objects. - * @returns {Object} Returns `object`. - * @example - * - * var object = { - * 'a': [{ 'b': 2 }, { 'd': 4 }] - * }; - * - * var other = { - * 'a': [{ 'c': 3 }, { 'e': 5 }] - * }; - * - * _.merge(object, other); - * // => { 'a': [{ 'b': 2, 'c': 3 }, { 'd': 4, 'e': 5 }] } - */ - var merge = createAssigner(function(object, source, srcIndex) { - baseMerge(object, source, srcIndex); - }); - - /** - * This method is like `_.merge` except that it accepts `customizer` which - * is invoked to produce the merged values of the destination and source - * properties. If `customizer` returns `undefined`, merging is handled by the - * method instead. The `customizer` is invoked with six arguments: - * (objValue, srcValue, key, object, source, stack). - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The destination object. - * @param {...Object} sources The source objects. - * @param {Function} customizer The function to customize assigned values. - * @returns {Object} Returns `object`. - * @example - * - * function customizer(objValue, srcValue) { - * if (_.isArray(objValue)) { - * return objValue.concat(srcValue); - * } - * } - * - * var object = { 'a': [1], 'b': [2] }; - * var other = { 'a': [3], 'b': [4] }; - * - * _.mergeWith(object, other, customizer); - * // => { 'a': [1, 3], 'b': [2, 4] } - */ - var mergeWith = createAssigner(function(object, source, srcIndex, customizer) { - baseMerge(object, source, srcIndex, customizer); - }); - - /** - * The opposite of `_.pick`; this method creates an object composed of the - * own and inherited enumerable property paths of `object` that are not omitted. - * - * **Note:** This method is considerably slower than `_.pick`. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to omit. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omit(object, ['a', 'c']); - * // => { 'b': '2' } - */ - var omit = flatRest(function(object, paths) { - var result = {}; - if (object == null) { - return result; - } - var isDeep = false; - paths = arrayMap(paths, function(path) { - path = castPath(path, object); - isDeep || (isDeep = path.length > 1); - return path; + + /** + * The opposite of `_.pick`; this method creates an object composed of the + * own and inherited enumerable property paths of `object` that are not omitted. + * + * **Note:** This method is considerably slower than `_.pick`. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to omit. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omit(object, ['a', 'c']); + * // => { 'b': '2' } + */ + var omit = flatRest(function (object, paths) { + var result = {}; + if (object == null) { + return result; + } + var isDeep = false; + paths = arrayMap(paths, function (path) { + path = castPath(path, object); + isDeep || (isDeep = path.length > 1); + return path; + }); + copyObject(object, getAllKeysIn(object), result); + if (isDeep) { + result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); + } + var length = paths.length; + while (length--) { + baseUnset(result, paths[length]); + } + return result; }); - copyObject(object, getAllKeysIn(object), result); - if (isDeep) { - result = baseClone(result, CLONE_DEEP_FLAG | CLONE_FLAT_FLAG | CLONE_SYMBOLS_FLAG, customOmitClone); - } - var length = paths.length; - while (length--) { - baseUnset(result, paths[length]); - } - return result; - }); - - /** - * The opposite of `_.pickBy`; this method creates an object composed of - * the own and inherited enumerable string keyed properties of `object` that - * `predicate` doesn't return truthy for. The predicate is invoked with two - * arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.omitBy(object, _.isNumber); - * // => { 'b': '2' } - */ - function omitBy(object, predicate) { - return pickBy(object, negate(baseIteratee(predicate))); - } - - /** - * Creates an object composed of the picked `object` properties. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The source object. - * @param {...(string|string[])} [paths] The property paths to pick. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pick(object, ['a', 'c']); - * // => { 'a': 1, 'c': 3 } - */ - var pick = flatRest(function(object, paths) { - return object == null ? {} : basePick(object, paths); - }); - - /** - * Creates an object composed of the `object` properties `predicate` returns - * truthy for. The predicate is invoked with two arguments: (value, key). - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Object - * @param {Object} object The source object. - * @param {Function} [predicate=_.identity] The function invoked per property. - * @returns {Object} Returns the new object. - * @example - * - * var object = { 'a': 1, 'b': '2', 'c': 3 }; - * - * _.pickBy(object, _.isNumber); - * // => { 'a': 1, 'c': 3 } - */ - function pickBy(object, predicate) { - if (object == null) { - return {}; - } - var props = arrayMap(getAllKeysIn(object), function(prop) { - return [prop]; + + /** + * The opposite of `_.pickBy`; this method creates an object composed of + * the own and inherited enumerable string keyed properties of `object` that + * `predicate` doesn't return truthy for. The predicate is invoked with two + * arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.omitBy(object, _.isNumber); + * // => { 'b': '2' } + */ + function omitBy(object, predicate) { + return pickBy(object, negate(baseIteratee(predicate))); + } + + /** + * Creates an object composed of the picked `object` properties. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The source object. + * @param {...(string|string[])} [paths] The property paths to pick. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pick(object, ['a', 'c']); + * // => { 'a': 1, 'c': 3 } + */ + var pick = flatRest(function (object, paths) { + return object == null ? {} : basePick(object, paths); }); - predicate = baseIteratee(predicate); - return basePickBy(object, props, function(value, path) { - return predicate(value, path[0]); + + /** + * Creates an object composed of the `object` properties `predicate` returns + * truthy for. The predicate is invoked with two arguments: (value, key). + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Object + * @param {Object} object The source object. + * @param {Function} [predicate=_.identity] The function invoked per property. + * @returns {Object} Returns the new object. + * @example + * + * var object = { 'a': 1, 'b': '2', 'c': 3 }; + * + * _.pickBy(object, _.isNumber); + * // => { 'a': 1, 'c': 3 } + */ + function pickBy(object, predicate) { + if (object == null) { + return {}; + } + var props = arrayMap(getAllKeysIn(object), function (prop) { + return [prop]; + }); + predicate = baseIteratee(predicate); + return basePickBy(object, props, function (value, path) { + return predicate(value, path[0]); + }); + } + + /** + * This method is like `_.get` except that if the resolved value is a + * function it's invoked with the `this` binding of its parent object and + * its result is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @param {Array|string} path The path of the property to resolve. + * @param {*} [defaultValue] The value returned for `undefined` resolved values. + * @returns {*} Returns the resolved value. + * @example + * + * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; + * + * _.result(object, 'a[0].b.c1'); + * // => 3 + * + * _.result(object, 'a[0].b.c2'); + * // => 4 + * + * _.result(object, 'a[0].b.c3', 'default'); + * // => 'default' + * + * _.result(object, 'a[0].b.c3', _.constant('default')); + * // => 'default' + */ + function result(object, path, defaultValue) { + path = castPath(path, object); + + var index = -1, + length = path.length; + + // Ensure the loop is entered when path is empty. + if (!length) { + length = 1; + object = undefined; + } + while (++index < length) { + var value = object == null ? undefined : object[toKey(path[index])]; + if (value === undefined) { + index = length; + value = defaultValue; + } + object = isFunction(value) ? value.call(object) : value; + } + return object; + } + + /** + * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, + * it's created. Arrays are created for missing index properties while objects + * are created for all other missing properties. Use `_.setWith` to customize + * `path` creation. + * + * **Note:** This method mutates `object`. + * + * @static + * @memberOf _ + * @since 3.7.0 + * @category Object + * @param {Object} object The object to modify. + * @param {Array|string} path The path of the property to set. + * @param {*} value The value to set. + * @returns {Object} Returns `object`. + * @example + * + * var object = { 'a': [{ 'b': { 'c': 3 } }] }; + * + * _.set(object, 'a[0].b.c', 4); + * console.log(object.a[0].b.c); + * // => 4 + * + * _.set(object, ['x', '0', 'y', 'z'], 5); + * console.log(object.x[0].y.z); + * // => 5 + */ + function set(object, path, value) { + return object == null ? object : baseSet(object, path, value); + } + + /** + * Creates an array of the own enumerable string keyed property values of `object`. + * + * **Note:** Non-object values are coerced to objects. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Object + * @param {Object} object The object to query. + * @returns {Array} Returns the array of property values. + * @example + * + * function Foo() { + * this.a = 1; + * this.b = 2; + * } + * + * Foo.prototype.c = 3; + * + * _.values(new Foo); + * // => [1, 2] (iteration order is not guaranteed) + * + * _.values('hi'); + * // => ['h', 'i'] + */ + function values(object) { + return object == null ? [] : baseValues(object, keys(object)); + } + + /*------------------------------------------------------------------------*/ + + /** + * Clamps `number` within the inclusive `lower` and `upper` bounds. + * + * @static + * @memberOf _ + * @since 4.0.0 + * @category Number + * @param {number} number The number to clamp. + * @param {number} [lower] The lower bound. + * @param {number} upper The upper bound. + * @returns {number} Returns the clamped number. + * @example + * + * _.clamp(-10, -5, 5); + * // => -5 + * + * _.clamp(10, -5, 5); + * // => 5 + */ + function clamp(number, lower, upper) { + if (upper === undefined) { + upper = lower; + lower = undefined; + } + if (upper !== undefined) { + upper = toNumber(upper); + upper = upper === upper ? upper : 0; + } + if (lower !== undefined) { + lower = toNumber(lower); + lower = lower === lower ? lower : 0; + } + return baseClamp(toNumber(number), lower, upper); + } + + /** + * Produces a random number between the inclusive `lower` and `upper` bounds. + * If only one argument is provided a number between `0` and the given number + * is returned. If `floating` is `true`, or either `lower` or `upper` are + * floats, a floating-point number is returned instead of an integer. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @memberOf _ + * @since 0.7.0 + * @category Number + * @param {number} [lower=0] The lower bound. + * @param {number} [upper=1] The upper bound. + * @param {boolean} [floating] Specify returning a floating-point number. + * @returns {number} Returns the random number. + * @example + * + * _.random(0, 5); + * // => an integer between 0 and 5 + * + * _.random(5); + * // => also an integer between 0 and 5 + * + * _.random(5, true); + * // => a floating-point number between 0 and 5 + * + * _.random(1.2, 5.2); + * // => a floating-point number between 1.2 and 5.2 + */ + function random(lower, upper, floating) { + if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { + upper = floating = undefined; + } + if (floating === undefined) { + if (typeof upper == 'boolean') { + floating = upper; + upper = undefined; + } else if (typeof lower == 'boolean') { + floating = lower; + lower = undefined; + } + } + if (lower === undefined && upper === undefined) { + lower = 0; + upper = 1; + } else { + lower = toFinite(lower); + if (upper === undefined) { + upper = lower; + lower = 0; + } else { + upper = toFinite(upper); + } + } + if (lower > upper) { + var temp = lower; + lower = upper; + upper = temp; + } + if (floating || lower % 1 || upper % 1) { + var rand = nativeRandom(); + return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); + } + return baseRandom(lower, upper); + } + + /*------------------------------------------------------------------------*/ + + /** + * Converts the characters "&", "<", ">", '"', and "'" in `string` to their + * corresponding HTML entities. + * + * **Note:** No other characters are escaped. To escape additional + * characters use a third-party library like [_he_](https://mths.be/he). + * + * Though the ">" character is escaped for symmetry, characters like + * ">" and "/" don't need escaping in HTML and have no special meaning + * unless they're part of a tag or unquoted attribute value. See + * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) + * (under "semi-related fun fact") for more details. + * + * When working with HTML you should always + * [quote attribute values](http://wonko.com/post/html-escaping) to reduce + * XSS vectors. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category String + * @param {string} [string=''] The string to escape. + * @returns {string} Returns the escaped string. + * @example + * + * _.escape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function escape(string) { + string = toString(string); + return (string && reHasUnescapedHtml.test(string)) + ? string.replace(reUnescapedHtml, escapeHtmlChar) + : string; + } + + /** + * Removes leading and trailing whitespace or specified characters from `string`. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category String + * @param {string} [string=''] The string to trim. + * @param {string} [chars=whitespace] The characters to trim. + * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. + * @returns {string} Returns the trimmed string. + * @example + * + * _.trim(' abc '); + * // => 'abc' + * + * _.trim('-_-abc-_-', '_-'); + * // => 'abc' + * + * _.map([' foo ', ' bar '], _.trim); + * // => ['foo', 'bar'] + */ + function trim(string, chars, guard) { + string = toString(string); + if (string && (guard || chars === undefined)) { + return string.replace(reTrim, ''); + } + if (!string || !(chars = baseToString(chars))) { + return string; + } + var strSymbols = stringToArray(string), + chrSymbols = stringToArray(chars), + start = charsStartIndex(strSymbols, chrSymbols), + end = charsEndIndex(strSymbols, chrSymbols) + 1; + + return castSlice(strSymbols, start, end).join(''); + } + + /** + * The inverse of `_.escape`; this method converts the HTML entities + * `&`, `<`, `>`, `"`, and `'` in `string` to + * their corresponding characters. + * + * **Note:** No other HTML entities are unescaped. To unescape additional + * HTML entities use a third-party library like [_he_](https://mths.be/he). + * + * @static + * @memberOf _ + * @since 0.6.0 + * @category String + * @param {string} [string=''] The string to unescape. + * @returns {string} Returns the unescaped string. + * @example + * + * _.unescape('fred, barney, & pebbles'); + * // => 'fred, barney, & pebbles' + */ + function unescape(string) { + string = toString(string); + return (string && reHasEscapedHtml.test(string)) + ? string.replace(reEscapedHtml, unescapeHtmlChar) + : string; + } + + /*------------------------------------------------------------------------*/ + + /** + * Creates a function that returns `value`. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {*} value The value to return from the new function. + * @returns {Function} Returns the new constant function. + * @example + * + * var objects = _.times(2, _.constant({ 'a': 1 })); + * + * console.log(objects); + * // => [{ 'a': 1 }, { 'a': 1 }] + * + * console.log(objects[0] === objects[1]); + * // => true + */ + function constant(value) { + return function () { + return value; + }; + } + + /** + * This method returns the first argument it receives. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {*} value Any value. + * @returns {*} Returns `value`. + * @example + * + * var object = { 'a': 1 }; + * + * console.log(_.identity(object) === object); + * // => true + */ + function identity(value) { + return value; + } + + /** + * Creates a function that invokes `func` with the arguments of the created + * function. If `func` is a property name, the created function returns the + * property value for a given element. If `func` is an array or object, the + * created function returns `true` for elements that contain the equivalent + * source properties, otherwise it returns `false`. + * + * @static + * @since 4.0.0 + * @memberOf _ + * @category Util + * @param {*} [func=_.identity] The value to convert to a callback. + * @returns {Function} Returns the callback. + * @example + * + * var users = [ + * { 'user': 'barney', 'age': 36, 'active': true }, + * { 'user': 'fred', 'age': 40, 'active': false } + * ]; + * + * // The `_.matches` iteratee shorthand. + * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true })); + * // => [{ 'user': 'barney', 'age': 36, 'active': true }] + * + * // The `_.matchesProperty` iteratee shorthand. + * _.filter(users, _.iteratee(['user', 'fred'])); + * // => [{ 'user': 'fred', 'age': 40 }] + * + * // The `_.property` iteratee shorthand. + * _.map(users, _.iteratee('user')); + * // => ['barney', 'fred'] + * + * // Create custom iteratee shorthands. + * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) { + * return !_.isRegExp(func) ? iteratee(func) : function(string) { + * return func.test(string); + * }; + * }); + * + * _.filter(['abc', 'def'], /ef/); + * // => ['def'] + */ + function iteratee(func) { + return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG)); + } + + /** + * Creates a function that performs a partial deep comparison between a given + * object and `source`, returning `true` if the given object has equivalent + * property values, else `false`. + * + * **Note:** The created function is equivalent to `_.isMatch` with `source` + * partially applied. + * + * Partial comparisons will match empty array and empty object `source` + * values against any array or object value, respectively. See `_.isEqual` + * for a list of supported value comparisons. + * + * @static + * @memberOf _ + * @since 3.0.0 + * @category Util + * @param {Object} source The object of property values to match. + * @returns {Function} Returns the new spec function. + * @example + * + * var objects = [ + * { 'a': 1, 'b': 2, 'c': 3 }, + * { 'a': 4, 'b': 5, 'c': 6 } + * ]; + * + * _.filter(objects, _.matches({ 'a': 4, 'c': 6 })); + * // => [{ 'a': 4, 'b': 5, 'c': 6 }] + */ + function matches(source) { + return baseMatches(baseClone(source, CLONE_DEEP_FLAG)); + } + + /** + * Adds all own enumerable string keyed function properties of a source + * object to the destination object. If `object` is a function, then methods + * are added to its prototype as well. + * + * **Note:** Use `_.runInContext` to create a pristine `lodash` function to + * avoid conflicts caused by modifying the original. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {Function|Object} [object=lodash] The destination object. + * @param {Object} source The object of functions to add. + * @param {Object} [options={}] The options object. + * @param {boolean} [options.chain=true] Specify whether mixins are chainable. + * @returns {Function|Object} Returns `object`. + * @example + * + * function vowels(string) { + * return _.filter(string, function(v) { + * return /[aeiou]/i.test(v); + * }); + * } + * + * _.mixin({ 'vowels': vowels }); + * _.vowels('fred'); + * // => ['e'] + * + * _('fred').vowels().value(); + * // => ['e'] + * + * _.mixin({ 'vowels': vowels }, { 'chain': false }); + * _('fred').vowels(); + * // => ['e'] + */ + function mixin(object, source, options) { + var props = keys(source), + methodNames = baseFunctions(source, props); + + if (options == null && + !(isObject(source) && (methodNames.length || !props.length))) { + options = source; + source = object; + object = this; + methodNames = baseFunctions(source, keys(source)); + } + var chain = !(isObject(options) && 'chain' in options) || !!options.chain, + isFunc = isFunction(object); + + arrayEach(methodNames, function (methodName) { + var func = source[methodName]; + object[methodName] = func; + if (isFunc) { + object.prototype[methodName] = function () { + var chainAll = this.__chain__; + if (chain || chainAll) { + var result = object(this.__wrapped__), + actions = result.__actions__ = copyArray(this.__actions__); + + actions.push({ 'func': func, 'args': arguments, 'thisArg': object }); + result.__chain__ = chainAll; + return result; + } + return func.apply(object, arrayPush([this.value()], arguments)); + }; + } + }); + + return object; + } + + /** + * Reverts the `_` variable to its previous value and returns a reference to + * the `lodash` function. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @returns {Function} Returns the `lodash` function. + * @example + * + * var lodash = _.noConflict(); + */ + function noConflict() { + if (root._ === this) { + root._ = oldDash; + } + return this; + } + + /** + * This method returns `undefined`. + * + * @static + * @memberOf _ + * @since 2.3.0 + * @category Util + * @example + * + * _.times(2, _.noop); + * // => [undefined, undefined] + */ + function noop() { + // No operation performed. + } + + /** + * Creates a function that returns the value at `path` of a given object. + * + * @static + * @memberOf _ + * @since 2.4.0 + * @category Util + * @param {Array|string} path The path of the property to get. + * @returns {Function} Returns the new accessor function. + * @example + * + * var objects = [ + * { 'a': { 'b': 2 } }, + * { 'a': { 'b': 1 } } + * ]; + * + * _.map(objects, _.property('a.b')); + * // => [2, 1] + * + * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); + * // => [1, 2] + */ + function property(path) { + return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); + } + + /** + * Creates an array of numbers (positive and/or negative) progressing from + * `start` up to, but not including, `end`. A step of `-1` is used if a negative + * `start` is specified without an `end` or `step`. If `end` is not specified, + * it's set to `start` with `start` then set to `0`. + * + * **Note:** JavaScript follows the IEEE-754 standard for resolving + * floating-point values which can produce unexpected results. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {number} [start=0] The start of the range. + * @param {number} end The end of the range. + * @param {number} [step=1] The value to increment or decrement by. + * @returns {Array} Returns the range of numbers. + * @see _.inRange, _.rangeRight + * @example + * + * _.range(4); + * // => [0, 1, 2, 3] + * + * _.range(-4); + * // => [0, -1, -2, -3] + * + * _.range(1, 5); + * // => [1, 2, 3, 4] + * + * _.range(0, 20, 5); + * // => [0, 5, 10, 15] + * + * _.range(0, -4, -1); + * // => [0, -1, -2, -3] + * + * _.range(1, 4, 0); + * // => [1, 1, 1] + * + * _.range(0); + * // => [] + */ + var range = createRange(); + + /** + * This method returns a new empty array. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {Array} Returns the new empty array. + * @example + * + * var arrays = _.times(2, _.stubArray); + * + * console.log(arrays); + * // => [[], []] + * + * console.log(arrays[0] === arrays[1]); + * // => false + */ + function stubArray() { + return []; + } + + /** + * This method returns `false`. + * + * @static + * @memberOf _ + * @since 4.13.0 + * @category Util + * @returns {boolean} Returns `false`. + * @example + * + * _.times(2, _.stubFalse); + * // => [false, false] + */ + function stubFalse() { + return false; + } + + /** + * Generates a unique ID. If `prefix` is given, the ID is appended to it. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Util + * @param {string} [prefix=''] The value to prefix the ID with. + * @returns {string} Returns the unique ID. + * @example + * + * _.uniqueId('contact_'); + * // => 'contact_104' + * + * _.uniqueId(); + * // => '105' + */ + function uniqueId(prefix) { + var id = ++idCounter; + return toString(prefix) + id; + } + + /*------------------------------------------------------------------------*/ + + /** + * Computes the maximum value of `array`. If `array` is empty or falsey, + * `undefined` is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @returns {*} Returns the maximum value. + * @example + * + * _.max([4, 2, 8, 6]); + * // => 8 + * + * _.max([]); + * // => undefined + */ + function max(array) { + return (array && array.length) + ? baseExtremum(array, identity, baseGt) + : undefined; + } + + /** + * Computes the minimum value of `array`. If `array` is empty or falsey, + * `undefined` is returned. + * + * @static + * @since 0.1.0 + * @memberOf _ + * @category Math + * @param {Array} array The array to iterate over. + * @returns {*} Returns the minimum value. + * @example + * + * _.min([4, 2, 8, 6]); + * // => 2 + * + * _.min([]); + * // => undefined + */ + function min(array) { + return (array && array.length) + ? baseExtremum(array, identity, baseLt) + : undefined; + } + + /*------------------------------------------------------------------------*/ + + // Add methods that return wrapped values in chain sequences. + lodash.after = after; + lodash.assignIn = assignIn; + lodash.before = before; + lodash.bind = bind; + lodash.chain = chain; + lodash.chunk = chunk; + lodash.compact = compact; + lodash.concat = concat; + lodash.countBy = countBy; + lodash.create = create; + lodash.debounce = debounce; + lodash.defaults = defaults; + lodash.defaultsDeep = defaultsDeep; + lodash.defer = defer; + lodash.delay = delay; + lodash.difference = difference; + lodash.drop = drop; + lodash.filter = filter; + lodash.flatten = flatten; + lodash.flattenDeep = flattenDeep; + lodash.groupBy = groupBy; + lodash.initial = initial; + lodash.intersection = intersection; + lodash.invert = invert; + lodash.invertBy = invertBy; + lodash.iteratee = iteratee; + lodash.keys = keys; + lodash.map = map; + lodash.matches = matches; + lodash.merge = merge; + lodash.mixin = mixin; + lodash.negate = negate; + lodash.omit = omit; + lodash.omitBy = omitBy; + lodash.once = once; + lodash.pick = pick; + lodash.range = range; + lodash.reject = reject; + lodash.rest = rest; + lodash.set = set; + lodash.slice = slice; + lodash.sortBy = sortBy; + lodash.take = take; + lodash.takeRight = takeRight; + lodash.tap = tap; + lodash.throttle = throttle; + lodash.thru = thru; + lodash.toArray = toArray; + lodash.union = union; + lodash.uniq = uniq; + lodash.uniqBy = uniqBy; + lodash.unzip = unzip; + lodash.values = values; + lodash.without = without; + lodash.zip = zip; + lodash.zipObject = zipObject; + + // Add aliases. + lodash.extend = assignIn; + + // Add methods to `lodash.prototype`. + mixin(lodash, lodash); + + /*------------------------------------------------------------------------*/ + + // Add methods that return unwrapped values in chain sequences. + lodash.clamp = clamp; + lodash.clone = clone; + lodash.cloneDeep = cloneDeep; + lodash.escape = escape; + lodash.every = every; + lodash.find = find; + lodash.findIndex = findIndex; + lodash.findKey = findKey; + lodash.findLastIndex = findLastIndex; + lodash.findLastKey = findLastKey; + lodash.forEach = forEach; + lodash.get = get; + lodash.has = has; + lodash.head = head; + lodash.identity = identity; + lodash.indexOf = indexOf; + lodash.isArguments = isArguments; + lodash.isArray = isArray; + lodash.isArrayLike = isArrayLike; + lodash.isBoolean = isBoolean; + lodash.isDate = isDate; + lodash.isEmpty = isEmpty; + lodash.isEqual = isEqual; + lodash.isFinite = isFinite; + lodash.isFunction = isFunction; + lodash.isNaN = isNaN; + lodash.isNull = isNull; + lodash.isNumber = isNumber; + lodash.isObject = isObject; + lodash.isPlainObject = isPlainObject; + lodash.isRegExp = isRegExp; + lodash.isString = isString; + lodash.isUndefined = isUndefined; + lodash.last = last; + lodash.max = max; + lodash.min = min; + lodash.noConflict = noConflict; + lodash.noop = noop; + lodash.random = random; + lodash.reduce = reduce; + lodash.result = result; + lodash.size = size; + lodash.some = some; + lodash.trim = trim; + lodash.unescape = unescape; + lodash.uniqueId = uniqueId; + + // Add aliases. + lodash.each = forEach; + lodash.first = head; + + mixin(lodash, (function () { + var source = {}; + baseForOwn(lodash, function (func, methodName) { + if (!hasOwnProperty.call(lodash.prototype, methodName)) { + source[methodName] = func; + } + }); + return source; + }()), { 'chain': false }); + + /*------------------------------------------------------------------------*/ + + /** + * The semantic version number. + * + * @static + * @memberOf _ + * @type {string} + */ + lodash.VERSION = VERSION; + + // Add `LazyWrapper` methods for `_.drop` and `_.take` variants. + arrayEach(['drop', 'take'], function (methodName, index) { + LazyWrapper.prototype[methodName] = function (n) { + n = n === undefined ? 1 : nativeMax(toInteger(n), 0); + + var result = (this.__filtered__ && !index) + ? new LazyWrapper(this) + : this.clone(); + + if (result.__filtered__) { + result.__takeCount__ = nativeMin(n, result.__takeCount__); + } else { + result.__views__.push({ + 'size': nativeMin(n, MAX_ARRAY_LENGTH), + 'type': methodName + (result.__dir__ < 0 ? 'Right' : '') + }); + } + return result; + }; + + LazyWrapper.prototype[methodName + 'Right'] = function (n) { + return this.reverse()[methodName](n).reverse(); + }; }); - } - - /** - * This method is like `_.get` except that if the resolved value is a - * function it's invoked with the `this` binding of its parent object and - * its result is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @param {Array|string} path The path of the property to resolve. - * @param {*} [defaultValue] The value returned for `undefined` resolved values. - * @returns {*} Returns the resolved value. - * @example - * - * var object = { 'a': [{ 'b': { 'c1': 3, 'c2': _.constant(4) } }] }; - * - * _.result(object, 'a[0].b.c1'); - * // => 3 - * - * _.result(object, 'a[0].b.c2'); - * // => 4 - * - * _.result(object, 'a[0].b.c3', 'default'); - * // => 'default' - * - * _.result(object, 'a[0].b.c3', _.constant('default')); - * // => 'default' - */ - function result(object, path, defaultValue) { - path = castPath(path, object); - - var index = -1, - length = path.length; - - // Ensure the loop is entered when path is empty. - if (!length) { - length = 1; - object = undefined; - } - while (++index < length) { - var value = object == null ? undefined : object[toKey(path[index])]; - if (value === undefined) { - index = length; - value = defaultValue; - } - object = isFunction(value) ? value.call(object) : value; - } - return object; - } - - /** - * Sets the value at `path` of `object`. If a portion of `path` doesn't exist, - * it's created. Arrays are created for missing index properties while objects - * are created for all other missing properties. Use `_.setWith` to customize - * `path` creation. - * - * **Note:** This method mutates `object`. - * - * @static - * @memberOf _ - * @since 3.7.0 - * @category Object - * @param {Object} object The object to modify. - * @param {Array|string} path The path of the property to set. - * @param {*} value The value to set. - * @returns {Object} Returns `object`. - * @example - * - * var object = { 'a': [{ 'b': { 'c': 3 } }] }; - * - * _.set(object, 'a[0].b.c', 4); - * console.log(object.a[0].b.c); - * // => 4 - * - * _.set(object, ['x', '0', 'y', 'z'], 5); - * console.log(object.x[0].y.z); - * // => 5 - */ - function set(object, path, value) { - return object == null ? object : baseSet(object, path, value); - } - - /** - * Creates an array of the own enumerable string keyed property values of `object`. - * - * **Note:** Non-object values are coerced to objects. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Object - * @param {Object} object The object to query. - * @returns {Array} Returns the array of property values. - * @example - * - * function Foo() { - * this.a = 1; - * this.b = 2; - * } - * - * Foo.prototype.c = 3; - * - * _.values(new Foo); - * // => [1, 2] (iteration order is not guaranteed) - * - * _.values('hi'); - * // => ['h', 'i'] - */ - function values(object) { - return object == null ? [] : baseValues(object, keys(object)); - } - - /*------------------------------------------------------------------------*/ - - /** - * Clamps `number` within the inclusive `lower` and `upper` bounds. - * - * @static - * @memberOf _ - * @since 4.0.0 - * @category Number - * @param {number} number The number to clamp. - * @param {number} [lower] The lower bound. - * @param {number} upper The upper bound. - * @returns {number} Returns the clamped number. - * @example - * - * _.clamp(-10, -5, 5); - * // => -5 - * - * _.clamp(10, -5, 5); - * // => 5 - */ - function clamp(number, lower, upper) { - if (upper === undefined) { - upper = lower; - lower = undefined; - } - if (upper !== undefined) { - upper = toNumber(upper); - upper = upper === upper ? upper : 0; - } - if (lower !== undefined) { - lower = toNumber(lower); - lower = lower === lower ? lower : 0; - } - return baseClamp(toNumber(number), lower, upper); - } - - /** - * Produces a random number between the inclusive `lower` and `upper` bounds. - * If only one argument is provided a number between `0` and the given number - * is returned. If `floating` is `true`, or either `lower` or `upper` are - * floats, a floating-point number is returned instead of an integer. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. - * - * @static - * @memberOf _ - * @since 0.7.0 - * @category Number - * @param {number} [lower=0] The lower bound. - * @param {number} [upper=1] The upper bound. - * @param {boolean} [floating] Specify returning a floating-point number. - * @returns {number} Returns the random number. - * @example - * - * _.random(0, 5); - * // => an integer between 0 and 5 - * - * _.random(5); - * // => also an integer between 0 and 5 - * - * _.random(5, true); - * // => a floating-point number between 0 and 5 - * - * _.random(1.2, 5.2); - * // => a floating-point number between 1.2 and 5.2 - */ - function random(lower, upper, floating) { - if (floating && typeof floating != 'boolean' && isIterateeCall(lower, upper, floating)) { - upper = floating = undefined; - } - if (floating === undefined) { - if (typeof upper == 'boolean') { - floating = upper; - upper = undefined; - } - else if (typeof lower == 'boolean') { - floating = lower; - lower = undefined; - } - } - if (lower === undefined && upper === undefined) { - lower = 0; - upper = 1; - } - else { - lower = toFinite(lower); - if (upper === undefined) { - upper = lower; - lower = 0; - } else { - upper = toFinite(upper); - } - } - if (lower > upper) { - var temp = lower; - lower = upper; - upper = temp; - } - if (floating || lower % 1 || upper % 1) { - var rand = nativeRandom(); - return nativeMin(lower + (rand * (upper - lower + freeParseFloat('1e-' + ((rand + '').length - 1)))), upper); - } - return baseRandom(lower, upper); - } - - /*------------------------------------------------------------------------*/ - - /** - * Converts the characters "&", "<", ">", '"', and "'" in `string` to their - * corresponding HTML entities. - * - * **Note:** No other characters are escaped. To escape additional - * characters use a third-party library like [_he_](https://mths.be/he). - * - * Though the ">" character is escaped for symmetry, characters like - * ">" and "/" don't need escaping in HTML and have no special meaning - * unless they're part of a tag or unquoted attribute value. See - * [Mathias Bynens's article](https://mathiasbynens.be/notes/ambiguous-ampersands) - * (under "semi-related fun fact") for more details. - * - * When working with HTML you should always - * [quote attribute values](http://wonko.com/post/html-escaping) to reduce - * XSS vectors. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category String - * @param {string} [string=''] The string to escape. - * @returns {string} Returns the escaped string. - * @example - * - * _.escape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function escape(string) { - string = toString(string); - return (string && reHasUnescapedHtml.test(string)) - ? string.replace(reUnescapedHtml, escapeHtmlChar) - : string; - } - - /** - * Removes leading and trailing whitespace or specified characters from `string`. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category String - * @param {string} [string=''] The string to trim. - * @param {string} [chars=whitespace] The characters to trim. - * @param- {Object} [guard] Enables use as an iteratee for methods like `_.map`. - * @returns {string} Returns the trimmed string. - * @example - * - * _.trim(' abc '); - * // => 'abc' - * - * _.trim('-_-abc-_-', '_-'); - * // => 'abc' - * - * _.map([' foo ', ' bar '], _.trim); - * // => ['foo', 'bar'] - */ - function trim(string, chars, guard) { - string = toString(string); - if (string && (guard || chars === undefined)) { - return string.replace(reTrim, ''); - } - if (!string || !(chars = baseToString(chars))) { - return string; - } - var strSymbols = stringToArray(string), - chrSymbols = stringToArray(chars), - start = charsStartIndex(strSymbols, chrSymbols), - end = charsEndIndex(strSymbols, chrSymbols) + 1; - - return castSlice(strSymbols, start, end).join(''); - } - - /** - * The inverse of `_.escape`; this method converts the HTML entities - * `&`, `<`, `>`, `"`, and `'` in `string` to - * their corresponding characters. - * - * **Note:** No other HTML entities are unescaped. To unescape additional - * HTML entities use a third-party library like [_he_](https://mths.be/he). - * - * @static - * @memberOf _ - * @since 0.6.0 - * @category String - * @param {string} [string=''] The string to unescape. - * @returns {string} Returns the unescaped string. - * @example - * - * _.unescape('fred, barney, & pebbles'); - * // => 'fred, barney, & pebbles' - */ - function unescape(string) { - string = toString(string); - return (string && reHasEscapedHtml.test(string)) - ? string.replace(reEscapedHtml, unescapeHtmlChar) - : string; - } - - /*------------------------------------------------------------------------*/ - - /** - * Creates a function that returns `value`. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Util - * @param {*} value The value to return from the new function. - * @returns {Function} Returns the new constant function. - * @example - * - * var objects = _.times(2, _.constant({ 'a': 1 })); - * - * console.log(objects); - * // => [{ 'a': 1 }, { 'a': 1 }] - * - * console.log(objects[0] === objects[1]); - * // => true - */ - function constant(value) { - return function() { - return value; - }; - } - - /** - * This method returns the first argument it receives. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {*} value Any value. - * @returns {*} Returns `value`. - * @example - * - * var object = { 'a': 1 }; - * - * console.log(_.identity(object) === object); - * // => true - */ - function identity(value) { - return value; - } - - /** - * Creates a function that invokes `func` with the arguments of the created - * function. If `func` is a property name, the created function returns the - * property value for a given element. If `func` is an array or object, the - * created function returns `true` for elements that contain the equivalent - * source properties, otherwise it returns `false`. - * - * @static - * @since 4.0.0 - * @memberOf _ - * @category Util - * @param {*} [func=_.identity] The value to convert to a callback. - * @returns {Function} Returns the callback. - * @example - * - * var users = [ - * { 'user': 'barney', 'age': 36, 'active': true }, - * { 'user': 'fred', 'age': 40, 'active': false } - * ]; - * - * // The `_.matches` iteratee shorthand. - * _.filter(users, _.iteratee({ 'user': 'barney', 'active': true })); - * // => [{ 'user': 'barney', 'age': 36, 'active': true }] - * - * // The `_.matchesProperty` iteratee shorthand. - * _.filter(users, _.iteratee(['user', 'fred'])); - * // => [{ 'user': 'fred', 'age': 40 }] - * - * // The `_.property` iteratee shorthand. - * _.map(users, _.iteratee('user')); - * // => ['barney', 'fred'] - * - * // Create custom iteratee shorthands. - * _.iteratee = _.wrap(_.iteratee, function(iteratee, func) { - * return !_.isRegExp(func) ? iteratee(func) : function(string) { - * return func.test(string); - * }; - * }); - * - * _.filter(['abc', 'def'], /ef/); - * // => ['def'] - */ - function iteratee(func) { - return baseIteratee(typeof func == 'function' ? func : baseClone(func, CLONE_DEEP_FLAG)); - } - - /** - * Creates a function that performs a partial deep comparison between a given - * object and `source`, returning `true` if the given object has equivalent - * property values, else `false`. - * - * **Note:** The created function is equivalent to `_.isMatch` with `source` - * partially applied. - * - * Partial comparisons will match empty array and empty object `source` - * values against any array or object value, respectively. See `_.isEqual` - * for a list of supported value comparisons. - * - * @static - * @memberOf _ - * @since 3.0.0 - * @category Util - * @param {Object} source The object of property values to match. - * @returns {Function} Returns the new spec function. - * @example - * - * var objects = [ - * { 'a': 1, 'b': 2, 'c': 3 }, - * { 'a': 4, 'b': 5, 'c': 6 } - * ]; - * - * _.filter(objects, _.matches({ 'a': 4, 'c': 6 })); - * // => [{ 'a': 4, 'b': 5, 'c': 6 }] - */ - function matches(source) { - return baseMatches(baseClone(source, CLONE_DEEP_FLAG)); - } - - /** - * Adds all own enumerable string keyed function properties of a source - * object to the destination object. If `object` is a function, then methods - * are added to its prototype as well. - * - * **Note:** Use `_.runInContext` to create a pristine `lodash` function to - * avoid conflicts caused by modifying the original. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {Function|Object} [object=lodash] The destination object. - * @param {Object} source The object of functions to add. - * @param {Object} [options={}] The options object. - * @param {boolean} [options.chain=true] Specify whether mixins are chainable. - * @returns {Function|Object} Returns `object`. - * @example - * - * function vowels(string) { - * return _.filter(string, function(v) { - * return /[aeiou]/i.test(v); - * }); - * } - * - * _.mixin({ 'vowels': vowels }); - * _.vowels('fred'); - * // => ['e'] - * - * _('fred').vowels().value(); - * // => ['e'] - * - * _.mixin({ 'vowels': vowels }, { 'chain': false }); - * _('fred').vowels(); - * // => ['e'] - */ - function mixin(object, source, options) { - var props = keys(source), - methodNames = baseFunctions(source, props); - - if (options == null && - !(isObject(source) && (methodNames.length || !props.length))) { - options = source; - source = object; - object = this; - methodNames = baseFunctions(source, keys(source)); - } - var chain = !(isObject(options) && 'chain' in options) || !!options.chain, - isFunc = isFunction(object); - - arrayEach(methodNames, function(methodName) { - var func = source[methodName]; - object[methodName] = func; - if (isFunc) { - object.prototype[methodName] = function() { - var chainAll = this.__chain__; - if (chain || chainAll) { - var result = object(this.__wrapped__), - actions = result.__actions__ = copyArray(this.__actions__); - - actions.push({ 'func': func, 'args': arguments, 'thisArg': object }); - result.__chain__ = chainAll; + + // Add `LazyWrapper` methods that accept an `iteratee` value. + arrayEach(['filter', 'map', 'takeWhile'], function (methodName, index) { + var type = index + 1, + isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG; + + LazyWrapper.prototype[methodName] = function (iteratee) { + var result = this.clone(); + result.__iteratees__.push({ + 'iteratee': getIteratee(iteratee, 3), + 'type': type + }); + result.__filtered__ = result.__filtered__ || isFilter; return result; - } - return func.apply(object, arrayPush([this.value()], arguments)); }; - } }); - return object; - } - - /** - * Reverts the `_` variable to its previous value and returns a reference to - * the `lodash` function. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @returns {Function} Returns the `lodash` function. - * @example - * - * var lodash = _.noConflict(); - */ - function noConflict() { - if (root._ === this) { - root._ = oldDash; - } - return this; - } - - /** - * This method returns `undefined`. - * - * @static - * @memberOf _ - * @since 2.3.0 - * @category Util - * @example - * - * _.times(2, _.noop); - * // => [undefined, undefined] - */ - function noop() { - // No operation performed. - } - - /** - * Creates a function that returns the value at `path` of a given object. - * - * @static - * @memberOf _ - * @since 2.4.0 - * @category Util - * @param {Array|string} path The path of the property to get. - * @returns {Function} Returns the new accessor function. - * @example - * - * var objects = [ - * { 'a': { 'b': 2 } }, - * { 'a': { 'b': 1 } } - * ]; - * - * _.map(objects, _.property('a.b')); - * // => [2, 1] - * - * _.map(_.sortBy(objects, _.property(['a', 'b'])), 'a.b'); - * // => [1, 2] - */ - function property(path) { - return isKey(path) ? baseProperty(toKey(path)) : basePropertyDeep(path); - } - - /** - * Creates an array of numbers (positive and/or negative) progressing from - * `start` up to, but not including, `end`. A step of `-1` is used if a negative - * `start` is specified without an `end` or `step`. If `end` is not specified, - * it's set to `start` with `start` then set to `0`. - * - * **Note:** JavaScript follows the IEEE-754 standard for resolving - * floating-point values which can produce unexpected results. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {number} [start=0] The start of the range. - * @param {number} end The end of the range. - * @param {number} [step=1] The value to increment or decrement by. - * @returns {Array} Returns the range of numbers. - * @see _.inRange, _.rangeRight - * @example - * - * _.range(4); - * // => [0, 1, 2, 3] - * - * _.range(-4); - * // => [0, -1, -2, -3] - * - * _.range(1, 5); - * // => [1, 2, 3, 4] - * - * _.range(0, 20, 5); - * // => [0, 5, 10, 15] - * - * _.range(0, -4, -1); - * // => [0, -1, -2, -3] - * - * _.range(1, 4, 0); - * // => [1, 1, 1] - * - * _.range(0); - * // => [] - */ - var range = createRange(); - - /** - * This method returns a new empty array. - * - * @static - * @memberOf _ - * @since 4.13.0 - * @category Util - * @returns {Array} Returns the new empty array. - * @example - * - * var arrays = _.times(2, _.stubArray); - * - * console.log(arrays); - * // => [[], []] - * - * console.log(arrays[0] === arrays[1]); - * // => false - */ - function stubArray() { - return []; - } - - /** - * This method returns `false`. - * - * @static - * @memberOf _ - * @since 4.13.0 - * @category Util - * @returns {boolean} Returns `false`. - * @example - * - * _.times(2, _.stubFalse); - * // => [false, false] - */ - function stubFalse() { - return false; - } - - /** - * Generates a unique ID. If `prefix` is given, the ID is appended to it. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Util - * @param {string} [prefix=''] The value to prefix the ID with. - * @returns {string} Returns the unique ID. - * @example - * - * _.uniqueId('contact_'); - * // => 'contact_104' - * - * _.uniqueId(); - * // => '105' - */ - function uniqueId(prefix) { - var id = ++idCounter; - return toString(prefix) + id; - } - - /*------------------------------------------------------------------------*/ - - /** - * Computes the maximum value of `array`. If `array` is empty or falsey, - * `undefined` is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Math - * @param {Array} array The array to iterate over. - * @returns {*} Returns the maximum value. - * @example - * - * _.max([4, 2, 8, 6]); - * // => 8 - * - * _.max([]); - * // => undefined - */ - function max(array) { - return (array && array.length) - ? baseExtremum(array, identity, baseGt) - : undefined; - } - - /** - * Computes the minimum value of `array`. If `array` is empty or falsey, - * `undefined` is returned. - * - * @static - * @since 0.1.0 - * @memberOf _ - * @category Math - * @param {Array} array The array to iterate over. - * @returns {*} Returns the minimum value. - * @example - * - * _.min([4, 2, 8, 6]); - * // => 2 - * - * _.min([]); - * // => undefined - */ - function min(array) { - return (array && array.length) - ? baseExtremum(array, identity, baseLt) - : undefined; - } - - /*------------------------------------------------------------------------*/ - - // Add methods that return wrapped values in chain sequences. - lodash.after = after; - lodash.assignIn = assignIn; - lodash.before = before; - lodash.bind = bind; - lodash.chain = chain; - lodash.compact = compact; - lodash.concat = concat; - lodash.countBy = countBy; - lodash.create = create; - lodash.debounce = debounce; - lodash.defaults = defaults; - lodash.defaultsDeep = defaultsDeep; - lodash.defer = defer; - lodash.delay = delay; - lodash.difference = difference; - lodash.drop = drop; - lodash.filter = filter; - lodash.flatten = flatten; - lodash.flattenDeep = flattenDeep; - lodash.groupBy = groupBy; - lodash.initial = initial; - lodash.intersection = intersection; - lodash.invert = invert; - lodash.invertBy = invertBy; - lodash.iteratee = iteratee; - lodash.keys = keys; - lodash.map = map; - lodash.matches = matches; - lodash.merge = merge; - lodash.mixin = mixin; - lodash.negate = negate; - lodash.omit = omit; - lodash.omitBy = omitBy; - lodash.once = once; - lodash.pick = pick; - lodash.range = range; - lodash.reject = reject; - lodash.rest = rest; - lodash.set = set; - lodash.slice = slice; - lodash.sortBy = sortBy; - lodash.take = take; - lodash.takeRight = takeRight; - lodash.tap = tap; - lodash.throttle = throttle; - lodash.thru = thru; - lodash.toArray = toArray; - lodash.union = union; - lodash.uniq = uniq; - lodash.uniqBy = uniqBy; - lodash.unzip = unzip; - lodash.values = values; - lodash.without = without; - lodash.zip = zip; - lodash.zipObject = zipObject; - - // Add aliases. - lodash.extend = assignIn; - - // Add methods to `lodash.prototype`. - mixin(lodash, lodash); - - /*------------------------------------------------------------------------*/ - - // Add methods that return unwrapped values in chain sequences. - lodash.clamp = clamp; - lodash.clone = clone; - lodash.cloneDeep = cloneDeep; - lodash.escape = escape; - lodash.every = every; - lodash.find = find; - lodash.findIndex = findIndex; - lodash.findKey = findKey; - lodash.findLastIndex = findLastIndex; - lodash.findLastKey = findLastKey; - lodash.forEach = forEach; - lodash.get = get; - lodash.has = has; - lodash.head = head; - lodash.identity = identity; - lodash.indexOf = indexOf; - lodash.isArguments = isArguments; - lodash.isArray = isArray; - lodash.isArrayLike = isArrayLike; - lodash.isBoolean = isBoolean; - lodash.isDate = isDate; - lodash.isEmpty = isEmpty; - lodash.isEqual = isEqual; - lodash.isFinite = isFinite; - lodash.isFunction = isFunction; - lodash.isNaN = isNaN; - lodash.isNull = isNull; - lodash.isNumber = isNumber; - lodash.isObject = isObject; - lodash.isPlainObject = isPlainObject; - lodash.isRegExp = isRegExp; - lodash.isString = isString; - lodash.isUndefined = isUndefined; - lodash.last = last; - lodash.max = max; - lodash.min = min; - lodash.noConflict = noConflict; - lodash.noop = noop; - lodash.random = random; - lodash.reduce = reduce; - lodash.result = result; - lodash.size = size; - lodash.some = some; - lodash.trim = trim; - lodash.unescape = unescape; - lodash.uniqueId = uniqueId; - - // Add aliases. - lodash.each = forEach; - lodash.first = head; - - mixin(lodash, (function() { - var source = {}; - baseForOwn(lodash, function(func, methodName) { - if (!hasOwnProperty.call(lodash.prototype, methodName)) { - source[methodName] = func; - } + // Add `LazyWrapper` methods for `_.head` and `_.last`. + arrayEach(['head', 'last'], function (methodName, index) { + var takeName = 'take' + (index ? 'Right' : ''); + + LazyWrapper.prototype[methodName] = function () { + return this[takeName](1).value()[0]; + }; + }); + + // Add `LazyWrapper` methods for `_.initial` and `_.tail`. + arrayEach(['initial', 'tail'], function (methodName, index) { + var dropName = 'drop' + (index ? '' : 'Right'); + + LazyWrapper.prototype[methodName] = function () { + return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1); + }; }); - return source; - }()), { 'chain': false }); - - /*------------------------------------------------------------------------*/ - - /** - * The semantic version number. - * - * @static - * @memberOf _ - * @type {string} - */ - lodash.VERSION = VERSION; - - // Add `LazyWrapper` methods for `_.drop` and `_.take` variants. - arrayEach(['drop', 'take'], function(methodName, index) { - LazyWrapper.prototype[methodName] = function(n) { - n = n === undefined ? 1 : nativeMax(toInteger(n), 0); - - var result = (this.__filtered__ && !index) - ? new LazyWrapper(this) - : this.clone(); - - if (result.__filtered__) { - result.__takeCount__ = nativeMin(n, result.__takeCount__); - } else { - result.__views__.push({ - 'size': nativeMin(n, MAX_ARRAY_LENGTH), - 'type': methodName + (result.__dir__ < 0 ? 'Right' : '') - }); - } - return result; + + LazyWrapper.prototype.compact = function () { + return this.filter(identity); }; - LazyWrapper.prototype[methodName + 'Right'] = function(n) { - return this.reverse()[methodName](n).reverse(); + LazyWrapper.prototype.find = function (predicate) { + return this.filter(predicate).head(); }; - }); - - // Add `LazyWrapper` methods that accept an `iteratee` value. - arrayEach(['filter', 'map', 'takeWhile'], function(methodName, index) { - var type = index + 1, - isFilter = type == LAZY_FILTER_FLAG || type == LAZY_WHILE_FLAG; - - LazyWrapper.prototype[methodName] = function(iteratee) { - var result = this.clone(); - result.__iteratees__.push({ - 'iteratee': getIteratee(iteratee, 3), - 'type': type - }); - result.__filtered__ = result.__filtered__ || isFilter; - return result; + + LazyWrapper.prototype.findLast = function (predicate) { + return this.reverse().find(predicate); }; - }); - // Add `LazyWrapper` methods for `_.head` and `_.last`. - arrayEach(['head', 'last'], function(methodName, index) { - var takeName = 'take' + (index ? 'Right' : ''); + LazyWrapper.prototype.invokeMap = baseRest(function (path, args) { + if (typeof path == 'function') { + return new LazyWrapper(this); + } + return this.map(function (value) { + return baseInvoke(value, path, args); + }); + }); - LazyWrapper.prototype[methodName] = function() { - return this[takeName](1).value()[0]; + LazyWrapper.prototype.reject = function (predicate) { + return this.filter(negate(getIteratee(predicate))); }; - }); - // Add `LazyWrapper` methods for `_.initial` and `_.tail`. - arrayEach(['initial', 'tail'], function(methodName, index) { - var dropName = 'drop' + (index ? '' : 'Right'); + LazyWrapper.prototype.slice = function (start, end) { + start = toInteger(start); - LazyWrapper.prototype[methodName] = function() { - return this.__filtered__ ? new LazyWrapper(this) : this[dropName](1); + var result = this; + if (result.__filtered__ && (start > 0 || end < 0)) { + return new LazyWrapper(result); + } + if (start < 0) { + result = result.takeRight(-start); + } else if (start) { + result = result.drop(start); + } + if (end !== undefined) { + end = toInteger(end); + result = end < 0 ? result.dropRight(-end) : result.take(end - start); + } + return result; }; - }); - LazyWrapper.prototype.compact = function() { - return this.filter(identity); - }; + LazyWrapper.prototype.takeRightWhile = function (predicate) { + return this.reverse().takeWhile(predicate).reverse(); + }; - LazyWrapper.prototype.find = function(predicate) { - return this.filter(predicate).head(); - }; + LazyWrapper.prototype.toArray = function () { + return this.take(MAX_ARRAY_LENGTH); + }; - LazyWrapper.prototype.findLast = function(predicate) { - return this.reverse().find(predicate); - }; + // Add `LazyWrapper` methods to `lodash.prototype`. + baseForOwn(LazyWrapper.prototype, function (func, methodName) { + var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName), + isTaker = /^(?:head|last)$/.test(methodName), + lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName], + retUnwrapped = isTaker || /^find/.test(methodName); - LazyWrapper.prototype.invokeMap = baseRest(function(path, args) { - if (typeof path == 'function') { - return new LazyWrapper(this); - } - return this.map(function(value) { - return baseInvoke(value, path, args); + if (!lodashFunc) { + return; + } + lodash.prototype[methodName] = function () { + var value = this.__wrapped__, + args = isTaker ? [1] : arguments, + isLazy = value instanceof LazyWrapper, + iteratee = args[0], + useLazy = isLazy || isArray(value); + + var interceptor = function (value) { + var result = lodashFunc.apply(lodash, arrayPush([value], args)); + return (isTaker && chainAll) ? result[0] : result; + }; + + if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) { + // Avoid lazy use if the iteratee has a "length" value other than `1`. + isLazy = useLazy = false; + } + var chainAll = this.__chain__, + isHybrid = !!this.__actions__.length, + isUnwrapped = retUnwrapped && !chainAll, + onlyLazy = isLazy && !isHybrid; + + if (!retUnwrapped && useLazy) { + value = onlyLazy ? value : new LazyWrapper(this); + var result = func.apply(value, args); + result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); + return new LodashWrapper(result, chainAll); + } + if (isUnwrapped && onlyLazy) { + return func.apply(this, args); + } + result = this.thru(interceptor); + return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result; + }; }); - }); - - LazyWrapper.prototype.reject = function(predicate) { - return this.filter(negate(getIteratee(predicate))); - }; - - LazyWrapper.prototype.slice = function(start, end) { - start = toInteger(start); - - var result = this; - if (result.__filtered__ && (start > 0 || end < 0)) { - return new LazyWrapper(result); - } - if (start < 0) { - result = result.takeRight(-start); - } else if (start) { - result = result.drop(start); - } - if (end !== undefined) { - end = toInteger(end); - result = end < 0 ? result.dropRight(-end) : result.take(end - start); - } - return result; - }; - - LazyWrapper.prototype.takeRightWhile = function(predicate) { - return this.reverse().takeWhile(predicate).reverse(); - }; - - LazyWrapper.prototype.toArray = function() { - return this.take(MAX_ARRAY_LENGTH); - }; - - // Add `LazyWrapper` methods to `lodash.prototype`. - baseForOwn(LazyWrapper.prototype, function(func, methodName) { - var checkIteratee = /^(?:filter|find|map|reject)|While$/.test(methodName), - isTaker = /^(?:head|last)$/.test(methodName), - lodashFunc = lodash[isTaker ? ('take' + (methodName == 'last' ? 'Right' : '')) : methodName], - retUnwrapped = isTaker || /^find/.test(methodName); - - if (!lodashFunc) { - return; - } - lodash.prototype[methodName] = function() { - var value = this.__wrapped__, - args = isTaker ? [1] : arguments, - isLazy = value instanceof LazyWrapper, - iteratee = args[0], - useLazy = isLazy || isArray(value); - - var interceptor = function(value) { - var result = lodashFunc.apply(lodash, arrayPush([value], args)); - return (isTaker && chainAll) ? result[0] : result; - }; - - if (useLazy && checkIteratee && typeof iteratee == 'function' && iteratee.length != 1) { - // Avoid lazy use if the iteratee has a "length" value other than `1`. - isLazy = useLazy = false; - } - var chainAll = this.__chain__, - isHybrid = !!this.__actions__.length, - isUnwrapped = retUnwrapped && !chainAll, - onlyLazy = isLazy && !isHybrid; - - if (!retUnwrapped && useLazy) { - value = onlyLazy ? value : new LazyWrapper(this); - var result = func.apply(value, args); - result.__actions__.push({ 'func': thru, 'args': [interceptor], 'thisArg': undefined }); - return new LodashWrapper(result, chainAll); - } - if (isUnwrapped && onlyLazy) { - return func.apply(this, args); - } - result = this.thru(interceptor); - return isUnwrapped ? (isTaker ? result.value()[0] : result.value()) : result; - }; - }); - - // Add `Array` methods to `lodash.prototype`. - arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function(methodName) { - var func = arrayProto[methodName], - chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru', - retUnwrapped = /^(?:pop|shift)$/.test(methodName); - - lodash.prototype[methodName] = function() { - var args = arguments; - if (retUnwrapped && !this.__chain__) { - var value = this.value(); - return func.apply(isArray(value) ? value : [], args); - } - return this[chainName](function(value) { - return func.apply(isArray(value) ? value : [], args); - }); - }; - }); - - // Map minified method names to their real names. - baseForOwn(LazyWrapper.prototype, function(func, methodName) { - var lodashFunc = lodash[methodName]; - if (lodashFunc) { - var key = (lodashFunc.name + ''), - names = realNames[key] || (realNames[key] = []); - - names.push({ 'name': methodName, 'func': lodashFunc }); - } - }); - - realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{ - 'name': 'wrapper', - 'func': undefined - }]; - - // Add methods to `LazyWrapper`. - LazyWrapper.prototype.clone = lazyClone; - LazyWrapper.prototype.reverse = lazyReverse; - LazyWrapper.prototype.value = lazyValue; - - // Add lazy aliases. - lodash.prototype.first = lodash.prototype.head; - - if (symIterator) { - lodash.prototype[symIterator] = wrapperToIterator; - } - - /*--------------------------------------------------------------------------*/ - - // Some AMD build optimizers, like r.js, check for condition patterns like: - if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { - // Expose Lodash on the global object to prevent errors when Lodash is - // loaded by a script tag in the presence of an AMD loader. - // See http://requirejs.org/docs/errors.html#mismatch for more details. - // Use `_.noConflict` to remove Lodash from the global object. - BI._ = lodash; - - // Define as an anonymous module so, through path mapping, it can be - // referenced as the "underscore" module. - define(function() { - return lodash; + + // Add `Array` methods to `lodash.prototype`. + arrayEach(['pop', 'push', 'shift', 'sort', 'splice', 'unshift'], function (methodName) { + var func = arrayProto[methodName], + chainName = /^(?:push|sort|unshift)$/.test(methodName) ? 'tap' : 'thru', + retUnwrapped = /^(?:pop|shift)$/.test(methodName); + + lodash.prototype[methodName] = function () { + var args = arguments; + if (retUnwrapped && !this.__chain__) { + var value = this.value(); + return func.apply(isArray(value) ? value : [], args); + } + return this[chainName](function (value) { + return func.apply(isArray(value) ? value : [], args); + }); + }; }); - } - // Check for `exports` after `define` in case a build optimizer adds it. - else if (freeModule) { - // Export for Node.js. - (freeModule.exports = lodash)._ = lodash; - // Export for CommonJS support. - freeExports._ = lodash; - } - else { - // Export to the global object. - BI._ = lodash; - } + + // Map minified method names to their real names. + baseForOwn(LazyWrapper.prototype, function (func, methodName) { + var lodashFunc = lodash[methodName]; + if (lodashFunc) { + var key = (lodashFunc.name + ''), + names = realNames[key] || (realNames[key] = []); + + names.push({ 'name': methodName, 'func': lodashFunc }); + } + }); + + realNames[createHybrid(undefined, WRAP_BIND_KEY_FLAG).name] = [{ + 'name': 'wrapper', + 'func': undefined + }]; + + // Add methods to `LazyWrapper`. + LazyWrapper.prototype.clone = lazyClone; + LazyWrapper.prototype.reverse = lazyReverse; + LazyWrapper.prototype.value = lazyValue; + + // Add lazy aliases. + lodash.prototype.first = lodash.prototype.head; + + if (symIterator) { + lodash.prototype[symIterator] = wrapperToIterator; + } + + /*--------------------------------------------------------------------------*/ + + // Some AMD build optimizers, like r.js, check for condition patterns like: + if (typeof define == 'function' && typeof define.amd == 'object' && define.amd) { + // Expose Lodash on the global object to prevent errors when Lodash is + // loaded by a script tag in the presence of an AMD loader. + // See http://requirejs.org/docs/errors.html#mismatch for more details. + // Use `_.noConflict` to remove Lodash from the global object. + BI._ = lodash; + + // Define as an anonymous module so, through path mapping, it can be + // referenced as the "underscore" module. + define(function () { + return lodash; + }); + } + // Check for `exports` after `define` in case a build optimizer adds it. + else if (freeModule) { + // Export for Node.js. + (freeModule.exports = lodash)._ = lodash; + // Export for CommonJS support. + freeExports._ = lodash; + } else { + // Export to the global object. + BI._ = lodash; + } }.call(this)); diff --git a/src/core/2.base.js b/src/core/2.base.js index 7071eb3e1..36291cee2 100644 --- a/src/core/2.base.js +++ b/src/core/2.base.js @@ -526,7 +526,7 @@ return obj != null && obj == obj.window; }, - isPromise: function(obj) { + isPromise: function (obj) { return !!obj && (BI.isObject(obj) || BI.isFunction(obj)) && BI.isFunction(obj.then); } }); @@ -651,7 +651,7 @@ }); // 通用方法 - BI._.each(["uniqueId", "result", "chain", "iteratee", "escape", "unescape", "before", "after"], function (name) { + BI._.each(["uniqueId", "result", "chain", "iteratee", "escape", "unescape", "before", "after", "chunk"], function (name) { BI[name] = function () { return BI._[name].apply(BI._, arguments); }; diff --git a/src/core/4.widget.js b/src/core/4.widget.js index ef412cafd..d24c01566 100644 --- a/src/core/4.widget.js +++ b/src/core/4.widget.js @@ -225,7 +225,7 @@ if (BI.isFunction(o.css)) { var css = this.__watch(o.css, function (context, newValue) { for (var k in css) { - if (!newValue[k]) { + if (BI.isNull(newValue[k])) { newValue[k] = ""; } } diff --git a/src/core/plugin.js b/src/core/6.plugin.js similarity index 100% rename from src/core/plugin.js rename to src/core/6.plugin.js diff --git a/src/core/controller/controller.bubbles.js b/src/core/controller/controller.bubbles.js index a705ef4a6..fa5cefb5f 100644 --- a/src/core/controller/controller.bubbles.js +++ b/src/core/controller/controller.bubbles.js @@ -30,7 +30,7 @@ BI.BubblesController = BI.inherit(BI.Controller, { if (!this.storeBubbles[name]) { this.storeBubbles[name] = BI.createWidget({ - type: "bi.label", + type: "bi.text", cls: "bi-bubble" + " bubble-" + level, text: text, hgap: 5, diff --git a/src/core/controller/controller.tooltips.js b/src/core/controller/controller.tooltips.js index 2e126b424..14dbba9e4 100644 --- a/src/core/controller/controller.tooltips.js +++ b/src/core/controller/controller.tooltips.js @@ -38,7 +38,7 @@ BI.TooltipsController = BI.inherit(BI.Controller, { }); this.showingTips = {}; if (!this.has(name)) { - this.create(name, tooltipOpt, opt.container || "body"); + this.create(name, tooltipOpt, document.fullscreenElement ? context : (opt.container || "body")); } if (!opt.belowMouse) { var offset = context.element.offset(); diff --git a/src/core/platform/web/config.js b/src/core/platform/web/config.js index 9c4ba840c..6a955a27e 100644 --- a/src/core/platform/web/config.js +++ b/src/core/platform/web/config.js @@ -1,5 +1,5 @@ // 工程配置 -BI.prepares.push(function () { +!(function () { // 注册布局 // adapt类布局优先级规则 // 1、支持flex的浏览器下使用flex布局 @@ -39,16 +39,16 @@ BI.prepares.push(function () { // return BI.extend({}, ob, {type: "bi.table_adapt"}); // } if (supportFlex) { - return BI.extend({}, ob, {type: "bi.flex_horizontal"}); + return BI.extend({}, ob, { type: "bi.flex_horizontal" }); } return BI.extend({ scrollx: true - }, ob, {type: "bi.inline"}); + }, ob, { type: "bi.inline" }); }); BI.Plugin.configWidget("bi.vertical", function (ob) { if (ob.horizontalAlign === BI.HorizontalAlign.Left || ob.horizontalAlign === BI.HorizontalAlign.Right) { if (isSupportFlex()) { - return BI.extend({}, ob, {type: "bi.flex_vertical"}); + return BI.extend({}, ob, { type: "bi.flex_vertical" }); } return BI.extend({}, ob, { horizontalAlign: BI.HorizontalAlign.Stretch, @@ -88,14 +88,14 @@ BI.prepares.push(function () { if ((ob.scrollable !== true && ob.scrollx !== true) || ob.horizontalAlign === BI.HorizontalAlign.Stretch) { return BI.extend({ verticalAlign: BI.VerticalAlign.Top - }, ob, {type: "bi.horizontal_float_fill"}); + }, ob, { type: "bi.horizontal_float_fill" }); } return BI.extend({ horizontalAlign: BI.HorizontalAlign.Stretch - }, ob, {type: "bi.table_adapt"}); + }, ob, { type: "bi.table_adapt" }); } if (BI.Providers.getProvider("bi.provider.system").getResponsiveMode()) { - return BI.extend({}, ob, {type: "bi.responsive_inline"}); + return BI.extend({}, ob, { type: "bi.responsive_inline" }); } return ob; }); @@ -104,9 +104,9 @@ BI.prepares.push(function () { // var isAdapt = !ob.horizontalAlign || ob.horizontalAlign === BI.HorizontalAlign.Center || ob.horizontalAlign === BI.HorizontalAlign.Stretch; // if (!isAdapt || justOneItem) { if (supportFlex) { - return BI.extend({}, ob, {type: "bi.flex_center_adapt"}); + return BI.extend({}, ob, { type: "bi.flex_center_adapt" }); } - return BI.extend({}, ob, {type: "bi.inline_center_adapt"}); + return BI.extend({}, ob, { type: "bi.inline_center_adapt" }); // } // return ob; }); @@ -115,9 +115,9 @@ BI.prepares.push(function () { // var isAdapt = ob.horizontalAlign === BI.HorizontalAlign.Center || ob.horizontalAlign === BI.HorizontalAlign.Stretch; // if (!isAdapt || justOneItem) { if (supportFlex) { - return BI.extend({}, ob, {type: "bi.flex_vertical_center_adapt"}); + return BI.extend({}, ob, { type: "bi.flex_vertical_center_adapt" }); } - return BI.extend({}, ob, {type: "bi.inline_vertical_adapt"}); + return BI.extend({}, ob, { type: "bi.inline_vertical_adapt" }); // } // return ob; }); @@ -126,7 +126,7 @@ BI.prepares.push(function () { var isAdapt = !ob.horizontalAlign || ob.horizontalAlign === BI.HorizontalAlign.Center || ob.horizontalAlign === BI.HorizontalAlign.Stretch; var verticalAlignTop = !ob.verticalAlign || ob.verticalAlign === BI.VerticalAlign.TOP; if (verticalAlignTop && justOneItem) { - return BI.extend({}, ob, {type: "bi.horizontal_auto"}); + return BI.extend({}, ob, { type: "bi.horizontal_auto" }); } var supportFlex = isSupportFlex(); // 在横向自适应场景下我们需要使用table的自适应撑出滚动条的特性(flex处理不了这种情况) @@ -134,24 +134,24 @@ BI.prepares.push(function () { if (isAdapt) { return BI.extend({ horizontalAlign: BI.HorizontalAlign.Center - }, ob, {type: "bi.table_adapt"}); + }, ob, { type: "bi.table_adapt" }); } if (supportFlex) { return BI.extend({ horizontalAlign: BI.HorizontalAlign.Center, scrollx: false - }, ob, {type: "bi.flex_horizontal"}); + }, ob, { type: "bi.flex_horizontal" }); } return BI.extend({ horizontalAlign: BI.HorizontalAlign.Center - }, ob, {type: "bi.table_adapt"}); + }, ob, { type: "bi.table_adapt" }); }); BI.Plugin.configWidget("bi.horizontal_float", function (ob) { if (isSupportFlex()) { - return BI.extend({}, ob, {type: "bi.flex_horizontal_adapt"}); + return BI.extend({}, ob, { type: "bi.flex_horizontal_adapt" }); } if (ob.items && ob.items.length <= 1) { - return BI.extend({}, ob, {type: "bi.inline_horizontal_adapt"}); + return BI.extend({}, ob, { type: "bi.inline_horizontal_adapt" }); } return ob; }); @@ -162,16 +162,16 @@ BI.prepares.push(function () { horizontalAlign: BI.HorizontalAlign.Stretch, verticalAlign: BI.VerticalAlign.Stretch, scrollx: false - }, ob, {type: "bi.flex_horizontal"}); + }, ob, { type: "bi.flex_horizontal" }); } if ((ob.horizontalAlign && ob.horizontalAlign !== BI.HorizontalAlign.Stretch) || (ob.scrollable === true || ob.scrollx === true)) { // 宽度不受限,要用table布局 return BI.extend({ horizontalAlign: BI.HorizontalAlign.Stretch, verticalAlign: BI.VerticalAlign.Stretch - }, ob, {type: "bi.table_adapt"}); + }, ob, { type: "bi.table_adapt" }); } - return BI.extend({}, ob, {type: "bi.horizontal_float_fill"}); + return BI.extend({}, ob, { type: "bi.horizontal_float_fill" }); }); BI.Plugin.configWidget("bi.vertical_fill", function (ob) { if (isSupportFlex()) { @@ -179,7 +179,7 @@ BI.prepares.push(function () { horizontalAlign: BI.HorizontalAlign.Stretch, verticalAlign: BI.VerticalAlign.Stretch, scrolly: false - }, ob, {type: "bi.flex_vertical"}); + }, ob, { type: "bi.flex_vertical" }); } if (ob.scrollable === true || ob.scrollx === true || ob.scrolly === true) { // 有滚动条,降级到table布局处理 @@ -204,18 +204,18 @@ BI.prepares.push(function () { } if (hasAuto) { // 有自动高的时候 - return BI.extend({}, ob, {type: "bi.vtape_auto"}); + return BI.extend({}, ob, { type: "bi.vtape_auto" }); } - return BI.extend({}, ob, {type: "bi.vtape"}); + return BI.extend({}, ob, { type: "bi.vtape" }); }); BI.Plugin.configWidget("bi.horizontal_sticky", function (ob) { if (!isSupportSticky) { - return BI.extend({ scrollx: true }, ob, {type: "bi.horizontal_fill"}); + return BI.extend({ scrollx: true }, ob, { type: "bi.horizontal_fill" }); } }); BI.Plugin.configWidget("bi.vertical_sticky", function (ob) { if (!isSupportSticky) { - return BI.extend({ scrolly: true }, ob, {type: "bi.vertical_fill"}); + return BI.extend({ scrolly: true }, ob, { type: "bi.vertical_fill" }); } }); @@ -223,7 +223,7 @@ BI.prepares.push(function () { if (isSupportFlex()) { // IE下其实也是可以使用flex布局的,只要排除掉出现滚动条的情况 // if (!BI.isIE() || (ob.scrollable !== true && ob.scrolly !== true)) { - return BI.extend({}, ob, {type: "bi.flex_left_right_vertical_adapt"}); + return BI.extend({}, ob, { type: "bi.flex_left_right_vertical_adapt" }); // } } return ob; @@ -232,40 +232,40 @@ BI.prepares.push(function () { if (ob.scrollable === true || ob.scrollx !== false) { if (ob.hgap > 0 || ob.lgap > 0 || ob.rgap > 0) { if (BI.Providers.getProvider("bi.provider.system").getResponsiveMode()) { - return BI.extend({}, ob, {type: "bi.responsive_flex_scrollable_horizontal"}); + return BI.extend({}, ob, { type: "bi.responsive_flex_scrollable_horizontal" }); } - return BI.extend({}, ob, {type: "bi.flex_scrollable_horizontal"}); + return BI.extend({}, ob, { type: "bi.flex_scrollable_horizontal" }); } } if (BI.Providers.getProvider("bi.provider.system").getResponsiveMode()) { - return BI.extend({}, ob, {type: "bi.responsive_flex_horizontal"}); + return BI.extend({}, ob, { type: "bi.responsive_flex_horizontal" }); } }); BI.Plugin.configWidget("bi.flex_vertical", function (ob) { if (ob.scrollable === true || ob.scrollx === true) { if (ob.hgap > 0 || ob.lgap > 0 || ob.rgap > 0) { - return BI.extend({}, ob, {type: "bi.flex_scrollable_vertical"}); + return BI.extend({}, ob, { type: "bi.flex_scrollable_vertical" }); } } }); BI.Plugin.configWidget("bi.table", function (ob) { if (!isSupportGrid()) { - return BI.extend({}, ob, {type: "bi.td"}); + return BI.extend({}, ob, { type: "bi.td" }); } return ob; }); BI.Plugin.configWidget("bi.radio", function (ob) { if (BI.isIE() && BI.getIEVersion() <= 9) { - return BI.extend({}, ob, {type: "bi.image_radio"}); + return BI.extend({}, ob, { type: "bi.image_radio" }); } return ob; }); BI.Plugin.configWidget("bi.checkbox", function (ob) { if (BI.isIE() && BI.getIEVersion() <= 9) { - return BI.extend({}, ob, {type: "bi.image_checkbox"}); + return BI.extend({}, ob, { type: "bi.image_checkbox" }); } return ob; }); @@ -274,6 +274,6 @@ BI.prepares.push(function () { if (BI.isIE() && BI.getIEVersion() < 9) { return ob; } - return BI.extend({}, ob, {type: "bi.half_button"}); + return BI.extend({}, ob, { type: "bi.half_button" }); }); -}); +}()); diff --git a/src/less/base/combo/combo.textvalue.less b/src/less/base/combo/combo.textvalue.less new file mode 100644 index 000000000..89329e60f --- /dev/null +++ b/src/less/base/combo/combo.textvalue.less @@ -0,0 +1,24 @@ +@import "../../index.less"; + +.bi-text-value-combo { + //将来统一变成combo的特性 + &.bi-status-error { + &.bi-border, &.bi-border-bottom { + border-color: @border-color-negative; + } + + .bi-trigger .select-text-label { + color: @color-bi-text-error-text-trigger; + } + } + + &.bi-status-warning { + &.bi-border, &.bi-border-bottom { + border-color: @border-color-warning; + } + + .bi-trigger .select-text-label { + color: @font-color-warning; + } + } +} diff --git a/src/less/base/single/button/button.less b/src/less/base/single/button/button.less index 6eae05320..b9aad6d1a 100644 --- a/src/less/base/single/button/button.less +++ b/src/less/base/single/button/button.less @@ -14,6 +14,9 @@ body .bi-button, #body .bi-button { text-align: center; vertical-align: middle; cursor: pointer; + &.loading { + cursor: not-allowed; + } &.block { font-size: inherit; border-width: 0; @@ -401,6 +404,10 @@ body .bi-button, #body .bi-button { } .bi-basic-button { + + // 按钮水波纹需要根据按钮根结点定位 + position: relative; + &.button-common, &.button-success, &.button-warning, &.button-error { &:after { content: ""; diff --git a/src/less/base/tree/ztree.less b/src/less/base/tree/ztree.less index c4a8b6097..4591f64ec 100644 --- a/src/less/base/tree/ztree.less +++ b/src/less/base/tree/ztree.less @@ -79,22 +79,20 @@ vertical-align: top; display: inline-block; - .tree-node-text { - &:not(.disabled) { - &:hover { - .background-color(@color-bi-background-highlight, 10%); - } + &:not(.disabled) { + &:hover { + .background-color(@color-bi-background-highlight, 10%); + } - &:active { - color: @color-bi-text-highlight; - .background-color(@color-bi-background-highlight, 15%); - } + &:active { + color: @color-bi-text-highlight; + .background-color(@color-bi-background-highlight, 15%); } } } .ztree.solid li a { - height: 32px; + height: 30px; } .ztree li a.curSelectedNode { @@ -145,22 +143,17 @@ } .ztree.solid li span { - line-height: 32px; + line-height: 30px; } .ztree li span.icon { display: inline-block; - vertical-align: top; text-align: center; - width: 24px; - height: 24px; - line-height: 24px; -} - -.ztree li span.icon { - width: 32px; - height: 32px; - line-height: 32px; + width: 16px; + height: 16px; + line-height: 16px; + padding: 0 2px; + vertical-align: middle; } .ztree li span.button { @@ -289,8 +282,8 @@ } .ztree.solid li span.button.switch { - width: 32px; - height: 32px + width: 30px; + height: 30px } .ztree li span.button.switch.noline_open { diff --git a/src/less/base/view/drawer.less b/src/less/base/view/drawer.less index 76ab23d18..940b9b7c9 100644 --- a/src/less/base/view/drawer.less +++ b/src/less/base/view/drawer.less @@ -2,5 +2,5 @@ .bi-drawer { .box-shadows(-6px 0 16px -8px #00000014, -9px 0 28px #0000000d, -12px 0 48px 16px #00000008); - .transitions(transform .3s cubic-bezier(.23, 1, .32, 1), box-shadow .3s cubic-bezier(.23, 1, .32, 1)); + .transitions(inset .3s cubic-bezier(.23, 1, .32, 1), box-shadow .3s cubic-bezier(.23, 1, .32, 1)); } diff --git a/src/less/core/utils/common.less b/src/less/core/utils/common.less index 036778c59..76a93b316 100644 --- a/src/less/core/utils/common.less +++ b/src/less/core/utils/common.less @@ -3,12 +3,17 @@ .base-disabled { cursor: not-allowed !important; color: @color-bi-text-disabled !important; + & .bi-input { color: @color-bi-text-disabled !important; + -webkit-text-fill-color: @color-bi-text-disabled; } + & .bi-textarea { color: @color-bi-text-disabled !important; + -webkit-text-fill-color: @color-bi-text-disabled; } + & .b-font:before { color: @color-bi-icon-disabled !important; } @@ -17,12 +22,17 @@ .bi-theme-dark { .base-disabled { color: @color-bi-text-disabled-theme-dark !important; + & .bi-input { color: @color-bi-text-disabled-theme-dark !important; + -webkit-text-fill-color: @color-bi-text-disabled-theme-dark; } + & .bi-textarea { color: @color-bi-text-disabled-theme-dark !important; + -webkit-text-fill-color: @color-bi-text-disabled-theme-dark; } + & .b-font:before { color: @color-bi-icon-disabled-theme-dark !important; } diff --git a/src/less/lib/font.less b/src/less/lib/font.less index ce865e30e..deb495daa 100644 --- a/src/less/lib/font.less +++ b/src/less/lib/font.less @@ -1,4 +1,5 @@ //字体库 +@font-button-loading: "e7cd"; @font-cross: "e1ab"; diff --git a/src/less/resource/font.less b/src/less/resource/font.less index be6730eca..fedc1b902 100644 --- a/src/less/resource/font.less +++ b/src/less/resource/font.less @@ -81,6 +81,10 @@ .font-hover(pull-down-h-font, @font-down-triangle, @color-bi-text-light-gray); .font-hover-active(pull-down-ha-font, @font-down-triangle, @color-bi-text-light-gray); +// button +.font(button-loading-font, @font-button-loading); + + //toast .font(toast-error-font, @font-tip-error, @color-bi-color-toast-error); .font(toast-success-font, @font-tip-success, @color-bi-color-toast-success); diff --git a/src/less/widget/multilayerselecttree/multilayerselecttree.combo.less b/src/less/widget/multilayerselecttree/multilayerselecttree.combo.less index d1c5771dc..ecb2dbf58 100644 --- a/src/less/widget/multilayerselecttree/multilayerselecttree.combo.less +++ b/src/less/widget/multilayerselecttree/multilayerselecttree.combo.less @@ -1,7 +1,22 @@ @import "../../index.less"; +@val: transform .3s ease; .bi-multilayer-select-tree-combo { + // 此combo的trigger_button是absolute上去的,与bi-combo在同一层级,独立写一下 + & .bi-combo.bi-combo-popup + .bi-trigger-icon-button { + & .x-icon { + .rotate(180deg); + .transition(@val); + } + } + + &:hover { + &.bi-border, &.bi-border-bottom { + border-color: @color-bi-border-hover-combo; + } + } + &.status-error { &.bi-border, &.bi-border-bottom { border-color: @border-color-negative; diff --git a/src/less/widget/multitree/multi.tree.combo.less b/src/less/widget/multitree/multi.tree.combo.less index 7e193b7d3..62b29c2a3 100644 --- a/src/less/widget/multitree/multi.tree.combo.less +++ b/src/less/widget/multitree/multi.tree.combo.less @@ -1,9 +1,11 @@ @import "../../index.less"; + @val: transform .3s ease; -.bi-multi-tree-combo{ - & .multi-select-trigger-icon-button{ +.bi-multi-tree-combo, .bi-multi-tree-insert-combo, .bi-multi-tree-list-combo { + & .multi-select-trigger-icon-button { font-size: @font-size-16; } + // 此combo的trigger_button是absolute上去的,与bi-combo在同一层级,独立写一下 & .bi-combo.bi-combo-popup + .bi-trigger-icon-button { & .x-icon { @@ -11,6 +13,7 @@ .transition(@val); } } + & .bi-combo + .bi-trigger-icon-button { & .x-icon { .rotate(0deg); diff --git a/src/widget/editor/editor.text.js b/src/widget/editor/editor.text.js index e50e153ae..02644b044 100644 --- a/src/widget/editor/editor.text.js +++ b/src/widget/editor/editor.text.js @@ -23,8 +23,7 @@ BI.TextEditor = BI.inherit(BI.Widget, { }); }, - _init: function () { - BI.TextEditor.superclass._init.apply(this, arguments); + render: function () { var self = this, o = this.options; var border = o.simple ? 1 : 2; if (BI.isNumber(o.height)) { diff --git a/src/widget/multilayerselecttree/multilayerselecttree.combo.js b/src/widget/multilayerselecttree/multilayerselecttree.combo.js index 48ff0cbe0..e748ee1c5 100644 --- a/src/widget/multilayerselecttree/multilayerselecttree.combo.js +++ b/src/widget/multilayerselecttree/multilayerselecttree.combo.js @@ -10,9 +10,9 @@ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { isDefaultInit: false, height: 24, text: "", + defaultText: "", itemsCreator: BI.emptyFn, items: [], - value: "", allowEdit: false, allowSearchValue: false, allowInsertValue: false, @@ -31,14 +31,49 @@ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { render: function () { var self = this, o = this.options; - return (o.itemsCreator === BI.emptyFn) ? this._getSyncConfig() : this._getAsyncConfig(); + var cls = (o.simple ? "bi-border-bottom " : "bi-border bi-border-radius ") + (BI.isKey(o.status) ? ("status-" + o.status) : ""); + + var baseConfig = this._getBaseConfig(); + + + if (o.allowEdit) { + return { + type: "bi.absolute", + cls, + items: [ + { + el: BI.extend(baseConfig, this._getSearchConfig()), + top: 0, bottom: 0, right: 0, left: 0 + }, { + el: self._getTriggerIconButton(), + top: 0, bottom: 0, right: 0, + }, + ] + }; + } + + return BI.extend(baseConfig, { + el: { + type: "bi.single_tree_trigger", + ref: function (_ref) { + self.textTrigger = _ref; + }, + text: o.text, + defaultText: o.defaultText, + height: o.height, + items: o.items, + value: o.value, + tipType: o.tipType, + warningTitle: o.warningTitle, + valueFormatter: o.valueFormatter, + } + }, { cls }); }, _getBaseConfig: function () { var self = this, o = this.options; return { type: "bi.combo", - cls: (o.simple ? "bi-border-bottom " : "bi-border bi-border-radius ") + (BI.isKey(o.status) ? ("status-" + o.status) : ""), container: o.container, destroyWhenHide: o.destroyWhenHide, adjustLength: 2, @@ -105,6 +140,7 @@ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { // height: o.height - (o.simple ? 1 : 2), height: o.height, text: o.text, + defaultText: o.defaultText, value: o.value, tipType: o.tipType, warningTitle: o.warningTitle, @@ -132,6 +168,11 @@ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { action: function () { self.fireEvent(BI.MultiLayerSelectTreeCombo.EVENT_SEARCHING); } + }, { + eventName: BI.MultiLayerSelectTreeTrigger.EVENT_STOP, + action: function () { + self.fireEvent(BI.MultiLayerSelectTreeCombo.EVENT_STOP); + } }, { eventName: BI.MultiLayerSelectTreeTrigger.EVENT_ADD_ITEM, action: function () { @@ -148,7 +189,7 @@ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { // IE11下,popover(position: fixed)下放置下拉控件(position: fixed), 滚动的时候会异常卡顿 // 通过container参数将popup放置于popover之外解决此问题, 其他下拉控件由于元素少或者有分页,所以 // 卡顿不明显, 先在此做尝试, 并在FineUI特殊处理待解决文档中标记跟踪 - return !(o.container && self.trigger.getSearcher().isSearching() && self.trigger.getSearcher().getView().element.find(e.target).length > 0); + return (o.container && self.trigger.getSearcher().isSearching() && self.trigger.getSearcher().getView().element.find(e.target).length > 0) ? false : self.triggerBtn?.element.find(e.target).length === 0; }, listeners: [{ @@ -165,28 +206,29 @@ BI.MultiLayerSelectTreeCombo = BI.inherit(BI.Widget, { }; }, - _getSyncConfig: function () { - var o = this.options, self = this; - var baseConfig = this._getBaseConfig(); - return BI.extend(baseConfig, o.allowEdit ? this._getSearchConfig() : { - el: { - type: "bi.single_tree_trigger", - ref: function (_ref) { - self.textTrigger = _ref; - }, - text: o.text, - height: o.height, - items: o.items, - value: o.value, - tipType: o.tipType, - warningTitle: o.warningTitle, - } - }); - }, - - _getAsyncConfig: function () { - var config = this._getBaseConfig(); - return BI.extend(config, this._getSearchConfig()); + _getTriggerIconButton: function () { + var self = this, o = this.options; + return { + type: "bi.trigger_icon_button", + cls: "trigger-icon-button", + ref: function (_ref) { + self.triggerBtn = _ref; + }, + width: o.height, + height: o.height, + listeners: [ + { + eventName: BI.TriggerIconButton.EVENT_CHANGE, + action: function () { + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + } + } + ] + }; }, setValue: function (v) { @@ -243,6 +285,7 @@ BI.MultiLayerSelectTreeCombo.EVENT_SEARCHING = "EVENT_SEARCHING"; BI.MultiLayerSelectTreeCombo.EVENT_BLUR = "EVENT_BLUR"; BI.MultiLayerSelectTreeCombo.EVENT_FOCUS = "EVENT_FOCUS"; BI.MultiLayerSelectTreeCombo.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiLayerSelectTreeCombo.EVENT_STOP = "EVENT_STOP"; BI.MultiLayerSelectTreeCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.MultiLayerSelectTreeCombo.EVENT_CLICK_ITEM = "EVENT_CLICK_ITEM"; BI.shortcut("bi.multilayer_select_tree_combo", BI.MultiLayerSelectTreeCombo); diff --git a/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js b/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js index 02209b0d2..9072c3284 100644 --- a/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js +++ b/src/widget/multilayerselecttree/multilayerselecttree.leveltree.js @@ -44,30 +44,12 @@ BI.MultiLayerSelectLevelTree = BI.inherit(BI.Pane, { node.keyword = node.keyword || keyword; extend.pNode = pNode; if (node.isParent === true || node.parent === true || BI.isNotEmptyArray(node.children)) { - - if (layer === 0 && extend.isFirstNode && extend.isLastNode) { - extend.type = "bi.multilayer_select_tree_plus_group_node"; - } else if (layer === 0 && extend.isFirstNode) { - extend.type = "bi.multilayer_select_tree_first_plus_group_node"; - } else if (extend.isLastNode) { - extend.type = "bi.multilayer_select_tree_last_plus_group_node"; - } else { - extend.type = "bi.multilayer_select_tree_mid_plus_group_node"; - } - + extend.type = "bi.tree_node"; + extend.selectable = true; BI.defaults(node, extend); self._formatItems(node.children, layer + 1, node); } else { - - if (layer === 0 && extend.isFirstNode && extend.isLastNode) { - extend.type = "bi.root_tree_leaf_item"; - } else if (layer === 0 && extend.isFirstNode) { - extend.type = "bi.multilayer_single_tree_first_tree_leaf_item"; - } else if (extend.isLastNode) { - extend.type = "bi.multilayer_single_tree_last_tree_leaf_item"; - } else { - extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item"; - } + extend.type = "bi.tree_item"; BI.defaults(node, extend); } }); diff --git a/src/widget/multilayerselecttree/multilayerselecttree.trigger.js b/src/widget/multilayerselecttree/multilayerselecttree.trigger.js index 11789b5ac..08f9f9a9e 100644 --- a/src/widget/multilayerselecttree/multilayerselecttree.trigger.js +++ b/src/widget/multilayerselecttree/multilayerselecttree.trigger.js @@ -19,7 +19,7 @@ BI.MultiLayerSelectTreeTrigger = BI.inherit(BI.Trigger, { if (o.itemsCreator === BI.emptyFn) { this._initData(); } - + return { type: "bi.horizontal_fill", items: [ @@ -37,12 +37,12 @@ BI.MultiLayerSelectTreeTrigger = BI.inherit(BI.Trigger, { }, isAutoSearch: false, el: { - type: "bi.state_editor", + type: "bi.default_text_editor", ref: function () { self.editor = this; }, - defaultText: o.text, - text: this._digest(o.value), + defaultText: o.defaultText, + text: BI.isKey(o.value) ? this._digest(o.value) : o.text, value: o.value, height: o.height, tipText: "", @@ -102,17 +102,8 @@ BI.MultiLayerSelectTreeTrigger = BI.inherit(BI.Trigger, { }] }, width: "fill", - }, { - el: { - type: "bi.trigger_icon_button", - cls: "trigger-icon-button", - ref: function (_ref) { - self.triggerBtn = _ref; - }, - width: 24, - }, - width: 24, - } + rgap: 24 + }, ] }; }, @@ -170,6 +161,7 @@ BI.MultiLayerSelectTreeTrigger = BI.inherit(BI.Trigger, { result.push(node); result = result.concat(self._getChildren(node)); }); + queue.reverse(); while (BI.isNotEmptyArray(queue)) { var node = queue.pop(); var pNode = this.tree.search(this.tree.getRoot(), node.pId, "id"); @@ -190,15 +182,11 @@ BI.MultiLayerSelectTreeTrigger = BI.inherit(BI.Trigger, { return o.valueFormatter(v); } - if (o.itemsCreator === BI.emptyFn) { - var result = BI.find(o.items, function (i, item) { - return item.value === v; - }); - - return BI.isNotNull(result) ? result.text : o.text; - } + var result = BI.find(o.items, function (i, item) { + return item.value === v; + }); - return v; + return BI.isNotNull(result) ? result.text : (o.text ?? v); }, _getShowText: function () { diff --git a/src/widget/multilayersingletree/multilayersingletree.combo.js b/src/widget/multilayersingletree/multilayersingletree.combo.js index 63f43b4f9..364f1e008 100644 --- a/src/widget/multilayersingletree/multilayersingletree.combo.js +++ b/src/widget/multilayersingletree/multilayersingletree.combo.js @@ -13,9 +13,9 @@ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { isDefaultInit: false, height: 24, text: "", + defaultText: "", itemsCreator: BI.emptyFn, items: [], - value: "", allowEdit: false, allowSearchValue: false, allowInsertValue: false, @@ -36,11 +36,6 @@ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { return (o.itemsCreator === BI.emptyFn) ? this._getSyncConfig() : this._getAsyncConfig(); }, - _shouldWrapper: function () { - var o = this.options; - return !o.allowEdit && o.itemsCreator === BI.emptyFn; - }, - _getBaseConfig: function () { var self = this, o = this.options; return { @@ -99,7 +94,6 @@ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { container: o.container, allowInsertValue: o.allowInsertValue, allowSearchValue: o.allowSearchValue, - allowEdit: o.allowEdit, cls: "multilayer-single-tree-trigger", ref: function (_ref) { self.trigger = _ref; @@ -110,6 +104,7 @@ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { valueFormatter: o.valueFormatter, height: o.height, text: o.text, + defaultText: o.defaultText, value: o.value, tipType: o.tipType, warningTitle: o.warningTitle, @@ -136,6 +131,11 @@ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { action: function () { self.fireEvent(BI.MultiLayerSingleTreeCombo.EVENT_SEARCHING); } + }, { + eventName: BI.MultiLayerSingleTreeTrigger.EVENT_STOP, + action: function () { + self.fireEvent(BI.MultiLayerSingleTreeCombo.EVENT_STOP); + } }, { eventName: BI.MultiLayerSingleTreeTrigger.EVENT_ADD_ITEM, action: function () { @@ -178,19 +178,36 @@ BI.MultiLayerSingleTreeCombo = BI.inherit(BI.Widget, { self.textTrigger = _ref; }, text: o.text, + defaultText: o.defaultText, height: o.height, items: o.items, value: o.value, tipType: o.tipType, warningTitle: o.warningTitle, valueFormatter: o.valueFormatter, - } + }, }); }, _getAsyncConfig: function () { - var config = this._getBaseConfig(); - return BI.extend(config, this._getSearchConfig()); + var o = this.options, self = this; + var baseConfig = this._getBaseConfig(); + return BI.extend(baseConfig, o.allowEdit ? this._getSearchConfig() : { + el: { + type: "bi.single_tree_trigger", + ref: function (_ref) { + self.textTrigger = _ref; + }, + text: o.text, + defaultText: o.defaultText, + height: o.height, + items: o.items, + value: o.value, + tipType: o.tipType, + warningTitle: o.warningTitle, + valueFormatter: o.valueFormatter, + }, + }); }, getSearcher: function () { @@ -243,5 +260,6 @@ BI.MultiLayerSingleTreeCombo.EVENT_SEARCHING = "EVENT_SEARCHING"; BI.MultiLayerSingleTreeCombo.EVENT_BLUR = "EVENT_BLUR"; BI.MultiLayerSingleTreeCombo.EVENT_FOCUS = "EVENT_FOCUS"; BI.MultiLayerSingleTreeCombo.EVENT_CHANGE = "EVENT_CHANGE"; +BI.MultiLayerSingleTreeCombo.EVENT_STOP = "EVENT_STOP"; BI.MultiLayerSingleTreeCombo.EVENT_BEFORE_POPUPVIEW = "EVENT_BEFORE_POPUPVIEW"; BI.shortcut("bi.multilayer_single_tree_combo", BI.MultiLayerSingleTreeCombo); diff --git a/src/widget/multilayersingletree/multilayersingletree.leveltree.js b/src/widget/multilayersingletree/multilayersingletree.leveltree.js index 186e2e0ae..8e14aa749 100644 --- a/src/widget/multilayersingletree/multilayersingletree.leveltree.js +++ b/src/widget/multilayersingletree/multilayersingletree.leveltree.js @@ -44,31 +44,12 @@ BI.MultiLayerSingleLevelTree = BI.inherit(BI.Pane, { node.keyword = node.keyword || keyword; extend.pNode = pNode; if (node.isParent === true || node.parent === true || BI.isNotEmptyArray(node.children)) { - - if (layer === 0 && extend.isFirstNode && extend.isLastNode) { - extend.type = "bi.multilayer_single_tree_plus_group_node"; - } else if (layer === 0 && extend.isFirstNode) { - extend.type = "bi.multilayer_single_tree_first_plus_group_node"; - } else if (extend.isLastNode) { - extend.type = "bi.multilayer_single_tree_last_plus_group_node"; - } else { - extend.type = "bi.multilayer_single_tree_mid_plus_group_node"; - } - + extend.type = "bi.tree_node"; + extend.selectable = false; BI.defaults(node, extend); self._formatItems(node.children, layer + 1, node); } else { - - if (layer === 0 && extend.isFirstNode && extend.isLastNode) { - extend.type = "bi.root_tree_leaf_item"; - } else if (layer === 0 && extend.isFirstNode) { - extend.type = "bi.multilayer_single_tree_first_tree_leaf_item"; - } else if (extend.isLastNode) { - extend.type = "bi.multilayer_single_tree_last_tree_leaf_item"; - } else { - extend.type = "bi.multilayer_single_tree_mid_tree_leaf_item"; - } - + extend.type = "bi.tree_item"; BI.defaults(node, extend); } }); diff --git a/src/widget/multilayersingletree/multilayersingletree.trigger.js b/src/widget/multilayersingletree/multilayersingletree.trigger.js index 8c58b0c8c..b4f5c8dd9 100644 --- a/src/widget/multilayersingletree/multilayersingletree.trigger.js +++ b/src/widget/multilayersingletree/multilayersingletree.trigger.js @@ -37,12 +37,12 @@ BI.MultiLayerSingleTreeTrigger = BI.inherit(BI.Trigger, { }, isAutoSearch: false, el: { - type: "bi.state_editor", + type: "bi.default_text_editor", ref: function () { self.editor = this; }, - defaultText: o.text, - text: this._digest(o.value), + defaultText: o.defaultText, + text: BI.isKey(o.value) ? this._digest(o.value) : o.text, value: o.value, height: o.height, tipText: "", @@ -170,6 +170,7 @@ BI.MultiLayerSingleTreeTrigger = BI.inherit(BI.Trigger, { result.push(node); result = result.concat(self._getChildren(node)); }); + queue.reverse(); while (BI.isNotEmptyArray(queue)) { var node = queue.pop(); var pNode = this.tree.search(this.tree.getRoot(), node.pId, "id"); @@ -191,16 +192,11 @@ BI.MultiLayerSingleTreeTrigger = BI.inherit(BI.Trigger, { return o.valueFormatter(v); } - if (o.itemsCreator === BI.emptyFn) { - var result = BI.find(o.items, function (i, item) { - return item.value === v; - }); - - return BI.isNotNull(result) ? result.text : o.text; - } - - return v; + var result = BI.find(o.items, function (i, item) { + return item.value === v; + }); + return BI.isNotNull(result) ? result.text : (o.text ?? v); }, _getShowText: function () { diff --git a/src/widget/multiselect/multiselect.combo.js b/src/widget/multiselect/multiselect.combo.js index 2e71071b8..00b035096 100644 --- a/src/widget/multiselect/multiselect.combo.js +++ b/src/widget/multiselect/multiselect.combo.js @@ -47,7 +47,7 @@ BI.MultiSelectCombo = BI.inherit(BI.Single, { allowEdit: o.allowEdit, height: o.height - (o.simple ? 1 : 2), text: o.text, - // adapter: this.popup, + defaultText: o.defaultText, masker: { offset: { left: 0, @@ -57,6 +57,7 @@ BI.MultiSelectCombo = BI.inherit(BI.Single, { }, }, valueFormatter: o.valueFormatter, + itemFormatter: o.itemFormatter, itemsCreator: BI.bind(this._itemsCreator4Trigger, this), itemHeight: o.itemHeight, value: this.storeValue, @@ -162,6 +163,7 @@ BI.MultiSelectCombo = BI.inherit(BI.Single, { itemsCreator: o.itemsCreator, itemHeight: o.itemHeight, valueFormatter: o.valueFormatter, + itemFormatter: o.itemFormatter, onLoaded: function () { BI.nextTick(function () { self.combo.adjustWidth(); @@ -173,7 +175,7 @@ BI.MultiSelectCombo = BI.inherit(BI.Single, { }, value: o.value, hideChecker: function (e) { - return self.numberCounter.element.find(e.target).length === 0; + return triggerBtn.element.find(e.target).length === 0 && self.numberCounter.element.find(e.target).length === 0; }, }); @@ -198,6 +200,21 @@ BI.MultiSelectCombo = BI.inherit(BI.Single, { } }); + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button", + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.numberCounter.hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + this.numberCounter = BI.createWidget({ type: "bi.multi_select_check_selected_switcher", masker: { @@ -248,6 +265,11 @@ BI.MultiSelectCombo = BI.inherit(BI.Single, { right: 0, top: 0, bottom: 0, + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0, }, { el: { type: "bi.vertical_adapt", diff --git a/src/widget/multiselect/multiselect.combo.nobar.js b/src/widget/multiselect/multiselect.combo.nobar.js index a72519750..0fe10f947 100644 --- a/src/widget/multiselect/multiselect.combo.nobar.js +++ b/src/widget/multiselect/multiselect.combo.nobar.js @@ -43,7 +43,7 @@ BI.MultiSelectNoBarCombo = BI.inherit(BI.Single, { type: "bi.multi_select_trigger", height: o.height - (o.simple ? 1 : 2), text: o.text, - // adapter: this.popup, + defaultText: o.defaultText, masker: { offset: { left: 0, diff --git a/src/widget/multiselect/multiselect.insert.combo.js b/src/widget/multiselect/multiselect.insert.combo.js index b1b4a202e..329c0f3f9 100644 --- a/src/widget/multiselect/multiselect.insert.combo.js +++ b/src/widget/multiselect/multiselect.insert.combo.js @@ -43,6 +43,7 @@ BI.MultiSelectInsertCombo = BI.inherit(BI.Single, { height: o.height - (o.simple ? 1 : 2), text: o.text, watermark: o.watermark, + defaultText: o.defaultText, // adapter: this.popup, masker: { offset: { @@ -55,7 +56,7 @@ BI.MultiSelectInsertCombo = BI.inherit(BI.Single, { valueFormatter: o.valueFormatter, itemsCreator: BI.bind(this._itemsCreator4Trigger, this), itemHeight: o.itemHeight, - value: o.value + value: this.storeValue, }); this.trigger.on(BI.MultiSelectInsertTrigger.EVENT_FOCUS, function () { diff --git a/src/widget/multiselect/multiselect.insert.trigger.js b/src/widget/multiselect/multiselect.insert.trigger.js index f0cf6054c..b04aebd07 100644 --- a/src/widget/multiselect/multiselect.insert.trigger.js +++ b/src/widget/multiselect/multiselect.insert.trigger.js @@ -37,6 +37,7 @@ BI.MultiSelectInsertTrigger = BI.inherit(BI.Trigger, { type: "bi.multi_select_insert_searcher", height: o.height, text: o.text, + defaultText: o.defaultText, itemsCreator: o.itemsCreator, valueFormatter: o.valueFormatter, itemHeight: o.itemHeight, @@ -109,7 +110,7 @@ BI.MultiSelectInsertTrigger = BI.inherit(BI.Trigger, { /** * 重新调整numberCounter的空白占位符 */ - refreshPlaceHolderWidth: function(width) { + refreshPlaceHolderWidth: function (width) { this.wrapper.attr("items")[1].width = width; this.wrapper.resize(); }, @@ -150,4 +151,4 @@ BI.MultiSelectInsertTrigger.EVENT_BEFORE_COUNTER_POPUPVIEW = "EVENT_BEFORE_COUNT BI.MultiSelectInsertTrigger.EVENT_FOCUS = "EVENT_FOCUS"; BI.MultiSelectInsertTrigger.EVENT_BLUR = "EVENT_BLUR"; -BI.shortcut("bi.multi_select_insert_trigger", BI.MultiSelectInsertTrigger); \ No newline at end of file +BI.shortcut("bi.multi_select_insert_trigger", BI.MultiSelectInsertTrigger); diff --git a/src/widget/multiselect/multiselect.loader.js b/src/widget/multiselect/multiselect.loader.js index 2f51ae181..7c45c68c1 100644 --- a/src/widget/multiselect/multiselect.loader.js +++ b/src/widget/multiselect/multiselect.loader.js @@ -64,7 +64,6 @@ BI.MultiSelectLoader = BI.inherit(BI.Widget, { value: v, title: txt, selected: self.storeValue.type === BI.Selection.Multi, - ...opts.itemFormatter(v), }; }); if (BI.isKey(self._startValue) && !BI.contains(self.storeValue.value, self._startValue)) { @@ -74,7 +73,6 @@ BI.MultiSelectLoader = BI.inherit(BI.Widget, { value: startValue, title: txt, selected: true, - ...opts.itemFormatter(startValue), }); } firstItems = self._createItems(json); @@ -110,13 +108,19 @@ BI.MultiSelectLoader = BI.inherit(BI.Widget, { }, _createItems: function (items) { - return BI.createItems(items, { - type: "bi.multi_select_item", - logic: this.options.logic, - cls: "bi-list-item-active", - height: this.options.itemHeight || BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, - selected: this.isAllSelected(), - iconWrapperWidth: 36 + var allSelected = this.isAllSelected(); + var itemFormatter = this.options.itemFormatter; + return BI.map(items, (i, item) => { + return { + type: "bi.multi_select_item", + logic: this.options.logic, + cls: "bi-list-item-active", + height: this.options.itemHeight || BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, + selected: allSelected, + iconWrapperWidth: 36, + ...item, + ...itemFormatter(item), + }; }); }, diff --git a/src/widget/multiselect/multiselect.loader.nobar.js b/src/widget/multiselect/multiselect.loader.nobar.js index d7744d042..d865b6d6b 100644 --- a/src/widget/multiselect/multiselect.loader.nobar.js +++ b/src/widget/multiselect/multiselect.loader.nobar.js @@ -18,7 +18,8 @@ BI.MultiSelectNoBarLoader = BI.inherit(BI.Widget, { valueFormatter: BI.emptyFn, itemsCreator: BI.emptyFn, itemHeight: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, - onLoaded: BI.emptyFn + onLoaded: BI.emptyFn, + itemFormatter: BI.emptyFn, }); }, @@ -113,12 +114,16 @@ BI.MultiSelectNoBarLoader = BI.inherit(BI.Widget, { }, _createItems: function (items) { - return BI.createItems(items, { - type: "bi.multi_select_item", - cls: "bi-list-item-active", - logic: this.options.logic, - height: this.options.itemHeight || BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, - iconWrapperWidth: 36 + return BI.map(items, (index, item) => { + return { + type: "bi.multi_select_item", + cls: "bi-list-item-active", + logic: this.options.logic, + height: this.options.itemHeight || BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, + iconWrapperWidth: 36, + ...item, + ...this.options.itemFormatter(item), + }; }); }, @@ -168,7 +173,7 @@ BI.MultiSelectNoBarLoader = BI.inherit(BI.Widget, { }, resetHeight: function (h) { - this.button_group.element.css({"max-height": h / BI.pixRatio + BI.pixUnit}); + this.button_group.element.css({ "max-height": h / BI.pixRatio + BI.pixUnit }); }, resetWidth: function () { diff --git a/src/widget/multiselect/multiselect.popup.view.js b/src/widget/multiselect/multiselect.popup.view.js index cefe9f0b2..1e11376d2 100644 --- a/src/widget/multiselect/multiselect.popup.view.js +++ b/src/widget/multiselect/multiselect.popup.view.js @@ -27,6 +27,7 @@ BI.MultiSelectPopupView = BI.inherit(BI.Widget, { itemsCreator: opts.itemsCreator, itemHeight: opts.itemHeight, valueFormatter: opts.valueFormatter, + itemFormatter: opts.itemFormatter, onLoaded: opts.onLoaded, value: opts.value }); diff --git a/src/widget/multiselect/multiselect.popup.view.nobar.js b/src/widget/multiselect/multiselect.popup.view.nobar.js index 9132ae5ee..c0007f85a 100644 --- a/src/widget/multiselect/multiselect.popup.view.nobar.js +++ b/src/widget/multiselect/multiselect.popup.view.nobar.js @@ -27,6 +27,7 @@ BI.MultiSelectNoBarPopupView = BI.inherit(BI.Widget, { itemsCreator: opts.itemsCreator, itemHeight: opts.itemHeight, valueFormatter: opts.valueFormatter, + itemFormatter: opts.itemFormatter, onLoaded: opts.onLoaded, value: opts.value }); diff --git a/src/widget/multiselect/multiselect.trigger.js b/src/widget/multiselect/multiselect.trigger.js index 4f75b38cb..937e83804 100644 --- a/src/widget/multiselect/multiselect.trigger.js +++ b/src/widget/multiselect/multiselect.trigger.js @@ -37,6 +37,7 @@ BI.MultiSelectTrigger = BI.inherit(BI.Trigger, { type: "bi.multi_select_searcher", height: o.height, text: o.text, + defaultText: o.defaultText, itemsCreator: o.itemsCreator, itemHeight: o.itemHeight, valueFormatter: o.valueFormatter, @@ -78,22 +79,10 @@ BI.MultiSelectTrigger = BI.inherit(BI.Trigger, { items: [ { el: this.searcher, - width: "fill" - }, { - el: this.wrapNumberCounter, - width: 0 - }, { - el: { - type: "bi.trigger_icon_button", - height: o.height, - stopPropagation: true, - cls: "multi-select-trigger-icon-button", - handler: function () { - self.fireEvent(BI.Controller.EVENT_CHANGE, BI.Events.TOGGLE); - } - }, - width: 24 - }] + width: "fill", + rgap: 24 + } + ] }); !o.allowEdit && BI.createWidget({ @@ -123,7 +112,7 @@ BI.MultiSelectTrigger = BI.inherit(BI.Trigger, { * 重新调整numberCounter的空白占位符 */ refreshPlaceHolderWidth: function (width) { - this.wrapper.attr("items")[1].width = width; + this.wrapper.attr("items")[0].rgap = 24 + width; this.wrapper.resize(); }, diff --git a/src/widget/multiselect/search/multiselect.search.loader.js b/src/widget/multiselect/search/multiselect.search.loader.js index 8f17eacfc..89e4cb318 100644 --- a/src/widget/multiselect/search/multiselect.search.loader.js +++ b/src/widget/multiselect/search/multiselect.search.loader.js @@ -91,13 +91,14 @@ BI.MultiSelectSearchLoader = BI.inherit(BI.Widget, { }, _createItems: function (items) { + var allSelected = this.isAllSelected(); return BI.createItems(items, { type: "bi.multi_select_item", logic: { dynamic: false }, height: this.options.itemHeight || BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, - selected: this.isAllSelected(), + selected: allSelected, cls: "bi-list-item-active", iconWrapperWidth: 36 }); @@ -127,7 +128,7 @@ BI.MultiSelectSearchLoader = BI.inherit(BI.Widget, { title: v.text, value: v.value, selected: src.type === BI.Selection.All, - ...o.itemFormatter(v.value), + ...o.itemFormatter(v), }; }); }, diff --git a/src/widget/multiselect/trigger/editor.multiselect.js b/src/widget/multiselect/trigger/editor.multiselect.js index 29ee8489b..db9acc9a4 100644 --- a/src/widget/multiselect/trigger/editor.multiselect.js +++ b/src/widget/multiselect/trigger/editor.multiselect.js @@ -24,7 +24,7 @@ BI.MultiSelectEditor = BI.inherit(BI.Widget, { watermark: o.watermark, allowBlank: true, value: o.value, - defaultText: o.text, + defaultText: o.defaultText, text: o.text, tipType: o.tipType, warningTitle: o.warningTitle, diff --git a/src/widget/multiselect/trigger/editor/editor.patch.js b/src/widget/multiselect/trigger/editor/editor.patch.js index d19bac9bb..bec2ae7db 100644 --- a/src/widget/multiselect/trigger/editor/editor.patch.js +++ b/src/widget/multiselect/trigger/editor/editor.patch.js @@ -30,7 +30,7 @@ BI.SelectPatchEditor = BI.inherit(BI.Widget, { watermark: o.watermark, allowBlank: true, value: o.value, - defaultText: o.text, + defaultText: o.defaultText, text: o.text, tipType: o.tipType, warningTitle: o.warningTitle, @@ -211,4 +211,4 @@ BI.SelectPatchEditor.EVENT_CHANGE = "EVENT_CHANGE"; BI.SelectPatchEditor.EVENT_FOCUS = "EVENT_FOCUS"; BI.SelectPatchEditor.EVENT_BLUR = "EVENT_BLUR"; -BI.shortcut("bi.select_patch_editor", BI.SelectPatchEditor); \ No newline at end of file +BI.shortcut("bi.select_patch_editor", BI.SelectPatchEditor); diff --git a/src/widget/multiselect/trigger/searcher.multiselect.insert.js b/src/widget/multiselect/trigger/searcher.multiselect.insert.js index 36b3a115f..bf77db1e7 100644 --- a/src/widget/multiselect/trigger/searcher.multiselect.insert.js +++ b/src/widget/multiselect/trigger/searcher.multiselect.insert.js @@ -16,7 +16,6 @@ BI.MultiSelectInsertSearcher = BI.inherit(BI.Widget, { valueFormatter: BI.emptyFn, adapter: null, masker: {}, - text: BI.i18nText("BI-Basic_Please_Select"), watermark: BI.i18nText("BI-Basic_Search_And_Patch_Paste"), }); }, @@ -29,6 +28,7 @@ BI.MultiSelectInsertSearcher = BI.inherit(BI.Widget, { watermark: o.watermark, height: o.height, text: o.text, + defaultText: o.defaultText, listeners: [{ eventName: BI.MultiSelectEditor.EVENT_FOCUS, action: function () { diff --git a/src/widget/multiselect/trigger/searcher.multiselect.js b/src/widget/multiselect/trigger/searcher.multiselect.js index 4dbfbead7..5744cd1de 100644 --- a/src/widget/multiselect/trigger/searcher.multiselect.js +++ b/src/widget/multiselect/trigger/searcher.multiselect.js @@ -15,7 +15,7 @@ BI.MultiSelectSearcher = BI.inherit(BI.Widget, { valueFormatter: BI.emptyFn, adapter: null, masker: {}, - text: BI.i18nText("BI-Basic_Please_Select"), + defaultText: BI.i18nText("BI-Basic_Please_Select"), itemHeight: 24 }); }, @@ -27,6 +27,7 @@ BI.MultiSelectSearcher = BI.inherit(BI.Widget, { type: "bi.multi_select_editor", height: o.height, text: o.text, + defaultText: o.defaultText, watermark: o.watermark, listeners: [{ eventName: BI.MultiSelectEditor.EVENT_FOCUS, diff --git a/src/widget/multitree/multi.tree.combo.js b/src/widget/multitree/multi.tree.combo.js index ec94374d8..f222e6f6e 100644 --- a/src/widget/multitree/multi.tree.combo.js +++ b/src/widget/multitree/multi.tree.combo.js @@ -30,8 +30,8 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { height: o.height - (o.simple ? 1 : 2), valueFormatter: o.valueFormatter, text: o.text, + defaultText: o.defaultText, watermark: o.watermark, - // adapter: this.popup, masker: { offset: { left: 0, @@ -107,7 +107,8 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { isNeedAdjustWidth: o.isNeedAdjustWidth, value: { value: o.value || {} }, hideChecker: function (e) { - return self.numberCounter.element.find(e.target).length === 0; + return triggerBtn.element.find(e.target).length === 0 && + self.numberCounter.element.find(e.target).length === 0; } }); @@ -211,6 +212,21 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { change = false; }); + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.numberCounter.hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + this.numberCounter = BI.createWidget({ type: "bi.multi_select_check_selected_switcher", el: { @@ -273,6 +289,11 @@ BI.MultiTreeCombo = BI.inherit(BI.Single, { right: 0, top: 0, bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 }, { el: { type: "bi.vertical_adapt", diff --git a/src/widget/multitree/multi.tree.insert.combo.js b/src/widget/multitree/multi.tree.insert.combo.js index 9823b37a7..5159c60dd 100644 --- a/src/widget/multitree/multi.tree.insert.combo.js +++ b/src/widget/multitree/multi.tree.insert.combo.js @@ -30,7 +30,9 @@ BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { allowEdit: o.allowEdit, height: o.height - (o.simple ? 1 : 2), valueFormatter: o.valueFormatter, - // adapter: this.popup, + text: o.text, + defaultText: o.defaultText, + watermark: o.watermark, masker: { offset: { left: 0, @@ -41,8 +43,7 @@ BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { }, searcher: { type: "bi.multi_tree_searcher", - text: o.text, - watermark: o.watermark, + itemsCreator: o.itemsCreator, popup: { type: "bi.multi_tree_search_insert_pane", @@ -123,7 +124,8 @@ BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { isNeedAdjustWidth: o.isNeedAdjustWidth, value: { value: o.value || {} }, hideChecker: function (e) { - return self.numberCounter.element.find(e.target).length === 0; + return triggerBtn.element.find(e.target).length === 0 && + self.numberCounter.element.find(e.target).length === 0; } }); @@ -222,6 +224,21 @@ BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { change = false; }); + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.numberCounter.hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + this.numberCounter = BI.createWidget({ type: "bi.multi_select_check_selected_switcher", el: { @@ -284,6 +301,11 @@ BI.MultiTreeInsertCombo = BI.inherit(BI.Single, { right: 0, top: 0, bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 }, { el: { type: "bi.vertical_adapt", diff --git a/src/widget/multitree/multi.tree.list.combo.js b/src/widget/multitree/multi.tree.list.combo.js index 2a378b1ae..e22c5a7e0 100644 --- a/src/widget/multitree/multi.tree.list.combo.js +++ b/src/widget/multitree/multi.tree.list.combo.js @@ -14,6 +14,7 @@ BI.MultiTreeListCombo = BI.inherit(BI.Single, { allowEdit: true, allowInsertValue: true, isNeedAdjustWidth: true, + text: "", }); }, @@ -29,10 +30,10 @@ BI.MultiTreeListCombo = BI.inherit(BI.Single, { type: "bi.multi_select_trigger", allowEdit: o.allowEdit, text: o.text, + defaultText: o.defaultText, watermark: o.watermark, height: o.height - (o.simple ? 1 : 2), valueFormatter: o.valueFormatter, - // adapter: this.popup, masker: { offset: { left: 0, @@ -74,8 +75,7 @@ BI.MultiTreeListCombo = BI.inherit(BI.Single, { itemsCreator: o.itemsCreator } }, - value: { value: o.value || {} } - + value: this.storeValue }); this.combo = BI.createWidget({ @@ -139,9 +139,10 @@ BI.MultiTreeListCombo = BI.inherit(BI.Single, { maxWidth: o.isNeedAdjustWidth ? "auto" : 500, }, isNeedAdjustWidth: o.isNeedAdjustWidth, - value: { value: o.value || {} }, + value: this.storeValue, hideChecker: function (e) { - return self.numberCounter.element.find(e.target).length === 0; + return triggerBtn.element.find(e.target).length === 0 && + self.numberCounter.element.find(e.target).length === 0; } }); @@ -240,6 +241,21 @@ BI.MultiTreeListCombo = BI.inherit(BI.Single, { change = false; }); + var triggerBtn = BI.createWidget({ + type: "bi.trigger_icon_button", + width: o.height, + height: o.height, + cls: "multi-select-trigger-icon-button" + }); + triggerBtn.on(BI.TriggerIconButton.EVENT_CHANGE, function () { + self.numberCounter.hideView(); + if (self.combo.isViewVisible()) { + self.combo.hideView(); + } else { + self.combo.showView(); + } + }); + this.numberCounter = BI.createWidget({ type: "bi.multi_select_check_selected_switcher", el: { @@ -302,6 +318,11 @@ BI.MultiTreeListCombo = BI.inherit(BI.Single, { right: 0, top: 0, bottom: 0 + }, { + el: triggerBtn, + right: 0, + top: 0, + bottom: 0 }, { el: { type: "bi.vertical_adapt", diff --git a/src/widget/multitree/trigger/searcher.list.multi.tree.js b/src/widget/multitree/trigger/searcher.list.multi.tree.js index 555d1b783..8c54afe63 100644 --- a/src/widget/multitree/trigger/searcher.list.multi.tree.js +++ b/src/widget/multitree/trigger/searcher.list.multi.tree.js @@ -8,7 +8,7 @@ BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { _defaultConfig: function () { return BI.extend(BI.MultiListTreeSearcher.superclass._defaultConfig.apply(this, arguments), { - baseCls: "bi-multi-tree-searcher", + baseCls: "bi-multi-list-tree-searcher", itemsCreator: BI.emptyFn, valueFormatter: function (v) { return v; @@ -27,6 +27,7 @@ BI.MultiListTreeSearcher = BI.inherit(BI.Widget, { type: "bi.multi_select_editor", height: o.height, text: o.text, + defaultText: o.defaultText, watermark: o.watermark, el: { type: "bi.simple_state_editor", diff --git a/src/widget/multitree/trigger/searcher.multi.tree.js b/src/widget/multitree/trigger/searcher.multi.tree.js index 35d59f200..8b9c4f004 100644 --- a/src/widget/multitree/trigger/searcher.multi.tree.js +++ b/src/widget/multitree/trigger/searcher.multi.tree.js @@ -30,6 +30,7 @@ BI.MultiTreeSearcher = BI.inherit(BI.Widget, { el: { type: "bi.simple_state_editor", text: o.text, + defaultText: o.defaultText, height: o.height }, listeners: [{ @@ -149,7 +150,7 @@ BI.MultiTreeSearcher = BI.inherit(BI.Widget, { } } - function getChildrenNode (ob) { + function getChildrenNode(ob) { var text = ""; var index = 0, size = BI.size(ob); var names = BI.Func.getSortedResult(BI.keys(ob)); diff --git a/src/widget/selecttree/selecttree.popup.js b/src/widget/selecttree/selecttree.popup.js index 1bd69a6cb..cfce060ef 100644 --- a/src/widget/selecttree/selecttree.popup.js +++ b/src/widget/selecttree/selecttree.popup.js @@ -17,32 +17,23 @@ BI.SelectTreePopup = BI.inherit(BI.Pane, { _formatItems: function (nodes, layer, pNode) { var self = this; BI.each(nodes, function (i, node) { - var extend = {layer: layer}; + var extend = { + layer: layer, + isFirstNode: i === 0, + isLastNode: i === nodes.length - 1, + height: BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT, + pNode: pNode, + }; node.id = node.id || BI.UUID(); - extend.pNode = pNode; - extend.height = BI.SIZE_CONSANTS.LIST_ITEM_HEIGHT; + if (node.isParent === true || node.parent === true || BI.isNotEmptyArray(node.children)) { - extend.type = "bi.select_tree_mid_plus_group_node"; - if (i === nodes.length - 1) { - extend.type = "bi.select_tree_last_plus_group_node"; - extend.isLastNode = true; - } - if (i === 0 && !pNode) { - extend.type = "bi.select_tree_first_plus_group_node" - } - if (i === 0 && i === nodes.length - 1) { // 根 - extend.type = "bi.select_tree_plus_group_node"; - } + + extend.type = "bi.tree_node"; + extend.selectable = true; BI.defaults(node, extend); self._formatItems(node.children, layer + 1, node); } else { - extend.type = "bi.mid_tree_leaf_item"; - if (i === 0 && !pNode) { - extend.type = "bi.first_tree_leaf_item" - } - if (i === nodes.length - 1) { - extend.type = "bi.last_tree_leaf_item"; - } + extend.type = "bi.tree_item"; BI.defaults(node, extend); } }); @@ -57,8 +48,9 @@ BI.SelectTreePopup = BI.inherit(BI.Pane, { this.tree = BI.createWidget({ type: "bi.level_tree", expander: { - type: "bi.select_tree_expander", - isDefaultInit: true + type: "bi.tree_expander", + // isDefaultInit: true, + selectable: true, }, items: this._formatItems(BI.Tree.transformToTreeFormat(o.items), 0), value: o.value, @@ -99,4 +91,4 @@ BI.SelectTreePopup = BI.inherit(BI.Pane, { }); BI.SelectTreePopup.EVENT_CHANGE = "EVENT_CHANGE"; -BI.shortcut("bi.select_level_tree", BI.SelectTreePopup); \ No newline at end of file +BI.shortcut("bi.select_level_tree", BI.SelectTreePopup); diff --git a/src/widget/singleselect/trigger/searcher.singleselect.js b/src/widget/singleselect/trigger/searcher.singleselect.js index aa5ece93b..a5674b8f1 100644 --- a/src/widget/singleselect/trigger/searcher.singleselect.js +++ b/src/widget/singleselect/trigger/searcher.singleselect.js @@ -125,9 +125,10 @@ BI.SingleSelectSearcher = BI.inherit(BI.Widget, { setState: function (v) { var o = this.options; - if (BI.isNull(v)) { + if (BI.isUndefined(v)) { this.editor.setState(BI.Selection.None); } else { + v = v || ""; this.editor.setState(o.valueFormatter(v + "") || (v + "")); } }, diff --git a/src/widget/singletree/singletree.combo.js b/src/widget/singletree/singletree.combo.js index ad6b85268..c42392db8 100644 --- a/src/widget/singletree/singletree.combo.js +++ b/src/widget/singletree/singletree.combo.js @@ -25,6 +25,7 @@ BI.SingleTreeCombo = BI.inherit(BI.Widget, { this.trigger = BI.createWidget(BI.extend({ type: "bi.single_tree_trigger", text: o.text, + defaultText: o.defaultText, height: o.height, items: o.items, value: o.value, diff --git a/src/widget/singletree/singletree.trigger.js b/src/widget/singletree/singletree.trigger.js index 8c5193d2d..221c8b069 100644 --- a/src/widget/singletree/singletree.trigger.js +++ b/src/widget/singletree/singletree.trigger.js @@ -26,6 +26,7 @@ BI.SingleTreeTrigger = BI.inherit(BI.Trigger, { type: "bi.select_text_trigger", element: this, text: o.text, + defaultText: o.defaultText, items: o.items, height: o.height, warningTitle: o.warningTitle, diff --git a/typescript/core/worker/worker.main_thread.ts b/typescript/core/worker/worker.main_thread.ts index 42e0c18dd..c87bc9833 100644 --- a/typescript/core/worker/worker.main_thread.ts +++ b/typescript/core/worker/worker.main_thread.ts @@ -5,7 +5,7 @@ import { IWorkerOptions } from "./worker.core"; /** * 主线程Worker */ -export abstract class MainThreadWorker { +export class MainThreadWorker { /** * Worker 名称 */ @@ -24,10 +24,12 @@ export abstract class MainThreadWorker { public constructor(options: IWorkerOptions) { this.name = options.workerName; this.controller = new WorkerMainThreadController(options); - this.initActions(); } - protected abstract initActions(): void; + /** + * 初始化业务actions + */ + public initActions() {} /** * 销毁 worker 实例 diff --git a/typescript/core/worker/worker.worker_thread.ts b/typescript/core/worker/worker.worker_thread.ts index 9907955fb..53b621403 100644 --- a/typescript/core/worker/worker.worker_thread.ts +++ b/typescript/core/worker/worker.worker_thread.ts @@ -4,7 +4,7 @@ import { WorkerThreadController } from "./controller/worker.worker_thread.contro /** * worker线程实例 */ -export abstract class WorkerThreadWorker { +export class WorkerThreadWorker { /** * Worker 线程通信控制器 */ @@ -12,11 +12,12 @@ export abstract class WorkerThreadWorker { public constructor() { this.controller = new WorkerThreadController(); - - this.initActions(); } - protected abstract initActions(): void; + /** + * 初始化业务actions + */ + public initActions() {} /** * 实例化action diff --git a/typescript/core/worker/workers.ts b/typescript/core/worker/workers.ts index f02447120..5ab99dddc 100644 --- a/typescript/core/worker/workers.ts +++ b/typescript/core/worker/workers.ts @@ -1,12 +1,22 @@ import { WorkerChannel } from "./worker.channel"; import { WorkerBaseController } from "./controller/worker.controller"; -import { WorkerMessageType } from "./worker.core"; +import { IWorkerOptions, WorkerMessageType } from "./worker.core"; import { WorkerMainThreadController } from "./controller/worker.main_thread.controller"; import { WorkerThreadController } from "./controller/worker.worker_thread.controller"; import { WorkerBaseAction } from "./action/worker.action"; import { MainThreadWorker } from "./worker.main_thread"; import { WorkerThreadWorker } from "./worker.worker_thread"; +function createWorker(ThreadWorker: T, options: IWorkerOptions): InstanceType +function createWorker(ThreadWorker: T): InstanceType +function createWorker(ThreadWorker: T, options?: IWorkerOptions): InstanceType { + const threadWorker = new ThreadWorker(options as any) as InstanceType; + + threadWorker.initActions(); + + return threadWorker; +} + export const Workers = { WorkerChannel, WorkerBaseController, @@ -16,4 +26,5 @@ export const Workers = { MainThreadWorker, WorkerThreadWorker, WorkerMessageType, + createWorker, }; diff --git a/webpack/webpack.prod.js b/webpack/webpack.prod.js index 89b7f18c8..a48a8c17f 100644 --- a/webpack/webpack.prod.js +++ b/webpack/webpack.prod.js @@ -73,7 +73,7 @@ module.exports = merge.smart(common, { }), new webpack.BannerPlugin({ banner: `time: ${new Date().toLocaleString()}; branch: ${git( - 'rev-parse --abbrev-ref HEAD' + 'name-rev --name-only HEAD' )} commit: ${git( 'rev-parse HEAD' )}`