Skip to content

Commit 2010655

Browse files
committed
feat(pat select2): Upgrade to Select2 4.0.x
1 parent f5861b7 commit 2010655

2 files changed

Lines changed: 100 additions & 228 deletions

File tree

src/pat/select2/select2.js

Lines changed: 97 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import $ from "jquery";
22
import Base from "@patternslib/patternslib/src/core/base";
33
import I18n from "../../core/i18n";
44
import utils from "../../core/utils";
5+
import _t from "../../core/i18n-wrapper";
56

67
export default Base.extend({
78
name: "select2",
@@ -14,56 +15,57 @@ export default Base.extend({
1415

1516
initializeValues() {
1617
// Init Selection ---------------------------------------------
17-
if (this.options.initialValues) {
18-
this.options.id = (term) => {
19-
return term.id;
20-
};
21-
this.options.initSelection = ($el, callback) => {
22-
const data = [];
23-
const value = $el.val();
24-
let seldefaults = this.options.initialValues;
25-
26-
// Create the initSelection value that contains the default selection,
27-
// but in a javascript object
28-
if (
29-
typeof this.options.initialValues === "string" &&
30-
this.options.initialValues !== ""
31-
) {
32-
// if default selection value starts with a '{', then treat the value as
33-
// a JSON object that needs to be parsed
34-
if (this.options.initialValues[0] === "{") {
35-
seldefaults = JSON.parse(this.options.initialValues);
36-
}
37-
// otherwise, treat the value as a list, separated by the defaults.separator value of
38-
// strings in the format "id:text", and convert it to an object
39-
else {
40-
seldefaults = {};
41-
const initial_values = $(
42-
this.options.initialValues.split(this.options.separator)
43-
);
44-
for (const it of initial_values) {
45-
const selection = it.split(":");
46-
const id = selection[0].trim();
47-
const text = selection[1].trim();
48-
seldefaults[id] = text;
49-
}
18+
if (!this.options.initialValues) {
19+
return;
20+
}
21+
this.options.id = (term) => {
22+
return term.id;
23+
};
24+
this.options.initSelection = ($el, callback) => {
25+
console.log("init selection");
26+
const data = [];
27+
const value = $el.val();
28+
let seldefaults = this.options.initialValues;
29+
// Create the initSelection value that contains the default selection,
30+
// but in a javascript object
31+
if (
32+
typeof this.options.initialValues === "string" &&
33+
this.options.initialValues !== ""
34+
) {
35+
// if default selection value starts with a '{', then treat the value as
36+
// a JSON object that needs to be parsed
37+
if (this.options.initialValues[0] === "{") {
38+
seldefaults = JSON.parse(this.options.initialValues);
39+
}
40+
// otherwise, treat the value as a list, separated by the defaults.separator value of
41+
// strings in the format "id:text", and convert it to an object
42+
else {
43+
seldefaults = {};
44+
const initial_values = $(
45+
this.options.initialValues.split(this.options.separator)
46+
);
47+
for (const it of initial_values) {
48+
const selection = it.split(":");
49+
const id = selection[0].trim();
50+
const text = selection[1].trim();
51+
seldefaults[id] = text;
5052
}
5153
}
54+
}
5255

53-
const items = $(value.split(this.options.separator));
54-
for (const it of items) {
55-
let text = it;
56-
if (seldefaults[it]) {
57-
text = seldefaults[it];
58-
}
59-
data.push({
60-
id: utils.removeHTML(it),
61-
text: utils.removeHTML(text),
62-
});
56+
const items = $(value.split(this.options.separator));
57+
for (const it of items) {
58+
let text = it;
59+
if (seldefaults[it]) {
60+
text = seldefaults[it];
6361
}
64-
callback(data);
65-
};
66-
}
62+
data.push({
63+
id: utils.removeHTML(it),
64+
text: utils.removeHTML(text),
65+
});
66+
}
67+
callback(data);
68+
};
6769
},
6870

6971
initializeTags() {
@@ -99,14 +101,14 @@ export default Base.extend({
99101
onEnd: () => this.$el.select2("onSortEnd"),
100102
});
101103
};
102-
this.$el.on("change", _initializeOrdering.bind(this));
104+
this.$el.on("change.select2", _initializeOrdering.bind(this));
103105
_initializeOrdering();
104106
},
105107

106108
async initializeSelect2() {
107-
import("select2/select2.css");
109+
import("select2/dist/css/select2.min.css");
108110
import("./select2.scss");
109-
await import("select2");
111+
await import("select2/dist/js/select2.full");
110112
try {
111113
// Don't load "en" which is the default where no separate language file exists.
112114
if (this.options.language && this.options.language !== "en") {
@@ -125,6 +127,10 @@ export default Base.extend({
125127
}
126128
};
127129

130+
if (this.options.allowClear & !this.options.placeholder) {
131+
this.options.placeholder = _t("choose");
132+
}
133+
128134
function callback(action, e) {
129135
if (action) {
130136
if (this.options.debug) {
@@ -139,13 +145,14 @@ export default Base.extend({
139145
}
140146
}
141147

148+
console.log(this.options);
142149
this.$el.select2(this.options);
143-
this.$el.on("select2-selected", (e) => callback(this.options.onSelected, e));
144-
this.$el.on("select2-selecting", (e) => callback(this.options.onSelecting, e));
145-
this.$el.on("select2-deselecting", (e) =>
150+
this.$el.on("select2:select", (e) => callback(this.options.onSelected, e));
151+
this.$el.on("select2:selecting", (e) => callback(this.options.onSelecting, e));
152+
this.$el.on("select2:unselecting", (e) =>
146153
callback(this.options.onDeselecting, e)
147154
);
148-
this.$el.on("select2-deselected", (e) => callback(this.options.onDeselected, e));
155+
this.$el.on("select2:unselect", (e) => callback(this.options.onDeselected, e));
149156
this.$select2 = this.$el.parent().find(".select2-container");
150157
this.$el.parent().off("close.plone-modal.patterns");
151158
if (this.options.orderable) {
@@ -181,88 +188,55 @@ export default Base.extend({
181188
this.options.multiple === undefined ? true : this.options.multiple;
182189
this.options.ajax = this.options.ajax || {};
183190
this.options.ajax.url = this.options.vocabularyUrl;
184-
// XXX removing the following function does'nt break tests. dead code?
185-
this.options.initSelection = ($el, callback) => {
186-
const data = [];
187-
const value = $el.val();
188-
for (const val of value.split(this.options.separator)) {
189-
const _val = utils.removeHTML(val);
190-
data.push({ id: _val, text: _val });
191-
}
192-
callback(data);
193-
};
194191
}
195192

196193
let queryTerm = "";
197194

198195
const ajaxTimeout = parseInt(this.options.ajaxTimeout || 300, 10);
199196
delete this.options.ajaxTimeout;
200-
this.options.ajax = $.extend(
201-
{
202-
quietMillis: ajaxTimeout,
203-
data: (term, page) => {
204-
queryTerm = term;
205-
return {
206-
query: term,
207-
page_limit: 10,
208-
page: page,
209-
};
210-
},
211-
results: (data) => {
212-
let results = data.results;
213-
if (this.options.vocabularyUrl) {
214-
const dataIds = [];
215-
for (const it of data.results) {
216-
dataIds.push(it.id);
217-
}
218-
results = [];
219-
220-
const haveResult =
221-
queryTerm === "" || dataIds.includes(queryTerm);
222-
if (this.options.allowNewItems && !haveResult) {
223-
queryTerm = utils.removeHTML(queryTerm);
224-
results.push({
225-
id: queryTerm,
226-
text: queryTerm,
227-
});
228-
}
197+
this.options.ajax = {
198+
quietMillis: ajaxTimeout,
199+
data: (term, page) => {
200+
queryTerm = term;
201+
return {
202+
query: term,
203+
page_limit: 10,
204+
page: page,
205+
};
206+
},
207+
results: (data) => {
208+
let results = data.results;
209+
if (this.options.vocabularyUrl) {
210+
const dataIds = [];
211+
for (const it of data.results) {
212+
dataIds.push(it.id);
213+
}
214+
results = [];
215+
216+
const haveResult =
217+
queryTerm === "" || dataIds.includes(queryTerm);
218+
if (this.options.allowNewItems && !haveResult) {
219+
queryTerm = utils.removeHTML(queryTerm);
220+
results.push({
221+
id: queryTerm,
222+
text: queryTerm,
223+
});
224+
}
229225

230-
for (const it of data.results) {
231-
results.push(it);
232-
}
226+
for (const it of data.results) {
227+
results.push(it);
233228
}
234-
return { results: results };
235-
},
229+
}
230+
return { results: results };
236231
},
237-
this.options.ajax
238-
);
239-
} else if (this.options.multiple && this.$el.is("select")) {
240-
// Multiselects are converted to input[type=hidden] for Select2
241-
// TODO: This should actually not be necessary.
242-
// This is kept for backwards compatibility but should be
243-
// re-checked and removed if possible.
244-
this.$el.attr("multiple", true);
245-
const vals = this.$el.val() || [];
246-
const options = [...this.el.querySelectorAll("option")].map((it) => {
247-
return { text: it.innerHTML, id: it.value };
248-
});
249-
250-
const el = document.createElement("input");
251-
el.type = "hidden";
252-
el.value = vals.join(this.options.separator);
253-
el.className = this.el.getAttribute("class");
254-
el.name = this.el.name;
255-
el.id = this.el.id;
256-
this.el.after(el);
257-
this.el.remove();
258-
this.el = el;
259-
this.$el = $(el);
260-
261-
this.options.data = options;
232+
...this.options.ajax
233+
};
262234
}
235+
263236
this.initializeValues();
264237
this.initializeTags();
238+
265239
await this.initializeSelect2();
266-
await this.initializeOrdering();
240+
// await this.initializeOrdering();
267241
},
268242
});

src/pat/select2/select2.scss

Lines changed: 3 additions & 105 deletions
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,5 @@
1-
.select2-container {
2-
margin-bottom: 1em;
3-
background: #fff!important;
4-
color: #000!important;
5-
border-radius: 4px;
6-
7-
.select2-choice {
8-
background: var(--bs-secondary-bg)!important;
9-
background-image: none!important;
10-
background-color: var(--bs-secondary-bg)!important;
11-
border-color: var(--bs-secondary)!important;
12-
color: var(--bs-dark-text)!important;
13-
box-shadow: none!important;
14-
15-
.select2-arrow b {
16-
background-color: var(--bs-secondary-bg)!important;
17-
}
18-
}
19-
20-
.select2-search {
21-
background-color: var(--bs-secondary-bg)!important;
22-
color: var(--bs-secondary-text)!important;
23-
}
24-
}
25-
26-
.select2-container-multi {
27-
background: #fff!important;
28-
color: #000!important;
29-
30-
.select2-choices {
31-
border-color: var(--bs-secondary)!important;
32-
33-
.select2-choice-dragging {
34-
border-color: #ff0000;
35-
}
36-
.select2-search-field {
37-
input {
38-
height: inherit;
39-
padding: 2px 1px 1px 8px;
40-
}
41-
}
42-
}
43-
44-
.select2-orderable {
45-
.select2-search-choice {
46-
&,
47-
& span {
48-
cursor: move;
49-
}
50-
}
51-
}
52-
}
53-
54-
// Overwrite default styles for dark mode theming
55-
.select2-drop {
56-
background: var(--bs-secondary-bg)!important;
57-
color: var(--bs-secondary-text)!important;
58-
}
591

60-
.select2-results {
61-
max-height: 950px;
62-
background: var(--bs-secondary-bg);
63-
color: var(--bs-secondary-text);
64-
65-
.select2-result {
66-
background-color: transparent;
67-
border-left: 0.3em solid transparent;
68-
border-right: 0.3em solid transparent;
69-
70-
&:nth-child(odd) {
71-
background-color: var(--bs-secondary-bg-subtle)!important;
72-
}
73-
74-
&.select2-highlighted {
75-
border-left: 0.3em solid #007bb3;
76-
border-right: 0.3em solid #007bb3;
77-
}
78-
79-
&-label {
80-
padding: 0;
81-
color: var(--bs-link-color);
82-
}
83-
}
84-
85-
.select2-no-results {
86-
background: transparent!important;
87-
}
88-
89-
> * {
90-
background: transparent!important;
91-
}
92-
93-
.select2-selected {
94-
display: list-item;
95-
}
96-
}
97-
98-
// Overwrite default style for links for Close button, as in Related Items
99-
#content-core {
100-
.select2-search-choice-close {
101-
border-bottom: 0;
102-
}
103-
}
104-
105-
.pat-select2 {
106-
min-width: 50%;
2+
.select2-container {
3+
display:block;
4+
width:100%;
1075
}

0 commit comments

Comments
 (0)