Cascader.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429
  1. 'use strict';
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. var _extends2 = require('babel-runtime/helpers/extends');
  6. var _extends3 = _interopRequireDefault(_extends2);
  7. var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
  8. var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
  9. var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
  10. var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
  11. var _propsUtil = require('../_util/props-util');
  12. var _vueTypes = require('../_util/vue-types');
  13. var _vueTypes2 = _interopRequireDefault(_vueTypes);
  14. var _vcTrigger = require('../vc-trigger');
  15. var _vcTrigger2 = _interopRequireDefault(_vcTrigger);
  16. var _Menus = require('./Menus');
  17. var _Menus2 = _interopRequireDefault(_Menus);
  18. var _KeyCode = require('../_util/KeyCode');
  19. var _KeyCode2 = _interopRequireDefault(_KeyCode);
  20. var _arrayTreeFilter = require('array-tree-filter');
  21. var _arrayTreeFilter2 = _interopRequireDefault(_arrayTreeFilter);
  22. var _arrays = require('shallow-equal/arrays');
  23. var _arrays2 = _interopRequireDefault(_arrays);
  24. var _BaseMixin = require('../_util/BaseMixin');
  25. var _BaseMixin2 = _interopRequireDefault(_BaseMixin);
  26. var _vnode = require('../_util/vnode');
  27. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { 'default': obj }; }
  28. var BUILT_IN_PLACEMENTS = {
  29. bottomLeft: {
  30. points: ['tl', 'bl'],
  31. offset: [0, 4],
  32. overflow: {
  33. adjustX: 1,
  34. adjustY: 1
  35. }
  36. },
  37. topLeft: {
  38. points: ['bl', 'tl'],
  39. offset: [0, -4],
  40. overflow: {
  41. adjustX: 1,
  42. adjustY: 1
  43. }
  44. },
  45. bottomRight: {
  46. points: ['tr', 'br'],
  47. offset: [0, 4],
  48. overflow: {
  49. adjustX: 1,
  50. adjustY: 1
  51. }
  52. },
  53. topRight: {
  54. points: ['br', 'tr'],
  55. offset: [0, -4],
  56. overflow: {
  57. adjustX: 1,
  58. adjustY: 1
  59. }
  60. }
  61. };
  62. exports['default'] = {
  63. mixins: [_BaseMixin2['default']],
  64. model: {
  65. prop: 'value',
  66. event: 'change'
  67. },
  68. props: {
  69. value: _vueTypes2['default'].array,
  70. defaultValue: _vueTypes2['default'].array,
  71. options: _vueTypes2['default'].array,
  72. // onChange: PropTypes.func,
  73. // onPopupVisibleChange: PropTypes.func,
  74. popupVisible: _vueTypes2['default'].bool,
  75. disabled: _vueTypes2['default'].bool.def(false),
  76. transitionName: _vueTypes2['default'].string.def(''),
  77. popupClassName: _vueTypes2['default'].string.def(''),
  78. popupStyle: _vueTypes2['default'].object.def(function () {
  79. return {};
  80. }),
  81. popupPlacement: _vueTypes2['default'].string.def('bottomLeft'),
  82. prefixCls: _vueTypes2['default'].string.def('rc-cascader'),
  83. dropdownMenuColumnStyle: _vueTypes2['default'].object,
  84. builtinPlacements: _vueTypes2['default'].object.def(BUILT_IN_PLACEMENTS),
  85. loadData: _vueTypes2['default'].func,
  86. changeOnSelect: _vueTypes2['default'].bool,
  87. // onKeyDown: PropTypes.func,
  88. expandTrigger: _vueTypes2['default'].string.def('click'),
  89. fieldNames: _vueTypes2['default'].object.def(function () {
  90. return {
  91. label: 'label',
  92. value: 'value',
  93. children: 'children'
  94. };
  95. }),
  96. expandIcon: _vueTypes2['default'].any,
  97. loadingIcon: _vueTypes2['default'].any,
  98. getPopupContainer: _vueTypes2['default'].func
  99. },
  100. data: function data() {
  101. var initialValue = [];
  102. var value = this.value,
  103. defaultValue = this.defaultValue,
  104. popupVisible = this.popupVisible;
  105. if ((0, _propsUtil.hasProp)(this, 'value')) {
  106. initialValue = value || [];
  107. } else if ((0, _propsUtil.hasProp)(this, 'defaultValue')) {
  108. initialValue = defaultValue || [];
  109. }
  110. // warning(!('filedNames' in props),
  111. // '`filedNames` of Cascader is a typo usage and deprecated, please use `fieldNames` instead.');
  112. return {
  113. sPopupVisible: popupVisible,
  114. sActiveValue: initialValue,
  115. sValue: initialValue
  116. };
  117. },
  118. watch: {
  119. value: function value(val, oldValue) {
  120. if (!(0, _arrays2['default'])(val, oldValue)) {
  121. var newValues = {
  122. sValue: val || []
  123. };
  124. // allow activeValue diff from value
  125. // https://github.com/ant-design/ant-design/issues/2767
  126. if (!(0, _propsUtil.hasProp)(this, 'loadData')) {
  127. newValues.sActiveValue = val || [];
  128. }
  129. this.setState(newValues);
  130. }
  131. },
  132. popupVisible: function popupVisible(val) {
  133. this.setState({
  134. sPopupVisible: val
  135. });
  136. }
  137. },
  138. methods: {
  139. getPopupDOMNode: function getPopupDOMNode() {
  140. return this.$refs.trigger.getPopupDomNode();
  141. },
  142. getFieldName: function getFieldName(name) {
  143. var defaultFieldNames = this.defaultFieldNames,
  144. fieldNames = this.fieldNames;
  145. return fieldNames[name] || defaultFieldNames[name];
  146. },
  147. getFieldNames: function getFieldNames() {
  148. return this.fieldNames;
  149. },
  150. getCurrentLevelOptions: function getCurrentLevelOptions() {
  151. var _this = this;
  152. var _options = this.options,
  153. options = _options === undefined ? [] : _options,
  154. _sActiveValue = this.sActiveValue,
  155. sActiveValue = _sActiveValue === undefined ? [] : _sActiveValue;
  156. var result = (0, _arrayTreeFilter2['default'])(options, function (o, level) {
  157. return o[_this.getFieldName('value')] === sActiveValue[level];
  158. }, { childrenKeyName: this.getFieldName('children') });
  159. if (result[result.length - 2]) {
  160. return result[result.length - 2][this.getFieldName('children')];
  161. }
  162. return [].concat((0, _toConsumableArray3['default'])(options)).filter(function (o) {
  163. return !o.disabled;
  164. });
  165. },
  166. getActiveOptions: function getActiveOptions(activeValue) {
  167. var _this2 = this;
  168. return (0, _arrayTreeFilter2['default'])(this.options || [], function (o, level) {
  169. return o[_this2.getFieldName('value')] === activeValue[level];
  170. }, { childrenKeyName: this.getFieldName('children') });
  171. },
  172. setPopupVisible: function setPopupVisible(popupVisible) {
  173. if (!(0, _propsUtil.hasProp)(this, 'popupVisible')) {
  174. this.setState({ sPopupVisible: popupVisible });
  175. }
  176. // sync activeValue with value when panel open
  177. if (popupVisible && !this.sPopupVisible) {
  178. this.setState({
  179. sActiveValue: this.sValue
  180. });
  181. }
  182. this.__emit('popupVisibleChange', popupVisible);
  183. },
  184. handleChange: function handleChange(options, setProps, e) {
  185. var _this3 = this;
  186. if (e.type !== 'keydown' || e.keyCode === _KeyCode2['default'].ENTER) {
  187. this.__emit('change', options.map(function (o) {
  188. return o[_this3.getFieldName('value')];
  189. }), options);
  190. this.setPopupVisible(setProps.visible);
  191. }
  192. },
  193. handlePopupVisibleChange: function handlePopupVisibleChange(popupVisible) {
  194. this.setPopupVisible(popupVisible);
  195. },
  196. handleMenuSelect: function handleMenuSelect(targetOption, menuIndex, e) {
  197. // Keep focused state for keyboard support
  198. var triggerNode = this.$refs.trigger.getRootDomNode();
  199. if (triggerNode && triggerNode.focus) {
  200. triggerNode.focus();
  201. }
  202. var changeOnSelect = this.changeOnSelect,
  203. loadData = this.loadData,
  204. expandTrigger = this.expandTrigger;
  205. if (!targetOption || targetOption.disabled) {
  206. return;
  207. }
  208. var sActiveValue = this.sActiveValue;
  209. sActiveValue = sActiveValue.slice(0, menuIndex + 1);
  210. sActiveValue[menuIndex] = targetOption[this.getFieldName('value')];
  211. var activeOptions = this.getActiveOptions(sActiveValue);
  212. if (targetOption.isLeaf === false && !targetOption[this.getFieldName('children')] && loadData) {
  213. if (changeOnSelect) {
  214. this.handleChange(activeOptions, { visible: true }, e);
  215. }
  216. this.setState({ sActiveValue: sActiveValue });
  217. loadData(activeOptions);
  218. return;
  219. }
  220. var newState = {};
  221. if (!targetOption[this.getFieldName('children')] || !targetOption[this.getFieldName('children')].length) {
  222. this.handleChange(activeOptions, { visible: false }, e);
  223. // set value to activeValue when select leaf option
  224. newState.sValue = sActiveValue;
  225. // add e.type judgement to prevent `onChange` being triggered by mouseEnter
  226. } else if (changeOnSelect && (e.type === 'click' || e.type === 'keydown')) {
  227. if (expandTrigger === 'hover') {
  228. this.handleChange(activeOptions, { visible: false }, e);
  229. } else {
  230. this.handleChange(activeOptions, { visible: true }, e);
  231. }
  232. // set value to activeValue on every select
  233. newState.sValue = sActiveValue;
  234. }
  235. newState.sActiveValue = sActiveValue;
  236. // not change the value by keyboard
  237. if ((0, _propsUtil.hasProp)(this, 'value') || e.type === 'keydown' && e.keyCode !== _KeyCode2['default'].ENTER) {
  238. delete newState.sValue;
  239. }
  240. this.setState(newState);
  241. },
  242. handleItemDoubleClick: function handleItemDoubleClick() {
  243. var changeOnSelect = this.$props.changeOnSelect;
  244. if (changeOnSelect) {
  245. this.setPopupVisible(false);
  246. }
  247. },
  248. handleKeyDown: function handleKeyDown(e) {
  249. var _this4 = this;
  250. var $slots = this.$slots;
  251. var children = $slots['default'] && $slots['default'][0];
  252. // https://github.com/ant-design/ant-design/issues/6717
  253. // Don't bind keyboard support when children specify the onKeyDown
  254. if (children) {
  255. var keydown = (0, _propsUtil.getEvents)(children).keydown;
  256. if (keydown) {
  257. keydown(e);
  258. return;
  259. }
  260. }
  261. var activeValue = [].concat((0, _toConsumableArray3['default'])(this.sActiveValue));
  262. var currentLevel = activeValue.length - 1 < 0 ? 0 : activeValue.length - 1;
  263. var currentOptions = this.getCurrentLevelOptions();
  264. var currentIndex = currentOptions.map(function (o) {
  265. return o[_this4.getFieldName('value')];
  266. }).indexOf(activeValue[currentLevel]);
  267. if (e.keyCode !== _KeyCode2['default'].DOWN && e.keyCode !== _KeyCode2['default'].UP && e.keyCode !== _KeyCode2['default'].LEFT && e.keyCode !== _KeyCode2['default'].RIGHT && e.keyCode !== _KeyCode2['default'].ENTER && e.keyCode !== _KeyCode2['default'].SPACE && e.keyCode !== _KeyCode2['default'].BACKSPACE && e.keyCode !== _KeyCode2['default'].ESC && e.keyCode !== _KeyCode2['default'].TAB) {
  268. return;
  269. }
  270. // Press any keys above to reopen menu
  271. if (!this.sPopupVisible && e.keyCode !== _KeyCode2['default'].BACKSPACE && e.keyCode !== _KeyCode2['default'].LEFT && e.keyCode !== _KeyCode2['default'].RIGHT && e.keyCode !== _KeyCode2['default'].ESC && e.keyCode !== _KeyCode2['default'].TAB) {
  272. this.setPopupVisible(true);
  273. return;
  274. }
  275. if (e.keyCode === _KeyCode2['default'].DOWN || e.keyCode === _KeyCode2['default'].UP) {
  276. e.preventDefault();
  277. var nextIndex = currentIndex;
  278. if (nextIndex !== -1) {
  279. if (e.keyCode === _KeyCode2['default'].DOWN) {
  280. nextIndex += 1;
  281. nextIndex = nextIndex >= currentOptions.length ? 0 : nextIndex;
  282. } else {
  283. nextIndex -= 1;
  284. nextIndex = nextIndex < 0 ? currentOptions.length - 1 : nextIndex;
  285. }
  286. } else {
  287. nextIndex = 0;
  288. }
  289. activeValue[currentLevel] = currentOptions[nextIndex][this.getFieldName('value')];
  290. } else if (e.keyCode === _KeyCode2['default'].LEFT || e.keyCode === _KeyCode2['default'].BACKSPACE) {
  291. e.preventDefault();
  292. activeValue.splice(activeValue.length - 1, 1);
  293. } else if (e.keyCode === _KeyCode2['default'].RIGHT) {
  294. e.preventDefault();
  295. if (currentOptions[currentIndex] && currentOptions[currentIndex][this.getFieldName('children')]) {
  296. activeValue.push(currentOptions[currentIndex][this.getFieldName('children')][0][this.getFieldName('value')]);
  297. }
  298. } else if (e.keyCode === _KeyCode2['default'].ESC || e.keyCode === _KeyCode2['default'].TAB) {
  299. this.setPopupVisible(false);
  300. return;
  301. }
  302. if (!activeValue || activeValue.length === 0) {
  303. this.setPopupVisible(false);
  304. }
  305. var activeOptions = this.getActiveOptions(activeValue);
  306. var targetOption = activeOptions[activeOptions.length - 1];
  307. this.handleMenuSelect(targetOption, activeOptions.length - 1, e);
  308. this.__emit('keydown', e);
  309. }
  310. },
  311. render: function render() {
  312. var h = arguments[0];
  313. var $props = this.$props,
  314. sActiveValue = this.sActiveValue,
  315. handleMenuSelect = this.handleMenuSelect,
  316. sPopupVisible = this.sPopupVisible,
  317. handlePopupVisibleChange = this.handlePopupVisibleChange,
  318. handleKeyDown = this.handleKeyDown;
  319. var listeners = (0, _propsUtil.getListeners)(this);
  320. var prefixCls = $props.prefixCls,
  321. transitionName = $props.transitionName,
  322. popupClassName = $props.popupClassName,
  323. _$props$options = $props.options,
  324. options = _$props$options === undefined ? [] : _$props$options,
  325. disabled = $props.disabled,
  326. builtinPlacements = $props.builtinPlacements,
  327. popupPlacement = $props.popupPlacement,
  328. restProps = (0, _objectWithoutProperties3['default'])($props, ['prefixCls', 'transitionName', 'popupClassName', 'options', 'disabled', 'builtinPlacements', 'popupPlacement']);
  329. // Did not show popup when there is no options
  330. var menus = h('div');
  331. var emptyMenuClassName = '';
  332. if (options && options.length > 0) {
  333. var loadingIcon = (0, _propsUtil.getComponentFromProp)(this, 'loadingIcon');
  334. var expandIcon = (0, _propsUtil.getComponentFromProp)(this, 'expandIcon') || '>';
  335. var menusProps = {
  336. props: (0, _extends3['default'])({}, $props, {
  337. fieldNames: this.getFieldNames(),
  338. defaultFieldNames: this.defaultFieldNames,
  339. activeValue: sActiveValue,
  340. visible: sPopupVisible,
  341. loadingIcon: loadingIcon,
  342. expandIcon: expandIcon
  343. }),
  344. on: (0, _extends3['default'])({}, listeners, {
  345. select: handleMenuSelect,
  346. itemDoubleClick: this.handleItemDoubleClick
  347. })
  348. };
  349. menus = h(_Menus2['default'], menusProps);
  350. } else {
  351. emptyMenuClassName = ' ' + prefixCls + '-menus-empty';
  352. }
  353. var triggerProps = {
  354. props: (0, _extends3['default'])({}, restProps, {
  355. disabled: disabled,
  356. popupPlacement: popupPlacement,
  357. builtinPlacements: builtinPlacements,
  358. popupTransitionName: transitionName,
  359. action: disabled ? [] : ['click'],
  360. popupVisible: disabled ? false : sPopupVisible,
  361. prefixCls: prefixCls + '-menus',
  362. popupClassName: popupClassName + emptyMenuClassName
  363. }),
  364. on: (0, _extends3['default'])({}, listeners, {
  365. popupVisibleChange: handlePopupVisibleChange
  366. }),
  367. ref: 'trigger'
  368. };
  369. var children = (0, _propsUtil.getSlot)(this, 'default')[0];
  370. return h(
  371. _vcTrigger2['default'],
  372. triggerProps,
  373. [children && (0, _vnode.cloneElement)(children, {
  374. on: {
  375. keydown: handleKeyDown
  376. },
  377. attrs: {
  378. tabIndex: disabled ? undefined : 0
  379. }
  380. }), h(
  381. 'template',
  382. { slot: 'popup' },
  383. [menus]
  384. )]
  385. );
  386. }
  387. };