diff --git a/src/pat/relateditems/relateditems.js b/src/pat/relateditems/relateditems.js
index 203664aa8..dad490755 100644
--- a/src/pat/relateditems/relateditems.js
+++ b/src/pat/relateditems/relateditems.js
@@ -4,7 +4,6 @@ import Base from "@patternslib/patternslib/src/core/base";
import _t from "../../core/i18n-wrapper";
import utils from "../../core/utils";
import registry from "@patternslib/patternslib/src/core/registry";
-import Select2 from "../select2/select2";
const KEY = {
LEFT: 37,
@@ -501,6 +500,9 @@ export default Base.extend({
},
async init() {
+ // select2 methods are borrowed onto this instance; load them lazily so
+ // the select2 body stays out of the eager patterns chunk.
+ this._select2 = (await import("../select2/select2--implementation")).default;
(await import("bootstrap")).Dropdown;
import("./relateditems.scss");
@@ -525,8 +527,8 @@ export default Base.extend({
this.$el.wrap('
');
this.$container = this.$el.parents(".pat-relateditems-container");
- Select2.prototype.initializeValues.call(this);
- Select2.prototype.initializeTags.call(this);
+ this._select2.initializeValues.call(this);
+ this._select2.initializeTags.call(this);
this.options.formatSelection = (item) => {
item = $.extend(
@@ -674,8 +676,8 @@ export default Base.extend({
this.options.id = (item) => item.UID;
- await Select2.prototype.initializeSelect2.call(this);
- await Select2.prototype.initializeOrdering.call(this);
+ await this._select2.initializeSelect2.call(this);
+ await this._select2.initializeOrdering.call(this);
this.$toolbar = $('');
this.$container.prepend(this.$toolbar);
@@ -697,7 +699,7 @@ export default Base.extend({
});
$(document).on("keyup", this.$el, (event) => {
- const isOpen = Select2.prototype.opened.call(this);
+ const isOpen = this._select2.opened.call(this);
if (!isOpen) {
return;
}
diff --git a/src/pat/select2/select2--implementation.js b/src/pat/select2/select2--implementation.js
new file mode 100644
index 000000000..18cdb5d4f
--- /dev/null
+++ b/src/pat/select2/select2--implementation.js
@@ -0,0 +1,312 @@
+import $ from "jquery";
+import events from "@patternslib/patternslib/src/core/events";
+import I18n from "../../core/i18n";
+import utils from "../../core/utils";
+
+// Pattern config object — grafted onto the thin registered pattern in
+// select2.js and run there. The select2 library, its CSS and the
+// select2_locale_* context all load from here, keeping them (and this
+// wrapper) out of the eager patterns chunk. pat-relateditems borrows
+// these methods via a lazy import of this module.
+export default {
+ defaults: {
+ separator: ",",
+ ajaxTimeout: 300,
+ },
+
+ 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;
+ }
+ }
+ }
+
+ 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),
+ });
+ }
+ callback(data);
+ };
+ }
+ },
+
+ initializeTags() {
+ if (this.options.tags && typeof this.options.tags === "string") {
+ if (this.options.tags.substr(0, 1) === "[") {
+ this.options.tags = JSON.parse(this.options.tags);
+ } else {
+ this.options.tags = this.options.tags.split(this.options.separator);
+ }
+ }
+
+ if (this.options.tags && !this.options.allowNewItems) {
+ this.options.data = this.options.tags.map((value) => {
+ return { id: value, text: value };
+ });
+ this.options.multiple = true;
+ delete this.options.tags;
+ }
+ },
+
+ async initializeOrdering() {
+ if (!this.options.orderable) {
+ return;
+ }
+ const Sortable = (await import("sortablejs")).default;
+ const _initializeOrdering = () => {
+ const sortable_el = this.$select2[0].querySelector(".select2-choices");
+ new Sortable(sortable_el, {
+ draggable: "li",
+ dragClass: "select2-choice-dragging",
+ chosenClass: "dragging",
+ onStart: () => this.$el.select2("onSortStart"),
+ onEnd: () => this.$el.select2("onSortEnd"),
+ });
+ };
+ this.$el.on("change", _initializeOrdering.bind(this));
+ _initializeOrdering();
+ },
+
+ async initializeSelect2() {
+ import("select2/select2.css");
+ import("./select2.scss");
+ await import("select2");
+ try {
+ // Don't load "en" which is the default where no separate language file exists.
+ if (this.options.language && this.options.language !== "en" && !this.options.language.startsWith("en")) {
+ let lang = this.options.language.split("-");
+ // Fix for country specific languages — only for supported combined locales
+ const supportedCombined = new Set(["pt-BR", "pt-PT", "ug-CN", "zh-CN", "zh-TW"]);
+ if(lang.length>1){
+ const combined =`${lang[0]}-${lang[1].toUpperCase()}`;
+ lang = supportedCombined.has(combined) ? combined : lang[0];
+ }else{
+ lang = lang[0];
+ }
+ await import(`select2/select2_locale_${lang}`);
+ }
+ } catch {
+ console.warn("Language file could not be loaded", this.options.language);
+ }
+
+ this.options.formatResultCssClass = (ob) => {
+ if (ob.id) {
+ return (
+ "select2-option-" +
+ ob.id.toLowerCase().replace(/[ \:\)\(\[\]\{\}\_\+\=\&\*\%\#]/g, "-")
+ );
+ }
+ };
+
+ function callback(action, e) {
+ if (action) {
+ if (this.options.debug) {
+ console.debug("callback", action, e);
+ }
+ if (typeof action === "string") {
+ action = window[action];
+ }
+ return action(e);
+ } else {
+ return action;
+ }
+ }
+
+ this.$el.select2(this.options);
+
+ // Select2 v3 signals changes via a jQuery `change` event, which isn't
+ // caught by native JavaScript event listeners.
+ // Let's re-trigger as native `input`- and `change`-events, so that
+ // those can pick it up. A native `