diginet-core-ui 1.4.1 → 1.4.2
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.
- package/components/form-control/dropdown/index.js +198 -89
- package/global/index.js +2 -0
- package/package.json +1 -1
- package/readme.md +5 -0
- package/styles/general.js +7 -1
- package/utils/parseHTML.js +11 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/** @jsxRuntime classic */
|
|
2
2
|
/** @jsx jsx */
|
|
3
3
|
import { css, jsx } from '@emotion/core';
|
|
4
|
-
import { Avatar, ButtonIcon, Checkbox, Chip, CircularProgress, HelperText, InputBase, Label, TreeView, Typography } from "../..";
|
|
4
|
+
import { Avatar, ButtonIcon, Checkbox, Chip, CircularProgress, HelperText, InputBase, Label, Popup, TreeView, Typography } from "../..";
|
|
5
5
|
import Popover from "../../popover";
|
|
6
6
|
import { getGlobal } from "../../../global";
|
|
7
7
|
import PropTypes from 'prop-types';
|
|
@@ -83,6 +83,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
83
83
|
searchExpr,
|
|
84
84
|
searchMode,
|
|
85
85
|
selectBox,
|
|
86
|
+
skip,
|
|
86
87
|
style,
|
|
87
88
|
subText,
|
|
88
89
|
total,
|
|
@@ -110,6 +111,11 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
110
111
|
// const timeout = useRef(null);
|
|
111
112
|
const loadMoreTimer = useRef(null);
|
|
112
113
|
const dataChosen = useRef([]);
|
|
114
|
+
const popupRef = useRef(null);
|
|
115
|
+
const filter = useRef({
|
|
116
|
+
skip: skip || 0,
|
|
117
|
+
limit: limit || 50
|
|
118
|
+
});
|
|
113
119
|
const [unique] = useState(randomString(6, {
|
|
114
120
|
allowNumber: false,
|
|
115
121
|
allowSymbol: false
|
|
@@ -119,6 +125,14 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
119
125
|
const [textValue, setTextValue] = useState('');
|
|
120
126
|
const [txtSearch, setTxtSearch] = useState('');
|
|
121
127
|
const [popoverWidth, setPopoverWidth] = useState(0);
|
|
128
|
+
const [loadingState, setLoadingState] = useState(loading);
|
|
129
|
+
const [totalState, setTotalState] = useState(total);
|
|
130
|
+
const [dataSourceState, setDataSourceState] = useState(dataSource);
|
|
131
|
+
const [popupDataState, setPopupDataState] = useState({
|
|
132
|
+
title: '',
|
|
133
|
+
substitle: '',
|
|
134
|
+
description: ''
|
|
135
|
+
});
|
|
122
136
|
let valueTemp = valueProp || defaultValue || [];
|
|
123
137
|
|
|
124
138
|
// only mode multi
|
|
@@ -131,7 +145,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
131
145
|
const _DropdownInputCSS = DropdownInputCSS(viewType, multiple, placeholder, disabled, readOnly, multilineSelectedItem);
|
|
132
146
|
const _IconCSS = IconCSS(viewType);
|
|
133
147
|
const _DropdownFormCSS = DropdownFormCSS(viewType, multiple, disabled, placeholder, _DropdownInputCSS.name);
|
|
134
|
-
const _DropdownListCSS = DropdownListCSS(
|
|
148
|
+
const _DropdownListCSS = DropdownListCSS(loadingState);
|
|
135
149
|
const _DropdownItemCSS = DropdownItemCSS(multiple, selectBox);
|
|
136
150
|
const _DropdownRootCSS = DropdownRootCSS(_DropdownFormCSS.name, _DropdownInputCSS.name);
|
|
137
151
|
|
|
@@ -148,7 +162,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
148
162
|
!!blur && inputRef.current.blur();
|
|
149
163
|
};
|
|
150
164
|
const onClickInput = e => {
|
|
151
|
-
if (disabled || readOnly ||
|
|
165
|
+
if (disabled || readOnly || loadingState) return;
|
|
152
166
|
if (!dropdownListRef.current) {
|
|
153
167
|
if (!multiple || !Array.from(inputRef.current.querySelectorAll('.DGN-UI-Chip')).some(item => item.contains(e === null || e === void 0 ? void 0 : e.target))) {
|
|
154
168
|
setOpenState(true);
|
|
@@ -181,7 +195,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
181
195
|
className: 'DGN-Dropdown-List',
|
|
182
196
|
onKeyDown: moveOnItem,
|
|
183
197
|
tabIndex: -1
|
|
184
|
-
},
|
|
198
|
+
}, dataSourceState !== null && dataSourceState !== void 0 && dataSourceState.length ? children : EmptyDataText) : itemMode === 'normal' ? mapDropdown() : mapTreeView();
|
|
185
199
|
// const { innerHeight } = window;
|
|
186
200
|
// const { top, left, height, width } = formRef.current.getBoundingClientRect();
|
|
187
201
|
|
|
@@ -220,12 +234,13 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
220
234
|
marginBottom: 1
|
|
221
235
|
},
|
|
222
236
|
onKeyDown: pressESCHandler,
|
|
237
|
+
readOnly: loadingState,
|
|
223
238
|
autoFocus: true
|
|
224
239
|
})) : null, multiple && maximumSelectionLength ? jsx(Typography, {
|
|
225
240
|
css: pd([2, 4])
|
|
226
241
|
}, getGlobal('selected'), " ", (valueMulti === null || valueMulti === void 0 ? void 0 : valueMulti.length) || 0, "/", maximumSelectionLength) : null, jsx("div", {
|
|
227
242
|
className: 'DGN-Dropdown-Box'
|
|
228
|
-
}, dropdown),
|
|
243
|
+
}, dropdown), loadingState ? jsx("div", {
|
|
229
244
|
css: LoadingProgressCSS,
|
|
230
245
|
className: 'DGN-Dropdown-Loading-Progress'
|
|
231
246
|
}, jsx(CircularProgress, {
|
|
@@ -239,7 +254,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
239
254
|
window.addEventListener('resize', customizeWidthDropdown);
|
|
240
255
|
// document.addEventListener('wheel', onWheelHandler);
|
|
241
256
|
// document.addEventListener('mousedown', onClickOutsideOfInput);
|
|
242
|
-
if (onLoadMore &&
|
|
257
|
+
if (onLoadMore && dataSourceState.length < totalState) {
|
|
243
258
|
dropdownListRef.current && dropdownListRef.current.addEventListener('scroll', onLoadMoreHandler);
|
|
244
259
|
}
|
|
245
260
|
}, 10);
|
|
@@ -317,13 +332,14 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
317
332
|
// }
|
|
318
333
|
// };
|
|
319
334
|
|
|
320
|
-
/**
|
|
321
|
-
* So sánh text đầu vào cáo map với txtSearch
|
|
322
|
-
* @param text
|
|
323
|
-
* @return {boolean}
|
|
335
|
+
/**
|
|
336
|
+
* So sánh text đầu vào cáo map với txtSearch
|
|
337
|
+
* @param text
|
|
338
|
+
* @return {boolean}
|
|
324
339
|
*/
|
|
325
340
|
const handleRenderBySearch = (text = '') => {
|
|
326
|
-
if (
|
|
341
|
+
if (typeof text !== 'string') text = text.toString();
|
|
342
|
+
if (!txtSearch) return true;
|
|
327
343
|
if (searchMode === 'startswith') {
|
|
328
344
|
return text.toLowerCase().startsWith(txtSearch.toLowerCase());
|
|
329
345
|
} else if (searchMode === 'equals') {
|
|
@@ -331,10 +347,10 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
331
347
|
} else return text.toLowerCase().includes(txtSearch.toLowerCase());
|
|
332
348
|
};
|
|
333
349
|
|
|
334
|
-
/**
|
|
335
|
-
* Chuyển đổi data thành giá trị cần hiện thị dựa vào displayExpr [string, string object {field} - {field}], renderSelectedItem, displayExpr, valueExpr
|
|
336
|
-
* @param data {object} rowData of dataSource
|
|
337
|
-
* @return {string}
|
|
350
|
+
/**
|
|
351
|
+
* Chuyển đổi data thành giá trị cần hiện thị dựa vào displayExpr [string, string object {field} - {field}], renderSelectedItem, displayExpr, valueExpr
|
|
352
|
+
* @param data {object} rowData of dataSource
|
|
353
|
+
* @return {string}
|
|
338
354
|
*/
|
|
339
355
|
const displayValue = data => {
|
|
340
356
|
let text = '';
|
|
@@ -353,20 +369,23 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
353
369
|
return text;
|
|
354
370
|
};
|
|
355
371
|
const mapDropdown = () => {
|
|
356
|
-
var
|
|
372
|
+
var _currentObjectDefault;
|
|
357
373
|
const items = [];
|
|
358
|
-
let dataSourceUsable = [...
|
|
374
|
+
let dataSourceUsable = [...dataSourceState];
|
|
359
375
|
|
|
360
376
|
// search dataSource dựa trên txtSearch
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
377
|
+
if (!onInput || action !== null && action !== void 0 && action.loadData) {
|
|
378
|
+
var _dataSourceUsable;
|
|
379
|
+
dataSourceUsable = (_dataSourceUsable = dataSourceUsable) === null || _dataSourceUsable === void 0 ? void 0 : _dataSourceUsable.filter(i => {
|
|
380
|
+
if (searchExpr) {
|
|
381
|
+
// nếu map đc vs 1 trong những <key>(data[key]) của searchExpr
|
|
382
|
+
return !!searchExpr.find(j => handleRenderBySearch(i[j]));
|
|
383
|
+
} else {
|
|
384
|
+
// nếu map đc vs displayValue
|
|
385
|
+
return handleRenderBySearch(displayValue(i)) || handleRenderBySearch(i === null || i === void 0 ? void 0 : i[valueExpr]);
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
}
|
|
370
389
|
if (currentObjectDefault[unique] && (_currentObjectDefault = currentObjectDefault[unique]) !== null && _currentObjectDefault !== void 0 && _currentObjectDefault.length) {
|
|
371
390
|
const length = currentObjectDefault[unique].length;
|
|
372
391
|
let existItemQuantity = 0;
|
|
@@ -385,6 +404,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
385
404
|
const length = dataSourceUsable.length;
|
|
386
405
|
for (let index = 0; index < length; index++) {
|
|
387
406
|
const data = dataSourceUsable[index];
|
|
407
|
+
if (!data) continue;
|
|
388
408
|
const itemHidden = typeof data === 'object' ? data['hidden'] : false;
|
|
389
409
|
if (itemHidden) continue;
|
|
390
410
|
let displayText = displayValue(data);
|
|
@@ -477,8 +497,8 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
477
497
|
className: 'DGN-Dropdown-List',
|
|
478
498
|
onKeyDown: moveOnItem,
|
|
479
499
|
tabIndex: -1
|
|
480
|
-
},
|
|
481
|
-
dataSource:
|
|
500
|
+
}, dataSourceState !== null && dataSourceState !== void 0 && dataSourceState.length ? jsx(TreeView, {
|
|
501
|
+
dataSource: dataSourceState,
|
|
482
502
|
displayExpr: displayExpr,
|
|
483
503
|
valueExpr: valueExpr,
|
|
484
504
|
multiple: multiple,
|
|
@@ -500,7 +520,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
500
520
|
// remove item cũ và append child item mới khi load more
|
|
501
521
|
const loadMoreItemsDropdown = (i = 0, pattern) => {
|
|
502
522
|
var _currentObjectDefault2, _displayExpr2;
|
|
503
|
-
const dataSourceUsable = [...
|
|
523
|
+
const dataSourceUsable = [...dataSourceState];
|
|
504
524
|
// Nếu có load more thì đẩy đội tượng mặc định lên đầu
|
|
505
525
|
let notExistItem = 0;
|
|
506
526
|
if (onLoadMore && (_currentObjectDefault2 = currentObjectDefault[unique]) !== null && _currentObjectDefault2 !== void 0 && _currentObjectDefault2.length) {
|
|
@@ -648,6 +668,65 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
648
668
|
// : updatePosition(formRef.current, dropdownRef.current, closeDropdown);
|
|
649
669
|
// };
|
|
650
670
|
|
|
671
|
+
const handleActionLoadData = isReset => {
|
|
672
|
+
const {
|
|
673
|
+
skip,
|
|
674
|
+
limit,
|
|
675
|
+
strSearch: search
|
|
676
|
+
} = filter.current;
|
|
677
|
+
const params = onLoadMore ? {
|
|
678
|
+
skip,
|
|
679
|
+
limit,
|
|
680
|
+
search
|
|
681
|
+
} : {
|
|
682
|
+
search
|
|
683
|
+
};
|
|
684
|
+
const callbackSave = (error, data) => {
|
|
685
|
+
setLoadingState(false);
|
|
686
|
+
if (error) {
|
|
687
|
+
let _data = {};
|
|
688
|
+
if (error.originalError) {
|
|
689
|
+
const {
|
|
690
|
+
message,
|
|
691
|
+
originalError,
|
|
692
|
+
customMessage,
|
|
693
|
+
code: codeError
|
|
694
|
+
} = error;
|
|
695
|
+
const _customMessage = customMessage && typeof customMessage === 'object' ? customMessage[codeError] : customMessage;
|
|
696
|
+
let messageError = '';
|
|
697
|
+
Object.keys(originalError).forEach(key => {
|
|
698
|
+
messageError += `${key}: ${JSON.stringify(originalError[key], null, 8)}\n`;
|
|
699
|
+
});
|
|
700
|
+
_data = {
|
|
701
|
+
title: getGlobal('error') + (codeError ? `: ${codeError}` : ''),
|
|
702
|
+
subtitle: _customMessage || message || getGlobal('unknownError'),
|
|
703
|
+
description: messageError
|
|
704
|
+
};
|
|
705
|
+
} else {
|
|
706
|
+
var _data$data;
|
|
707
|
+
const message = (data === null || data === void 0 ? void 0 : data.message) || (data === null || data === void 0 ? void 0 : (_data$data = data.data) === null || _data$data === void 0 ? void 0 : _data$data.Message) || data;
|
|
708
|
+
_data = {
|
|
709
|
+
description: message || getGlobal('unknownError')
|
|
710
|
+
};
|
|
711
|
+
}
|
|
712
|
+
setPopupDataState(_data);
|
|
713
|
+
popupRef.current.instance.show();
|
|
714
|
+
return false;
|
|
715
|
+
} else if (data) {
|
|
716
|
+
let rows = [];
|
|
717
|
+
if (Array.isArray(data)) {
|
|
718
|
+
rows = data;
|
|
719
|
+
} else {
|
|
720
|
+
rows = data && data.rows ? data.rows : dataSourceState;
|
|
721
|
+
const total = data && data.total ? data.total : data.length;
|
|
722
|
+
setTotalState(total);
|
|
723
|
+
}
|
|
724
|
+
setDataSourceState(isReset ? rows : dataSourceState.concat(rows));
|
|
725
|
+
}
|
|
726
|
+
};
|
|
727
|
+
setLoadingState(true);
|
|
728
|
+
action.loadData(params, callbackSave);
|
|
729
|
+
};
|
|
651
730
|
const onLoadMoreHandler = e => {
|
|
652
731
|
if (loadMoreTimer.current) {
|
|
653
732
|
clearTimeout(loadMoreTimer.current);
|
|
@@ -662,12 +741,16 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
662
741
|
var _dropdownListRef$curr, _currentObjectDefault3;
|
|
663
742
|
const length = ((_dropdownListRef$curr = dropdownListRef.current.children) === null || _dropdownListRef$curr === void 0 ? void 0 : _dropdownListRef$curr.length) - (((_currentObjectDefault3 = currentObjectDefault[unique]) === null || _currentObjectDefault3 === void 0 ? void 0 : _currentObjectDefault3.length) || 0);
|
|
664
743
|
dropdownListRef.current.removeEventListener('scroll', onLoadMoreHandler);
|
|
665
|
-
!!onLoadMore && onLoadMore
|
|
744
|
+
if (!!onLoadMore && typeof onLoadMore === 'boolean' && action !== null && action !== void 0 && action.loadData) {
|
|
745
|
+
filter.current.skip = length;
|
|
746
|
+
filter.current.limit = limit;
|
|
747
|
+
handleActionLoadData();
|
|
748
|
+
} else !!onLoadMore && onLoadMore({
|
|
666
749
|
skip: length,
|
|
667
750
|
limit: limit
|
|
668
751
|
});
|
|
669
752
|
}
|
|
670
|
-
});
|
|
753
|
+
}, 300);
|
|
671
754
|
};
|
|
672
755
|
const onPreventKeyDownHandler = e => {
|
|
673
756
|
e.preventDefault();
|
|
@@ -700,6 +783,11 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
700
783
|
// }
|
|
701
784
|
// return;
|
|
702
785
|
}
|
|
786
|
+
|
|
787
|
+
if (action !== null && action !== void 0 && action.loadData && !!onLoadMore) {
|
|
788
|
+
filter.current.strSearch = e.target.value;
|
|
789
|
+
handleActionLoadData(true);
|
|
790
|
+
}
|
|
703
791
|
// const value = e.target.value || e.target.textContent;
|
|
704
792
|
// if (
|
|
705
793
|
// typeof renderSelectedItem === 'function' &&
|
|
@@ -721,7 +809,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
721
809
|
if (valueProp === undefined) {
|
|
722
810
|
setValueMulti(value);
|
|
723
811
|
setValueIntoInput(value);
|
|
724
|
-
setShowClear(clearAble && checkHasValue(value) && !disabled && !readOnly && !
|
|
812
|
+
setShowClear(clearAble && checkHasValue(value) && !disabled && !readOnly && !loadingState);
|
|
725
813
|
}
|
|
726
814
|
!!onChange && onChange({
|
|
727
815
|
value
|
|
@@ -840,7 +928,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
840
928
|
});
|
|
841
929
|
};
|
|
842
930
|
const onClear = e => {
|
|
843
|
-
if (disabled || readOnly ||
|
|
931
|
+
if (disabled || readOnly || loadingState || !clearAble) return;
|
|
844
932
|
currentValue[unique] = multiple ? [] : '';
|
|
845
933
|
if (multiple) {
|
|
846
934
|
setValueMulti([]);
|
|
@@ -886,7 +974,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
886
974
|
}
|
|
887
975
|
return;
|
|
888
976
|
}
|
|
889
|
-
const length =
|
|
977
|
+
const length = dataSourceState.length;
|
|
890
978
|
const displayKey = typeof renderSelectedItem === 'string' ? renderSelectedItem : displayExpr;
|
|
891
979
|
if (displayKey && Array.isArray(displayKey)) {
|
|
892
980
|
displayExpr = displayExpr.join(' - ');
|
|
@@ -903,8 +991,9 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
903
991
|
valueArr.forEach(v => {
|
|
904
992
|
var _currentObjectDefault4;
|
|
905
993
|
for (let i = 0; i < length; i++) {
|
|
906
|
-
if (
|
|
907
|
-
|
|
994
|
+
if (!dataSourceState[i]) continue;
|
|
995
|
+
if (typeof dataSourceState[i] === 'object' && dataSourceState[i][valueExpr] === v || dataSourceState[i] === v) {
|
|
996
|
+
setMultipleValueHandler(dataSourceState[i], v, keyArr, i);
|
|
908
997
|
return;
|
|
909
998
|
}
|
|
910
999
|
}
|
|
@@ -919,8 +1008,9 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
919
1008
|
var _currentObjectDefault5;
|
|
920
1009
|
currentValue[unique] = source;
|
|
921
1010
|
for (let i = 0; i < length; i++) {
|
|
922
|
-
if (
|
|
923
|
-
|
|
1011
|
+
if (!dataSourceState[i]) continue;
|
|
1012
|
+
if (dataSourceState[i][valueExpr] === source || dataSourceState[i] === source) {
|
|
1013
|
+
setSingleValueHandler(dataSourceState[i], keyArr);
|
|
924
1014
|
return;
|
|
925
1015
|
}
|
|
926
1016
|
}
|
|
@@ -1027,8 +1117,17 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1027
1117
|
return currentRef;
|
|
1028
1118
|
});
|
|
1029
1119
|
useEffect(() => {
|
|
1030
|
-
|
|
1031
|
-
}, [
|
|
1120
|
+
setLoadingState(loading);
|
|
1121
|
+
}, [loading]);
|
|
1122
|
+
useEffect(() => {
|
|
1123
|
+
setTotalState(total);
|
|
1124
|
+
}, [total]);
|
|
1125
|
+
useEffect(() => {
|
|
1126
|
+
setDataSourceState(dataSource);
|
|
1127
|
+
}, [dataSource]);
|
|
1128
|
+
useEffect(() => {
|
|
1129
|
+
setShowClear(clearAble && checkHasValue(valueProp !== null && valueProp !== void 0 ? valueProp : defaultValue) && !disabled && !readOnly && !loadingState);
|
|
1130
|
+
}, [clearAble, valueProp, defaultValue, disabled, readOnly, loadingState]);
|
|
1032
1131
|
useEffect(() => {
|
|
1033
1132
|
if (valueObjectDefault) {
|
|
1034
1133
|
if (Array.isArray(valueObjectDefault)) {
|
|
@@ -1047,8 +1146,9 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1047
1146
|
allValue[unique] = [];
|
|
1048
1147
|
if (defaultValue !== undefined && JSON.stringify(defaultValue) !== '[]') {
|
|
1049
1148
|
setValueIntoInput(defaultValue);
|
|
1050
|
-
setShowClear(clearAble && checkHasValue(defaultValue) && !disabled && !readOnly && !
|
|
1149
|
+
setShowClear(clearAble && checkHasValue(defaultValue) && !disabled && !readOnly && !loadingState);
|
|
1051
1150
|
}
|
|
1151
|
+
if (action !== null && action !== void 0 && action.loadData) handleActionLoadData();
|
|
1052
1152
|
return () => {
|
|
1053
1153
|
allValue[unique] = null;
|
|
1054
1154
|
closeDropdown();
|
|
@@ -1087,10 +1187,12 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1087
1187
|
}
|
|
1088
1188
|
}, [valueProp]);
|
|
1089
1189
|
useEffect(() => {
|
|
1090
|
-
if (
|
|
1190
|
+
if (
|
|
1191
|
+
// valueProp !== undefined &&
|
|
1192
|
+
!dropdownListRef.current || children || JSON.stringify(valueProp) !== JSON.stringify(currentValue[unique])) {
|
|
1091
1193
|
setValueIntoInput(valueProp);
|
|
1092
1194
|
}
|
|
1093
|
-
}, [valueProp,
|
|
1195
|
+
}, [valueProp, dataSourceState]);
|
|
1094
1196
|
useEffect(() => {
|
|
1095
1197
|
inputRef.current.readOnly = readOnly || inputProps.readOnly;
|
|
1096
1198
|
if (!readOnly && !disabled) {
|
|
@@ -1133,9 +1235,9 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1133
1235
|
inputRef.current.addEventListener('input', onChangeInput);
|
|
1134
1236
|
}
|
|
1135
1237
|
const length = (_dropdownListRef$curr2 = dropdownListRef.current) === null || _dropdownListRef$curr2 === void 0 ? void 0 : (_dropdownListRef$curr3 = _dropdownListRef$curr2.children) === null || _dropdownListRef$curr3 === void 0 ? void 0 : _dropdownListRef$curr3.length;
|
|
1136
|
-
if (length <
|
|
1238
|
+
if (length < dataSourceState.length + ((_currentObjectDefault6 = currentObjectDefault[unique]) === null || _currentObjectDefault6 === void 0 ? void 0 : _currentObjectDefault6.length) && !isSearch[unique]) {
|
|
1137
1239
|
loadMoreItemsDropdown(length);
|
|
1138
|
-
!!onLoadMore &&
|
|
1240
|
+
!!onLoadMore && dataSourceState.length < totalState && dropdownListRef.current.addEventListener('scroll', onLoadMoreHandler);
|
|
1139
1241
|
} else {
|
|
1140
1242
|
isSearch[unique] = false;
|
|
1141
1243
|
}
|
|
@@ -1151,7 +1253,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1151
1253
|
}
|
|
1152
1254
|
!!dropdownListRef.current && dropdownListRef.current.removeEventListener('scroll', onLoadMoreHandler);
|
|
1153
1255
|
};
|
|
1154
|
-
}, [
|
|
1256
|
+
}, [dataSourceState]);
|
|
1155
1257
|
useLayoutEffect(() => {
|
|
1156
1258
|
if (ref.current) {
|
|
1157
1259
|
const {
|
|
@@ -1173,7 +1275,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1173
1275
|
...labelProps
|
|
1174
1276
|
}, label) : null, [label, required, disabled, labelProps]);
|
|
1175
1277
|
const getData = () => {
|
|
1176
|
-
let dataFilter = JSON.parse(JSON.stringify(
|
|
1278
|
+
let dataFilter = JSON.parse(JSON.stringify(dataSourceState));
|
|
1177
1279
|
if (Array.isArray(valueObjectDefault)) {
|
|
1178
1280
|
dataFilter = [...dataFilter, ...dataChosen.current, ...valueObjectDefault];
|
|
1179
1281
|
} else if (typeof valueObjectDefault === 'object') {
|
|
@@ -1269,14 +1371,14 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1269
1371
|
ref: iconRef,
|
|
1270
1372
|
css: _IconCSS,
|
|
1271
1373
|
className: 'DGN-UI-Dropdown-Icon'
|
|
1272
|
-
},
|
|
1374
|
+
}, loadingState ? jsx(CircularProgress, {
|
|
1273
1375
|
size: 24
|
|
1274
1376
|
}) : null, showClear ? jsx(ButtonIcon, {
|
|
1275
1377
|
css: mgr([1]),
|
|
1276
1378
|
viewType: 'ghost',
|
|
1277
1379
|
name: 'Close',
|
|
1278
1380
|
onClick: onClear
|
|
1279
|
-
}) : null, !
|
|
1381
|
+
}) : null, !loadingState ? jsx(ButtonIcon, {
|
|
1280
1382
|
key: openState,
|
|
1281
1383
|
css: animation,
|
|
1282
1384
|
viewType: 'ghost',
|
|
@@ -1284,7 +1386,7 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1284
1386
|
onClick: setShowDropdown,
|
|
1285
1387
|
disabled: disabled || readOnly
|
|
1286
1388
|
}) : null));
|
|
1287
|
-
}, [openState, showClear, textValue, valueMulti, clearAble, dataSource, disabled, displayExpr, inputProps, inputStyle,
|
|
1389
|
+
}, [openState, showClear, textValue, valueMulti, loadingState, dataSourceState, clearAble, dataSource, disabled, displayExpr, inputProps, inputStyle, multilineSelectedItem, multiple, onChange, placeholder, readOnly, renderSelectedItem, valueExpr, valueObjectDefault, viewType]);
|
|
1288
1390
|
const ErrorView = useMemo(() => {
|
|
1289
1391
|
return error ? jsx(HelperText, {
|
|
1290
1392
|
...helperTextProps,
|
|
@@ -1301,15 +1403,19 @@ const Dropdown = /*#__PURE__*/memo( /*#__PURE__*/forwardRef(({
|
|
|
1301
1403
|
onClose: closeDropdown
|
|
1302
1404
|
}, showDropdown());
|
|
1303
1405
|
// return openState ? createPortal(showDropdown(), document.body) : null;
|
|
1304
|
-
}, [openState, popoverWidth, valueMulti,
|
|
1406
|
+
}, [openState, popoverWidth, valueMulti, loadingState, dataSourceState, dataSource, maximumSelectionLength, multilineSelectedItem, multiple, selectBox, txtSearch]);
|
|
1305
1407
|
/* End component */
|
|
1306
1408
|
|
|
1307
1409
|
return jsx(Fragment, null, jsx("div", {
|
|
1308
1410
|
ref: ref,
|
|
1309
1411
|
css: _DropdownRootCSS,
|
|
1310
1412
|
style: style,
|
|
1311
|
-
className: classNames('DGN-UI-Dropdown', className, error && 'error',
|
|
1312
|
-
}, LabelView, InputView, ErrorView), DropdownView
|
|
1413
|
+
className: classNames('DGN-UI-Dropdown', className, error && 'error', loadingState && 'dgn-dropdown-loading', disabled ? 'disabled' : readOnly && 'readOnly')
|
|
1414
|
+
}, LabelView, InputView, ErrorView), DropdownView, jsx(Popup, {
|
|
1415
|
+
ref: popupRef,
|
|
1416
|
+
type: 'danger',
|
|
1417
|
+
...popupDataState
|
|
1418
|
+
}));
|
|
1313
1419
|
}));
|
|
1314
1420
|
|
|
1315
1421
|
/* Start styled */
|
|
@@ -1633,6 +1739,9 @@ Dropdown.defaultProps = {
|
|
|
1633
1739
|
viewType: 'underlined'
|
|
1634
1740
|
};
|
|
1635
1741
|
Dropdown.propTypes = {
|
|
1742
|
+
action: PropTypes.shape({
|
|
1743
|
+
loadData: PropTypes.func
|
|
1744
|
+
}),
|
|
1636
1745
|
/** If `true`, display input box search. */
|
|
1637
1746
|
allowSearch: PropTypes.bool,
|
|
1638
1747
|
/** The contents in Dropdown box (Exp: TreeView). */
|
|
@@ -1649,9 +1758,9 @@ Dropdown.propTypes = {
|
|
|
1649
1758
|
defaultValue: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]),
|
|
1650
1759
|
/** If `true`, the component is disabled. */
|
|
1651
1760
|
disabled: PropTypes.bool,
|
|
1652
|
-
/** Field name used for text display in dropdown list.<br/>
|
|
1653
|
-
* Example: 'name', '{id} - {name}', '{age} age(s)'<br/>
|
|
1654
|
-
* Note: don't use 'id - name', return undefined
|
|
1761
|
+
/** Field name used for text display in dropdown list.<br/>
|
|
1762
|
+
* Example: 'name', '{id} - {name}', '{age} age(s)'<br/>
|
|
1763
|
+
* Note: don't use 'id - name', return undefined
|
|
1655
1764
|
*/
|
|
1656
1765
|
displayExpr: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.array]),
|
|
1657
1766
|
/** Style inline of dropdown items. */
|
|
@@ -1660,14 +1769,14 @@ Dropdown.propTypes = {
|
|
|
1660
1769
|
error: PropTypes.oneOfType([PropTypes.bool, PropTypes.string]),
|
|
1661
1770
|
/** Props applied to the [HelperText](https://core.diginet.com.vn/ui/?path=/story/form-control-text-helpertext) element. */
|
|
1662
1771
|
helperTextProps: PropTypes.object,
|
|
1663
|
-
/** Field name used for icon display.<br/>
|
|
1664
|
-
* Example:<br/>
|
|
1665
|
-
* string: 'icon'<br/>
|
|
1666
|
-
* object: {<br/>
|
|
1667
|
-
* key: 'icon',<br/>
|
|
1668
|
-
* prefix: 'https://imglink.com',<br/>
|
|
1669
|
-
* suffix: '.jpg'<br/>
|
|
1670
|
-
* }
|
|
1772
|
+
/** Field name used for icon display.<br/>
|
|
1773
|
+
* Example:<br/>
|
|
1774
|
+
* string: 'icon'<br/>
|
|
1775
|
+
* object: {<br/>
|
|
1776
|
+
* key: 'icon',<br/>
|
|
1777
|
+
* prefix: 'https://imglink.com',<br/>
|
|
1778
|
+
* suffix: '.jpg'<br/>
|
|
1779
|
+
* }
|
|
1671
1780
|
*/
|
|
1672
1781
|
iconExpr: PropTypes.oneOfType([PropTypes.string, PropTypes.shape({
|
|
1673
1782
|
key: PropTypes.string,
|
|
@@ -1701,33 +1810,33 @@ Dropdown.propTypes = {
|
|
|
1701
1810
|
onChange: PropTypes.func,
|
|
1702
1811
|
/** Callback fired when dropdown closed. */
|
|
1703
1812
|
onClosed: PropTypes.func,
|
|
1704
|
-
/** Callback fired when the input value changes.<br/>
|
|
1705
|
-
* if undefined: the filter function will run (default)
|
|
1813
|
+
/** Callback fired when the input value changes.<br/>
|
|
1814
|
+
* if undefined: the filter function will run (default)
|
|
1706
1815
|
*/
|
|
1707
1816
|
onInput: PropTypes.func,
|
|
1708
1817
|
/** Callback fired when key down input */
|
|
1709
1818
|
onKeyDown: PropTypes.func,
|
|
1710
1819
|
/** Callback fired when scroll near the end. */
|
|
1711
|
-
onLoadMore: PropTypes.func,
|
|
1820
|
+
onLoadMore: PropTypes.oneOfType([PropTypes.func, PropTypes.bool]),
|
|
1712
1821
|
/** The short hint displayed in the input before the user select a value. */
|
|
1713
1822
|
placeholder: PropTypes.string,
|
|
1714
1823
|
/** If `true`, the component is read-only. */
|
|
1715
1824
|
readOnly: PropTypes.bool,
|
|
1716
|
-
/** Function displays items by custom.<br/>
|
|
1717
|
-
* renderItem={(data, index) => data.name + ' - ' + data.role}<br/>
|
|
1718
|
-
* --> such as: displayExpr={'name - role'}
|
|
1825
|
+
/** Function displays items by custom.<br/>
|
|
1826
|
+
* renderItem={(data, index) => data.name + ' - ' + data.role}<br/>
|
|
1827
|
+
* --> such as: displayExpr={'name - role'}
|
|
1719
1828
|
*/
|
|
1720
1829
|
renderItem: PropTypes.func,
|
|
1721
|
-
/** Function or field name used for display selected items, example:<br/>
|
|
1722
|
-
* renderSelectedItem={(data, index) => index + ' - ' + data.name}<br/>
|
|
1830
|
+
/** Function or field name used for display selected items, example:<br/>
|
|
1831
|
+
* renderSelectedItem={(data, index) => index + ' - ' + data.name}<br/>
|
|
1723
1832
|
*/
|
|
1724
1833
|
renderSelectedItem: PropTypes.oneOfType([PropTypes.func, PropTypes.string]),
|
|
1725
1834
|
/** If `true`, the label will indicate that the input is required. */
|
|
1726
1835
|
required: PropTypes.bool,
|
|
1727
|
-
/**
|
|
1728
|
-
* Duration wait enter search content on search.<br/>
|
|
1729
|
-
* Example: 700 -> 700ms, '700ms' -> 700ms, '0.7s' -> 700ms, '1m' -> 60000ms
|
|
1730
|
-
* If `true`, used default delayOnInput.
|
|
1836
|
+
/**
|
|
1837
|
+
* Duration wait enter search content on search.<br/>
|
|
1838
|
+
* Example: 700 -> 700ms, '700ms' -> 700ms, '0.7s' -> 700ms, '1m' -> 60000ms
|
|
1839
|
+
* If `true`, used default delayOnInput.
|
|
1731
1840
|
*/
|
|
1732
1841
|
searchDelayTime: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]),
|
|
1733
1842
|
/** Specifies a data object's field name or an expression whose value is compared to the search string. */
|
|
@@ -1754,19 +1863,19 @@ Dropdown.propTypes = {
|
|
|
1754
1863
|
valueObjectDefault: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
|
|
1755
1864
|
/**The variant to use. */
|
|
1756
1865
|
viewType: PropTypes.oneOf(['underlined', 'outlined', 'none'])
|
|
1757
|
-
/**
|
|
1758
|
-
* ref methods
|
|
1759
|
-
*
|
|
1760
|
-
* how to get component element? ref.current
|
|
1761
|
-
*
|
|
1762
|
-
* how to call method? ref.current.instance.{method}
|
|
1763
|
-
*
|
|
1764
|
-
* * showDropdown(): Show dropdown
|
|
1765
|
-
* * closeDropdown(): Close dropdown
|
|
1766
|
-
* * onClear(): Clear selected value
|
|
1767
|
-
* * setPreviousValue(): Set value to previous value
|
|
1768
|
-
* * setValue(value): Set value of dropdown
|
|
1769
|
-
* * @param {value} - string || number || array
|
|
1866
|
+
/**
|
|
1867
|
+
* ref methods
|
|
1868
|
+
*
|
|
1869
|
+
* how to get component element? ref.current
|
|
1870
|
+
*
|
|
1871
|
+
* how to call method? ref.current.instance.{method}
|
|
1872
|
+
*
|
|
1873
|
+
* * showDropdown(): Show dropdown
|
|
1874
|
+
* * closeDropdown(): Close dropdown
|
|
1875
|
+
* * onClear(): Clear selected value
|
|
1876
|
+
* * setPreviousValue(): Set value to previous value
|
|
1877
|
+
* * setValue(value): Set value of dropdown
|
|
1878
|
+
* * @param {value} - string || number || array
|
|
1770
1879
|
*/
|
|
1771
1880
|
};
|
|
1772
1881
|
|
package/global/index.js
CHANGED
|
@@ -7,6 +7,7 @@ const globalObject = {
|
|
|
7
7
|
close: 'Đóng',
|
|
8
8
|
confirm: 'Xác nhận',
|
|
9
9
|
error: 'Lỗi',
|
|
10
|
+
unknownError: 'Lỗi chưa xác định',
|
|
10
11
|
no: 'Không',
|
|
11
12
|
noDataText: 'Không có dữ liệu',
|
|
12
13
|
notify: 'Thông báo',
|
|
@@ -79,6 +80,7 @@ const globalObject = {
|
|
|
79
80
|
close: 'Close',
|
|
80
81
|
confirm: 'Confirm',
|
|
81
82
|
error: 'Error',
|
|
83
|
+
unknownError: 'Unknown Error',
|
|
82
84
|
no: 'No',
|
|
83
85
|
noDataText: 'No data',
|
|
84
86
|
notify: 'Notify',
|
package/package.json
CHANGED
package/readme.md
CHANGED
|
@@ -38,6 +38,11 @@ npm test
|
|
|
38
38
|
```
|
|
39
39
|
|
|
40
40
|
## Changelog
|
|
41
|
+
## 1.4.2
|
|
42
|
+
- \[Changed\]: Dropdown – Add action loadData
|
|
43
|
+
- \[Fixed\]: Dropdown – Fix bug search filter data when using remote; Fix bug not render invalid html tag
|
|
44
|
+
- \[Fixed\]: Dropdown – Fix bug if item of dataSource is null
|
|
45
|
+
|
|
41
46
|
## 1.4.1
|
|
42
47
|
- \[Fixed\]: Dropdown – Fix bug render data wrong after search when not have searchExpr
|
|
43
48
|
|
package/styles/general.js
CHANGED
|
@@ -417,9 +417,15 @@ const selfEnd = css`
|
|
|
417
417
|
const selfStart = css`
|
|
418
418
|
align-self: flex-start;
|
|
419
419
|
`;
|
|
420
|
+
const shadowLarge = css`
|
|
421
|
+
box-shadow: 0 4px 4px 0 rgba(0, 0, 0, 0.25);
|
|
422
|
+
`;
|
|
420
423
|
const shadowNone = css`
|
|
421
424
|
box-shadow: none;
|
|
422
425
|
`;
|
|
426
|
+
const shadowSmall = css`
|
|
427
|
+
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.25);
|
|
428
|
+
`;
|
|
423
429
|
const textCapitalize = css`
|
|
424
430
|
text-transform: capitalize;
|
|
425
431
|
`;
|
|
@@ -487,4 +493,4 @@ const whiteSpacePreWrap = css`
|
|
|
487
493
|
const z = vl => css`
|
|
488
494
|
z-index: ${zIndex(vl)};
|
|
489
495
|
`;
|
|
490
|
-
export { animation, aspectSquare, bgColor, bgCurrent, bgTransparent, border, borderBottom, borderBottomColor, borderColor, borderDashed, borderNone, borderRadius, borderRadius100, borderRadius4px, borderRadius50, borderRight, borderTop, borderTopColor, bottom, boxBorder, boxContent, breakAll, breakWord, cursorDefault, cursorInherit, cursorInitial, cursorMove, cursorNoDrop, cursorNotAllowed, cursorPointer, cursorText, displayBlock, displayFlex, displayInlineBlock, displayInlineFlex, displayNone, fill, flexCol, flexColReverse, flexNowrap, flexRow, flexRowReverse, flexShrink, flexShrink0, flexWrap, flexWrapReverse, floatLeft, floatNone, floatRight, gap, gapX, gapY, inset, insetX, insetY, invisible, italic, itemsCenter, itemsEnd, itemsStart, justifyAround, justifyBetween, justifyCenter, justifyEnd, justifyEvenly, justifyStart, left, listNone, mg, mgb, mgl, mgr, mgt, mgx, mgy, noBorder, noBoxShadow, noMargin, noPadding, objectContain, objectCover, objectFill, objectNone, order, outlineNone, overflowAuto, overflowHidden, overflowXHidden, parseHeight, parseMaxHeight, parseMaxWidth, parseMaxWidthHeight, parseMinHeight, parseMinWidth, parseMinWidthHeight, parseWidth, parseWidthHeight, pd, pdb, pdl, pdr, pdt, pdx, pdy, pointerEventsAuto, pointerEventsInherit, pointerEventsInitial, pointerEventsNone, positionAbsolute, positionFixed, positionRelative, positionSticky, right, scale, scaleX, scaleY, selfCenter, selfEnd, selfStart, shadowNone, textCapitalize, textCenter, textColor, textCurrent, textEllipsis, textLeft, textLineThrough, textLowercase, textRight, textSentence, textUnderline, textUppercase, top, truncate, userSelectNone, visible, whiteSpaceBreakSpaces, whiteSpaceNoWrap, whiteSpacePreWrap, z };
|
|
496
|
+
export { animation, aspectSquare, bgColor, bgCurrent, bgTransparent, border, borderBottom, borderBottomColor, borderColor, borderDashed, borderNone, borderRadius, borderRadius100, borderRadius4px, borderRadius50, borderRight, borderTop, borderTopColor, bottom, boxBorder, boxContent, breakAll, breakWord, cursorDefault, cursorInherit, cursorInitial, cursorMove, cursorNoDrop, cursorNotAllowed, cursorPointer, cursorText, displayBlock, displayFlex, displayInlineBlock, displayInlineFlex, displayNone, fill, flexCol, flexColReverse, flexNowrap, flexRow, flexRowReverse, flexShrink, flexShrink0, flexWrap, flexWrapReverse, floatLeft, floatNone, floatRight, gap, gapX, gapY, inset, insetX, insetY, invisible, italic, itemsCenter, itemsEnd, itemsStart, justifyAround, justifyBetween, justifyCenter, justifyEnd, justifyEvenly, justifyStart, left, listNone, mg, mgb, mgl, mgr, mgt, mgx, mgy, noBorder, noBoxShadow, noMargin, noPadding, objectContain, objectCover, objectFill, objectNone, order, outlineNone, overflowAuto, overflowHidden, overflowXHidden, parseHeight, parseMaxHeight, parseMaxWidth, parseMaxWidthHeight, parseMinHeight, parseMinWidth, parseMinWidthHeight, parseWidth, parseWidthHeight, pd, pdb, pdl, pdr, pdt, pdx, pdy, pointerEventsAuto, pointerEventsInherit, pointerEventsInitial, pointerEventsNone, positionAbsolute, positionFixed, positionRelative, positionSticky, right, scale, scaleX, scaleY, selfCenter, selfEnd, selfStart, shadowLarge, shadowNone, shadowSmall, textCapitalize, textCenter, textColor, textCurrent, textEllipsis, textLeft, textLineThrough, textLowercase, textRight, textSentence, textUnderline, textUppercase, top, truncate, userSelectNone, visible, whiteSpaceBreakSpaces, whiteSpaceNoWrap, whiteSpacePreWrap, z };
|
package/utils/parseHTML.js
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
const parseHTML = (text, output = 'innerHTML') => {
|
|
2
2
|
if (!text) return null;
|
|
3
|
+
|
|
4
|
+
// Check if text contains unescaped angle brackets that are not valid HTML tags
|
|
5
|
+
const invalidTagsRegex = /<(?!\s*\/?\s*(a|abbr|acronym|address|area|article|aside|audio|b|base|bdi|bdo|blockquote|body|br|button|canvas|caption|cite|code|col|colgroup|data|datalist|dd|del|details|dfn|dialog|div|dl|dt|em|embed|fieldset|figcaption|figure|footer|form|head|header|h1|h2|h3|h4|h5|h6|hr|html|i|iframe|img|input|ins|kbd|label|legend|li|link|main|map|mark|meta|meter|nav|noscript|object|ol|optgroup|option|output|p|param|picture|pre|progress|q|rp|rt|ruby|s|samp|script|section|select|small|source|span|strong|style|sub|summary|sup|svg|table|tbody|td|template|textarea|tfoot|th|thead|time|title|tr|track|u|ul|var|video|wbr)\b)[^>]*>/g;
|
|
6
|
+
const invalidTags = text.match(invalidTagsRegex);
|
|
7
|
+
|
|
8
|
+
// If text contains invalid tags, replace angle brackets with HTML entities for those tags only
|
|
9
|
+
if (invalidTags) {
|
|
10
|
+
invalidTags.forEach(tag => {
|
|
11
|
+
text = text.replace(tag, tag.replace(/</g, '<').replace(/>/g, '>'));
|
|
12
|
+
});
|
|
13
|
+
}
|
|
3
14
|
const DOM = new DOMParser().parseFromString(text, 'text/html').querySelector('body');
|
|
4
15
|
const result = DOM[output];
|
|
5
16
|
return result && result.trim ? result.trim() : result;
|