Skip to content

Commit d789961

Browse files
authored
Merge pull request #679 from wenzhixin/feature/es6-refactor
Refactor: Replace jQuery utilities with ES6+ alternatives
2 parents e4cadaf + bb0196a commit d789961

3 files changed

Lines changed: 122 additions & 11 deletions

File tree

src/MultipleSelect.js

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import Constants from './constants/index.js'
22
import VirtualScroll from './virtual-scroll/index.js'
33
import {
44
compareObjects,
5+
extend,
56
findByParam,
67
getDocumentClickEvent,
78
removeDiacritics,
@@ -13,7 +14,7 @@ import {
1314
class MultipleSelect {
1415
constructor ($el, options) {
1516
this.$el = $el
16-
this.options = $.extend({}, Constants.DEFAULTS, options)
17+
this.options = extend({}, Constants.DEFAULTS, options)
1718
}
1819

1920
init () {
@@ -194,13 +195,13 @@ class MultipleSelect {
194195
this.data = data
195196
}
196197
} else {
197-
$.each(this.$el.children(), (i, elm) => {
198+
for (const [i, elm] of Array.from(this.$el.children()).entries()) {
198199
const row = this.initRow(i, elm)
199200

200201
if (row) {
201-
data.push(this.initRow(i, elm))
202+
data.push(row)
202203
}
203-
})
204+
}
204205

205206
this.options.data = data
206207
this.data = data
@@ -248,9 +249,9 @@ class MultipleSelect {
248249
row._data = $elm.data()
249250
}
250251

251-
$.each($elm.children(), (j, elem) => {
252+
for (const [j, elem] of Array.from($elm.children()).entries()) {
252253
row.children.push(this.initRow(j, elem, row.disabled))
253-
})
254+
}
254255

255256
return row
256257
}
@@ -907,18 +908,18 @@ class MultipleSelect {
907908

908909
getOptions () {
909910
// deep copy and remove data
910-
const options = $.extend({}, this.options)
911+
const options = extend({}, this.options)
911912

912913
delete options.data
913-
return $.extend(true, {}, options)
914+
return extend(true, {}, options)
914915
}
915916

916917
refreshOptions (options) {
917918
// If the objects are equivalent then avoid the call of destroy / init methods
918919
if (compareObjects(this.options, options, true)) {
919920
return
920921
}
921-
this.options = $.extend(this.options, options)
922+
this.options = extend(this.options, options)
922923
this.destroy()
923924
this.init()
924925
}

src/multiple-select.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
import Constants from './constants/index.js'
99
import MultipleSelect from './MultipleSelect.js'
10+
import { extend } from './utils/index.js'
1011

1112
$.fn.multipleSelect = function (option, ...args) {
1213
let value
@@ -15,7 +16,7 @@ $.fn.multipleSelect = function (option, ...args) {
1516
const $this = $(el)
1617
let data = $this.data('multipleSelect')
1718

18-
const options = $.extend(
19+
const options = extend(
1920
{},
2021
$this.data(),
2122
typeof option === 'object' && option
@@ -27,7 +28,7 @@ $.fn.multipleSelect = function (option, ...args) {
2728
}
2829

2930
if (typeof option === 'string') {
30-
if ($.inArray(option, Constants.METHODS) < 0) {
31+
if (!Constants.METHODS.includes(option)) {
3132
throw new Error(`Unknown method: ${option}`)
3233
}
3334
value = data[option](...args)

src/utils/index.js

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,111 @@
1+
/**
2+
* Checks if a value is a plain object.
3+
*
4+
* @param {*} obj - The value to check.
5+
* @returns {boolean} True if the value is a plain object, false otherwise.
6+
*/
7+
const isObject = obj => {
8+
if (typeof obj !== 'object' || obj === null) {
9+
return false
10+
}
11+
12+
// Objects with null prototype are considered plain objects (jQuery compatible)
13+
if (Object.getPrototypeOf(obj) === null) {
14+
return true
15+
}
16+
17+
let proto = obj
18+
19+
while (Object.getPrototypeOf(proto) !== null) {
20+
proto = Object.getPrototypeOf(proto)
21+
}
22+
23+
return Object.getPrototypeOf(obj) === proto
24+
}
25+
26+
/**
27+
* Merges the contents of two or more objects together into the first object.
28+
* This is a re-implementation of jQuery's extend function.
29+
* Based on: https://github.com/jquery/jquery/blob/3.6.2/src/core.js#L132
30+
*
31+
* @param {boolean|Object} [deep=false] - If true, the merge becomes recursive (deep copy).
32+
* @param {Object} target - The object to extend.
33+
* @param {...Object} objects - The objects to merge into the target.
34+
* @returns {Object} The extended target object.
35+
*/
36+
const extend = (...args) => {
37+
let target = args[0] || {}
38+
let i = 1
39+
let deep = false
40+
let clone
41+
42+
// Handle a deep copy situation
43+
if (typeof target === 'boolean') {
44+
deep = target
45+
46+
// Skip the boolean and the target
47+
target = args[i] || {}
48+
i++
49+
}
50+
51+
// Handle case when target is a string or something (possible in deep copy)
52+
if (typeof target !== 'object' && typeof target !== 'function') {
53+
target = {}
54+
}
55+
56+
for (; i < args.length; i++) {
57+
const options = args[i]
58+
59+
// Ignore undefined/null values
60+
if (typeof options === 'undefined' || options === null) {
61+
continue
62+
}
63+
64+
// Extend the base object
65+
// eslint-disable-next-line guard-for-in
66+
for (const name in options) {
67+
const copy = options[name]
68+
69+
// Prevent Object.prototype pollution
70+
// Prevent never-ending loop
71+
if (name === '__proto__' || target === copy) {
72+
continue
73+
}
74+
75+
const copyIsArray = Array.isArray(copy)
76+
77+
// Recurse if we're merging plain objects or arrays
78+
if (deep && copy && (isObject(copy) || copyIsArray)) {
79+
const src = target[name]
80+
81+
if (copyIsArray && Array.isArray(src)) {
82+
if (src.every(it => !isObject(it) && !Array.isArray(it))) {
83+
target[name] = copy.slice()
84+
continue
85+
}
86+
}
87+
88+
if (copyIsArray && !Array.isArray(src)) {
89+
clone = []
90+
} else if (!copyIsArray && !isObject(src)) {
91+
clone = {}
92+
} else {
93+
clone = src
94+
}
95+
96+
// Never move original objects, clone them
97+
target[name] = extend(deep, clone, copy)
98+
99+
// Don't bring in undefined values
100+
} else if (copy !== undefined) {
101+
target[name] = copy
102+
}
103+
}
104+
}
105+
106+
return target
107+
}
108+
1109
const compareObjects = (objectA, objectB, compareLength) => {
2110
const aKeys = Object.keys(objectA)
3111
const bKeys = Object.keys(objectB)
@@ -178,6 +286,7 @@ const toRaw = proxy => {
178286

179287
export {
180288
compareObjects,
289+
extend,
181290
findByParam,
182291
getDocumentClickEvent,
183292
removeDiacritics,

0 commit comments

Comments
 (0)