Skip to content

Commit

Permalink
feat(pat select2): Upgrade to Select2 4.0.x
Browse files Browse the repository at this point in the history
  • Loading branch information
petschki committed Mar 20, 2023
1 parent f5861b7 commit 2010655
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 228 deletions.
220 changes: 97 additions & 123 deletions src/pat/select2/select2.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import $ from "jquery";
import Base from "@patternslib/patternslib/src/core/base";
import I18n from "../../core/i18n";
import utils from "../../core/utils";
import _t from "../../core/i18n-wrapper";

export default Base.extend({
name: "select2",
Expand All @@ -14,56 +15,57 @@ export default Base.extend({

initializeValues() {
// Init Selection ---------------------------------------------
if (this.options.initialValues) {
this.options.id = (term) => {
return term.id;
};
this.options.initSelection = ($el, callback) => {
const data = [];
const value = $el.val();
let seldefaults = this.options.initialValues;

// Create the initSelection value that contains the default selection,
// but in a javascript object
if (
typeof this.options.initialValues === "string" &&
this.options.initialValues !== ""
) {
// if default selection value starts with a '{', then treat the value as
// a JSON object that needs to be parsed
if (this.options.initialValues[0] === "{") {
seldefaults = JSON.parse(this.options.initialValues);
}
// otherwise, treat the value as a list, separated by the defaults.separator value of
// strings in the format "id:text", and convert it to an object
else {
seldefaults = {};
const initial_values = $(
this.options.initialValues.split(this.options.separator)
);
for (const it of initial_values) {
const selection = it.split(":");
const id = selection[0].trim();
const text = selection[1].trim();
seldefaults[id] = text;
}
if (!this.options.initialValues) {
return;
}
this.options.id = (term) => {
return term.id;
};
this.options.initSelection = ($el, callback) => {
console.log("init selection");
const data = [];
const value = $el.val();
let seldefaults = this.options.initialValues;
// Create the initSelection value that contains the default selection,
// but in a javascript object
if (
typeof this.options.initialValues === "string" &&
this.options.initialValues !== ""
) {
// if default selection value starts with a '{', then treat the value as
// a JSON object that needs to be parsed
if (this.options.initialValues[0] === "{") {
seldefaults = JSON.parse(this.options.initialValues);
}
// otherwise, treat the value as a list, separated by the defaults.separator value of
// strings in the format "id:text", and convert it to an object
else {
seldefaults = {};
const initial_values = $(
this.options.initialValues.split(this.options.separator)
);
for (const it of initial_values) {
const selection = it.split(":");
const id = selection[0].trim();
const text = selection[1].trim();
seldefaults[id] = text;
}
}
}

const items = $(value.split(this.options.separator));
for (const it of items) {
let text = it;
if (seldefaults[it]) {
text = seldefaults[it];
}
data.push({
id: utils.removeHTML(it),
text: utils.removeHTML(text),
});
const items = $(value.split(this.options.separator));
for (const it of items) {
let text = it;
if (seldefaults[it]) {
text = seldefaults[it];
}
callback(data);
};
}
data.push({
id: utils.removeHTML(it),
text: utils.removeHTML(text),
});
}
callback(data);
};
},

initializeTags() {
Expand Down Expand Up @@ -99,14 +101,14 @@ export default Base.extend({
onEnd: () => this.$el.select2("onSortEnd"),
});
};
this.$el.on("change", _initializeOrdering.bind(this));
this.$el.on("change.select2", _initializeOrdering.bind(this));
_initializeOrdering();
},

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

if (this.options.allowClear & !this.options.placeholder) {
this.options.placeholder = _t("choose");
}

function callback(action, e) {
if (action) {
if (this.options.debug) {
Expand All @@ -139,13 +145,14 @@ export default Base.extend({
}
}

console.log(this.options);
this.$el.select2(this.options);
this.$el.on("select2-selected", (e) => callback(this.options.onSelected, e));
this.$el.on("select2-selecting", (e) => callback(this.options.onSelecting, e));
this.$el.on("select2-deselecting", (e) =>
this.$el.on("select2:select", (e) => callback(this.options.onSelected, e));
this.$el.on("select2:selecting", (e) => callback(this.options.onSelecting, e));
this.$el.on("select2:unselecting", (e) =>
callback(this.options.onDeselecting, e)
);
this.$el.on("select2-deselected", (e) => callback(this.options.onDeselected, e));
this.$el.on("select2:unselect", (e) => callback(this.options.onDeselected, e));
this.$select2 = this.$el.parent().find(".select2-container");
this.$el.parent().off("close.plone-modal.patterns");
if (this.options.orderable) {
Expand Down Expand Up @@ -181,88 +188,55 @@ export default Base.extend({
this.options.multiple === undefined ? true : this.options.multiple;
this.options.ajax = this.options.ajax || {};
this.options.ajax.url = this.options.vocabularyUrl;
// XXX removing the following function does'nt break tests. dead code?
this.options.initSelection = ($el, callback) => {
const data = [];
const value = $el.val();
for (const val of value.split(this.options.separator)) {
const _val = utils.removeHTML(val);
data.push({ id: _val, text: _val });
}
callback(data);
};
}

let queryTerm = "";

const ajaxTimeout = parseInt(this.options.ajaxTimeout || 300, 10);
delete this.options.ajaxTimeout;
this.options.ajax = $.extend(
{
quietMillis: ajaxTimeout,
data: (term, page) => {
queryTerm = term;
return {
query: term,
page_limit: 10,
page: page,
};
},
results: (data) => {
let results = data.results;
if (this.options.vocabularyUrl) {
const dataIds = [];
for (const it of data.results) {
dataIds.push(it.id);
}
results = [];

const haveResult =
queryTerm === "" || dataIds.includes(queryTerm);
if (this.options.allowNewItems && !haveResult) {
queryTerm = utils.removeHTML(queryTerm);
results.push({
id: queryTerm,
text: queryTerm,
});
}
this.options.ajax = {
quietMillis: ajaxTimeout,
data: (term, page) => {
queryTerm = term;
return {
query: term,
page_limit: 10,
page: page,
};
},
results: (data) => {
let results = data.results;
if (this.options.vocabularyUrl) {
const dataIds = [];
for (const it of data.results) {
dataIds.push(it.id);
}
results = [];

const haveResult =
queryTerm === "" || dataIds.includes(queryTerm);
if (this.options.allowNewItems && !haveResult) {
queryTerm = utils.removeHTML(queryTerm);
results.push({
id: queryTerm,
text: queryTerm,
});
}

for (const it of data.results) {
results.push(it);
}
for (const it of data.results) {
results.push(it);
}
return { results: results };
},
}
return { results: results };
},
this.options.ajax
);
} else if (this.options.multiple && this.$el.is("select")) {
// Multiselects are converted to input[type=hidden] for Select2
// TODO: This should actually not be necessary.
// This is kept for backwards compatibility but should be
// re-checked and removed if possible.
this.$el.attr("multiple", true);
const vals = this.$el.val() || [];
const options = [...this.el.querySelectorAll("option")].map((it) => {
return { text: it.innerHTML, id: it.value };
});

const el = document.createElement("input");
el.type = "hidden";
el.value = vals.join(this.options.separator);
el.className = this.el.getAttribute("class");
el.name = this.el.name;
el.id = this.el.id;
this.el.after(el);
this.el.remove();
this.el = el;
this.$el = $(el);

this.options.data = options;
...this.options.ajax
};
}

this.initializeValues();
this.initializeTags();

await this.initializeSelect2();
await this.initializeOrdering();
// await this.initializeOrdering();
},
});
108 changes: 3 additions & 105 deletions src/pat/select2/select2.scss
Original file line number Diff line number Diff line change
@@ -1,107 +1,5 @@
.select2-container {
margin-bottom: 1em;
background: #fff!important;
color: #000!important;
border-radius: 4px;

.select2-choice {
background: var(--bs-secondary-bg)!important;
background-image: none!important;
background-color: var(--bs-secondary-bg)!important;
border-color: var(--bs-secondary)!important;
color: var(--bs-dark-text)!important;
box-shadow: none!important;

.select2-arrow b {
background-color: var(--bs-secondary-bg)!important;
}
}

.select2-search {
background-color: var(--bs-secondary-bg)!important;
color: var(--bs-secondary-text)!important;
}
}

.select2-container-multi {
background: #fff!important;
color: #000!important;

.select2-choices {
border-color: var(--bs-secondary)!important;

.select2-choice-dragging {
border-color: #ff0000;
}
.select2-search-field {
input {
height: inherit;
padding: 2px 1px 1px 8px;
}
}
}

.select2-orderable {
.select2-search-choice {
&,
& span {
cursor: move;
}
}
}
}

// Overwrite default styles for dark mode theming
.select2-drop {
background: var(--bs-secondary-bg)!important;
color: var(--bs-secondary-text)!important;
}

.select2-results {
max-height: 950px;
background: var(--bs-secondary-bg);
color: var(--bs-secondary-text);

.select2-result {
background-color: transparent;
border-left: 0.3em solid transparent;
border-right: 0.3em solid transparent;

&:nth-child(odd) {
background-color: var(--bs-secondary-bg-subtle)!important;
}

&.select2-highlighted {
border-left: 0.3em solid #007bb3;
border-right: 0.3em solid #007bb3;
}

&-label {
padding: 0;
color: var(--bs-link-color);
}
}

.select2-no-results {
background: transparent!important;
}

> * {
background: transparent!important;
}

.select2-selected {
display: list-item;
}
}

// Overwrite default style for links for Close button, as in Related Items
#content-core {
.select2-search-choice-close {
border-bottom: 0;
}
}

.pat-select2 {
min-width: 50%;
.select2-container {
display:block;
width:100%;
}

0 comments on commit 2010655

Please sign in to comment.