dtable-ui-component 6.0.110-tru.3 → 6.0.110-vjs.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -32,6 +32,22 @@ class CollaboratorSelect extends _react.Component {
32
32
  isShowSelectOptions: !this.state.isShowSelectOptions
33
33
  });
34
34
  };
35
+ this.onClick = event => {
36
+ const target = event.target;
37
+ const name = target.className;
38
+ const {
39
+ isShowSelectOptions
40
+ } = this.state;
41
+ if (!isShowSelectOptions || name === 'select-placeholder' || name.includes('icon-fork-number') || this.selector.contains(target)) {
42
+ return;
43
+ }
44
+ const {
45
+ isUsePopover
46
+ } = this.props;
47
+ if (isUsePopover && !this.collaboratorSelectPopoverRef.contains(target) || !isUsePopover && !this.selector.contains(target)) {
48
+ this.closeSelect();
49
+ }
50
+ };
35
51
  this.onMousedown = event => {
36
52
  const name = event.target.className;
37
53
  if (name === 'select-placeholder' || name.includes('icon-fork-number')) {
@@ -81,7 +97,8 @@ class CollaboratorSelect extends _react.Component {
81
97
  getFilterOptions: this.getFilterOptions,
82
98
  supportMultipleSelect: this.props.supportMultipleSelect,
83
99
  stopClickEvent: true,
84
- isShowSelected: true
100
+ isShowSelected: true,
101
+ onClickOutside: this.onClick
85
102
  });
86
103
  }
87
104
  return /*#__PURE__*/(0, _jsxRuntime.jsx)(_reactstrap.Popover, {
@@ -106,7 +123,8 @@ class CollaboratorSelect extends _react.Component {
106
123
  getFilterOptions: this.getFilterOptions,
107
124
  supportMultipleSelect: this.props.supportMultipleSelect,
108
125
  stopClickEvent: true,
109
- isShowSelected: true
126
+ isShowSelected: true,
127
+ onClickOutside: this.onClick
110
128
  })
111
129
  });
112
130
  };
@@ -0,0 +1,82 @@
1
+
2
+ .seatable-search-input {
3
+ width: 100%;
4
+ padding: 6px 10px;
5
+ min-width: 170px;
6
+ position: relative;
7
+ padding: 0;
8
+ height: 32px;
9
+ border-bottom: 1px solid var(--bs-border-color);
10
+ }
11
+
12
+ .seatable-search-input .form-control {
13
+ height: 32px;
14
+ border: none;
15
+ padding: .375rem 0 .375rem 1rem;
16
+ cursor: pointer;
17
+ border-bottom: 1px solid var(--bs-border-color);
18
+ }
19
+
20
+ .seatable-search-input-multiple .form-control:focus,
21
+ .seatable-search-input .form-control:focus {
22
+ outline: none;
23
+ box-shadow: none;
24
+ }
25
+
26
+ .seatable-search-input .input-icon-addon {
27
+ z-index: 1;
28
+ pointer-events: auto;
29
+ min-width: 2.75rem !important;
30
+ }
31
+
32
+ .seatable-search-input .input-icon-addon svg {
33
+ color: var(--bs-body-secondary-color);
34
+ cursor: pointer;
35
+ }
36
+
37
+ .seatable-search-input .none-search-result {
38
+ height: 100px;
39
+ width: 100%;
40
+ padding: 10px;
41
+ color: var(--bs-body-secondary-color);
42
+ }
43
+
44
+
45
+ .seatable-search-input-multiple {
46
+ width: 100%;
47
+ padding: 6px 10px;
48
+ min-width: 170px;
49
+ position: relative;
50
+ height: 40px;
51
+ }
52
+
53
+ .seatable-search-input-multiple .form-control {
54
+ height: 30px;
55
+ padding: .375rem 2.5rem .375rem 1rem;
56
+ cursor: pointer;
57
+ }
58
+
59
+ .seatable-search-input-multiple .input-icon-addon {
60
+ z-index: 1;
61
+ pointer-events: auto;
62
+ min-width: 2.75rem !important;
63
+ top: 10px;
64
+ height: 30px;
65
+ right: 10px;
66
+ }
67
+
68
+ .seatable-search-input-multiple .input-icon-addon svg {
69
+ color: var(--bs-body-secondary-color);
70
+ cursor: pointer;
71
+ }
72
+
73
+ .seatable-search-input-multiple .none-search-result {
74
+ height: 100px;
75
+ width: 100%;
76
+ padding: 10px;
77
+ color: var(--bs-body-secondary-color);
78
+ }
79
+
80
+ .multiple-selects-editor-list .seatable-search-input-multiple {
81
+ padding: 10px 10px 0;
82
+ }
@@ -0,0 +1,141 @@
1
+ "use strict";
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault").default;
4
+ var _interopRequireWildcard = require("@babel/runtime/helpers/interopRequireWildcard").default;
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = void 0;
9
+ var _react = _interopRequireWildcard(require("react"));
10
+ var _classnames = _interopRequireDefault(require("classnames"));
11
+ var _DTableIcon = _interopRequireDefault(require("../DTableIcon"));
12
+ require("./index.css");
13
+ var _jsxRuntime = require("react/jsx-runtime");
14
+ class DTableCustomizeSearchInput extends _react.Component {
15
+ constructor(props) {
16
+ super(props);
17
+ this.onCompositionStart = () => {
18
+ this.isInputtingChinese = true;
19
+ };
20
+ this.onChange = e => {
21
+ this.timer && clearTimeout(this.timer);
22
+ const {
23
+ onChange,
24
+ wait = 100
25
+ } = this.props;
26
+ let text = e.target.value;
27
+ this.setState({
28
+ searchValue: text || ''
29
+ }, () => {
30
+ if (this.isInputtingChinese) return;
31
+ this.timer = setTimeout(() => {
32
+ onChange && onChange(this.state.searchValue.trim());
33
+ }, wait);
34
+ });
35
+ };
36
+ this.onCompositionEnd = e => {
37
+ this.isInputtingChinese = false;
38
+ this.onChange(e);
39
+ };
40
+ this.clearSearch = e => {
41
+ e && e.stopPropagation && e.stopPropagation();
42
+ const {
43
+ clearValue
44
+ } = this.props;
45
+ this.setState({
46
+ searchValue: ''
47
+ }, () => {
48
+ clearValue && clearValue();
49
+ });
50
+ };
51
+ this.setFocus = isSelectAllText => {
52
+ if (this.inputRef === document.activeElement) return;
53
+ this.inputRef.focus();
54
+ if (isSelectAllText) {
55
+ const txtLength = this.state.searchValue.length;
56
+ this.inputRef.setSelectionRange(0, txtLength);
57
+ }
58
+ };
59
+ this.renderClear = () => {
60
+ const {
61
+ isClearable,
62
+ clearClassName
63
+ } = this.props;
64
+ const {
65
+ searchValue
66
+ } = this.state;
67
+ if (!isClearable || !searchValue) return null;
68
+ return /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
69
+ className: (0, _classnames.default)('search-text-clear input-icon-addon', clearClassName),
70
+ style: {
71
+ fontSize: '12px'
72
+ },
73
+ onClick: this.clearSearch,
74
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_DTableIcon.default, {
75
+ symbol: "close",
76
+ color: "var(--bs-icon-secondary-color)"
77
+ })
78
+ });
79
+ };
80
+ this.state = {
81
+ searchValue: props.value || ''
82
+ };
83
+ this.isInputtingChinese = false;
84
+ this.timer = null;
85
+ this.inputRef = null;
86
+ }
87
+ componentDidMount() {
88
+ if (this.props.autoFocus && this.inputRef && this.inputRef !== document.activeElement) {
89
+ setTimeout(() => {
90
+ this.inputRef.focus();
91
+ }, 0);
92
+ }
93
+ }
94
+ UNSAFE_componentWillReceiveProps(nextProps) {
95
+ if (nextProps.value !== this.props.value) {
96
+ this.setState({
97
+ searchValue: nextProps.value
98
+ });
99
+ }
100
+ }
101
+ componentWillUnmount() {
102
+ this.timer && clearTimeout(this.timer);
103
+ this.timer = null;
104
+ this.inputRef = null;
105
+ }
106
+ render() {
107
+ const {
108
+ placeholder,
109
+ autoFocus,
110
+ className,
111
+ onKeyDown,
112
+ disabled = false,
113
+ style = {},
114
+ isClearable,
115
+ isMultiple = false
116
+ } = this.props;
117
+ const {
118
+ searchValue
119
+ } = this.state;
120
+ const inputWidth = isClearable && searchValue && !isMultiple ? 'calc(100% - 40px)' : '100%';
121
+ style.width = inputWidth;
122
+ return /*#__PURE__*/(0, _jsxRuntime.jsxs)(_react.Fragment, {
123
+ children: [/*#__PURE__*/(0, _jsxRuntime.jsx)("input", {
124
+ type: "text",
125
+ name: "search-input",
126
+ value: searchValue,
127
+ className: (0, _classnames.default)('form-control', className),
128
+ onChange: this.onChange,
129
+ autoFocus: autoFocus,
130
+ placeholder: placeholder,
131
+ onCompositionStart: this.onCompositionStart,
132
+ onCompositionEnd: this.onCompositionEnd,
133
+ onKeyDown: onKeyDown,
134
+ disabled: disabled,
135
+ style: style,
136
+ ref: ref => this.inputRef = ref
137
+ }), this.renderClear()]
138
+ });
139
+ }
140
+ }
141
+ var _default = exports.default = DTableCustomizeSearchInput;
@@ -1,121 +1,118 @@
1
- .dtable-select {
1
+ .seatable-customize-select {
2
2
  position: relative;
3
- }
4
-
5
- .dtable-select.custom-select {
6
3
  display: flex;
7
4
  padding: 0 16px;
8
- border-radius: 3px;
5
+ border-radius: 4px;
9
6
  align-items: center;
10
7
  justify-content: space-between;
11
8
  max-width: 900px;
12
9
  user-select: none;
13
- -webkit-user-select: none;
14
- -moz-user-select: none;
15
- -o-user-select: none;
16
- -ms-user-select: none;
17
10
  text-align: left;
11
+ line-height: 1.5;
12
+ background-image: none;
13
+ font-size: 14px;
14
+ color: var(--bs-body-color);
15
+ border: 1px solid rgba(0, 40, 100, 0.12);
18
16
  }
19
17
 
20
- .dtable-select.custom-select:focus,
21
- .dtable-select.custom-select.focus {
22
- border-color: #1991eb !important;
23
- box-shadow: 0 0 0 2px rgba(70, 127, 207, 0.25);
18
+ .seatable-customize-select:focus,
19
+ .seatable-customize-select.focus {
20
+ border-color: #3E84F7 !important;
24
21
  }
25
22
 
26
- .dtable-select.custom-select.disabled:focus,
27
- .dtable-select.custom-select.focus.disabled,
28
- .dtable-select.custom-select.disabled:hover {
23
+ .seatable-customize-select.disabled:focus,
24
+ .seatable-customize-select.focus.disabled,
25
+ .seatable-customize-select.disabled:hover {
29
26
  border-color: rgba(0, 40, 100, 0.12) !important;
30
27
  box-shadow: unset;
31
28
  cursor: default;
32
29
  }
33
30
 
34
- .dtable-select.custom-select:hover {
31
+ .seatable-customize-select:hover {
35
32
  cursor: pointer;
36
- border-color: rgb(179, 179, 179);
37
- }
38
-
39
- .dtable-select .dtable-icon-down3 {
40
- display: inline-block;
41
- font-size: 12px;
42
- color: #666666;
43
- transition: all 0.1s;
33
+ border-color: var(--bs-border-color);
44
34
  }
45
35
 
46
- .dtable-select .select-option-name {
47
- color: #868e96 !important;
36
+ .seatable-customize-select .seatable-multicolor-icon-down {
37
+ width: 12px;
38
+ height: 12px;
39
+ color: var(--bs-icon-color);
48
40
  }
49
41
 
50
- .dtable-select .selected-option {
42
+ .seatable-customize-select .selected-option {
51
43
  display: flex;
52
44
  flex: 1;
53
45
  overflow: hidden;
54
46
  flex-wrap: nowrap;
55
47
  align-items: center;
56
48
  justify-content: space-between;
57
- background: #fff;
49
+ background: inherit;
58
50
  }
59
51
 
60
- .dtable-select.dtable-ui-collaborator-selector .option-group .option-group-content,
61
- .dtable-select.selector-group .option-group .option-group-content {
52
+ .seatable-check-color {
53
+ color: var(--bs-icon-color);
54
+ }
55
+
56
+ .seatable-customize-select.dtable-ui-collaborator-selector .seatable-option-group .seatable-option-group-content,
57
+ .seatable-customize-select.selector-group .seatable-option-group .seatable-option-group-content {
62
58
  padding: 10px;
63
59
  }
64
60
 
65
- .dtable-select.custom-select.dtable-ui-collaborator-selector .option-group .option-group-content {
61
+ .seatable-customize-select.dtable-ui-collaborator-selector .seatable-option-group .seatable-option-group-content {
66
62
  padding: 10px 0;
67
63
  }
68
64
 
69
- .dtable-select.custom-select.dtable-ui-collaborator-selector .option {
65
+ .seatable-customize-select.dtable-ui-collaborator-selector .option {
70
66
  padding: 5px 0 5px 10px !important;
71
67
  line-height: 20px;
72
68
  }
73
69
 
74
- .dtable-select.selector-group .option {
70
+ .seatable-customize-select.selector-group .option {
75
71
  height: 30px;
76
72
  display: flex;
77
73
  align-items: center;
78
74
  }
79
75
 
80
- .dtable-select.selector-group .select-group-option {
76
+ .seatable-customize-select.selector-group .select-group-option {
81
77
  justify-content: space-between;
82
78
  }
83
79
 
84
- .dtable-select.selector-group .selected-option .selected-group {
80
+ .seatable-customize-select.selector-group .selected-option .selected-group {
85
81
  padding: 0 2px;
86
82
  background: #eceff4;
87
83
  border-radius: 3px;
88
84
  }
89
85
 
90
- .dtable-select .selected-option-show {
91
- overflow: hidden;
92
- text-overflow: ellipsis;
93
- white-space: nowrap;
94
- }
95
-
96
- .dtable-select .select-placeholder {
86
+ .seatable-customize-select .select-placeholder {
97
87
  line-height: 1;
98
88
  font-size: 14px;
99
89
  white-space: nowrap;
90
+ color: #868E96;
91
+ margin-right: 8px;
92
+ }
93
+
94
+ .seatable-customize-select .disabled .select-placeholder {
95
+ opacity: 0.65;
100
96
  }
101
97
 
102
- .option-group .option-group-selector-multiple-select .option-group-search,
103
- .option-group .option-group-selector-single-select .option-group-search {
104
- padding: 0 0 8px 0 !important;
98
+ .seatable-customize-select .selected-option-show {
99
+ height: 20px;
100
+ line-height: 20px;
101
+ margin-right: 8px;
102
+ width: calc(100% - 20px);
103
+ white-space: nowrap;
105
104
  }
106
105
 
107
- .option-group-selector-multiple-select .form-control,
108
- .option-group-selector-single-select .form-control {
109
- border: none;
110
- border-bottom: 1px solid rgb(0 40 100 / 12%) !important;
111
- border-radius: 4px 4px 0 0;
112
- padding: .375rem .5rem !important;
113
- height: 32px;
106
+ .seatable-customize-select .multiple-check-icon,
107
+ .seatable-customize-select .header-icon .dtable-font,
108
+ .seatable-option-group .select-label .header-icon .dtable-font {
109
+ color: var(--bs-icon-secondary-color) !important;
110
+ cursor: default;
111
+ font-size: 14px;
114
112
  }
115
113
 
116
- .option-group-selector-multiple-select .form-control:focus,
117
- .option-group-selector-single-select .form-control:focus {
118
- border-color: transparent !important;
119
- border-bottom: 1px solid rgb(0 40 100 / 12%) !important;
120
- box-shadow: none !important;
114
+ .seatable-customize-select .header-icon {
115
+ display: inline-block;
116
+ padding: 0 .5rem 0 0!important;
117
+ margin-left: 0 !important;
121
118
  }
@@ -7,9 +7,11 @@ Object.defineProperty(exports, "__esModule", {
7
7
  });
8
8
  exports.default = void 0;
9
9
  var _react = _interopRequireWildcard(require("react"));
10
- var _SelectOptionGroup = _interopRequireDefault(require("../SelectOptionGroup"));
11
10
  var _classnames = _interopRequireDefault(require("classnames"));
11
+ var _selectOptionGroup = _interopRequireDefault(require("./select-option-group"));
12
12
  var _ModalPortal = _interopRequireDefault(require("../ModalPortal"));
13
+ var _util = require("./util");
14
+ var _DTableIcon = _interopRequireDefault(require("../DTableIcon"));
13
15
  require("./index.css");
14
16
  var _jsxRuntime = require("react/jsx-runtime");
15
17
  class DTableCustomizeSelect extends _react.Component {
@@ -23,8 +25,8 @@ class DTableCustomizeSelect extends _react.Component {
23
25
  */
24
26
  if (this.state.isShowSelectOptions) event.stopPropagation();
25
27
  let eventClassName = event.target.className;
26
- if (this.props.isLocked || eventClassName.indexOf('option-search-control') > -1 || eventClassName === 'option-group-search') return;
27
- // Prevent closing by pressing the spacebar in the search input
28
+ if (this.props.isLocked || eventClassName.indexOf('option-search-control') > -1 || eventClassName === 'seatable-option-group-search') return;
29
+ // Prevent closing by pressing the space bar in the search input
28
30
  if (event.target.value === '') return;
29
31
  this.setState({
30
32
  isShowSelectOptions: !this.state.isShowSelectOptions
@@ -83,7 +85,7 @@ class DTableCustomizeSelect extends _react.Component {
83
85
  };
84
86
  }
85
87
  render() {
86
- let {
88
+ const {
87
89
  className,
88
90
  value,
89
91
  options,
@@ -93,17 +95,19 @@ class DTableCustomizeSelect extends _react.Component {
93
95
  noOptionsPlaceholder,
94
96
  isLocked,
95
97
  isInModal,
96
- addOptionAble,
97
98
  component
98
99
  } = this.props;
99
100
  return /*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
101
+ tabIndex: "0",
102
+ role: "button",
100
103
  ref: node => this.selector = node,
101
- className: (0, _classnames.default)('dtable-select custom-select', {
104
+ className: (0, _classnames.default)('seatable-customize-select custom-select', {
102
105
  'focus': this.state.isShowSelectOptions
103
106
  }, {
104
107
  'disabled': isLocked
105
108
  }, className),
106
109
  onClick: this.onSelectToggle,
110
+ onKeyDown: _util.onKeyDown,
107
111
  children: [/*#__PURE__*/(0, _jsxRuntime.jsxs)("div", {
108
112
  className: "selected-option",
109
113
  children: [value && value.label ? /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
@@ -112,12 +116,15 @@ class DTableCustomizeSelect extends _react.Component {
112
116
  }) : /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
113
117
  className: "select-placeholder",
114
118
  children: placeholder
115
- }), !isLocked && /*#__PURE__*/(0, _jsxRuntime.jsx)("i", {
116
- className: "dtable-font dtable-icon-down3"
119
+ }), !isLocked && /*#__PURE__*/(0, _jsxRuntime.jsx)("span", {
120
+ className: "d-inline-flex align-items-center",
121
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_DTableIcon.default, {
122
+ symbol: "down",
123
+ color: "var(--bs-icon-color)"
124
+ })
117
125
  })]
118
- }), this.state.isShowSelectOptions && !isInModal && /*#__PURE__*/(0, _jsxRuntime.jsx)(_SelectOptionGroup.default, {
126
+ }), this.state.isShowSelectOptions && !isInModal && /*#__PURE__*/(0, _jsxRuntime.jsx)(_selectOptionGroup.default, {
119
127
  value: value,
120
- addOptionAble: addOptionAble,
121
128
  component: component,
122
129
  isShowSelected: this.props.isShowSelected,
123
130
  top: this.getSelectedOptionTop(),
@@ -131,10 +138,9 @@ class DTableCustomizeSelect extends _react.Component {
131
138
  getFilterOptions: this.getFilterOptions,
132
139
  supportMultipleSelect: this.props.supportMultipleSelect
133
140
  }), this.state.isShowSelectOptions && isInModal && /*#__PURE__*/(0, _jsxRuntime.jsx)(_ModalPortal.default, {
134
- children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_SelectOptionGroup.default, {
141
+ children: /*#__PURE__*/(0, _jsxRuntime.jsx)(_selectOptionGroup.default, {
135
142
  className: className,
136
143
  value: value,
137
- addOptionAble: addOptionAble,
138
144
  component: component,
139
145
  isShowSelected: this.props.isShowSelected,
140
146
  position: this.selector.getBoundingClientRect(),
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ const KeyCodes = {
8
+ Backspace: 8,
9
+ Tab: 9,
10
+ Enter: 13,
11
+ Shift: 16,
12
+ Ctrl: 17,
13
+ Alt: 18,
14
+ PauseBreak: 19,
15
+ CapsLock: 20,
16
+ Escape: 27,
17
+ Esc: 27,
18
+ Space: 32,
19
+ PageUp: 33,
20
+ PageDown: 34,
21
+ End: 35,
22
+ Home: 36,
23
+ LeftArrow: 37,
24
+ UpArrow: 38,
25
+ RightArrow: 39,
26
+ DownArrow: 40,
27
+ Insert: 45,
28
+ Delete: 46,
29
+ 0: 48,
30
+ 1: 49,
31
+ 2: 50,
32
+ 3: 51,
33
+ 4: 52,
34
+ 5: 53,
35
+ 6: 54,
36
+ 7: 55,
37
+ 8: 56,
38
+ 9: 57,
39
+ a: 65,
40
+ b: 66,
41
+ c: 67,
42
+ d: 68,
43
+ e: 69,
44
+ f: 70,
45
+ g: 71,
46
+ h: 72,
47
+ i: 73,
48
+ j: 74,
49
+ k: 75,
50
+ l: 76,
51
+ m: 77,
52
+ n: 78,
53
+ o: 79,
54
+ p: 80,
55
+ q: 81,
56
+ r: 82,
57
+ s: 83,
58
+ t: 84,
59
+ u: 85,
60
+ v: 86,
61
+ w: 87,
62
+ x: 88,
63
+ y: 89,
64
+ z: 90,
65
+ LeftWindowKey: 91,
66
+ RightWindowKey: 92,
67
+ SelectKey: 93,
68
+ NumPad0: 96,
69
+ NumPad1: 97,
70
+ NumPad2: 98,
71
+ NumPad3: 99,
72
+ NumPad4: 100,
73
+ NumPad5: 101,
74
+ NumPad6: 102,
75
+ NumPad7: 103,
76
+ NumPad8: 104,
77
+ NumPad9: 105,
78
+ Multiply: 106,
79
+ Add: 107,
80
+ Subtract: 109,
81
+ DecimalPoint: 110,
82
+ Divide: 111,
83
+ F1: 112,
84
+ F2: 113,
85
+ F3: 114,
86
+ F4: 115,
87
+ F5: 116,
88
+ F6: 117,
89
+ F7: 118,
90
+ F8: 119,
91
+ F9: 120,
92
+ F10: 121,
93
+ F12: 123,
94
+ NumLock: 144,
95
+ ScrollLock: 145,
96
+ SemiColon: 186,
97
+ EqualSign: 187,
98
+ Comma: 188,
99
+ Dash: 189,
100
+ Period: 190,
101
+ ForwardSlash: 191,
102
+ GraveAccent: 192,
103
+ OpenBracket: 219,
104
+ BackSlash: 220,
105
+ CloseBracket: 221,
106
+ SingleQuote: 222,
107
+ ChineseInputMethod: 229
108
+ };
109
+ var _default = exports.default = KeyCodes;