diff --git a/phpstan-baseline.neon b/phpstan-baseline.neon
index 28119ea1d8..5f8e5d2beb 100644
--- a/phpstan-baseline.neon
+++ b/phpstan-baseline.neon
@@ -8430,6 +8430,11 @@ parameters:
count: 1
path: src/lib/REST/Input/Parser/Operation.php
+ -
+ message: "#^Cannot call method resolve\\(\\) on Ibexa\\\\Contracts\\\\AdminUi\\\\REST\\\\ApplicationConfigRestResolverInterface\\|null\\.$#"
+ count: 1
+ path: src/lib/REST/Output/ValueObjectVisitor/ApplicationConfigVisitor.php
+
-
message: "#^Method Ibexa\\\\AdminUi\\\\REST\\\\Output\\\\ValueObjectVisitor\\\\BulkOperationResponse\\:\\:visit\\(\\) has no return type specified\\.$#"
count: 1
diff --git a/src/bundle/Resources/config/services/controllers.yaml b/src/bundle/Resources/config/services/controllers.yaml
index 0d3ebae38b..9c6adb1153 100644
--- a/src/bundle/Resources/config/services/controllers.yaml
+++ b/src/bundle/Resources/config/services/controllers.yaml
@@ -237,7 +237,6 @@ services:
parent: Ibexa\Contracts\AdminUi\Controller\Controller
autowire: true
-
Ibexa\Bundle\AdminUi\Controller\ApplicationConfigController:
parent: Ibexa\Rest\Server\Controller
autowire: true
diff --git a/src/bundle/Resources/encore/ibexa.config.setup.js b/src/bundle/Resources/encore/ibexa.config.setup.js
index eddeab341e..940ab5c287 100644
--- a/src/bundle/Resources/encore/ibexa.config.setup.js
+++ b/src/bundle/Resources/encore/ibexa.config.setup.js
@@ -3,5 +3,6 @@ const path = require('path');
module.exports = (Encore) => {
Encore.addAliases({
'@ibexa-admin-ui': path.resolve('./vendor/ibexa/admin-ui'),
+ '@ibexa-admin-ui-modules': path.resolve('./vendor/ibexa/admin-ui/src/bundle/ui-dev/src/modules'),
});
};
diff --git a/src/bundle/Resources/encore/ibexa.js.config.js b/src/bundle/Resources/encore/ibexa.js.config.js
index 0b9e8bae74..72deeb9054 100644
--- a/src/bundle/Resources/encore/ibexa.js.config.js
+++ b/src/bundle/Resources/encore/ibexa.js.config.js
@@ -3,25 +3,7 @@ const fs = require('fs');
const translationsPath = path.resolve('./public/assets/translations/');
const fieldTypesPath = path.resolve(__dirname, '../public/js/scripts/fieldType/');
const layout = [
- path.resolve(__dirname, '../public/js/scripts/helpers/icon.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/location.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/text.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/request.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/notification.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/timezone.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/content.type.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/user.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/tooltips.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/table.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/cookies.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/tag.view.select.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/pagination.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/object.instances.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/middle.ellipsis.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/form.validation.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/form.error.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/system.helper.js'),
- path.resolve(__dirname, '../public/js/scripts/helpers/highlight.helper.js'),
+ path.resolve(__dirname, '../public/js/scripts/helpers/config.loader.js'),
path.resolve(__dirname, '../public/js/scripts/admin.format.date.js'),
path.resolve(__dirname, '../public/js/scripts/core/draggable.js'),
path.resolve(__dirname, '../public/js/scripts/core/dropdown.js'),
@@ -219,6 +201,7 @@ module.exports = (Encore) => {
path.resolve(__dirname, '../public/js/scripts/admin.settings.datetimeformat.update.js'),
])
.addEntry('ibexa-admin-ui-udw-js', [
+ path.resolve(__dirname, '../../ui-dev/src/modules/universal-discovery/config.loader.js'),
path.resolve(__dirname, '../../ui-dev/src/modules/universal-discovery/universal.discovery.module.js'),
])
.addEntry('ibexa-admin-ui-udw-tabs-js', [
@@ -251,6 +234,7 @@ module.exports = (Encore) => {
.addEntry('ibexa-admin-ui-subitems-js', [path.resolve(__dirname, '../../ui-dev/src/modules/sub-items/sub.items.module.js')])
.addEntry('ibexa-admin-ui-content-tree-js', [
path.resolve(__dirname, '../../ui-dev/src/modules/content-tree/content.tree.module.js'),
+ path.resolve(__dirname, '../../ui-dev/src/modules/content-tree/config.loader.js'),
])
.addEntry('ibexa-admin-ui-url-management-js', [
path.resolve(__dirname, '../public/js/scripts/button.state.toggle.js'),
diff --git a/src/bundle/Resources/public/js/scripts/core/date.time.picker.js b/src/bundle/Resources/public/js/scripts/core/date.time.picker.js
index 3541f8352e..6bb2b08a70 100644
--- a/src/bundle/Resources/public/js/scripts/core/date.time.picker.js
+++ b/src/bundle/Resources/public/js/scripts/core/date.time.picker.js
@@ -1,118 +1,124 @@
-(function (global, doc, ibexa, flatpickr) {
- const { convertDateToTimezone, formatShortDateTime } = ibexa.helpers.timezone;
- const userTimezone = ibexa.adminUiConfig.timezone;
- const DEFAULT_CONFIG = {
- enableTime: true,
- time_24hr: true,
- formatDate: (date) => formatShortDateTime(date, null),
- };
-
- class DateTimePicker {
- constructor(config) {
- this.container = config.container;
- this.fieldWrapper = this.container.querySelector('.ibexa-date-time-picker');
- this.inputField = this.fieldWrapper.querySelector('.ibexa-date-time-picker__input');
- this.actionsWrapper = this.fieldWrapper.querySelector('.ibexa-input-text-wrapper__actions');
- this.calendarBtn = this.actionsWrapper.querySelector('.ibexa-input-text-wrapper__action-btn--calendar');
- this.clearBtn = this.fieldWrapper.querySelector('.ibexa-input-text-wrapper__action-btn--clear');
- this.customOnChange = config.onChange;
-
- this.init = this.init.bind(this);
- this.onChange = this.onChange.bind(this);
- this.onInput = this.onInput.bind(this);
- this.clear = this.clear.bind(this);
-
- this.flatpickrConfig = {
- ...DEFAULT_CONFIG,
- inline: this.fieldWrapper.classList.contains('ibexa-date-time-picker--inline-datetime-popup'),
- onChange: this.onChange,
- ignoredFocusElements: [this.actionsWrapper],
- ...(config.flatpickrConfig ?? {}),
- };
-
- ibexa.helpers.objectInstances.setInstance(this.container, this);
- }
+import { getAdminUiConfig, getFlatpickr } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+import { convertDateToTimezone, formatShortDateTime } from '../helpers/timezone.helper';
+import { setInstance } from '../helpers/object.instances';
+
+const { ibexa } = window;
+
+const DEFAULT_CONFIG = {
+ enableTime: true,
+ time_24hr: true,
+ formatDate: (date) => formatShortDateTime(date, null),
+};
+
+class DateTimePicker {
+ constructor(config) {
+ this.container = config.container;
+ this.fieldWrapper = this.container.querySelector('.ibexa-date-time-picker');
+ this.inputField = this.fieldWrapper.querySelector('.ibexa-date-time-picker__input');
+ this.actionsWrapper = this.fieldWrapper.querySelector('.ibexa-input-text-wrapper__actions');
+ this.calendarBtn = this.actionsWrapper.querySelector('.ibexa-input-text-wrapper__action-btn--calendar');
+ this.clearBtn = this.fieldWrapper.querySelector('.ibexa-input-text-wrapper__action-btn--clear');
+ this.customOnChange = config.onChange;
+
+ this.init = this.init.bind(this);
+ this.onChange = this.onChange.bind(this);
+ this.onInput = this.onInput.bind(this);
+ this.clear = this.clear.bind(this);
+
+ this.flatpickrConfig = {
+ ...DEFAULT_CONFIG,
+ inline: this.fieldWrapper.classList.contains('ibexa-date-time-picker--inline-datetime-popup'),
+ onChange: this.onChange,
+ ignoredFocusElements: [this.actionsWrapper],
+ ...(config.flatpickrConfig ?? {}),
+ };
+
+ setInstance(this.container, this);
+ }
- clear() {
- this.flatpickrInstance.clear();
- }
+ clear() {
+ this.flatpickrInstance.clear();
+ }
- onChange(dates) {
- const isDateSelected = !!dates[0];
- const otherArguments = { inputField: this.inputField, dates };
+ onChange(dates) {
+ const isDateSelected = !!dates[0];
+ const otherArguments = { inputField: this.inputField, dates };
- if (!isDateSelected) {
- this.inputField.dataset.timestamp = '';
+ if (!isDateSelected) {
+ this.inputField.dataset.timestamp = '';
- this.customOnChange([''], otherArguments);
+ this.customOnChange([''], otherArguments);
- return;
- }
+ return;
+ }
- const timestamps = dates.map((date) => {
- const selectedDateWithUserTimezone = convertDateToTimezone(date, userTimezone, true);
- const timestamp = Math.floor(selectedDateWithUserTimezone.valueOf() / 1000);
+ const timestamps = dates.map((date) => {
+ const { timezone } = getAdminUiConfig();
+ const selectedDateWithUserTimezone = convertDateToTimezone(date, timezone, true);
+ const timestamp = Math.floor(selectedDateWithUserTimezone.valueOf() / 1000);
- return timestamp;
- });
+ return timestamp;
+ });
- [this.inputField.dataset.timestamp] = timestamps;
+ [this.inputField.dataset.timestamp] = timestamps;
- this.customOnChange(timestamps, otherArguments);
- }
+ this.customOnChange(timestamps, otherArguments);
+ }
- onInput(event) {
- event.preventDefault();
+ onInput(event) {
+ event.preventDefault();
- if (event.target.value === '' && this.inputField.dataset.timestamp !== '') {
- this.clear();
- }
+ if (event.target.value === '' && this.inputField.dataset.timestamp !== '') {
+ this.clear();
}
+ }
- onKeyUp(isMinute, event) {
- const inputValue = event.target.value;
-
- if (inputValue.length === 0) {
- return;
- }
+ onKeyUp(isMinute, event) {
+ const inputValue = event.target.value;
- const value = parseInt(inputValue, 10);
+ if (inputValue.length === 0) {
+ return;
+ }
- if (typeof value === 'number' && value >= 0) {
- const flatpickrDate = this.flatpickrInstance.selectedDates[0];
+ const value = parseInt(inputValue, 10);
- if (isMinute) {
- flatpickrDate.setMinutes(value);
- } else {
- flatpickrDate.setHours(value);
- }
+ if (typeof value === 'number' && value >= 0) {
+ const flatpickrDate = this.flatpickrInstance.selectedDates[0];
- if (this.flatpickrConfig.minDate.getTime() > flatpickrDate.getTime()) {
- return;
- }
+ if (isMinute) {
+ flatpickrDate.setMinutes(value);
+ } else {
+ flatpickrDate.setHours(value);
+ }
- this.flatpickrInstance.setDate(flatpickrDate, true);
+ if (this.flatpickrConfig.minDate.getTime() > flatpickrDate.getTime()) {
+ return;
}
+
+ this.flatpickrInstance.setDate(flatpickrDate, true);
}
+ }
- init() {
- this.flatpickrInstance = flatpickr(this.inputField, this.flatpickrConfig);
-
- this.inputField.addEventListener('input', this.onInput, false);
- this.calendarBtn.addEventListener(
- 'click',
- () => {
- this.flatpickrInstance.open();
- },
- false,
- );
-
- if (this.flatpickrInstance.config.enableTime) {
- this.flatpickrInstance.minuteElement.addEventListener('keyup', this.onKeyUp.bind(this, true), false);
- this.flatpickrInstance.hourElement.addEventListener('keyup', this.onKeyUp.bind(this, false), false);
- }
+ init() {
+ const flatpickr = getFlatpickr();
+ this.flatpickrInstance = flatpickr(this.inputField, this.flatpickrConfig);
+
+ this.inputField.addEventListener('input', this.onInput, false);
+ this.calendarBtn.addEventListener(
+ 'click',
+ () => {
+ this.flatpickrInstance.open();
+ },
+ false,
+ );
+
+ if (this.flatpickrInstance.config.enableTime) {
+ this.flatpickrInstance.minuteElement.addEventListener('keyup', this.onKeyUp.bind(this, true), false);
+ this.flatpickrInstance.hourElement.addEventListener('keyup', this.onKeyUp.bind(this, false), false);
}
}
+}
+
+ibexa?.addConfig('core.DateTimePicker', DateTimePicker);
- ibexa.addConfig('core.DateTimePicker', DateTimePicker);
-})(window, window.document, window.ibexa, window.flatpickr);
+export { DateTimePicker };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/config.loader.js b/src/bundle/Resources/public/js/scripts/helpers/config.loader.js
new file mode 100644
index 0000000000..038cc15882
--- /dev/null
+++ b/src/bundle/Resources/public/js/scripts/helpers/config.loader.js
@@ -0,0 +1,41 @@
+import * as contentType from './content.type.helper';
+import * as cookies from './cookies.helper';
+import * as formError from './form.error.helper';
+import * as formValidation from './form.validation.helper';
+import * as highlight from './highlight.helper';
+import * as icon from './icon.helper';
+import * as location from './location.helper';
+import * as middleEllipsis from './middle.ellipsis';
+import * as notification from './notification.helper';
+import * as objectInstances from './object.instances';
+import * as pagination from './pagination.helper';
+import * as request from './request.helper';
+import * as system from './system.helper';
+import * as table from './table.helper';
+import * as tagViewSelect from './tag.view.select.helper';
+import * as text from './text.helper';
+import * as timezone from './timezone.helper';
+import * as tooltips from './tooltips.helper';
+import * as user from './user.helper';
+
+(function (ibexa) {
+ ibexa.addConfig('helpers.contentType', contentType);
+ ibexa.addConfig('helpers.cookies', cookies);
+ ibexa.addConfig('helpers.formError', formError);
+ ibexa.addConfig('helpers.formValidation', formValidation);
+ ibexa.addConfig('helpers.highlight', highlight);
+ ibexa.addConfig('helpers.icon', icon);
+ ibexa.addConfig('helpers.location', location);
+ ibexa.addConfig('helpers.ellipsis.middle', middleEllipsis);
+ ibexa.addConfig('helpers.notification', notification);
+ ibexa.addConfig('helpers.objectInstances', objectInstances);
+ ibexa.addConfig('helpers.pagination', pagination);
+ ibexa.addConfig('helpers.request', request);
+ ibexa.addConfig('helpers.system', system);
+ ibexa.addConfig('helpers.table', table);
+ ibexa.addConfig('helpers.tagViewSelect', tagViewSelect);
+ ibexa.addConfig('helpers.text', text);
+ ibexa.addConfig('helpers.timezone', timezone);
+ ibexa.addConfig('helpers.tooltips', tooltips);
+ ibexa.addConfig('helpers.user', user);
+})(window.ibexa);
diff --git a/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js b/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js
index 5a729f4773..0d1d8ed005 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/content.type.helper.js
@@ -1,106 +1,100 @@
-(function (global, doc, ibexa) {
- let contentTypesDataMap = null;
- let contentTypesDataMapByHref = null;
-
- /**
- * Creates map with content types identifiers as keys for faster lookup
- *
- * @function createContentTypeDataMap
- * @returns {Object} contentTypesDataMap
- */
- const createContentTypeDataMap = () =>
- Object.values(ibexa.adminUiConfig.contentTypes).reduce((contentTypeDataMap, contentTypeGroup) => {
- for (const contentTypeData of contentTypeGroup) {
- contentTypeDataMap[contentTypeData.identifier] = contentTypeData;
- }
-
- return contentTypeDataMap;
- }, {});
-
- const createContentTypeDataMapByHref = () =>
- Object.values(ibexa.adminUiConfig.contentTypes).reduce((contentTypeDataMapByHref, contentTypeGroup) => {
- for (const contentTypeData of contentTypeGroup) {
- contentTypeDataMapByHref[contentTypeData.href] = contentTypeData;
- }
-
- return contentTypeDataMapByHref;
- }, {});
-
- /**
- * Returns an URL to a content type icon
- *
- * @function getContentTypeIcon
- * @param {String} contentTypeIdentifier
- * @returns {String|null} url to icon
- */
- const getContentTypeIconUrl = (contentTypeIdentifier) => {
- if (!contentTypesDataMap) {
- contentTypesDataMap = createContentTypeDataMap();
+import { getAdminUiConfig } from './context.helper';
+
+let contentTypesDataMap = null;
+let contentTypesDataMapByHref = null;
+
+/**
+ * Creates map with content types identifiers as keys for faster lookup
+ *
+ * @function createContentTypeDataMap
+ * @returns {Object} contentTypesDataMap
+ */
+const createContentTypeDataMap = () =>
+ Object.values(getAdminUiConfig().contentTypes).reduce((contentTypeDataMap, contentTypeGroup) => {
+ for (const contentTypeData of contentTypeGroup) {
+ contentTypeDataMap[contentTypeData.identifier] = contentTypeData;
}
- if (!contentTypeIdentifier || !contentTypesDataMap[contentTypeIdentifier]) {
- return null;
- }
-
- const iconUrl = contentTypesDataMap[contentTypeIdentifier].thumbnail;
-
- return iconUrl;
- };
-
- /**
- * Returns contentType name from contentType identifier
- *
- * @function getContentTypeName
- * @param {String} contentTypeIdentifier
- * @returns {String|null} contentType name
- */
- const getContentTypeName = (contentTypeIdentifier) => {
- if (!contentTypesDataMap) {
- contentTypesDataMap = createContentTypeDataMap();
- }
-
- if (!contentTypeIdentifier || !contentTypesDataMap[contentTypeIdentifier]) {
- return null;
- }
-
- return contentTypesDataMap[contentTypeIdentifier].name;
- };
-
- const getContentTypeIconUrlByHref = (contentTypeHref) => {
- if (!contentTypesDataMapByHref) {
- contentTypesDataMapByHref = createContentTypeDataMapByHref();
- }
-
- if (!contentTypeHref || !contentTypesDataMapByHref[contentTypeHref]) {
- return null;
- }
-
- const iconUrl = contentTypesDataMapByHref[contentTypeHref].thumbnail;
-
- return iconUrl;
- };
-
- const getContentTypeDataByHref = (contentTypeHref) => {
- if (!contentTypesDataMapByHref) {
- contentTypesDataMapByHref = createContentTypeDataMapByHref();
- }
+ return contentTypeDataMap;
+ }, {});
- if (!contentTypeHref || !contentTypesDataMapByHref[contentTypeHref]) {
- return null;
+const createContentTypeDataMapByHref = () =>
+ Object.values(getAdminUiConfig().contentTypes).reduce((contentTypeDataMapByHref, contentTypeGroup) => {
+ for (const contentTypeData of contentTypeGroup) {
+ contentTypeDataMapByHref[contentTypeData.href] = contentTypeData;
}
- return contentTypesDataMapByHref[contentTypeHref];
- };
-
- const getContentTypeNameByHref = (contentTypeHref) => {
- return getContentTypeDataByHref(contentTypeHref)?.name ?? null;
- };
-
- ibexa.addConfig('helpers.contentType', {
- getContentTypeIconUrl,
- getContentTypeName,
- getContentTypeIconUrlByHref,
- getContentTypeDataByHref,
- getContentTypeNameByHref,
- });
-})(window, window.document, window.ibexa);
+ return contentTypeDataMapByHref;
+ }, {});
+
+/**
+ * Returns an URL to a content type icon
+ *
+ * @function getContentTypeIcon
+ * @param {String} contentTypeIdentifier
+ * @returns {String|null} url to icon
+ */
+const getContentTypeIconUrl = (contentTypeIdentifier) => {
+ if (!contentTypesDataMap) {
+ contentTypesDataMap = createContentTypeDataMap();
+ }
+
+ if (!contentTypeIdentifier || !contentTypesDataMap[contentTypeIdentifier]) {
+ return null;
+ }
+
+ const iconUrl = contentTypesDataMap[contentTypeIdentifier].thumbnail;
+
+ return iconUrl;
+};
+
+/**
+ * Returns contentType name from contentType identifier
+ *
+ * @function getContentTypeName
+ * @param {String} contentTypeIdentifier
+ * @returns {String|null} contentType name
+ */
+const getContentTypeName = (contentTypeIdentifier) => {
+ if (!contentTypesDataMap) {
+ contentTypesDataMap = createContentTypeDataMap();
+ }
+
+ if (!contentTypeIdentifier || !contentTypesDataMap[contentTypeIdentifier]) {
+ return null;
+ }
+
+ return contentTypesDataMap[contentTypeIdentifier].name;
+};
+
+const getContentTypeIconUrlByHref = (contentTypeHref) => {
+ if (!contentTypesDataMapByHref) {
+ contentTypesDataMapByHref = createContentTypeDataMapByHref();
+ }
+
+ if (!contentTypeHref || !contentTypesDataMapByHref[contentTypeHref]) {
+ return null;
+ }
+
+ const iconUrl = contentTypesDataMapByHref[contentTypeHref].thumbnail;
+
+ return iconUrl;
+};
+
+const getContentTypeNameByHref = (contentTypeHref) => {
+ return getContentTypeDataByHref(contentTypeHref)?.name ?? null;
+};
+
+const getContentTypeDataByHref = (contentTypeHref) => {
+ if (!contentTypesDataMapByHref) {
+ contentTypesDataMapByHref = createContentTypeDataMapByHref();
+ }
+
+ if (!contentTypeHref || !contentTypesDataMapByHref[contentTypeHref]) {
+ return null;
+ }
+
+ return contentTypesDataMapByHref[contentTypeHref];
+};
+
+export { getContentTypeIconUrl, getContentTypeName, getContentTypeIconUrlByHref, getContentTypeDataByHref, getContentTypeNameByHref };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/context.helper.js b/src/bundle/Resources/public/js/scripts/helpers/context.helper.js
new file mode 100644
index 0000000000..016b150042
--- /dev/null
+++ b/src/bundle/Resources/public/js/scripts/helpers/context.helper.js
@@ -0,0 +1,55 @@
+let { bootstrap, flatpickr, moment, Popper, Routing, Translator } = window;
+let adminUiConfig = window.ibexa?.adminUiConfig;
+const restInfo = {
+ accessToken: null,
+ instanceUrl: window.location.origin,
+ token: document.querySelector('meta[name="CSRF-Token"]')?.content,
+ siteaccess: document.querySelector('meta[name="SiteAccess"]')?.content,
+};
+
+export const setRestInfo = ({ instanceUrl, token, csrfToken, siteaccess }) => {
+ restInfo.instanceUrl = instanceUrl ?? restInfo.instanceUrl;
+ restInfo.token = token ?? restInfo.token;
+ restInfo.csrfToken = csrfToken ?? restInfo.csrfToken;
+ restInfo.siteaccess = siteaccess ?? restInfo.siteaccess;
+};
+export const setAdminUiConfig = (loadedAdminUiConfig) => (adminUiConfig = loadedAdminUiConfig);
+export const setBootstrap = (bootstrapInstance, forceSet = false) => {
+ if (!bootstrap || forceSet) {
+ bootstrap = bootstrapInstance;
+ }
+};
+export const setFlatpickr = (flatpickrInstance, forceSet = false) => {
+ if (!flatpickr || forceSet) {
+ flatpickr = flatpickrInstance;
+ }
+};
+export const setMoment = (momentInstance, forceSet = false) => {
+ if (!moment || forceSet) {
+ moment = momentInstance;
+ }
+};
+export const setPopper = (PopperInstance, forceSet = false) => {
+ if (!Popper || forceSet) {
+ Popper = PopperInstance;
+ }
+};
+export const setRouting = (RoutingInstance, forceSet = false) => {
+ if (!Routing || forceSet) {
+ Routing = RoutingInstance;
+ }
+};
+export const setTranslator = (TranslatorInstance, forceSet = false) => {
+ if (!Translator || forceSet) {
+ Translator = TranslatorInstance;
+ }
+};
+
+export const getAdminUiConfig = () => adminUiConfig;
+export const getBootstrap = () => bootstrap;
+export const getFlatpickr = () => flatpickr;
+export const getMoment = () => moment;
+export const getPopper = () => Popper;
+export const getRouting = () => Routing;
+export const getTranslator = () => Translator;
+export const getRestInfo = () => restInfo;
diff --git a/src/bundle/Resources/public/js/scripts/helpers/cookies.helper.js b/src/bundle/Resources/public/js/scripts/helpers/cookies.helper.js
index 4eebda855e..700a844e90 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/cookies.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/cookies.helper.js
@@ -1,30 +1,27 @@
-(function (global, doc, ibexa) {
- const { backOfficePath } = ibexa.adminUiConfig;
- const setBackOfficeCookie = (name, value, maxAgeDays = 356, path = backOfficePath) => {
- setCookie(name, value, maxAgeDays, path);
- };
- const setCookie = (name, value, maxAgeDays = 356, path = '/') => {
- const maxAge = maxAgeDays * 24 * 60 * 60;
+import { getAdminUiConfig } from './context.helper';
- doc.cookie = `${name}=${value};max-age=${maxAge};path=${path}`;
- };
- const getCookie = (name) => {
- const decodedCookie = decodeURIComponent(doc.cookie);
- const cookiesArray = decodedCookie.split(';');
+const { document: doc } = window;
- const cookieValue = cookiesArray.find((cookie) => {
- const cookieString = cookie.trim();
- const seachingString = `${name}=`;
+const setBackOfficeCookie = (name, value, maxAgeDays = 356, path = getAdminUiConfig().backOfficePath) => {
+ setCookie(name, value, maxAgeDays, path);
+};
+const setCookie = (name, value, maxAgeDays = 356, path = '/') => {
+ const maxAge = maxAgeDays * 24 * 60 * 60;
- return cookieString.indexOf(seachingString) === 0;
- });
+ doc.cookie = `${name}=${value};max-age=${maxAge};path=${path}`;
+};
+const getCookie = (name) => {
+ const decodedCookie = decodeURIComponent(doc.cookie);
+ const cookiesArray = decodedCookie.split(';');
- return cookieValue ? cookieValue.split('=')[1] : null;
- };
+ const cookieValue = cookiesArray.find((cookie) => {
+ const cookieString = cookie.trim();
+ const seachingString = `${name}=`;
- ibexa.addConfig('helpers.cookies', {
- getCookie,
- setCookie,
- setBackOfficeCookie,
+ return cookieString.indexOf(seachingString) === 0;
});
-})(window, window.document, window.ibexa);
+
+ return cookieValue ? cookieValue.split('=')[1] : null;
+};
+
+export { getCookie, setCookie, setBackOfficeCookie };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/form.error.helper.js b/src/bundle/Resources/public/js/scripts/helpers/form.error.helper.js
index 6bc39c4760..c5f8c0f52e 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/form.error.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/form.error.helper.js
@@ -1,12 +1,12 @@
-(function (global, doc, ibexa) {
- // @deprecated, will be removed in 5.0
- ibexa.addConfig('helpers.formError', {
- formatLine: (...args) => {
- console.warn(
- 'helpers.formError.formatLine method is deprecated and will be removed in 5.0, please use helpers.formValidation.formatErrorLine instead.',
- );
+import { formatErrorLine } from './form.validation.helper';
- return ibexa.helpers.formValidation.formatErrorLine(...args);
- },
- });
-})(window, window.document, window.ibexa);
+// @deprecated, will be removed in 5.0
+const formatLine = (...args) => {
+ console.warn(
+ 'helpers.formError.formatLine method is deprecated and will be removed in 5.0, please use helpers.formValidation.formatErrorLine instead.',
+ );
+
+ return formatErrorLine(...args);
+};
+
+export { formatLine };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/form.validation.helper.js b/src/bundle/Resources/public/js/scripts/helpers/form.validation.helper.js
index 7cfedc9457..aae1b04286 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/form.validation.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/form.validation.helper.js
@@ -1,52 +1,52 @@
-(function (global, doc, ibexa, Translator) {
- const formatErrorLine = (errorMessage) => {
- const errorIcon = ``;
- const container = document.createElement('em');
- const errorMessageNode = document.createTextNode(errorMessage);
-
- container.classList.add('ibexa-form-error__row');
- container.insertAdjacentHTML('beforeend', errorIcon);
- container.append(errorMessageNode);
-
- return container;
+import { getTranslator } from './context.helper';
+import { getIconPath } from './icon.helper';
+
+const formatErrorLine = (errorMessage) => {
+ const errorIcon = ``;
+ const container = document.createElement('em');
+ const errorMessageNode = document.createTextNode(errorMessage);
+
+ container.classList.add('ibexa-form-error__row');
+ container.insertAdjacentHTML('beforeend', errorIcon);
+ container.append(errorMessageNode);
+
+ return container;
+};
+const checkIsEmpty = (field) => {
+ let errorMessage = '';
+ const Translator = getTranslator();
+ const input = field.querySelector('.ibexa-input');
+ const label = field.querySelector('.ibexa-label');
+
+ if (label) {
+ const fieldName = label.innerText;
+
+ errorMessage = Translator.trans(/*@Desc("%fieldName% cannot be empty")*/ 'error.required.field', { fieldName }, 'forms');
+ } else {
+ errorMessage = Translator.trans(/*@Desc("This value should not be blank")*/ 'error.required.field_not_blank', {}, 'forms');
+ }
+
+ return {
+ isValid: input.value,
+ errorMessage,
};
- const checkIsEmpty = (field) => {
- let errorMessage = '';
- const input = field.querySelector('.ibexa-input');
- const label = field.querySelector('.ibexa-label');
-
- if (label) {
- const fieldName = label.innerText;
-
- errorMessage = Translator.trans(/*@Desc("%fieldName% cannot be empty")*/ 'error.required.field', { fieldName }, 'forms');
- } else {
- errorMessage = Translator.trans(/*@Desc("This value should not be blank")*/ 'error.required.field_not_blank', {}, 'forms');
- }
-
- return {
- isValid: input.value,
- errorMessage,
- };
- };
- const validateIsEmptyField = (field) => {
- const input = field.querySelector('.ibexa-input');
- const errorWrapper = field.querySelector('.ibexa-form-error');
- const validatorOutput = checkIsEmpty(field);
- const { isValid, errorMessage } = validatorOutput;
+};
+const validateIsEmptyField = (field) => {
+ const input = field.querySelector('.ibexa-input');
+ const errorWrapper = field.querySelector('.ibexa-form-error');
+ const validatorOutput = checkIsEmpty(field);
+ const { isValid, errorMessage } = validatorOutput;
- input.classList.toggle('is-invalid', !isValid);
- errorWrapper.innerText = '';
+ input.classList.toggle('is-invalid', !isValid);
+ errorWrapper.innerText = '';
- if (!isValid) {
- errorWrapper.append(formatErrorLine(errorMessage));
- }
+ if (!isValid) {
+ errorWrapper.append(formatErrorLine(errorMessage));
+ }
- return validatorOutput;
- };
- ibexa.addConfig('helpers.formValidation', {
- formatErrorLine,
- validateIsEmptyField,
- });
-})(window, window.document, window.ibexa, window.Translator);
+ return validatorOutput;
+};
+
+export { formatErrorLine, validateIsEmptyField };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/highlight.helper.js b/src/bundle/Resources/public/js/scripts/helpers/highlight.helper.js
index c3a11812cc..961dd0a8ea 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/highlight.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/highlight.helper.js
@@ -1,28 +1,25 @@
-(function (global, doc, ibexa) {
- const { escapeHTML } = ibexa.helpers.text;
- const highlightText = (searchText, string, template) => {
- const stringLowerCase = string.toLowerCase();
- const searchTextLowerCase = searchText.toLowerCase();
- const matches = stringLowerCase.matchAll(searchTextLowerCase);
- const stringArray = [];
- let previousIndex = 0;
+import { escapeHTML } from './text.helper';
- for (const match of matches) {
- const endOfSearchTextIndex = match.index + searchText.length;
- const renderedTemplate = template.replace('{{ highlightText }}', escapeHTML(string.slice(match.index, endOfSearchTextIndex)));
+const highlightText = (searchText, string, template) => {
+ const stringLowerCase = string.toLowerCase();
+ const searchTextLowerCase = searchText.toLowerCase();
+ const matches = stringLowerCase.matchAll(searchTextLowerCase);
+ const stringArray = [];
+ let previousIndex = 0;
- stringArray.push(escapeHTML(string.slice(previousIndex, match.index)));
- stringArray.push(renderedTemplate);
+ for (const match of matches) {
+ const endOfSearchTextIndex = match.index + searchText.length;
+ const renderedTemplate = template.replace('{{ highlightText }}', escapeHTML(string.slice(match.index, endOfSearchTextIndex)));
- previousIndex = match.index + searchText.length;
- }
+ stringArray.push(escapeHTML(string.slice(previousIndex, match.index)));
+ stringArray.push(renderedTemplate);
- stringArray.push(escapeHTML(string.slice(previousIndex)));
+ previousIndex = match.index + searchText.length;
+ }
- return stringArray.join('');
- };
+ stringArray.push(escapeHTML(string.slice(previousIndex)));
- ibexa.addConfig('helpers.highlight', {
- highlightText,
- });
-})(window, window.document, window.ibexa);
+ return stringArray.join('');
+};
+
+export { highlightText };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js b/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js
index 14e98289a9..9d7c000a3e 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js
@@ -1,11 +1,15 @@
-(function (global, doc, ibexa) {
- const getIconPath = (path, iconSet = ibexa.adminUiConfig.iconPaths.defaultIconSet) => {
- const iconSetPath = ibexa.adminUiConfig.iconPaths.iconSets[iconSet];
+import { getAdminUiConfig } from './context.helper';
- return `${iconSetPath}#${path}`;
- };
+const getIconPath = (path, iconSet) => {
+ const adminUiConfig = getAdminUiConfig();
- ibexa.addConfig('helpers.icon', {
- getIconPath,
- });
-})(window, window.document, window.ibexa);
+ if (!iconSet) {
+ iconSet = adminUiConfig.iconPaths.defaultIconSet;
+ }
+
+ const iconSetPath = adminUiConfig.iconPaths.iconSets[iconSet];
+
+ return `${iconSetPath}#${path}`;
+};
+
+export { getIconPath };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/location.helper.js b/src/bundle/Resources/public/js/scripts/helpers/location.helper.js
index b27e565dda..6898569789 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/location.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/location.helper.js
@@ -1,57 +1,59 @@
-(function (global, doc, ibexa, Translator) {
- const token = doc.querySelector('meta[name="CSRF-Token"]').content;
- const siteaccess = doc.querySelector('meta[name="SiteAccess"]').content;
- const removeRootFromPathString = (pathString) => {
- const pathArray = pathString.split('/').filter((id) => id);
+import { escapeHTML } from './text.helper';
+import { getJsonFromResponse, getRequestHeaders, getRequestMode } from './request.helper';
+import { showErrorNotification } from './notification.helper';
+import { getRestInfo, getTranslator } from './context.helper';
- return pathArray.splice(1, pathArray.length - 1);
- };
- const buildLocationsBreadcrumbs = (locations) =>
- locations.map((Location) => ibexa.helpers.text.escapeHTML(Location.ContentInfo.Content.TranslatedName)).join(' / ');
- const findLocationsByIds = (idList, callback) => {
- const body = JSON.stringify({
- ViewInput: {
- identifier: `locations-by-path-string-${idList.join('-')}`,
- public: false,
- LocationQuery: {
- FacetBuilders: {},
- SortClauses: { SectionIdentifier: 'ascending' },
- Filter: { LocationIdCriterion: idList.join(',') },
- limit: 50,
- offset: 0,
- },
+const removeRootFromPathString = (pathString) => {
+ const pathArray = pathString.split('/').filter((id) => id);
+
+ return pathArray.splice(1, pathArray.length - 1);
+};
+const buildLocationsBreadcrumbs = (locations) =>
+ locations.map((Location) => escapeHTML(Location.ContentInfo.Content.TranslatedName)).join(' / ');
+const findLocationsByIds = (idList, callback) => {
+ const { token, siteaccess, accessToken, instanceUrl } = getRestInfo();
+ const Translator = getTranslator();
+ const body = JSON.stringify({
+ ViewInput: {
+ identifier: `locations-by-path-string-${idList.join('-')}`,
+ public: false,
+ LocationQuery: {
+ FacetBuilders: {},
+ SortClauses: { SectionIdentifier: 'ascending' },
+ Filter: { LocationIdCriterion: idList.join(',') },
+ limit: 50,
+ offset: 0,
},
- });
- const request = new Request('/api/ibexa/v2/views', {
- method: 'POST',
- headers: {
+ },
+ });
+ const request = new Request(`${instanceUrl}/api/ibexa/v2/views`, {
+ method: 'POST',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
Accept: 'application/vnd.ibexa.api.View+json; version=1.1',
'Content-Type': 'application/vnd.ibexa.api.ViewInput+json; version=1.1',
'X-Requested-With': 'XMLHttpRequest',
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
},
- body,
- mode: 'same-origin',
- credentials: 'same-origin',
- });
- const errorMessage = Translator.trans(
- /*@Desc("Cannot find children Locations with ID %idList%")*/ 'select_location.error',
- { idList: idList.join(',') },
- 'ibexa_universal_discovery_widget',
- );
+ }),
+ body,
+ mode: getRequestMode({ instanceUrl }),
+ credentials: 'same-origin',
+ });
+ const errorMessage = Translator.trans(
+ /*@Desc("Cannot find children Locations with ID %idList%")*/ 'select_location.error',
+ { idList: idList.join(',') },
+ 'ibexa_universal_discovery_widget',
+ );
- fetch(request)
- .then(ibexa.helpers.request.getJsonFromResponse)
- .then((viewData) => viewData.View.Result.searchHits.searchHit)
- .then((searchHits) => searchHits.map((searchHit) => searchHit.value.Location))
- .then(callback)
- .catch(() => ibexa.helpers.notification.showErrorNotification(errorMessage));
- };
+ fetch(request)
+ .then(getJsonFromResponse)
+ .then((viewData) => viewData.View.Result.searchHits.searchHit)
+ .then((searchHits) => searchHits.map((searchHit) => searchHit.value.Location))
+ .then(callback)
+ .catch(() => showErrorNotification(errorMessage));
+};
- ibexa.addConfig('helpers.location', {
- removeRootFromPathString,
- findLocationsByIds,
- buildLocationsBreadcrumbs,
- });
-})(window, window.document, window.ibexa, window.Translator);
+export { removeRootFromPathString, findLocationsByIds, buildLocationsBreadcrumbs };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/middle.ellipsis.js b/src/bundle/Resources/public/js/scripts/helpers/middle.ellipsis.js
index 248238284b..43e53abb4b 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/middle.ellipsis.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/middle.ellipsis.js
@@ -1,58 +1,56 @@
-(function (global, doc, ibexa) {
- const resizeEllipsisObserver = new ResizeObserver((entries) => {
- entries.forEach((entry) => {
- parse(entry.target);
- });
+import { parse as parseTooltips } from './tooltips.helper';
+import { escapeHTML } from './text.helper';
+
+const { document: doc } = window;
+const resizeEllipsisObserver = new ResizeObserver((entries) => {
+ entries.forEach((entry) => {
+ parse(entry.target);
});
- const parse = (baseElement = doc) => {
- const isHTMLElement = baseElement instanceof Element || baseElement instanceof Document;
+});
+const parse = (baseElement = doc) => {
+ const isHTMLElement = baseElement instanceof Element || baseElement instanceof Document;
- if (!isHTMLElement) {
- console.warn('Provided element does not belong to Document interface');
+ if (!isHTMLElement) {
+ console.warn('Provided element does not belong to Document interface');
- return;
- }
+ return;
+ }
+
+ const middleEllipsisContainers = [...baseElement.querySelectorAll('.ibexa-middle-ellipsis')];
+
+ if (baseElement instanceof Element && baseElement.classList.contains('ibexa-middle-ellipsis')) {
+ middleEllipsisContainers.push(baseElement);
+ }
- const middleEllipsisContainers = [...baseElement.querySelectorAll('.ibexa-middle-ellipsis')];
+ middleEllipsisContainers.forEach((middleEllipsisContainer) => {
+ const partStart = middleEllipsisContainer.querySelector('.ibexa-middle-ellipsis__name--start');
+ const isEllipsized = partStart.scrollWidth > partStart.offsetWidth;
- if (baseElement instanceof Element && baseElement.classList.contains('ibexa-middle-ellipsis')) {
- middleEllipsisContainers.push(baseElement);
+ if (!isEllipsized) {
+ middleEllipsisContainer.dataset.bsOriginalTitle = '';
+ } else {
+ const partStartContentNode = partStart.querySelector('.ibexa-middle-ellipsis__name-ellipsized');
+
+ middleEllipsisContainer.dataset.bsOriginalTitle = partStartContentNode.innerHTML;
}
- middleEllipsisContainers.forEach((middleEllipsisContainer) => {
- const partStart = middleEllipsisContainer.querySelector('.ibexa-middle-ellipsis__name--start');
- const isEllipsized = partStart.scrollWidth > partStart.offsetWidth;
-
- if (!isEllipsized) {
- middleEllipsisContainer.dataset.bsOriginalTitle = '';
- } else {
- const partStartContentNode = partStart.querySelector('.ibexa-middle-ellipsis__name-ellipsized');
-
- middleEllipsisContainer.dataset.bsOriginalTitle = partStartContentNode.innerHTML;
- }
-
- middleEllipsisContainer.classList.toggle('ibexa-middle-ellipsis--ellipsized', isEllipsized);
- ibexa.helpers.tooltips.parse(middleEllipsisContainer);
-
- resizeEllipsisObserver.observe(middleEllipsisContainer);
- });
- };
- // @deprecated, will be removed in 5.0
- const parseAll = () => parse(doc);
- const update = (baseElement, content) => {
- const contentElements = [...baseElement.querySelectorAll('.ibexa-middle-ellipsis__name-ellipsized')];
- const contentEscaped = ibexa.helpers.text.escapeHTML(content);
-
- baseElement.dataset.bsOriginalTitle = contentEscaped;
- contentElements.forEach((contentElement) => {
- contentElement.innerHTML = contentEscaped;
- });
- parse(baseElement);
- };
-
- ibexa.addConfig('helpers.ellipsis.middle', {
- parse,
- parseAll,
- update,
+ middleEllipsisContainer.classList.toggle('ibexa-middle-ellipsis--ellipsized', isEllipsized);
+ parseTooltips(middleEllipsisContainer);
+
+ resizeEllipsisObserver.observe(middleEllipsisContainer);
});
-})(window, window.document, window.ibexa);
+};
+// @deprecated, will be removed in 5.0
+const parseAll = () => parse(doc);
+const update = (baseElement, content) => {
+ const contentElements = [...baseElement.querySelectorAll('.ibexa-middle-ellipsis__name-ellipsized')];
+ const contentEscaped = escapeHTML(content);
+
+ baseElement.dataset.bsOriginalTitle = contentEscaped;
+ contentElements.forEach((contentElement) => {
+ contentElement.innerHTML = contentEscaped;
+ });
+ parse(baseElement);
+};
+
+export { parse, parseAll, update };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/notification.helper.js b/src/bundle/Resources/public/js/scripts/helpers/notification.helper.js
index 48d3351edc..fbaee33f5a 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/notification.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/notification.helper.js
@@ -1,98 +1,92 @@
-(function (global, doc, ibexa) {
- const NOTIFICATION_INFO_LABEL = 'info';
- const NOTIFICATION_SUCCESS_LABEL = 'success';
- const NOTIFICATION_WARNING_LABEL = 'warning';
- const NOTIFICATION_ERROR_LABEL = 'error';
+const { document: doc } = window;
- /**
- * Dispatches notification event
- *
- * @function showNotification
- * @param {Object} detail
- * @param {String} detail.message
- * @param {String} detail.label
- * @param {Function} [detail.onShow] to be called after notification Node was added
- * @param {Object} detail.rawPlaceholdersMap
- */
- const showNotification = (detail) => {
- const event = new CustomEvent('ibexa-notify', { detail });
+const NOTIFICATION_INFO_LABEL = 'info';
+const NOTIFICATION_SUCCESS_LABEL = 'success';
+const NOTIFICATION_WARNING_LABEL = 'warning';
+const NOTIFICATION_ERROR_LABEL = 'error';
- doc.body.dispatchEvent(event);
- };
+/**
+ * Dispatches notification event
+ *
+ * @function showNotification
+ * @param {Object} detail
+ * @param {String} detail.message
+ * @param {String} detail.label
+ * @param {Function} [detail.onShow] to be called after notification Node was added
+ * @param {Object} detail.rawPlaceholdersMap
+ */
+const showNotification = (detail) => {
+ const event = new CustomEvent('ibexa-notify', { detail });
- /**
- * Dispatches info notification event
- *
- * @function showInfoNotification
- * @param {String} message
- * @param {Function} [onShow] to be called after notification Node was added
- * @param {Object} rawPlaceholdersMap
- */
- const showInfoNotification = (message, onShow, rawPlaceholdersMap = {}) =>
- showNotification({
- message,
- label: NOTIFICATION_INFO_LABEL,
- onShow,
- rawPlaceholdersMap,
- });
+ doc.body.dispatchEvent(event);
+};
- /**
- * Dispatches success notification event
- *
- * @function showSuccessNotification
- * @param {String} message
- * @param {Function} [onShow] to be called after notification Node was added
- * @param {Object} rawPlaceholdersMap
- */
- const showSuccessNotification = (message, onShow, rawPlaceholdersMap = {}) =>
- showNotification({
- message,
- label: NOTIFICATION_SUCCESS_LABEL,
- onShow,
- rawPlaceholdersMap,
- });
+/**
+ * Dispatches info notification event
+ *
+ * @function showInfoNotification
+ * @param {String} message
+ * @param {Function} [onShow] to be called after notification Node was added
+ * @param {Object} rawPlaceholdersMap
+ */
+const showInfoNotification = (message, onShow, rawPlaceholdersMap = {}) =>
+ showNotification({
+ message,
+ label: NOTIFICATION_INFO_LABEL,
+ onShow,
+ rawPlaceholdersMap,
+ });
- /**
- * Dispatches warning notification event
- *
- * @function showWarningNotification
- * @param {String} message
- * @param {Function} [onShow] to be called after notification Node was added
- * @param {Object} rawPlaceholdersMap
- */
- const showWarningNotification = (message, onShow, rawPlaceholdersMap = {}) =>
- showNotification({
- message,
- label: NOTIFICATION_WARNING_LABEL,
- onShow,
- rawPlaceholdersMap,
- });
+/**
+ * Dispatches success notification event
+ *
+ * @function showSuccessNotification
+ * @param {String} message
+ * @param {Function} [onShow] to be called after notification Node was added
+ * @param {Object} rawPlaceholdersMap
+ */
+const showSuccessNotification = (message, onShow, rawPlaceholdersMap = {}) =>
+ showNotification({
+ message,
+ label: NOTIFICATION_SUCCESS_LABEL,
+ onShow,
+ rawPlaceholdersMap,
+ });
- /**
- * Dispatches error notification event
- *
- * @function showErrorNotification
- * @param {(string | Error)} error
- * @param {Function} [onShow] to be called after notification Node was added
- * @param {Object} rawPlaceholdersMap
- */
- const showErrorNotification = (error, onShow, rawPlaceholdersMap = {}) => {
- const isErrorObj = error instanceof Error;
- const message = isErrorObj ? error.message : error;
+/**
+ * Dispatches warning notification event
+ *
+ * @function showWarningNotification
+ * @param {String} message
+ * @param {Function} [onShow] to be called after notification Node was added
+ * @param {Object} rawPlaceholdersMap
+ */
+const showWarningNotification = (message, onShow, rawPlaceholdersMap = {}) =>
+ showNotification({
+ message,
+ label: NOTIFICATION_WARNING_LABEL,
+ onShow,
+ rawPlaceholdersMap,
+ });
- showNotification({
- message,
- label: NOTIFICATION_ERROR_LABEL,
- onShow,
- rawPlaceholdersMap,
- });
- };
+/**
+ * Dispatches error notification event
+ *
+ * @function showErrorNotification
+ * @param {(string | Error)} error
+ * @param {Function} [onShow] to be called after notification Node was added
+ * @param {Object} rawPlaceholdersMap
+ */
+const showErrorNotification = (error, onShow, rawPlaceholdersMap = {}) => {
+ const isErrorObj = error instanceof Error;
+ const message = isErrorObj ? error.message : error;
- ibexa.addConfig('helpers.notification', {
- showNotification,
- showInfoNotification,
- showSuccessNotification,
- showWarningNotification,
- showErrorNotification,
+ showNotification({
+ message,
+ label: NOTIFICATION_ERROR_LABEL,
+ onShow,
+ rawPlaceholdersMap,
});
-})(window, window.document, window.ibexa);
+};
+
+export { showNotification, showInfoNotification, showSuccessNotification, showWarningNotification, showErrorNotification };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/object.instances.js b/src/bundle/Resources/public/js/scripts/helpers/object.instances.js
index f5dfb49fb7..05f8632c21 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/object.instances.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/object.instances.js
@@ -1,21 +1,15 @@
-(function (global, doc, ibexa) {
- const setInstance = (domElement, instance) => {
- if (domElement.ibexaInstance) {
- throw new Error('Instance for this DOM element already exists!');
- }
+const setInstance = (domElement, instance) => {
+ if (domElement.ibexaInstance) {
+ throw new Error('Instance for this DOM element already exists!');
+ }
- domElement.ibexaInstance = instance;
- };
- const getInstance = (domElement) => {
- return domElement.ibexaInstance;
- };
- const clearInstance = (domElement) => {
- delete domElement.ibexaInstance;
- };
+ domElement.ibexaInstance = instance;
+};
+const getInstance = (domElement) => {
+ return domElement.ibexaInstance;
+};
+const clearInstance = (domElement) => {
+ delete domElement.ibexaInstance;
+};
- ibexa.addConfig('helpers.objectInstances', {
- setInstance,
- getInstance,
- clearInstance,
- });
-})(window, window.document, window.ibexa);
+export { setInstance, getInstance, clearInstance };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/pagination.helper.js b/src/bundle/Resources/public/js/scripts/helpers/pagination.helper.js
index de49ca2c4a..cb3e78de2d 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/pagination.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/pagination.helper.js
@@ -1,41 +1,37 @@
-(function (global, doc, ibexa) {
- /**
- * Computes array with pagination pages.
- *
- * Example 1: [ 1, "...", 5, 6, 7, 8, 9, 10 ] (for: proximity = 2; pagesNumber = 10; activePageIndex = 7)
- * Example 2: [ 1, "...", 3, 4, 5, 6, 7, "...", 10 ] (for: proximity = 2; pagesNumber = 10; activePageIndex = 5)
- * Example 3: [ 1, "...", 8, 9, 10, 11, 12, "...", 20 ] (for: proximity = 2; pagesNumber = 20; activePageIndex = 10)
- *
- * @param {Object} params
- * @param {Number} params.proximity
- * @param {Number} params.activePageIndex
- * @param {Number} params.pagesCount
- * @param {String} params.separator
- *
- * @returns {Array}
- */
- const computePages = ({ proximity = 2, activePageIndex, pagesCount, separator = '...' }) => {
- const pages = [];
- let wasSeparator = false;
+/**
+ * Computes array with pagination pages.
+ *
+ * Example 1: [ 1, "...", 5, 6, 7, 8, 9, 10 ] (for: proximity = 2; pagesNumber = 10; activePageIndex = 7)
+ * Example 2: [ 1, "...", 3, 4, 5, 6, 7, "...", 10 ] (for: proximity = 2; pagesNumber = 10; activePageIndex = 5)
+ * Example 3: [ 1, "...", 8, 9, 10, 11, 12, "...", 20 ] (for: proximity = 2; pagesNumber = 20; activePageIndex = 10)
+ *
+ * @param {Object} params
+ * @param {Number} params.proximity
+ * @param {Number} params.activePageIndex
+ * @param {Number} params.pagesCount
+ * @param {String} params.separator
+ *
+ * @returns {Array}
+ */
+const computePages = ({ proximity = 2, activePageIndex, pagesCount, separator = '...' }) => {
+ const pages = [];
+ let wasSeparator = false;
- for (let i = 1; i <= pagesCount; i++) {
- const isFirstPage = i === 1;
- const isLastPage = i === pagesCount;
- const isInRange = i >= activePageIndex + 1 - proximity && i <= activePageIndex + 1 + proximity;
+ for (let i = 1; i <= pagesCount; i++) {
+ const isFirstPage = i === 1;
+ const isLastPage = i === pagesCount;
+ const isInRange = i >= activePageIndex + 1 - proximity && i <= activePageIndex + 1 + proximity;
- if (isFirstPage || isLastPage || isInRange) {
- pages.push(i);
- wasSeparator = false;
- } else if (!wasSeparator) {
- pages.push(separator);
- wasSeparator = true;
- }
+ if (isFirstPage || isLastPage || isInRange) {
+ pages.push(i);
+ wasSeparator = false;
+ } else if (!wasSeparator) {
+ pages.push(separator);
+ wasSeparator = true;
}
+ }
- return pages;
- };
+ return pages;
+};
- ibexa.addConfig('helpers.pagination', {
- computePages,
- });
-})(window, window.document, window.ibexa);
+export { computePages };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/request.helper.js b/src/bundle/Resources/public/js/scripts/helpers/request.helper.js
index a3d4714ec6..ea378f2d86 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/request.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/request.helper.js
@@ -1,55 +1,41 @@
-(function (global, doc, ibexa) {
- /**
- * Handles request error
- *
- * @function handleRequest
- * @param {Response} response
- * @returns {Error|Response}
- */
- const handleRequest = (response) => {
- if (!response.ok) {
- throw Error(response.statusText);
- }
-
- return response;
- };
+const handleRequest = (response) => {
+ if (!response.ok) {
+ throw Error(response.statusText);
+ }
- /**
- * Handles request JSON response
- *
- * @function getJsonFromResponse
- * @param {Response} response
- * @returns {Error|Promise}
- */
- const getJsonFromResponse = (response) => {
- return handleRequest(response).json();
- };
+ return response;
+};
- /**
- * Handles request text response
- *
- * @function getTextFromResponse
- * @param {Response} response
- * @returns {Error|Promise}
- */
- const getTextFromResponse = (response) => {
- return handleRequest(response).text();
- };
+const getJsonFromResponse = (response) => {
+ return handleRequest(response).json();
+};
+
+const getTextFromResponse = (response) => {
+ return handleRequest(response).text();
+};
+
+const getStatusFromResponse = (response) => {
+ return handleRequest(response).status;
+};
+
+const getRequestMode = ({ instanceUrl }) => {
+ return window.location.origin === instanceUrl ? 'same-origin' : 'cors';
+};
+
+const getRequestHeaders = ({ token, siteaccess, accessToken, extraHeaders }) => {
+ if (accessToken) {
+ return {
+ Authorization: `Bearer ${accessToken}`,
+ ...(siteaccess && { 'X-Siteaccess': siteaccess }),
+ ...extraHeaders,
+ };
+ }
- /**
- * Handles request response; returns status if response is OK
- *
- * @function getStatusFromResponse
- * @param {Response} response
- * @returns {Error|Promise}
- */
- const getStatusFromResponse = (response) => {
- return handleRequest(response).status;
+ return {
+ ...(token && { 'X-CSRF-Token': token }),
+ ...(siteaccess && { 'X-Siteaccess': siteaccess }),
+ ...extraHeaders,
};
+};
- ibexa.addConfig('helpers.request', {
- getJsonFromResponse,
- getTextFromResponse,
- getStatusFromResponse,
- });
-})(window, window.document, window.ibexa);
+export { getJsonFromResponse, getTextFromResponse, getStatusFromResponse, getRequestMode, getRequestHeaders };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/system.helper.js b/src/bundle/Resources/public/js/scripts/helpers/system.helper.js
index 3fc127ba5e..1b362f7559 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/system.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/system.helper.js
@@ -1,79 +1,77 @@
-(function (global, doc, ibexa) {
- const { userAgent } = window.navigator;
- const isWindows = () => {
- return userAgent.includes('Windows');
- };
- const isMac = () => {
- return userAgent.includes('Mac OS X');
- };
- const isLinux = () => {
- return userAgent.includes('Linux');
- };
- const isShortcutWithLetter = (event, letter) => {
- if (isMac()) {
- return event.metaKey && event.key === letter;
- }
+const { userAgent } = window.navigator;
+const isWindows = () => {
+ return userAgent.includes('Windows');
+};
+const isMac = () => {
+ return userAgent.includes('Mac OS X');
+};
+const isLinux = () => {
+ return userAgent.includes('Linux');
+};
+const isShortcutWithLetter = (event, letter) => {
+ if (isMac()) {
+ return event.metaKey && event.key === letter;
+ }
- if (isWindows() || isLinux()) {
- return event.ctrlKey && event.key === letter;
- }
+ if (isWindows() || isLinux()) {
+ return event.ctrlKey && event.key === letter;
+ }
- return false;
- };
- const isUndoPressed = (event) => {
- if (isMac()) {
- return event.metaKey && !event.shiftKey && event.key === 'z';
- }
+ return false;
+};
+const isUndoPressed = (event) => {
+ if (isMac()) {
+ return event.metaKey && !event.shiftKey && event.key === 'z';
+ }
- if (isWindows() || isLinux()) {
- return event.ctrlKey && event.key === 'z';
- }
+ if (isWindows() || isLinux()) {
+ return event.ctrlKey && event.key === 'z';
+ }
- return false;
- };
+ return false;
+};
- const isRedoPressed = (event) => {
- if (isMac()) {
- return event.metaKey && event.shiftKey && event.key === 'z';
- }
+const isRedoPressed = (event) => {
+ if (isMac()) {
+ return event.metaKey && event.shiftKey && event.key === 'z';
+ }
- if (isWindows() || isLinux()) {
- return event.ctrlKey && event.key === 'y';
- }
+ if (isWindows() || isLinux()) {
+ return event.ctrlKey && event.key === 'y';
+ }
- return false;
- };
- const isSavePressed = (event) => {
- return isShortcutWithLetter(event, 's');
- };
- const isCopyPressed = (event) => {
- return isShortcutWithLetter(event, 'c');
- };
- const isCutPressed = (event) => {
- return isShortcutWithLetter(event, 'x');
- };
- const isPastePressed = (event) => {
- return isShortcutWithLetter(event, 'v');
- };
- const isPrintPressed = (event) => {
- return isShortcutWithLetter(event, 'p');
- };
- const isSelectAllPressed = (event) => {
- return isShortcutWithLetter(event, 'a');
- };
+ return false;
+};
+const isSavePressed = (event) => {
+ return isShortcutWithLetter(event, 's');
+};
+const isCopyPressed = (event) => {
+ return isShortcutWithLetter(event, 'c');
+};
+const isCutPressed = (event) => {
+ return isShortcutWithLetter(event, 'x');
+};
+const isPastePressed = (event) => {
+ return isShortcutWithLetter(event, 'v');
+};
+const isPrintPressed = (event) => {
+ return isShortcutWithLetter(event, 'p');
+};
+const isSelectAllPressed = (event) => {
+ return isShortcutWithLetter(event, 'a');
+};
- ibexa.addConfig('helpers.system', {
- isWindows: isWindows(),
- isMac: isMac(),
- isLinux: isLinux(),
- isUndoPressed,
- isRedoPressed,
- isSavePressed,
- isCopyPressed,
- isCutPressed,
- isPastePressed,
- isPrintPressed,
- isSelectAllPressed,
- isShortcutWithLetter,
- });
-})(window, window.document, window.ibexa);
+export {
+ isWindows,
+ isMac,
+ isLinux,
+ isUndoPressed,
+ isRedoPressed,
+ isSavePressed,
+ isCopyPressed,
+ isCutPressed,
+ isPastePressed,
+ isPrintPressed,
+ isSelectAllPressed,
+ isShortcutWithLetter,
+};
diff --git a/src/bundle/Resources/public/js/scripts/helpers/table.helper.js b/src/bundle/Resources/public/js/scripts/helpers/table.helper.js
index 2545b91436..cd3f01041c 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/table.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/table.helper.js
@@ -1,18 +1,16 @@
-(function (global, doc, ibexa) {
- const onChangeHandler = (activeClass, event) => {
- const { checked } = event.target;
- const action = checked ? 'add' : 'remove';
- const parentRow = event.target.closest('tr');
+const { document: doc } = window;
- parentRow.classList[action](activeClass);
- };
- const parseCheckbox = (checkboxSelector, activeClass) => {
- doc.querySelectorAll(checkboxSelector).forEach((checkboxNode) => {
- checkboxNode.addEventListener('change', onChangeHandler.bind(this, activeClass), false);
- });
- };
+const onChangeHandler = (activeClass, event) => {
+ const { checked } = event.target;
+ const action = checked ? 'add' : 'remove';
+ const parentRow = event.target.closest('tr');
- ibexa.addConfig('helpers.table', {
- parseCheckbox,
+ parentRow.classList[action](activeClass);
+};
+const parseCheckbox = (checkboxSelector, activeClass) => {
+ doc.querySelectorAll(checkboxSelector).forEach((checkboxNode) => {
+ checkboxNode.addEventListener('change', onChangeHandler.bind(this, activeClass), false);
});
-})(window, window.document, window.ibexa);
+};
+
+export { parseCheckbox };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/tag.view.select.helper.js b/src/bundle/Resources/public/js/scripts/helpers/tag.view.select.helper.js
index e294c13060..924bbc7bda 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/tag.view.select.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/tag.view.select.helper.js
@@ -1,23 +1,19 @@
-(function (global, doc, ibexa) {
- const buildItemsFromUDWResponse = (udwItems, getId, callback) => {
- const { removeRootFromPathString, findLocationsByIds, buildLocationsBreadcrumbs } = window.ibexa.helpers.location;
+import { removeRootFromPathString, findLocationsByIds, buildLocationsBreadcrumbs } from './location.helper';
- Promise.all(
- udwItems.map(
- (item) =>
- new Promise((resolve) => {
- findLocationsByIds(removeRootFromPathString(item.pathString), (locations) => {
- resolve({
- id: getId(item),
- name: buildLocationsBreadcrumbs(locations),
- });
+const buildItemsFromUDWResponse = (udwItems, getId, callback) => {
+ Promise.all(
+ udwItems.map(
+ (item) =>
+ new Promise((resolve) => {
+ findLocationsByIds(removeRootFromPathString(item.pathString), (locations) => {
+ resolve({
+ id: getId(item),
+ name: buildLocationsBreadcrumbs(locations),
});
- }),
- ),
- ).then(callback);
- };
+ });
+ }),
+ ),
+ ).then(callback);
+};
- ibexa.addConfig('helpers.tagViewSelect', {
- buildItemsFromUDWResponse,
- });
-})(window, window.document, window.ibexa);
+export { buildItemsFromUDWResponse };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js
index 4a42f9b113..1775fa510f 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/text.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/text.helper.js
@@ -1,13 +1,11 @@
-(function (global, doc, ibexa) {
- const escapeHTML = (string) => {
- const stringTempNode = doc.createElement('div');
+const { document: doc } = window;
- stringTempNode.appendChild(doc.createTextNode(string));
+const escapeHTML = (string) => {
+ const stringTempNode = doc.createElement('div');
- return stringTempNode.innerHTML;
- };
+ stringTempNode.appendChild(doc.createTextNode(string));
- ibexa.addConfig('helpers.text', {
- escapeHTML,
- });
-})(window, window.document, window.ibexa);
+ return stringTempNode.innerHTML;
+};
+
+export { escapeHTML };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/timezone.helper.js b/src/bundle/Resources/public/js/scripts/helpers/timezone.helper.js
index 5272f5c053..b2f8f6f039 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/timezone.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/timezone.helper.js
@@ -1,32 +1,27 @@
-(function (global, doc, ibexa, moment) {
- const userPreferredTimezone = ibexa.adminUiConfig.timezone;
- const userPreferredFullDateTimeFormat = ibexa.adminUiConfig.dateFormat.fullDateTime;
- const userPreferredShortDateTimeFormat = ibexa.adminUiConfig.dateFormat.shortDateTime;
+import { getAdminUiConfig, getMoment } from './context.helper';
- const convertDateToTimezone = (date, timezone = userPreferredTimezone, forceSameTime = false) => {
- return moment(date).tz(timezone, forceSameTime);
- };
- const formatDate = (date, timezone = null, format) => {
- if (timezone) {
- date = convertDateToTimezone(date, timezone);
- }
+const convertDateToTimezone = (date, timezone = getAdminUiConfig().timezone, forceSameTime = false) => {
+ const moment = getMoment();
- return moment(date).formatICU(format);
- };
- const formatFullDateTime = (date, timezone = userPreferredTimezone, format = userPreferredFullDateTimeFormat) => {
- return formatDate(date, timezone, format);
- };
- const formatShortDateTime = (date, timezone = userPreferredTimezone, format = userPreferredShortDateTimeFormat) => {
- return formatDate(date, timezone, format);
- };
- const getBrowserTimezone = () => {
- return Intl.DateTimeFormat().resolvedOptions().timeZone;
- };
+ return moment(date).tz(timezone, forceSameTime);
+};
+const formatDate = (date, timezone = null, format) => {
+ if (timezone) {
+ date = convertDateToTimezone(date, timezone);
+ }
- ibexa.addConfig('helpers.timezone', {
- convertDateToTimezone,
- formatFullDateTime,
- formatShortDateTime,
- getBrowserTimezone,
- });
-})(window, window.document, window.ibexa, window.moment);
+ const moment = getMoment();
+
+ return moment(date).formatICU(format);
+};
+const formatFullDateTime = (date, timezone = getAdminUiConfig().timezone, format = getAdminUiConfig().dateFormat.fullDateTime) => {
+ return formatDate(date, timezone, format);
+};
+const formatShortDateTime = (date, timezone = getAdminUiConfig().timezone, format = getAdminUiConfig().dateFormat.shortDateTime) => {
+ return formatDate(date, timezone, format);
+};
+const getBrowserTimezone = () => {
+ return Intl.DateTimeFormat().resolvedOptions().timeZone;
+};
+
+export { convertDateToTimezone, formatFullDateTime, formatShortDateTime, getBrowserTimezone };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper.js b/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper.js
index 32cd2bf521..b17a1d1168 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper.js
@@ -1,222 +1,222 @@
-(function (global, doc, ibexa, bootstrap) {
- let lastInsertTooltipTarget = null;
- const TOOLTIPS_SELECTOR = '[title], [data-tooltip-title]';
- const observerConfig = {
- childList: true,
- subtree: true,
- };
- const resizeEllipsisObserver = new ResizeObserver((entries) => {
- entries.forEach((entry) => {
- ibexa.helpers.tooltips.parse(entry.target);
- });
- });
- const observer = new MutationObserver((mutationsList) => {
- if (lastInsertTooltipTarget) {
- mutationsList.forEach((mutation) => {
- const { addedNodes, removedNodes } = mutation;
-
- if (addedNodes.length) {
- addedNodes.forEach((addedNode) => {
- if (addedNode instanceof Element) {
- parse(addedNode);
- }
- });
- }
-
- if (removedNodes.length) {
- removedNodes.forEach((removedNode) => {
- if (removedNode.classList && !removedNode.classList.contains('ibexa-tooltip')) {
- lastInsertTooltipTarget = null;
- doc.querySelectorAll('.ibexa-tooltip.show').forEach((tooltipNode) => {
- tooltipNode.remove();
- });
- }
- });
- }
- });
- }
+import { getBootstrap } from './context.helper';
+
+const { document: doc } = window;
+
+let lastInsertTooltipTarget = null;
+const TOOLTIPS_SELECTOR = '[title], [data-tooltip-title]';
+const observerConfig = {
+ childList: true,
+ subtree: true,
+};
+const resizeEllipsisObserver = new ResizeObserver((entries) => {
+ entries.forEach((entry) => {
+ parse(entry.target);
});
- const modifyPopperConfig = (iframe, defaultBsPopperConfig) => {
- if (!iframe) {
- return defaultBsPopperConfig;
- }
-
- const iframeDOMRect = iframe.getBoundingClientRect();
- const offsetX = iframeDOMRect.x;
- const offsetY = iframeDOMRect.y;
- const offsetModifier = {
- name: 'offset',
- options: {
- offset: ({ placement }) => {
- const [basePlacement] = placement.split('-');
-
- switch (basePlacement) {
- case 'top':
- return [offsetX, -offsetY];
- case 'bottom':
- return [offsetX, offsetY];
- case 'right':
- return [offsetY, offsetX];
- case 'left':
- return [offsetY, -offsetX];
- default:
- return [];
+});
+const observer = new MutationObserver((mutationsList) => {
+ if (lastInsertTooltipTarget) {
+ mutationsList.forEach((mutation) => {
+ const { addedNodes, removedNodes } = mutation;
+
+ if (addedNodes.length) {
+ addedNodes.forEach((addedNode) => {
+ if (addedNode instanceof Element) {
+ parse(addedNode);
}
- },
- },
- };
- const offsetModifierIndex = defaultBsPopperConfig.modifiers.findIndex((modifier) => modifier.name == 'offset');
-
- if (offsetModifierIndex != -1) {
- defaultBsPopperConfig.modifiers[offsetModifierIndex] = offsetModifier;
- } else {
- defaultBsPopperConfig.modifiers.push(offsetModifier);
- }
+ });
+ }
+ if (removedNodes.length) {
+ removedNodes.forEach((removedNode) => {
+ if (removedNode.classList && !removedNode.classList.contains('ibexa-tooltip')) {
+ lastInsertTooltipTarget = null;
+ doc.querySelectorAll('.ibexa-tooltip.show').forEach((tooltipNode) => {
+ tooltipNode.remove();
+ });
+ }
+ });
+ }
+ });
+ }
+});
+const modifyPopperConfig = (iframe, defaultBsPopperConfig) => {
+ if (!iframe) {
return defaultBsPopperConfig;
+ }
+
+ const iframeDOMRect = iframe.getBoundingClientRect();
+ const offsetX = iframeDOMRect.x;
+ const offsetY = iframeDOMRect.y;
+ const offsetModifier = {
+ name: 'offset',
+ options: {
+ offset: ({ placement }) => {
+ const [basePlacement] = placement.split('-');
+
+ switch (basePlacement) {
+ case 'top':
+ return [offsetX, -offsetY];
+ case 'bottom':
+ return [offsetX, offsetY];
+ case 'right':
+ return [offsetY, offsetX];
+ case 'left':
+ return [offsetY, -offsetX];
+ default:
+ return [];
+ }
+ },
+ },
};
- const getTextHeight = (text, styles) => {
- const tag = doc.createElement('div');
-
- tag.innerHTML = text;
-
- for (const key in styles) {
- tag.style[key] = styles[key];
- }
-
- doc.body.appendChild(tag);
-
- const { height: texHeight } = tag.getBoundingClientRect();
-
- doc.body.removeChild(tag);
-
- return texHeight;
- };
- const isTitleEllipsized = (node) => {
- const title = node.dataset.originalTitle;
- const { width: nodeWidth, height: nodeHeight } = node.getBoundingClientRect();
- const computedNodeStyles = getComputedStyle(node);
- const styles = {
- width: `${nodeWidth}px`,
- padding: computedNodeStyles.getPropertyValue('padding'),
- 'font-size': computedNodeStyles.getPropertyValue('font-size'),
- 'font-family': computedNodeStyles.getPropertyValue('font-family'),
- 'font-weight': computedNodeStyles.getPropertyValue('font-weight'),
- 'font-style': computedNodeStyles.getPropertyValue('font-style'),
- 'font-variant': computedNodeStyles.getPropertyValue('font-variant'),
- 'line-height': computedNodeStyles.getPropertyValue('line-height'),
- 'word-break': 'break-all',
- };
-
- const textHeight = getTextHeight(title, styles);
-
- return textHeight > nodeHeight;
+ const offsetModifierIndex = defaultBsPopperConfig.modifiers.findIndex((modifier) => modifier.name == 'offset');
+
+ if (offsetModifierIndex != -1) {
+ defaultBsPopperConfig.modifiers[offsetModifierIndex] = offsetModifier;
+ } else {
+ defaultBsPopperConfig.modifiers.push(offsetModifier);
+ }
+
+ return defaultBsPopperConfig;
+};
+const getTextHeight = (text, styles) => {
+ const tag = doc.createElement('div');
+
+ tag.innerHTML = text;
+
+ for (const key in styles) {
+ tag.style[key] = styles[key];
+ }
+
+ doc.body.appendChild(tag);
+
+ const { height: texHeight } = tag.getBoundingClientRect();
+
+ doc.body.removeChild(tag);
+
+ return texHeight;
+};
+const isTitleEllipsized = (node) => {
+ const title = node.dataset.originalTitle;
+ const { width: nodeWidth, height: nodeHeight } = node.getBoundingClientRect();
+ const computedNodeStyles = getComputedStyle(node);
+ const styles = {
+ width: `${nodeWidth}px`,
+ padding: computedNodeStyles.getPropertyValue('padding'),
+ 'font-size': computedNodeStyles.getPropertyValue('font-size'),
+ 'font-family': computedNodeStyles.getPropertyValue('font-family'),
+ 'font-weight': computedNodeStyles.getPropertyValue('font-weight'),
+ 'font-style': computedNodeStyles.getPropertyValue('font-style'),
+ 'font-variant': computedNodeStyles.getPropertyValue('font-variant'),
+ 'line-height': computedNodeStyles.getPropertyValue('line-height'),
+ 'word-break': 'break-all',
};
- const initializeTooltip = (tooltipNode) => {
- const { delayShow, delayHide } = tooltipNode.dataset;
- const delay = {
- show: delayShow ? parseInt(delayShow, 10) : 150,
- hide: delayHide ? parseInt(delayHide, 10) : 75,
- };
- const extraClass = tooltipNode.dataset.tooltipExtraClass ?? '';
- const placement = tooltipNode.dataset.tooltipPlacement ?? 'bottom';
- const trigger = tooltipNode.dataset.tooltipTrigger ?? 'hover';
- const useHtml = tooltipNode.dataset.tooltipUseHtml !== undefined;
- const container = tooltipNode.dataset.tooltipContainerSelector
- ? tooltipNode.closest(tooltipNode.dataset.tooltipContainerSelector)
- : 'body';
- const iframe = document.querySelector(tooltipNode.dataset.tooltipIframeSelector);
-
- new bootstrap.Tooltip(tooltipNode, {
- delay,
- placement,
- trigger,
- container,
- popperConfig: modifyPopperConfig.bind(null, iframe),
- html: useHtml,
- template: `
`,
- });
- tooltipNode.addEventListener('inserted.bs.tooltip', (event) => {
- lastInsertTooltipTarget = event.currentTarget;
- });
- };
- const parse = (baseElement = doc) => {
- if (!baseElement) {
- return;
- }
-
- const tooltipNodes = [...baseElement.querySelectorAll(TOOLTIPS_SELECTOR)];
+ const textHeight = getTextHeight(title, styles);
- if (baseElement instanceof Element) {
- tooltipNodes.push(baseElement);
- }
+ return textHeight > nodeHeight;
+};
+const initializeTooltip = (tooltipNode) => {
+ const bootstrap = getBootstrap();
+ const { delayShow, delayHide } = tooltipNode.dataset;
+ const delay = {
+ show: delayShow ? parseInt(delayShow, 10) : 150,
+ hide: delayHide ? parseInt(delayHide, 10) : 75,
+ };
+ const extraClass = tooltipNode.dataset.tooltipExtraClass ?? '';
+ const placement = tooltipNode.dataset.tooltipPlacement ?? 'bottom';
+ const trigger = tooltipNode.dataset.tooltipTrigger ?? 'hover';
+ const useHtml = tooltipNode.dataset.tooltipUseHtml !== undefined;
+ const container = tooltipNode.dataset.tooltipContainerSelector
+ ? tooltipNode.closest(tooltipNode.dataset.tooltipContainerSelector)
+ : 'body';
+ const iframe = document.querySelector(tooltipNode.dataset.tooltipIframeSelector);
+
+ new bootstrap.Tooltip(tooltipNode, {
+ delay,
+ placement,
+ trigger,
+ container,
+ popperConfig: modifyPopperConfig.bind(null, iframe),
+ html: useHtml,
+ template: ``,
+ });
- for (const tooltipNode of tooltipNodes) {
- const hasEllipsisStyle = getComputedStyle(tooltipNode).textOverflow === 'ellipsis';
- const hasNewTitle = tooltipNode.hasAttribute('title');
- const tooltipInitialized = !!tooltipNode.dataset.originalTitle;
- let shouldHaveTooltip = !hasEllipsisStyle;
+ tooltipNode.addEventListener('inserted.bs.tooltip', (event) => {
+ lastInsertTooltipTarget = event.currentTarget;
+ });
+};
+const parse = (baseElement = doc) => {
+ if (!baseElement) {
+ return;
+ }
+ const bootstrap = getBootstrap();
+ const tooltipNodes = [...baseElement.querySelectorAll(TOOLTIPS_SELECTOR)];
+
+ if (baseElement instanceof Element) {
+ tooltipNodes.push(baseElement);
+ }
+
+ for (const tooltipNode of tooltipNodes) {
+ const hasEllipsisStyle = getComputedStyle(tooltipNode).textOverflow === 'ellipsis';
+ const hasNewTitle = tooltipNode.hasAttribute('title');
+ const tooltipInitialized = !!tooltipNode.dataset.originalTitle;
+ let shouldHaveTooltip = !hasEllipsisStyle;
+
+ if (!tooltipInitialized && hasNewTitle) {
+ resizeEllipsisObserver.observe(tooltipNode);
+ tooltipNode.dataset.originalTitle = tooltipNode.title;
+
+ if (!shouldHaveTooltip) {
+ shouldHaveTooltip = isTitleEllipsized(tooltipNode);
+ }
- if (!tooltipInitialized && hasNewTitle) {
- resizeEllipsisObserver.observe(tooltipNode);
+ if (shouldHaveTooltip) {
+ initializeTooltip(tooltipNode);
+ } else {
+ tooltipNode.removeAttribute('title');
+ }
+ } else if (tooltipInitialized && (hasNewTitle || hasEllipsisStyle)) {
+ if (hasNewTitle) {
tooltipNode.dataset.originalTitle = tooltipNode.title;
+ }
+ const tooltipInstance = bootstrap.Tooltip.getInstance(tooltipNode);
+ const hasTooltip = !!tooltipInstance;
- if (!shouldHaveTooltip) {
- shouldHaveTooltip = isTitleEllipsized(tooltipNode);
- }
-
- if (shouldHaveTooltip) {
- initializeTooltip(tooltipNode);
- } else {
- tooltipNode.removeAttribute('title');
- }
- } else if (tooltipInitialized && (hasNewTitle || hasEllipsisStyle)) {
- if (hasNewTitle) {
- tooltipNode.dataset.originalTitle = tooltipNode.title;
- }
- const tooltipInstance = bootstrap.Tooltip.getInstance(tooltipNode);
- const hasTooltip = !!tooltipInstance;
-
- if (!shouldHaveTooltip) {
- shouldHaveTooltip = isTitleEllipsized(tooltipNode);
- }
-
- if (hasTooltip && ((hasNewTitle && shouldHaveTooltip) || !shouldHaveTooltip)) {
- tooltipInstance.dispose();
- }
-
- if (shouldHaveTooltip && (hasNewTitle || !hasTooltip)) {
- tooltipNode.title = tooltipNode.dataset.originalTitle;
+ if (!shouldHaveTooltip) {
+ shouldHaveTooltip = isTitleEllipsized(tooltipNode);
+ }
- initializeTooltip(tooltipNode);
- } else {
- tooltipNode.removeAttribute('title');
- }
+ if (hasTooltip && ((hasNewTitle && shouldHaveTooltip) || !shouldHaveTooltip)) {
+ tooltipInstance.dispose();
}
- }
- };
- const hideAll = (baseElement = doc) => {
- if (!baseElement) {
- return;
- }
- const tooltipsNode = baseElement.querySelectorAll(TOOLTIPS_SELECTOR);
+ if (shouldHaveTooltip && (hasNewTitle || !hasTooltip)) {
+ tooltipNode.title = tooltipNode.dataset.originalTitle;
- for (const tooltipNode of tooltipsNode) {
- bootstrap.Tooltip.getOrCreateInstance(tooltipNode).hide();
+ initializeTooltip(tooltipNode);
+ } else {
+ tooltipNode.removeAttribute('title');
+ }
}
- };
- const observe = (baseElement = doc) => {
- observer.observe(baseElement, observerConfig);
- };
-
- ibexa.addConfig('helpers.tooltips', {
- parse,
- hideAll,
- observe,
- });
-})(window, window.document, window.ibexa, window.bootstrap);
+ }
+};
+const hideAll = (baseElement = doc) => {
+ if (!baseElement) {
+ return;
+ }
+
+ const bootstrap = getBootstrap();
+ const tooltipsNode = baseElement.querySelectorAll(TOOLTIPS_SELECTOR);
+
+ for (const tooltipNode of tooltipsNode) {
+ bootstrap.Tooltip.getOrCreateInstance(tooltipNode).hide();
+ }
+};
+const observe = (baseElement = doc) => {
+ observer.observe(baseElement, observerConfig);
+};
+
+export { parse, hideAll, observe };
diff --git a/src/bundle/Resources/public/js/scripts/helpers/user.helper.js b/src/bundle/Resources/public/js/scripts/helpers/user.helper.js
index 07443b4c73..a860d27ea4 100644
--- a/src/bundle/Resources/public/js/scripts/helpers/user.helper.js
+++ b/src/bundle/Resources/public/js/scripts/helpers/user.helper.js
@@ -1,7 +1,7 @@
-(function (global, doc, ibexa) {
- const getId = () => doc.querySelector('meta[name="UserId"]').content;
+const { document: doc } = window;
- ibexa.addConfig('helpers.user', {
- getId,
- });
-})(window, window.document, window.ibexa);
+const getId = () => {
+ return doc.querySelector('meta[name="UserId"]')?.content ?? 0;
+};
+
+export { getId };
diff --git a/src/bundle/Resources/public/scss/ui/modules/_universal.discovery.scss b/src/bundle/Resources/public/scss/ui/modules/_universal.discovery.scss
index 1b37921cd3..022c324534 100644
--- a/src/bundle/Resources/public/scss/ui/modules/_universal.discovery.scss
+++ b/src/bundle/Resources/public/scss/ui/modules/_universal.discovery.scss
@@ -29,3 +29,4 @@
@import 'universal-discovery/tree';
@import 'universal-discovery/toggle.selection';
@import 'universal-discovery/dropdown';
+@import 'universal-discovery/global.loader';
diff --git a/src/bundle/Resources/public/scss/ui/modules/universal-discovery/_global.loader.scss b/src/bundle/Resources/public/scss/ui/modules/universal-discovery/_global.loader.scss
new file mode 100644
index 0000000000..9e9f0110a2
--- /dev/null
+++ b/src/bundle/Resources/public/scss/ui/modules/universal-discovery/_global.loader.scss
@@ -0,0 +1,22 @@
+.m-ud-global-loader {
+ position: fixed;
+ z-index: 99999;
+ background: $ibexa-color-dark;
+ width: 100%;
+ height: 100%;
+ padding: calculateRem(16px);
+
+ &__spinner-container {
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ width: 100%;
+ height: 100%;
+ border-radius: $ibexa-border-radius;
+ background: $ibexa-color-white;
+ }
+
+ &__spinner {
+ @include spinner(calculateRem(48px), calculateRem(6px), $ibexa-color-primary);
+ }
+}
diff --git a/src/bundle/ui-dev/src/modules/common/dropdown/dropdown.js b/src/bundle/ui-dev/src/modules/common/dropdown/dropdown.js
index 33745cf612..3ee63d8a10 100644
--- a/src/bundle/ui-dev/src/modules/common/dropdown/dropdown.js
+++ b/src/bundle/ui-dev/src/modules/common/dropdown/dropdown.js
@@ -4,8 +4,9 @@ import PropTypes from 'prop-types';
import { createCssClassNames } from '../../common/helpers/css.class.names';
import Icon from '../../common/icon/icon';
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
-const { Translator, document } = window;
+const { document } = window;
const MIN_SEARCH_ITEMS_DEFAULT = 5;
const MIN_ITEMS_LIST_HEIGHT = 150;
const ITEMS_LIST_WIDGET_MARGIN = 8;
@@ -25,6 +26,7 @@ const Dropdown = ({
renderSelectedItem,
minSearchItems,
}) => {
+ const Translator = getTranslator();
const containerRef = useRef();
const containerItemsRef = useRef();
const selectionInfoRef = useRef();
@@ -185,7 +187,7 @@ const Dropdown = ({
};
document.body.addEventListener('click', onInteractionOutside, false);
- scrollContainer.addEventListener('scroll', calculateAndSetItemsListStyles, false);
+ scrollContainer?.addEventListener('scroll', calculateAndSetItemsListStyles, false);
return () => {
document.body.removeEventListener('click', onInteractionOutside);
diff --git a/src/bundle/ui-dev/src/modules/common/icon/icon.js b/src/bundle/ui-dev/src/modules/common/icon/icon.js
index 38f05f09b6..d286ca28ad 100644
--- a/src/bundle/ui-dev/src/modules/common/icon/icon.js
+++ b/src/bundle/ui-dev/src/modules/common/icon/icon.js
@@ -1,8 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper';
+
const Icon = (props) => {
- const linkHref = props.customPath ? props.customPath : window.ibexa.helpers.icon.getIconPath(props.name);
+ const linkHref = props.customPath ? props.customPath : getIconPath(props.name);
let className = 'ibexa-icon';
if (props.extraClasses) {
diff --git a/src/bundle/ui-dev/src/modules/common/input/filter.search.js b/src/bundle/ui-dev/src/modules/common/input/filter.search.js
index 54cae92876..5ecbb223a9 100644
--- a/src/bundle/ui-dev/src/modules/common/input/filter.search.js
+++ b/src/bundle/ui-dev/src/modules/common/input/filter.search.js
@@ -1,11 +1,11 @@
import React from 'react';
import PropTypes from 'prop-types';
import { createCssClassNames } from '../../common/helpers/css.class.names';
-
-const { Translator } = window;
-const defaultPlaceholder = Translator.trans(/*@Desc("Search...")*/ 'search.placeholder', {}, 'ibexa_universal_discovery_widget');
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const Search = ({ onChange, placeholder, extraClasses, value }) => {
+ const inputPlaceholder =
+ placeholder ?? getTranslator().trans(/*@Desc("Search...")*/ 'search.placeholder', {}, 'ibexa_universal_discovery_widget');
const searchClassName = createCssClassNames({
'form-control': true,
'ibexa-input': true,
@@ -13,7 +13,7 @@ const Search = ({ onChange, placeholder, extraClasses, value }) => {
[extraClasses]: true,
});
- return ;
+ return ;
};
Search.propTypes = {
@@ -24,7 +24,7 @@ Search.propTypes = {
};
Search.defaultProps = {
- placeholder: defaultPlaceholder,
+ placeholder: '',
extraClasses: '',
};
diff --git a/src/bundle/ui-dev/src/modules/common/pagination/pagination.info.js b/src/bundle/ui-dev/src/modules/common/pagination/pagination.info.js
index c91bafad46..f9bab3982f 100644
--- a/src/bundle/ui-dev/src/modules/common/pagination/pagination.info.js
+++ b/src/bundle/ui-dev/src/modules/common/pagination/pagination.info.js
@@ -2,13 +2,13 @@ import React from 'react';
import PropTypes from 'prop-types';
import { createCssClassNames } from '../helpers/css.class.names';
-const { Translator } = window;
+import { getTranslator } from '../../../../../Resources/public/js/scripts/helpers/context.helper';
const PaginationInfo = ({ totalCount, viewingCount, extraClasses }) => {
if (totalCount === 0) {
return null;
}
-
+ const Translator = getTranslator();
const className = createCssClassNames({
'ibexa-pagination__info': true,
[extraClasses]: true,
diff --git a/src/bundle/ui-dev/src/modules/common/pagination/pagination.js b/src/bundle/ui-dev/src/modules/common/pagination/pagination.js
index 8d82d99bd5..e041bc1a95 100644
--- a/src/bundle/ui-dev/src/modules/common/pagination/pagination.js
+++ b/src/bundle/ui-dev/src/modules/common/pagination/pagination.js
@@ -1,10 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
+import { computePages as computePagesPagination } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/pagination.helper';
import PaginationButton from './pagination.button';
const DOTS = '...';
-const { ibexa } = window;
const Pagination = ({ totalCount, itemsPerPage, proximity, activePageIndex, onPageChange, disabled: paginationDisabled }) => {
const pagesCount = Math.ceil(totalCount / itemsPerPage);
@@ -17,7 +17,7 @@ const Pagination = ({ totalCount, itemsPerPage, proximity, activePageIndex, onPa
const nextPage = activePageIndex + 1;
const isFirstPage = activePageIndex === 0;
const isLastPage = activePageIndex + 1 === pagesCount;
- const pages = ibexa.helpers.pagination.computePages({ proximity, activePageIndex, pagesCount, separator: DOTS });
+ const pages = computePagesPagination({ proximity, activePageIndex, pagesCount, separator: DOTS });
const paginationButtons = pages.map((page, index) => {
if (page === DOTS) {
const key = `dots-${index}`;
diff --git a/src/bundle/ui-dev/src/modules/common/popup/popup.component.js b/src/bundle/ui-dev/src/modules/common/popup/popup.component.js
index bb671b2269..af3eba92c9 100644
--- a/src/bundle/ui-dev/src/modules/common/popup/popup.component.js
+++ b/src/bundle/ui-dev/src/modules/common/popup/popup.component.js
@@ -3,8 +3,7 @@ import PropTypes from 'prop-types';
import Icon from '../icon/icon';
import { createCssClassNames } from '@ibexa-admin-ui/src/bundle/ui-dev/src/modules/common/helpers/css.class.names';
-
-const { bootstrap, Translator } = window;
+import { getTranslator, getBootstrap } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const CLASS_NON_SCROLLABLE = 'ibexa-non-scrollable';
const CLASS_MODAL_OPEN = 'modal-open';
@@ -33,6 +32,8 @@ const Popup = ({
extraClasses,
}) => {
const modalRef = useRef(null);
+ const Translator = getTranslator();
+ const bootstrap = getBootstrap();
useEffect(() => {
document.body.classList.toggle(CLASS_MODAL_OPEN, isVisible);
diff --git a/src/bundle/ui-dev/src/modules/common/simple-dropdown/simple.dropdown.js b/src/bundle/ui-dev/src/modules/common/simple-dropdown/simple.dropdown.js
index d7007de970..5c6488d2b0 100644
--- a/src/bundle/ui-dev/src/modules/common/simple-dropdown/simple.dropdown.js
+++ b/src/bundle/ui-dev/src/modules/common/simple-dropdown/simple.dropdown.js
@@ -36,7 +36,7 @@ const SimpleDropdown = ({ options, selectedOption, extraClasses, onOptionClick,
return (
onOptionClickWrapper(item)}>
{item.iconName && }
- {item.label}
+ {item.label ?? item.getLabel()}
{isItemSelected && (
@@ -57,7 +57,7 @@ const SimpleDropdown = ({ options, selectedOption, extraClasses, onOptionClick,
return (
- {selectedItemLabel.length ? selectedItemLabel : selectedOption.label}
+ {selectedItemLabel.length ? selectedItemLabel : selectedOption.label ?? selectedOption.getLabel()}
);
};
diff --git a/src/bundle/ui-dev/src/modules/content-tree/components/header/header.js b/src/bundle/ui-dev/src/modules/content-tree/components/header/header.js
index 9225a460a1..245b6d4c61 100644
--- a/src/bundle/ui-dev/src/modules/content-tree/components/header/header.js
+++ b/src/bundle/ui-dev/src/modules/content-tree/components/header/header.js
@@ -4,10 +4,10 @@ import PropTypes from 'prop-types';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import Icon from '../../../common/icon/icon';
import PopupActions from '../popup-actions/popup.actions';
-
-const { Translator } = window;
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const Header = ({ isCollapsed, toggleCollapseTree, actions, popupRef }) => {
+ const Translator = getTranslator();
const headerTitle = Translator.trans(/*@Desc("Content tree")*/ 'content_tree.header', {}, 'ibexa_content_tree');
const renderCollapseButton = () => {
const iconName = isCollapsed ? 'caret-next' : 'caret-back';
diff --git a/src/bundle/ui-dev/src/modules/content-tree/components/list-item/list.item.component.js b/src/bundle/ui-dev/src/modules/content-tree/components/list-item/list.item.component.js
index 888f452783..acc72f72cd 100644
--- a/src/bundle/ui-dev/src/modules/content-tree/components/list-item/list.item.component.js
+++ b/src/bundle/ui-dev/src/modules/content-tree/components/list-item/list.item.component.js
@@ -2,7 +2,9 @@ import React, { Component } from 'react';
import PropTypes from 'prop-types';
import Icon from '../../../common/icon/icon';
-const { ibexa, Translator } = window;
+import { showWarningNotification } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/notification.helper';
+import { getContentTypeIconUrl } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/content.type.helper';
+import { getTranslator, getAdminUiConfig } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
class ListItem extends Component {
constructor(props) {
@@ -13,6 +15,8 @@ class ListItem extends Component {
this.loadMoreSubitems = this.loadMoreSubitems.bind(this);
this.handleAfterExpandedStateChange = this.handleAfterExpandedStateChange.bind(this);
+ this.Translator = getTranslator();
+ this.adminUiConfig = getAdminUiConfig();
this.secondaryItemActions = this.getSecondaryItemActions();
this.sortedActions = this.getSortedActions();
@@ -23,7 +27,7 @@ class ListItem extends Component {
}
getSecondaryItemActions() {
- const { secondaryItemActions } = ibexa.adminUiConfig.contentTreeWidget;
+ const { secondaryItemActions } = this.adminUiConfig.contentTreeWidget;
if (!secondaryItemActions) {
return [];
@@ -35,7 +39,7 @@ class ListItem extends Component {
}
getSortedActions() {
- const { itemActions } = ibexa.adminUiConfig.contentTreeWidget;
+ const { itemActions } = this.adminUiConfig.contentTreeWidget;
const actions = itemActions ? [...itemActions] : [];
return actions.sort((actionA, actionB) => {
@@ -52,13 +56,13 @@ class ListItem extends Component {
const currentDepth = currentPath.split(',').length - 1;
if (currentDepth >= treeMaxDepth) {
- const notificationMessage = Translator.trans(
+ const notificationMessage = this.Translator.trans(
/*@Desc("Cannot load sub-items for this Location because you reached max tree depth.")*/ 'expand_item.limit.message',
{},
'ibexa_content_tree',
);
- ibexa.helpers.notification.showWarningNotification(notificationMessage);
+ showWarningNotification(notificationMessage);
return;
}
@@ -121,11 +125,9 @@ class ListItem extends Component {
if (!this.state.isLoading || this.props.subitems.length) {
if (locationId === 1) {
- iconAttrs.customPath = ibexa.helpers.contentType.getContentTypeIconUrl('folder');
+ iconAttrs.customPath = getContentTypeIconUrl('folder');
} else {
- iconAttrs.customPath =
- ibexa.helpers.contentType.getContentTypeIconUrl(contentTypeIdentifier) ||
- ibexa.helpers.contentType.getContentTypeIconUrl('file');
+ iconAttrs.customPath = getContentTypeIconUrl(contentTypeIdentifier) || getContentTypeIconUrl('file');
}
} else {
iconAttrs.name = 'spinner';
@@ -148,8 +150,8 @@ class ListItem extends Component {
}
const { isLoading } = this.state;
- const seeMoreLabel = Translator.trans(/*@Desc("See more")*/ 'see_more', {}, 'ibexa_content_tree');
- const loadingMoreLabel = Translator.trans(/*@Desc("Loading more...")*/ 'loading_more', {}, 'ibexa_content_tree');
+ const seeMoreLabel = this.Translator.trans(/*@Desc("See more")*/ 'see_more', {}, 'ibexa_content_tree');
+ const loadingMoreLabel = this.Translator.trans(/*@Desc("Loading more...")*/ 'loading_more', {}, 'ibexa_content_tree');
const btnLabel = isLoading ? loadingMoreLabel : seeMoreLabel;
let loadingSpinner = null;
@@ -172,7 +174,7 @@ class ListItem extends Component {
return null;
}
- const message = Translator.trans(/*@Desc("Loading limit reached")*/ 'show_more.limit_reached', {}, 'ibexa_content_tree');
+ const message = this.Translator.trans(/*@Desc("Loading limit reached")*/ 'show_more.limit_reached', {}, 'ibexa_content_tree');
return
{message}
;
}
@@ -287,6 +289,7 @@ ListItem.propTypes = {
isRootItem: PropTypes.bool,
onClick: PropTypes.func,
indent: PropTypes.number,
+ adminUiConfig: PropTypes.object,
};
ListItem.defaultProps = {
@@ -296,6 +299,7 @@ ListItem.defaultProps = {
onClick: () => {},
subitemsLoadLimit: null,
indent: 0,
+ adminUiConfig: window.ibexa?.adminUiConfig,
};
export default ListItem;
diff --git a/src/bundle/ui-dev/src/modules/content-tree/components/list/list.component.js b/src/bundle/ui-dev/src/modules/content-tree/components/list/list.component.js
index 0ac20f2575..1f7cea6d7c 100644
--- a/src/bundle/ui-dev/src/modules/content-tree/components/list/list.component.js
+++ b/src/bundle/ui-dev/src/modules/content-tree/components/list/list.component.js
@@ -1,8 +1,7 @@
import React from 'react';
import PropTypes from 'prop-types';
import ListItem from '../list-item/list.item.component';
-
-const { Translator } = window;
+import { getTranslator, getRouting } from '../../../../../../Resources/public/js/scripts/helpers/context.helper';
const List = ({
items,
@@ -17,6 +16,8 @@ const List = ({
isRoot,
onClickItem,
}) => {
+ const Translator = getTranslator();
+ const Routing = getRouting();
const commonAttrs = { loadMoreSubitems, subitemsLoadLimit, subitemsLimit, treeMaxDepth, afterItemToggle, onClickItem };
const listAttrs = { ...commonAttrs, currentLocationId };
const listItemAttrs = commonAttrs;
@@ -36,7 +37,7 @@ const List = ({
{items.map((item) => {
const hasPreviousPath = path && path.length;
- const locationHref = window.Routing.generate('ibexa.content.view', {
+ const locationHref = Routing.generate('ibexa.content.view', {
contentId: item.contentId,
locationId: item.locationId,
});
diff --git a/src/bundle/ui-dev/src/modules/content-tree/config.loader.js b/src/bundle/ui-dev/src/modules/content-tree/config.loader.js
new file mode 100644
index 0000000000..6b2bac911f
--- /dev/null
+++ b/src/bundle/ui-dev/src/modules/content-tree/config.loader.js
@@ -0,0 +1,5 @@
+import ContentTreeModule from './content.tree.module';
+
+(function (ibexa) {
+ ibexa.addConfig('modules.ContentTree', ContentTreeModule);
+})(window.ibexa);
diff --git a/src/bundle/ui-dev/src/modules/content-tree/content.tree.module.js b/src/bundle/ui-dev/src/modules/content-tree/content.tree.module.js
index 153edb86f0..312d4de187 100644
--- a/src/bundle/ui-dev/src/modules/content-tree/content.tree.module.js
+++ b/src/bundle/ui-dev/src/modules/content-tree/content.tree.module.js
@@ -347,6 +347,7 @@ export default class ContentTreeModule extends Component {
return {
token: this.props.restInfo.token,
siteaccess: this.props.restInfo.siteaccess,
+ accessToken: this.props.restInfo.accessToken,
subtree: this.subtree,
sortClause: this.props.sort.sortClause,
sortOrder: this.props.sort.sortOrder,
@@ -373,8 +374,6 @@ export default class ContentTreeModule extends Component {
}
}
-ibexa.addConfig('modules.ContentTree', ContentTreeModule);
-
ContentTreeModule.propTypes = {
rootLocationId: PropTypes.number,
currentLocationPath: PropTypes.number.isRequired,
@@ -386,6 +385,7 @@ ContentTreeModule.propTypes = {
restInfo: PropTypes.shape({
token: PropTypes.string.isRequired,
siteaccess: PropTypes.string.isRequired,
+ accessToken: PropTypes.string,
}).isRequired,
onClickItem: PropTypes.func,
readSubtree: PropTypes.func,
@@ -399,10 +399,10 @@ ContentTreeModule.propTypes = {
ContentTreeModule.defaultProps = {
preloadedLocations: [],
- rootLocationId: ibexa.adminUiConfig.contentTree.treeRootLocationId,
- subitemsLimit: ibexa.adminUiConfig.contentTree.childrenLoadMaxLimit,
- subitemsLoadLimit: ibexa.adminUiConfig.contentTree.loadMoreLimit,
- treeMaxDepth: ibexa.adminUiConfig.contentTree.treeMaxDepth,
+ rootLocationId: ibexa?.adminUiConfig.contentTree.treeRootLocationId,
+ subitemsLimit: ibexa?.adminUiConfig.contentTree.childrenLoadMaxLimit,
+ subitemsLoadLimit: ibexa?.adminUiConfig.contentTree.loadMoreLimit,
+ treeMaxDepth: ibexa?.adminUiConfig.contentTree.treeMaxDepth,
afterItemToggle: () => {},
sort: {},
resizable: true,
diff --git a/src/bundle/ui-dev/src/modules/content-tree/services/content.tree.service.js b/src/bundle/ui-dev/src/modules/content-tree/services/content.tree.service.js
index a42d59d5a4..1de0e50cc5 100644
--- a/src/bundle/ui-dev/src/modules/content-tree/services/content.tree.service.js
+++ b/src/bundle/ui-dev/src/modules/content-tree/services/content.tree.service.js
@@ -1,18 +1,29 @@
+import { getRequestHeaders, getRequestMode } from '../../../../../Resources/public/js/scripts/helpers/request.helper';
import { handleRequestResponse } from '../../common/helpers/request.helper';
import { showErrorNotification } from '../../common/services/notification.service';
const ENDPOINT_LOAD_SUBITEMS = '/api/ibexa/v2/location/tree/load-subitems';
const ENDPOINT_LOAD_SUBTREE = '/api/ibexa/v2/location/tree/load-subtree';
+const DEFAULT_INSTANCE_URL = window.location.origin;
-export const loadLocationItems = ({ siteaccess }, parentLocationId, callback, limit = 50, offset = 0) => {
+export const loadLocationItems = (
+ { siteaccess, accessToken, instanceUrl = DEFAULT_INSTANCE_URL },
+ parentLocationId,
+ callback,
+ limit = 50,
+ offset = 0,
+) => {
const request = new Request(`${ENDPOINT_LOAD_SUBITEMS}/${parentLocationId}/${limit}/${offset}`, {
method: 'GET',
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
- headers: {
- Accept: 'application/vnd.ibexa.api.ContentTreeNode+json',
- 'X-Siteaccess': siteaccess,
- },
+ headers: getRequestHeaders({
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/vnd.ibexa.api.ContentTreeNode+json',
+ },
+ }),
});
fetch(request)
@@ -28,8 +39,11 @@ export const loadLocationItems = ({ siteaccess }, parentLocationId, callback, li
.catch(showErrorNotification);
};
-export const loadSubtree = ({ token, siteaccess, subtree, sortClause, sortOrder }, callback) => {
- let path = ENDPOINT_LOAD_SUBTREE;
+export const loadSubtree = (
+ { token, siteaccess, accessToken, subtree, sortClause, sortOrder, instanceUrl = DEFAULT_INSTANCE_URL },
+ callback,
+) => {
+ let path = `${instanceUrl}${ENDPOINT_LOAD_SUBTREE}`;
if (sortClause && sortOrder) {
path += `?sortClause=${sortClause}&sortOrder=${sortOrder}`;
@@ -37,7 +51,7 @@ export const loadSubtree = ({ token, siteaccess, subtree, sortClause, sortOrder
const request = new Request(path, {
method: 'POST',
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
body: JSON.stringify({
LoadSubtreeRequest: {
@@ -45,12 +59,15 @@ export const loadSubtree = ({ token, siteaccess, subtree, sortClause, sortOrder
nodes: subtree,
},
}),
- headers: {
- Accept: 'application/vnd.ibexa.api.ContentTreeRoot+json',
- 'Content-Type': 'application/vnd.ibexa.api.ContentTreeLoadSubtreeRequest+json',
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
- },
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/vnd.ibexa.api.ContentTreeRoot+json',
+ 'Content-Type': 'application/vnd.ibexa.api.ContentTreeLoadSubtreeRequest+json',
+ },
+ }),
});
fetch(request)
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/bookmarks.tab.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/bookmarks.tab.module.js
index 09e74c558e..7c8352d0f3 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/bookmarks.tab.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/bookmarks.tab.module.js
@@ -18,7 +18,8 @@ import {
} from './universal.discovery.module';
import { loadAccordionData } from './services/universal.discovery.service';
-const { Translator, ibexa } = window;
+import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper';
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const BookmarksTabModule = () => {
const shouldRestorePreviousStateRef = useRef(true);
@@ -95,17 +96,11 @@ const BookmarksTabModule = () => {
);
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.tabs',
- [
- {
- id: 'bookmarks',
- component: BookmarksTabModule,
- label: Translator.trans(/*@Desc("Bookmarks")*/ 'bookmarks.label', {}, 'ibexa_universal_discovery_widget'),
- icon: ibexa.helpers.icon.getIconPath('bookmark'),
- },
- ],
- true,
-);
+export const BookmarksTab = {
+ id: 'bookmarks',
+ component: BookmarksTabModule,
+ getLabel: () => getTranslator().trans(/*@Desc("Bookmarks")*/ 'bookmarks.label', {}, 'ibexa_universal_discovery_widget'),
+ getIcon: () => getIconPath('bookmark'),
+};
export default BookmarksTabModule;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/browse.tab.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/browse.tab.module.js
index 2892faa225..124e0ae6a8 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/browse.tab.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/browse.tab.module.js
@@ -7,7 +7,8 @@ import TreeView from './components/tree-view/tree.view';
import { CurrentViewContext, TabsConfigContext } from './universal.discovery.module';
-const { Translator, ibexa } = window;
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper';
const BrowseTabModule = () => {
const [currentView] = useContext(CurrentViewContext);
@@ -25,17 +26,11 @@ const BrowseTabModule = () => {
);
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.tabs',
- [
- {
- id: 'browse',
- component: BrowseTabModule,
- label: Translator.trans(/*@Desc("Browse")*/ 'browse.label', {}, 'ibexa_universal_discovery_widget'),
- icon: window.ibexa.helpers.icon.getIconPath('browse'),
- },
- ],
- true,
-);
+export const BrowseTab = {
+ id: 'browse',
+ component: BrowseTabModule,
+ getLabel: () => getTranslator().trans(/*@Desc("Browse")*/ 'browse.label', {}, 'ibexa_universal_discovery_widget'),
+ getIcon: () => getIconPath('browse'),
+};
export default BrowseTabModule;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/actions-menu/actions.menu.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/actions-menu/actions.menu.js
index 32703fecca..339875195b 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/actions-menu/actions.menu.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/actions-menu/actions.menu.js
@@ -1,10 +1,10 @@
import React, { useContext } from 'react';
import { AllowConfirmationContext, ConfirmContext, CancelContext, SelectedLocationsContext } from '../../universal.discovery.module';
-
-const { Translator } = window;
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const ActionsMenu = () => {
+ const Translator = getTranslator();
const onConfirm = useContext(ConfirmContext);
const cancelUDW = useContext(CancelContext);
const allowConfirmation = useContext(AllowConfirmationContext);
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/bookmarks-list/bookmarks.list.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/bookmarks-list/bookmarks.list.js
index 35a50aae60..47467506b3 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/bookmarks-list/bookmarks.list.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/bookmarks-list/bookmarks.list.js
@@ -1,6 +1,8 @@
import React, { useContext, useState, useEffect, useRef } from 'react';
import PropTypes from 'prop-types';
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+
import Icon from '../../../common/icon/icon';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
@@ -15,8 +17,6 @@ import {
AllowedContentTypesContext,
} from '../../universal.discovery.module';
-const { ibexa } = window;
-
const SCROLL_OFFSET = 200;
const BookmarksList = ({ setBookmarkedLocationMarked, itemsPerPage }) => {
@@ -62,7 +62,7 @@ const BookmarksList = ({ setBookmarkedLocationMarked, itemsPerPage }) => {
}, [data.items, isLoading]);
useEffect(() => {
- ibexa.helpers.tooltips.parse(refBookmarksList.current);
+ parseTooltip(refBookmarksList.current);
}, [bookmarks]);
if (!bookmarks.length) {
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/breadcrumbs/breadcrumbs.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/breadcrumbs/breadcrumbs.js
index 9608b37260..e2a2feafd1 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/breadcrumbs/breadcrumbs.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/breadcrumbs/breadcrumbs.js
@@ -4,10 +4,10 @@ import Icon from '../../../common/icon/icon';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import { LoadedLocationsMapContext } from '../../universal.discovery.module';
-
-const { Translator } = window;
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const Breadcrumbs = () => {
+ const Translator = getTranslator();
const [loadedLocationsMap, dispatchLoadedLocationsAction] = useContext(LoadedLocationsMapContext);
const [hiddenListVisible, setHiddenListVisible] = useState(false);
const { visibleItems, hiddenItems } = useMemo(() => {
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/collapsible/collapsible.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/collapsible/collapsible.js
index be4f682c19..232ae1c7c0 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/collapsible/collapsible.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/collapsible/collapsible.js
@@ -1,8 +1,7 @@
import React, { useState } from 'react';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
-
-const { ibexa } = window;
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
const Collapsible = ({ isInitiallyExpanded, title, children }) => {
const [isExpanded, setIsExpanded] = useState(isInitiallyExpanded);
@@ -12,7 +11,7 @@ const Collapsible = ({ isInitiallyExpanded, title, children }) => {
});
const toggleCollapsed = () => setIsExpanded((prevState) => !prevState);
const initTooltipsRef = (node) => {
- ibexa.helpers.tooltips.parse(node);
+ parseTooltip(node);
};
return (
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-button/content.create.button.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-button/content.create.button.js
index e2bbe92d49..0d9b89606e 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-button/content.create.button.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-button/content.create.button.js
@@ -1,6 +1,8 @@
import React, { useContext } from 'react';
import PropTypes from 'prop-types';
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+import { hideAll as hideAllTooltips } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
import Icon from '../../../common/icon/icon';
import {
@@ -13,9 +15,8 @@ import {
ContentTypesMapContext,
} from '../../universal.discovery.module';
-const { Translator, ibexa } = window;
-
const ContentCreateButton = ({ isDisabled }) => {
+ const Translator = getTranslator();
const [markedLocationId] = useContext(MarkedLocationIdContext);
const [loadedLocationsMap] = useContext(LoadedLocationsMapContext);
const [, setCreateContentVisible] = useContext(CreateContentWidgetContext);
@@ -25,7 +26,7 @@ const ContentCreateButton = ({ isDisabled }) => {
const contentTypesMap = useContext(ContentTypesMapContext);
const createLabel = Translator.trans(/*@Desc("Create")*/ 'create_content.create', {}, 'ibexa_universal_discovery_widget');
const toggleContentCreateVisibility = () => {
- ibexa.helpers.tooltips.hideAll();
+ hideAllTooltips();
setCreateContentVisible((prevState) => !prevState);
};
let selectedLocation = loadedLocationsMap.find((loadedLocation) => loadedLocation.parentLocationId === markedLocationId);
@@ -72,16 +73,10 @@ ContentCreateButton.defaultProps = {
isDisabled: false,
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.topMenuActions',
- [
- {
- id: 'content-create-button',
- priority: 30,
- component: ContentCreateButton,
- },
- ],
- true,
-);
+export const ContentCreateButtonMenuItem = {
+ id: 'content-create-button',
+ priority: 30,
+ component: ContentCreateButton,
+};
export default ContentCreateButton;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js
index 39bbc825db..3dda5eb95b 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-create-widget/content.create.widget.js
@@ -1,8 +1,9 @@
import React, { useContext, useState, useEffect, useRef } from 'react';
+import { createCssClassNames } from '../../../common/helpers/css.class.names';
import Icon from '../../../common/icon/icon';
+import Dropdown from '../../../common/dropdown/dropdown';
-import { createCssClassNames } from '../../../common/helpers/css.class.names';
import {
DropdownPortalRefContext,
CreateContentWidgetContext,
@@ -13,25 +14,25 @@ import {
ContentOnTheFlyConfigContext,
AllowedContentTypesContext,
} from '../../universal.discovery.module';
-import Dropdown from '../../../common/dropdown/dropdown';
-
-const { Translator, ibexa } = window;
-const configLanguages = ibexa.adminUiConfig.languages;
-const languages = configLanguages.priority.map((languageCode) => {
- return configLanguages.mappings[languageCode];
-});
-const contentTypes = Object.entries(ibexa.adminUiConfig.contentTypes);
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const ContentCreateWidget = () => {
+ const Translator = getTranslator();
+ const adminUiConfig = getAdminUiConfig();
const refContentTree = useRef(null);
const dropdownListRef = useContext(DropdownPortalRefContext);
const [markedLocationId] = useContext(MarkedLocationIdContext);
const [loadedLocationsMap] = useContext(LoadedLocationsMapContext);
const { allowedLanguages, preselectedLanguage, preselectedContentType } = useContext(ContentOnTheFlyConfigContext);
const allowedContentTypes = useContext(AllowedContentTypesContext);
+ const { languages, contentTypes } = adminUiConfig;
const selectedLocation = loadedLocationsMap.find((loadedLocation) => loadedLocation.parentLocationId === markedLocationId);
- const filteredLanguages = languages.filter((language) => {
+ const mappedLanguages = languages.priority.map((languageCode) => {
+ return languages.mappings[languageCode];
+ });
+ const filteredLanguages = mappedLanguages.filter((language) => {
const userHasPermission =
!selectedLocation ||
!selectedLocation.permissions ||
@@ -101,7 +102,7 @@ const ContentCreateWidget = () => {
'ibexa-extra-actions--hidden': !createContentVisible,
'c-content-create': true,
});
- const languageOptions = languages
+ const languageOptions = mappedLanguages
.filter((language) => language.enabled)
.map((language) => ({
value: language.languageCode,
@@ -113,7 +114,7 @@ const ContentCreateWidget = () => {
}, [preselectedLanguage, firstLanguageCode]);
useEffect(() => {
- ibexa.helpers.tooltips.parse(refContentTree.current);
+ parseTooltip(refContentTree.current);
}, []);
return (
@@ -160,7 +161,7 @@ const ContentCreateWidget = () => {
{filtersDescLabel}
- {contentTypes.map(([groupName, groupItems]) => {
+ {Object.entries(contentTypes).map(([groupName, groupItems]) => {
const restrictedContentTypeIds = selectedLocation?.permissions?.create.restrictedContentTypeIds ?? [];
const isHiddenGroup = groupItems.every((groupItem) => {
const isNotSearchedName = filterQuery && !groupItem.name.toLowerCase().includes(filterQuery);
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/content.edit.button.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/content.edit.button.js
index 0d07884e4b..511f305da1 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/content.edit.button.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/content.edit.button.js
@@ -4,7 +4,8 @@ import PropTypes from 'prop-types';
import Icon from '../../../common/icon/icon';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import TranslationSelector from '../translation-selector/translation.selector';
-import { createDraft } from '../..//services/universal.discovery.service';
+import { getAdminUiConfig, getRouting } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+import { createDraft } from '../../services/universal.discovery.service';
import {
RestInfoContext,
EditOnTheFlyDataContext,
@@ -13,9 +14,9 @@ import {
ContentTypesMapContext,
} from '../..//universal.discovery.module';
-const { Routing, ibexa } = window;
-
const ContentEditButton = ({ version, location, isDisabled, label }) => {
+ const Routing = getRouting();
+ const adminUiConfig = getAdminUiConfig();
const restInfo = useContext(RestInfoContext);
const allowRedirects = useContext(AllowRedirectsContext);
const [, setEditOnTheFlyData] = useContext(EditOnTheFlyDataContext);
@@ -23,7 +24,7 @@ const ContentEditButton = ({ version, location, isDisabled, label }) => {
const contentTypesMap = useContext(ContentTypesMapContext);
const [isTranslationSelectorVisible, setIsTranslationSelectorVisible] = useState(false);
const contentTypeInfo = contentTypesMap[location.ContentInfo.Content.ContentType._href];
- const isUserContentType = ibexa.adminUiConfig.userContentTypes.includes(contentTypeInfo.identifier);
+ const isUserContentType = adminUiConfig.userContentTypes.includes(contentTypeInfo.identifier);
const btnClassName = createCssClassNames({
'c-content-edit-button__btn btn ibexa-btn ibexa-btn--ghost': true,
'ibexa-btn--no-text': label !== null,
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/selected.item.edit.button.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/selected.item.edit.button.js
index c7cd0e7825..63670503a0 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/selected.item.edit.button.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-edit-button/selected.item.edit.button.js
@@ -3,8 +3,6 @@ import PropTypes from 'prop-types';
import ContentEditButton from '../content-edit-button/content.edit.button';
-const { ibexa } = window;
-
const SelectedItemEditButton = ({ location, permissions }) => {
const hasAccess = permissions && permissions.edit.hasAccess;
@@ -15,21 +13,15 @@ const SelectedItemEditButton = ({ location, permissions }) => {
);
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.selectedItemActions',
- [
- {
- id: 'content-edit-button',
- priority: 30,
- component: SelectedItemEditButton,
- },
- ],
- true,
-);
-
SelectedItemEditButton.propTypes = {
location: PropTypes.object.isRequired,
permissions: PropTypes.object.isRequired,
};
+export const SelectedItemEditMenuButton = {
+ id: 'content-edit-button',
+ priority: 30,
+ component: SelectedItemEditButton,
+};
+
export default SelectedItemEditButton;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.item.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.item.js
index 41a9e68836..bf42a03d8b 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.item.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.item.js
@@ -4,6 +4,7 @@ import PropTypes from 'prop-types';
import ToggleSelection from '../toggle-selection/toggle.selection';
import Icon from '../../../common/icon/icon';
+import { formatShortDateTime } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/timezone.helper';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import { loadAccordionData } from '../../services/universal.discovery.service';
import {
@@ -32,7 +33,6 @@ const ContentTableItem = ({ location }) => {
const [, dispatchSelectedLocationsAction] = useContext(SelectedLocationsContext);
const [multiple] = useContext(MultipleConfigContext);
const rootLocationId = useContext(RootLocationIdContext);
- const { formatShortDateTime } = window.ibexa.helpers.timezone;
const allowedContentTypes = useContext(AllowedContentTypesContext);
const contentTypeInfo = contentTypesMap[location.ContentInfo.Content.ContentType._href];
const containersOnly = useContext(ContainersOnlyContext);
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.js
index b19a3ea303..6060316e67 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-table/content.table.js
@@ -5,9 +5,11 @@ import ContentTableItem from './content.table.item';
import Pagination from '../../../common/pagination/pagination';
import { MultipleConfigContext } from '../../universal.discovery.module';
-const { Translator, ibexa } = window;
+import { getTranslator } from '../../../../../../Resources/public/js/scripts/helpers/context.helper';
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
const ContentTable = ({ count, itemsPerPage, items, activePageIndex, title, onPageChange, renderCustomHeader }) => {
+ const Translator = getTranslator();
const [multiple] = useContext(MultipleConfigContext);
const refContentTable = useRef(null);
const nameLabel = Translator.trans(/*@Desc("Name")*/ 'content_table.name', {}, 'ibexa_universal_discovery_widget');
@@ -24,7 +26,7 @@ const ContentTable = ({ count, itemsPerPage, items, activePageIndex, title, onPa
);
useEffect(() => {
- ibexa.helpers.tooltips.parse(refContentTable.current);
+ parseTooltip(refContentTable.current);
}, []);
return (
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-type-selector/content.type.selector.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-type-selector/content.type.selector.js
index 2402cccbb5..fc06e1bcb3 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/content-type-selector/content.type.selector.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/content-type-selector/content.type.selector.js
@@ -4,11 +4,11 @@ import { SelectedContentTypesContext } from '../search/search';
import { AllowedContentTypesContext } from '../../universal.discovery.module';
import Collapsible from '../collapsible/collapsible';
-
-const { ibexa } = window;
+import { getAdminUiConfig } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const ContentTypeSelector = () => {
- const { contentTypes: contentTypesMap } = ibexa.adminUiConfig;
+ const adminUiConfig = getAdminUiConfig();
+ const { contentTypes: contentTypesMap } = adminUiConfig;
const allowedContentTypes = useContext(AllowedContentTypesContext);
const [selectedContentTypes, dispatchSelectedContentTypesAction] = useContext(SelectedContentTypesContext);
const handleContentTypeSelect = ({ nativeEvent }) => {
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js
index bfe98ee34b..8bc781a9df 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/filters/filters.js
@@ -9,17 +9,23 @@ import {
SelectedLanguageContext,
SelectedSubtreeBreadcrumbsContext,
} from '../search/search';
+
import UniversalDiscoveryModule, { DropdownPortalRefContext } from '../../universal.discovery.module';
import Dropdown from '../../../common/dropdown/dropdown';
import ContentTypeSelector from '../content-type-selector/content.type.selector';
import Icon from '../../../common/icon/icon';
-const { Translator, ibexa } = window;
-
-const languages = Object.values(ibexa.adminUiConfig.languages.mappings);
+import {
+ removeRootFromPathString,
+ findLocationsByIds,
+ buildLocationsBreadcrumbs,
+} from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/location.helper';
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const Filters = ({ search }) => {
+ const Translator = getTranslator();
+ const adminUiConfig = getAdminUiConfig();
const [selectedContentTypes, dispatchSelectedContentTypesAction] = useContext(SelectedContentTypesContext);
const [selectedSection, setSelectedSection] = useContext(SelectedSectionContext);
const [selectedSubtree, setSelectedSubtree] = useContext(SelectedSubtreeContext);
@@ -31,7 +37,6 @@ const Filters = ({ search }) => {
const [isNestedUdwOpened, setIsNestedUdwOpened] = useState(false);
const filterSubtreeUdwConfig = JSON.parse(window.document.querySelector('#react-udw').dataset.filterSubtreeUdwConfig);
const handleNestedUdwConfirm = (items) => {
- const { removeRootFromPathString, findLocationsByIds, buildLocationsBreadcrumbs } = ibexa.helpers.location;
const [{ pathString }] = items;
findLocationsByIds(removeRootFromPathString(pathString), (locations) =>
@@ -41,11 +46,10 @@ const Filters = ({ search }) => {
setSelectedSubtree(pathString);
setIsNestedUdwOpened(false);
};
-
const nestedUdwConfig = {
onConfirm: handleNestedUdwConfirm,
onCancel: () => setIsNestedUdwOpened(false),
- tabs: ibexa.adminUiConfig.universalDiscoveryWidget.tabs,
+ tabs: adminUiConfig.universalDiscoveryWidget.tabs,
title: 'Browsing content',
...filterSubtreeUdwConfig,
};
@@ -113,13 +117,13 @@ const Filters = ({ search }) => {
const subtreeLabel = Translator.trans(/*@Desc("Subtree")*/ 'filters.subtree', {}, 'ibexa_universal_discovery_widget');
const clearLabel = Translator.trans(/*@Desc("Clear")*/ 'filters.clear', {}, 'ibexa_universal_discovery_widget');
const applyLabel = Translator.trans(/*@Desc("Apply")*/ 'filters.apply', {}, 'ibexa_universal_discovery_widget');
- const languageOptions = languages
+ const languageOptions = Object.values(adminUiConfig.languages.mappings)
.filter((language) => language.enabled)
.map((language) => ({
value: language.languageCode,
label: language.name,
}));
- const sectionOptions = Object.entries(ibexa.adminUiConfig.sections).map(([sectionIdentifier, sectionName]) => ({
+ const sectionOptions = Object.entries(adminUiConfig.sections).map(([sectionIdentifier, sectionName]) => ({
value: sectionIdentifier,
label: sectionName,
}));
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.branch.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.branch.js
index 11125f165f..31cb4ac20d 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.branch.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.branch.js
@@ -3,6 +3,7 @@ import PropTypes from 'prop-types';
import FinderLeaf from './finder.leaf';
import Icon from '../../../common/icon/icon';
+import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper.js';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import { useFindLocationsByParentLocationIdFetch } from '../../hooks/useFindLocationsByParentLocationIdFetch';
@@ -15,8 +16,6 @@ import {
SORTING_OPTIONS,
} from '../../universal.discovery.module';
-const { ibexa } = window;
-
const CLASS_IS_BRANCH_RESIZING = 'ibexa-is-branch-resizing';
const SCROLL_OFFSET = 200;
@@ -89,7 +88,7 @@ const FinderBranch = ({ locationData, itemsPerPage }) => {
const contentName = selectedLocation ? selectedLocation.location.ContentInfo.Content.TranslatedName : '';
const iconPath = locationData.location
? contentTypesMap[locationData.location.ContentInfo.Content.ContentType._href].thumbnail
- : ibexa.helpers.icon.getIconPath('folder');
+ : getIconPath('folder');
return (
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.leaf.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.leaf.js
index 4d279e2331..045fd38639 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.leaf.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/finder/finder.leaf.js
@@ -1,6 +1,8 @@
import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+
import ToggleSelection from '../toggle-selection/toggle.selection';
import Icon from '../../../common/icon/icon';
@@ -15,7 +17,7 @@ import {
AllowedContentTypesContext,
} from '../../universal.discovery.module';
-const { document, ibexa } = window;
+const { document } = window;
const FinderLeaf = ({ location }) => {
const [markedLocationId, setMarkedLocationId] = useContext(MarkedLocationIdContext);
@@ -62,7 +64,7 @@ const FinderLeaf = ({ location }) => {
});
useEffect(() => {
- ibexa.helpers.tooltips.parse(document.querySelector('.c-udw-tab'));
+ parseTooltip(document.querySelector('.c-udw-tab'));
}, []);
return (
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.js
index 6e1d2775c8..48c072c7d1 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.js
@@ -14,8 +14,7 @@ import SearchTags from './search.tags';
import { useSearchByQueryFetch } from '../../hooks/useSearchByQueryFetch';
import { AllowedContentTypesContext, SearchTextContext } from '../../universal.discovery.module';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
-
-const { Translator, ibexa } = window;
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const selectedContentTypesReducer = (state, action) => {
switch (action.type) {
@@ -30,12 +29,9 @@ const selectedContentTypesReducer = (state, action) => {
}
};
-const configLanguages = ibexa.adminUiConfig.languages;
-const languages = configLanguages.priority.map((value) => {
- return configLanguages.mappings[value];
-});
-
const Search = ({ itemsPerPage }) => {
+ const Translator = getTranslator();
+ const adminUiConfig = getAdminUiConfig();
const allowedContentTypes = useContext(AllowedContentTypesContext);
const [searchText] = useContext(SearchTextContext);
const [offset, setOffset] = useState(0);
@@ -43,10 +39,15 @@ const Search = ({ itemsPerPage }) => {
const [selectedSection, setSelectedSection] = useState('');
const [selectedSubtree, setSelectedSubtree] = useState('');
const [selectedSubtreeBreadcrumbs, setSelectedSubtreeBreadcrumbs] = useState('');
- const firstLanguageCode = languages.length ? languages[0].languageCode : '';
+ const { languages } = adminUiConfig;
+ const mappedLanguages = languages.priority.map((value) => {
+ return languages.mappings[value];
+ });
+ const firstLanguageCode = mappedLanguages.length ? mappedLanguages[0].languageCode : '';
const [selectedLanguage, setSelectedLanguage] = useState(firstLanguageCode);
const prevSearchText = useRef(null);
const [isLoading, data, searchByQuery] = useSearchByQueryFetch();
+
const search = () => {
const shouldResetOffset = prevSearchText.current !== searchText && offset !== 0;
@@ -64,7 +65,7 @@ const Search = ({ itemsPerPage }) => {
};
const changePage = (pageIndex) => setOffset(pageIndex * itemsPerPage);
const renderCustomTableHeader = () => {
- const selectedLanguageName = ibexa.adminUiConfig.languages.mappings[selectedLanguage].name;
+ const selectedLanguageName = languages.mappings[selectedLanguage].name;
const searchResultsTitle = Translator.trans(
/*@Desc("Results for “%search_phrase%” (%total%)")*/ 'search.search_results',
{
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.tags.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.tags.js
index 9cf2c3feea..bd58bbfbc7 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.tags.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/search/search.tags.js
@@ -6,10 +6,10 @@ import {
SelectedSubtreeBreadcrumbsContext,
} from '../search/search';
import Tag from '../../../common/tag/tag';
-
-const { ibexa } = window;
+import { getAdminUiConfig } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const SearchTags = () => {
+ const adminUiConfig = getAdminUiConfig();
const [selectedContentTypes, dispatchSelectedContentTypesAction] = useContext(SelectedContentTypesContext);
const [selectedSection, setSelectedSection] = useContext(SelectedSectionContext);
const [, setSelectedSubtree] = useContext(SelectedSubtreeContext);
@@ -18,7 +18,7 @@ const SearchTags = () => {
setSelectedSubtree('');
setSelectedSubtreeBreadcrumbs('');
};
- const contentTypesMap = Object.values(ibexa.adminUiConfig.contentTypes).reduce((contentTypeDataMap, contentTypeGroup) => {
+ const contentTypesMap = Object.values(adminUiConfig.contentTypes).reduce((contentTypeDataMap, contentTypeGroup) => {
for (const contentTypeData of contentTypeGroup) {
contentTypeDataMap[contentTypeData.identifier] = contentTypeData;
}
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.item.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.item.js
index 42c674a898..010f4b082d 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.item.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.item.js
@@ -1,14 +1,20 @@
import React, { useContext, useEffect, useMemo, useRef } from 'react';
import PropTypes from 'prop-types';
+import {
+ parse as parseTooltip,
+ hideAll as hideAllTooltips,
+} from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+
import Icon from '../../../common/icon/icon';
import Thumbnail from '../../../common/thumbnail/thumbnail';
import { SelectedLocationsContext, ContentTypesMapContext } from '../../universal.discovery.module';
-
-const { Translator, ibexa } = window;
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const SelectedLocationsItem = ({ location, permissions }) => {
+ const adminUiConfig = getAdminUiConfig();
+ const Translator = getTranslator();
const refSelectedLocationsItem = useRef(null);
const [, dispatchSelectedLocationsAction] = useContext(SelectedLocationsContext);
const contentTypesMap = useContext(ContentTypesMapContext);
@@ -18,11 +24,11 @@ const SelectedLocationsItem = ({ location, permissions }) => {
'ibexa_universal_discovery_widget',
);
const removeFromSelection = () => {
- ibexa.helpers.tooltips.hideAll(refSelectedLocationsItem.current);
+ hideAllTooltips(refSelectedLocationsItem.current);
dispatchSelectedLocationsAction({ type: 'REMOVE_SELECTED_LOCATION', id: location.id });
};
const sortedActions = useMemo(() => {
- const { selectedItemActions } = ibexa.adminUiConfig.universalDiscoveryWidget;
+ const { selectedItemActions } = adminUiConfig.universalDiscoveryWidget;
const actions = selectedItemActions ? [...selectedItemActions] : [];
return actions.sort((actionA, actionB) => {
@@ -33,7 +39,7 @@ const SelectedLocationsItem = ({ location, permissions }) => {
const thumbnailData = version ? version.Thumbnail : {};
useEffect(() => {
- ibexa.helpers.tooltips.parse(refSelectedLocationsItem.current);
+ parseTooltip(refSelectedLocationsItem.current);
}, []);
return (
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.js
index 26b3dc0451..87fe7a38ca 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/selected-locations/selected.locations.js
@@ -1,14 +1,19 @@
import React, { useContext, useState, useEffect, useRef } from 'react';
+import {
+ parse as parseTooltip,
+ hideAll as hideAllTooltips,
+} from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+import { getBootstrap, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+
import Icon from '../../../common/icon/icon';
import SelectedLocationsItem from './selected.locations.item';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import { SelectedLocationsContext, AllowConfirmationContext } from '../../universal.discovery.module';
-const { Translator, ibexa, bootstrap } = window;
-
const SelectedLocations = () => {
+ const Translator = getTranslator();
const refSelectedLocations = useRef(null);
const refTogglerButton = useRef(null);
const [selectedLocations, dispatchSelectedLocationsAction] = useContext(SelectedLocationsContext);
@@ -30,7 +35,7 @@ const SelectedLocations = () => {
);
const togglerLabel = isExpanded ? collapseLabel : expandLabel;
const clearSelection = () => {
- ibexa.helpers.tooltips.hideAll(refSelectedLocations.current);
+ hideAllTooltips(refSelectedLocations.current);
dispatchSelectedLocationsAction({ type: 'CLEAR_SELECTED_LOCATIONS' });
};
const toggleExpanded = () => {
@@ -102,9 +107,10 @@ const SelectedLocations = () => {
};
useEffect(() => {
- ibexa.helpers.tooltips.parse(refSelectedLocations.current);
- ibexa.helpers.tooltips.hideAll();
+ parseTooltip(refSelectedLocations.current);
+ hideAllTooltips();
+ const bootstrap = getBootstrap();
const toggleButtonTooltip = bootstrap.Tooltip.getOrCreateInstance('.c-selected-locations__toggle-button');
toggleButtonTooltip.setContent({ '.tooltip-inner': togglerLabel });
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/sort-switcher/sort.switcher.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/sort-switcher/sort.switcher.js
index 023119ee90..c398082678 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/sort-switcher/sort.switcher.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/sort-switcher/sort.switcher.js
@@ -4,8 +4,6 @@ import PropTypes from 'prop-types';
import SimpleDropdown from '../../../common/simple-dropdown/simple.dropdown';
import { SortingContext, SortOrderContext, SORTING_OPTIONS } from '../../universal.discovery.module';
-const { ibexa } = window;
-
const SortSwitcher = ({ isDisabled }) => {
const [sorting, setSorting] = useContext(SortingContext);
const [sortOrder, setSortOrder] = useContext(SortOrderContext);
@@ -36,16 +34,10 @@ SortSwitcher.defaultProps = {
isDisabled: false,
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.topMenuActions',
- [
- {
- id: 'sort-switcher',
- priority: 20,
- component: SortSwitcher,
- },
- ],
- true,
-);
+export const SortSwitcherMenuButton = {
+ id: 'sort-switcher',
+ priority: 20,
+ component: SortSwitcher,
+};
export default SortSwitcher;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/tab-selector/tab.selector.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/tab-selector/tab.selector.js
index 701a7a398e..2a7b5c3b31 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/tab-selector/tab.selector.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/tab-selector/tab.selector.js
@@ -39,10 +39,10 @@ const TabSelector = () => {
className={className}
key={tab.id}
onClick={onClick}
- title={tab.label}
+ title={tab.getLabel()}
data-tooltip-container-selector=".c-udw-tab"
>
-
+
);
})}
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/tab/tab.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/tab/tab.js
index d705f0f5f3..82964f0856 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/tab/tab.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/tab/tab.js
@@ -6,16 +6,14 @@ import ActionsMenu from '../actions-menu/actions.menu';
import TabSelector from '../tab-selector/tab.selector';
import SelectedLocations from '../selected-locations/selected.locations';
import ContentCreateWidget from '../content-create-widget/content.create.widget';
+import ContentMetaPreview from '../../content.meta.preview.module';
import { SelectedLocationsContext, DropdownPortalRefContext, MultipleConfigContext } from '../../universal.discovery.module';
-const { ibexa } = window;
-
const Tab = ({ children, actionsDisabledMap }) => {
const topBarRef = useRef();
const bottomBarRef = useRef();
const [contentHeight, setContentHeight] = useState('100%');
- const ContentMetaPreview = ibexa.adminUiConfig.universalDiscoveryWidget.contentMetaPreview;
const [selectedLocations] = useContext(SelectedLocationsContext);
const dropdownPortalRef = useContext(DropdownPortalRefContext);
const [multiple] = useContext(MultipleConfigContext);
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/top-menu/top.menu.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/top-menu/top.menu.js
index 153ad69752..4e6555c1cb 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/top-menu/top.menu.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/top-menu/top.menu.js
@@ -6,15 +6,17 @@ import Icon from '../../../common/icon/icon';
import { TitleContext, CancelContext } from '../../universal.discovery.module';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
-
-const { Translator, ibexa } = window;
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const TopMenu = ({ actionsDisabledMap }) => {
+ const Translator = getTranslator();
+ const adminUiConfig = getAdminUiConfig();
+ const { topMenuActions } = adminUiConfig.universalDiscoveryWidget;
const title = useContext(TitleContext);
const cancelUDW = useContext(CancelContext);
const [isSearchOpened, setIsSearchOpened] = useState(false);
const sortedActions = useMemo(() => {
- const actions = [...ibexa.adminUiConfig.universalDiscoveryWidget.topMenuActions];
+ const actions = topMenuActions;
return actions.sort((actionA, actionB) => {
return actionB.priority - actionA.priority;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/translation-selector/translation.selector.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/translation-selector/translation.selector.js
index 202da88f31..32e4b4d050 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/translation-selector/translation.selector.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/translation-selector/translation.selector.js
@@ -4,9 +4,11 @@ import PropTypes from 'prop-types';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
import Icon from '../../../common/icon/icon';
-const { Translator, ibexa } = window;
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const TranslationSelectorButton = ({ hideTranslationSelector, selectTranslation, version, isOpen }) => {
+ const Translator = getTranslator();
+ const adminUiConfig = getAdminUiConfig();
const languageCodes = version ? version.VersionInfo.languageCodes.split(',') : [];
const editTranslationLabel = Translator.trans(
/*@Desc("Select translation")*/ 'meta_preview.edit_translation',
@@ -33,7 +35,7 @@ const TranslationSelectorButton = ({ hideTranslationSelector, selectTranslation,
className="c-translation-selector__language"
onClick={selectTranslation.bind(this, languageCode)}
>
- {ibexa.adminUiConfig.languages.mappings[languageCode].name}
+ {adminUiConfig.languages.mappings[languageCode].name}
))}
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-item-toggle-selection/tree.item.toggle.selection.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-item-toggle-selection/tree.item.toggle.selection.js
index 29d2640e8d..6fbea50985 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-item-toggle-selection/tree.item.toggle.selection.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-item-toggle-selection/tree.item.toggle.selection.js
@@ -1,6 +1,8 @@
import React, { useContext, useEffect } from 'react';
import PropTypes from 'prop-types';
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+
import {
UDWContext,
SelectedLocationsContext,
@@ -12,13 +14,13 @@ import {
import { findLocationsById } from '../../services/universal.discovery.service';
import ToggleSelection from '../toggle-selection/toggle.selection';
-const { ibexa, document } = window;
+const { document } = window;
const TreeItemToggleSelection = ({ locationId, isContainer, contentTypeIdentifier }) => {
const isUDW = useContext(UDWContext);
useEffect(() => {
- ibexa.helpers.tooltips.parse(document.querySelector('.c-list'));
+ parseTooltip(document.querySelector('.c-list'));
}, []);
if (!isUDW) {
@@ -53,17 +55,11 @@ const TreeItemToggleSelection = ({ locationId, isContainer, contentTypeIdentifie
);
};
-ibexa.addConfig(
- 'adminUiConfig.contentTreeWidget.secondaryItemActions',
- [
- {
- id: 'toggle-selection-button',
- priority: 30,
- component: TreeItemToggleSelection,
- },
- ],
- true,
-);
+export const TreeItemToggleSelectionMenuButton = {
+ id: 'toggle-selection-button',
+ priority: 30,
+ component: TreeItemToggleSelection,
+};
TreeItemToggleSelection.propTypes = {
locationId: PropTypes.number.isRequired,
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-view/tree.view.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-view/tree.view.js
index 1a9728b8d1..b57a1310f3 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-view/tree.view.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/tree-view/tree.view.js
@@ -1,7 +1,9 @@
import React, { useContext, useMemo } from 'react';
import PropTypes from 'prop-types';
+import { getId as getUserId } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/user.helper';
import { createCssClassNames } from '../../../common/helpers/css.class.names';
+
import ContentTreeModule from '../../../content-tree/content.tree.module';
import { loadAccordionData } from '../../services/universal.discovery.service';
import { getLocationData } from '../../content.meta.preview.module';
@@ -18,10 +20,10 @@ import {
SortOrderContext,
SortingContext,
} from '../../universal.discovery.module';
-
-const { ibexa } = window;
+import { getAdminUiConfig } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const TreeView = ({ itemsPerPage }) => {
+ const adminUiConfig = getAdminUiConfig();
const [loadedLocationsMap, dispatchLoadedLocationsAction] = useContext(LoadedLocationsMapContext);
const [markedLocationId, setMarkedLocationId] = useContext(MarkedLocationIdContext);
const [multiple] = useContext(MultipleConfigContext);
@@ -34,7 +36,7 @@ const TreeView = ({ itemsPerPage }) => {
const restInfo = useContext(RestInfoContext);
const rootLocationId = useContext(RootLocationIdContext);
const locationData = useMemo(() => getLocationData(loadedLocationsMap, markedLocationId), [markedLocationId, loadedLocationsMap]);
- const userId = ibexa.helpers.user.getId();
+ const userId = adminUiConfig.userId ?? getUserId();
const expandItem = (item, event) => {
event.preventDefault();
event.currentTarget.closest('.c-list-item__row').querySelector('.c-list-item__toggler').click();
@@ -107,6 +109,9 @@ const TreeView = ({ itemsPerPage }) => {
userId={userId}
currentLocationPath={currentLocationPath}
rootLocationId={rootLocationId}
+ subitemsLimit={adminUiConfig.contentTree.childrenLoadMaxLimi}
+ subitemsLoadLimit={adminUiConfig.contentTree.loadMoreLimit}
+ treeMaxDepth={adminUiConfig.contentTree.treeMaxDepth}
restInfo={restInfo}
onClickItem={expandItem}
readSubtree={readSubtree}
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/components/view-switcher/view.switcher.js b/src/bundle/ui-dev/src/modules/universal-discovery/components/view-switcher/view.switcher.js
index e2d734b90e..770e5df0fc 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/components/view-switcher/view.switcher.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/components/view-switcher/view.switcher.js
@@ -2,11 +2,11 @@ import React, { useContext } from 'react';
import PropTypes from 'prop-types';
import SimpleDropdown from '../../../common/simple-dropdown/simple.dropdown';
+import { getTranslator } from '../../../../../../Resources/public/js/scripts/helpers/context.helper';
import { CurrentViewContext, VIEWS } from '../../universal.discovery.module';
-const { ibexa, Translator } = window;
-
const ViewSwitcher = ({ isDisabled }) => {
+ const Translator = getTranslator();
const viewLabel = Translator.trans(/*@Desc("View")*/ 'view_switcher.view', {}, 'ibexa_universal_discovery_widget');
const [currentView, setCurrentView] = useContext(CurrentViewContext);
const selectedOption = VIEWS.find((option) => option.value === currentView);
@@ -36,16 +36,10 @@ ViewSwitcher.defaultProps = {
isDisabled: false,
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.topMenuActions',
- [
- {
- id: 'view-switcher',
- priority: 10,
- component: ViewSwitcher,
- },
- ],
- true,
-);
+export const ViewSwitcherButton = {
+ id: 'view-switcher',
+ priority: 10,
+ component: ViewSwitcher,
+};
export default ViewSwitcher;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/config.loader.js b/src/bundle/ui-dev/src/modules/universal-discovery/config.loader.js
new file mode 100644
index 0000000000..47e693aeb6
--- /dev/null
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/config.loader.js
@@ -0,0 +1,32 @@
+import UniversalDiscoveryModule from './universal.discovery.module';
+
+import { BookmarksTab } from './bookmarks.tab.module';
+import { BrowseTab } from './browse.tab.module';
+import { ContentCreateTab } from './content.create.tab.module';
+import { ContentEditTab } from './content.edit.tab.module';
+import { SearchTab } from './search.tab.module';
+
+import { SortSwitcherMenuButton } from './components/sort-switcher/sort.switcher';
+import { ContentCreateButtonMenuItem } from './components/content-create-button/content.create.button';
+import { ViewSwitcherButton } from './components/view-switcher/view.switcher';
+
+import { SelectedItemEditMenuButton } from './components/content-edit-button/selected.item.edit.button';
+
+import { TreeItemToggleSelectionMenuButton } from './components/tree-item-toggle-selection/tree.item.toggle.selection';
+
+(function (ibexa) {
+ ibexa.addConfig('modules.UniversalDiscovery', UniversalDiscoveryModule);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.tabs', [BookmarksTab], true);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.tabs', [BrowseTab], true);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.tabs', [ContentCreateTab], true);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.tabs', [ContentEditTab], true);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.tabs', [SearchTab], true);
+
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.topMenuActions', [ContentCreateButtonMenuItem], true);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.topMenuActions', [SortSwitcherMenuButton], true);
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.topMenuActions', [ViewSwitcherButton], true);
+
+ ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.selectedItemActions', [SelectedItemEditMenuButton], true);
+
+ ibexa.addConfig('adminUiConfig.contentTreeWidget.secondaryItemActions', [TreeItemToggleSelectionMenuButton], true);
+})(window.ibexa);
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/content.create.tab.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/content.create.tab.module.js
index f298094027..760ee79e3b 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/content.create.tab.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/content.create.tab.module.js
@@ -12,20 +12,15 @@ import {
LoadedLocationsMapContext,
MultipleConfigContext,
} from './universal.discovery.module';
+
import { findLocationsById } from './services/universal.discovery.service';
import deepClone from '../common/helpers/deep.clone.helper';
-const { ibexa, Translator, Routing } = window;
-
-const generateIframeUrl = ({ locationId, languageCode, contentTypeIdentifier }) => {
- return Routing.generate('ibexa.content.on_the_fly.create', {
- locationId,
- languageCode,
- contentTypeIdentifier,
- });
-};
+import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper';
+import { getTranslator, getRouting } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
const ContentCreateTabModule = () => {
+ const Routing = getRouting();
const [contentOnTheFlyData, setContentOnTheFlyData] = useContext(ContentOnTheFlyDataContext);
const tabs = useContext(TabsContext);
const contentOnTheFlyConfig = useContext(ContentOnTheFlyConfigContext);
@@ -36,8 +31,16 @@ const ContentCreateTabModule = () => {
const [selectedLocations, dispatchSelectedLocationsAction] = useContext(SelectedLocationsContext);
const [loadedLocationsMap, dispatchLoadedLocationsAction] = useContext(LoadedLocationsMapContext);
const [multiple] = useContext(MultipleConfigContext);
- const iframeUrl = generateIframeUrl(contentOnTheFlyData);
const iframeRef = createRef();
+ const getIframeUrl = () => {
+ const { locationId, languageCode, contentTypeIdentifier } = contentOnTheFlyData;
+
+ return Routing.generate('ibexa.content.on_the_fly.create', {
+ locationId,
+ languageCode,
+ contentTypeIdentifier,
+ });
+ };
const cancelContentCreate = () => {
setCreateContentVisible(false);
setContentOnTheFlyData({});
@@ -93,23 +96,17 @@ const ContentCreateTabModule = () => {
return (
-
+
);
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.tabs',
- [
- {
- id: 'content-create',
- component: ContentCreateTabModule,
- label: Translator.trans(/*@Desc("Content create")*/ 'content_create.label', {}, 'ibexa_universal_discovery_widget'),
- icon: ibexa.helpers.icon.getIconPath('search'),
- isHiddenOnList: true,
- },
- ],
- true,
-);
-
-export default ContentCreateTabModule;
+const ContentCreateTab = {
+ id: 'content-create',
+ component: ContentCreateTabModule,
+ getLabel: () => getTranslator().trans(/*@Desc("Content create")*/ 'content_create.label', {}, 'ibexa_universal_discovery_widget'),
+ getIcon: () => getIconPath('search'),
+ isHiddenOnList: true,
+};
+
+export { ContentCreateTabModule as default, ContentCreateTab };
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/content.edit.tab.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/content.edit.tab.module.js
index c39a690624..c5de0ccf22 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/content.edit.tab.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/content.edit.tab.module.js
@@ -8,12 +8,12 @@ import {
LoadedLocationsMapContext,
EditOnTheFlyDataContext,
} from './universal.discovery.module';
+import { getTranslator, getRouting } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
import { findLocationsByParentLocationId } from './services/universal.discovery.service';
import deepClone from '../common/helpers/deep.clone.helper';
-const { ibexa, Translator, Routing } = window;
-
const ContentEditTabModule = () => {
+ const Routing = getRouting();
const restInfo = useContext(RestInfoContext);
const tabs = useContext(TabsContext);
const [, setActiveTab] = useContext(ActiveTabContext);
@@ -99,17 +99,11 @@ const ContentEditTabModule = () => {
);
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.tabs',
- [
- {
- id: 'content-edit',
- component: ContentEditTabModule,
- label: Translator.trans(/*@Desc("Content edit")*/ 'content_edit.label', {}, 'ibexa_universal_discovery_widget'),
- isHiddenOnList: true,
- },
- ],
- true,
-);
+const ContentEditTab = {
+ id: 'content-edit',
+ component: ContentEditTabModule,
+ getLabel: () => getTranslator().trans(/*@Desc("Content edit")*/ 'content_edit.label', {}, 'ibexa_universal_discovery_widget'),
+ isHiddenOnList: true,
+};
-export default ContentEditTabModule;
+export { ContentEditTabModule as default, ContentEditTab };
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/content.meta.preview.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/content.meta.preview.module.js
index f01726b444..d335cebcff 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/content.meta.preview.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/content.meta.preview.module.js
@@ -3,9 +3,8 @@ import React, { useContext, useEffect, useMemo, useRef } from 'react';
import Icon from '../common/icon/icon';
import Thumbnail from '../common/thumbnail/thumbnail';
import { createCssClassNames } from '../common/helpers/css.class.names';
-import ContentEditButton from './components/content-edit-button/content.edit.button';
-
import { addBookmark, removeBookmark } from './services/universal.discovery.service';
+import ContentEditButton from './components/content-edit-button/content.edit.button';
import {
MarkedLocationIdContext,
LoadedLocationsMapContext,
@@ -14,7 +13,9 @@ import {
AllowRedirectsContext,
} from './universal.discovery.module';
-const { Translator, ibexa, Routing } = window;
+import { formatShortDateTime } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/timezone.helper';
+import { parse as parseTooltip } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+import { getTranslator, getRouting, getAdminUiConfig } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
export const getLocationData = (loadedLocationsMap, markedLocationId) =>
loadedLocationsMap.find((loadedLocation) => loadedLocation.parentLocationId === markedLocationId) ||
@@ -22,13 +23,15 @@ export const getLocationData = (loadedLocationsMap, markedLocationId) =>
loadedLocationsMap[loadedLocationsMap.length - 1].subitems.find((subitem) => subitem.location.id === markedLocationId));
const ContentMetaPreview = () => {
+ const Translator = getTranslator();
+ const Routing = getRouting();
+ const adminUiConfig = getAdminUiConfig();
const refContentMetaPreview = useRef(null);
const [markedLocationId] = useContext(MarkedLocationIdContext);
const [loadedLocationsMap, dispatchLoadedLocationsAction] = useContext(LoadedLocationsMapContext);
const contentTypesMap = useContext(ContentTypesMapContext);
const restInfo = useContext(RestInfoContext);
const allowRedirects = useContext(AllowRedirectsContext);
- const { formatShortDateTime } = ibexa.helpers.timezone;
const locationData = useMemo(() => getLocationData(loadedLocationsMap, markedLocationId), [markedLocationId, loadedLocationsMap]);
const lastModifiedLabel = Translator.trans(/*@Desc("Modified")*/ 'meta_preview.last_modified', {}, 'ibexa_universal_discovery_widget');
const creationDateLabel = Translator.trans(/*@Desc("Created")*/ 'meta_preview.creation_date', {}, 'ibexa_universal_discovery_widget');
@@ -37,9 +40,10 @@ const ContentMetaPreview = () => {
{},
'ibexa_universal_discovery_widget',
);
+ const { languages, timezone, dateFormat } = adminUiConfig;
useEffect(() => {
- ibexa.helpers.tooltips.parse(refContentMetaPreview.current);
+ parseTooltip(refContentMetaPreview.current);
});
if (!markedLocationId || markedLocationId === 1 || !locationData) {
@@ -144,13 +148,21 @@ const ContentMetaPreview = () => {
{lastModifiedLabel}
- {formatShortDateTime(new Date(location.ContentInfo.Content.lastModificationDate))}
+ {formatShortDateTime(
+ new Date(location.ContentInfo.Content.lastModificationDate),
+ timezone,
+ dateFormat.shortDateTimeFormat,
+ )}
{creationDateLabel}
- {formatShortDateTime(new Date(location.ContentInfo.Content.publishedDate))}
+ {formatShortDateTime(
+ new Date(location.ContentInfo.Content.publishedDate),
+ timezone,
+ dateFormat.shortDateTimeFormat,
+ )}
@@ -159,7 +171,7 @@ const ContentMetaPreview = () => {
{version.VersionInfo.languageCodes.split(',').map((languageCode) => {
return (
- {window.ibexa.adminUiConfig.languages.mappings[languageCode].name}
+ {languages.mappings[languageCode].name}
);
})}
@@ -179,6 +191,4 @@ const ContentMetaPreview = () => {
);
};
-ibexa.addConfig('adminUiConfig.universalDiscoveryWidget.contentMetaPreview', ContentMetaPreview);
-
export default ContentMetaPreview;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/hooks/useSearchByQueryFetch.js b/src/bundle/ui-dev/src/modules/universal-discovery/hooks/useSearchByQueryFetch.js
index d01f65f83a..b32baf9888 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/hooks/useSearchByQueryFetch.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/hooks/useSearchByQueryFetch.js
@@ -44,7 +44,15 @@ export const useSearchByQueryFetch = () => {
dispatchLoadedLocationsAction({ type: 'CLEAR_LOCATIONS' });
dispatch({ type: SEARCH_END, response });
};
- const query = { FullTextCriterion: fullTextCriterion ? fullTextCriterion : `${searchText}*` };
+ const query = {};
+
+ if (searchText) {
+ query.FullTextCriterion = `${searchText}*`;
+ }
+
+ if (fullTextCriterion) {
+ query.FullTextCriterion = fullTextCriterion;
+ }
if (contentTypesIdentifiers && contentTypesIdentifiers.length) {
query.ContentTypeIdentifierCriterion = contentTypesIdentifiers;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/search.tab.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/search.tab.module.js
index a1684df8bf..0e4479ba53 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/search.tab.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/search.tab.module.js
@@ -5,7 +5,8 @@ import Search from './components/search/search';
import { LoadedLocationsMapContext, MarkedLocationIdContext, TabsConfigContext } from './universal.discovery.module';
-const { ibexa, Translator } = window;
+import { getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+import { getIconPath } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/icon.helper';
const SearchTabModule = () => {
const tabsConfig = useContext(TabsConfigContext);
@@ -34,18 +35,12 @@ const SearchTabModule = () => {
);
};
-ibexa.addConfig(
- 'adminUiConfig.universalDiscoveryWidget.tabs',
- [
- {
- id: 'search',
- component: SearchTabModule,
- label: Translator.trans(/*@Desc("Search")*/ 'search.label', {}, 'ibexa_universal_discovery_widget'),
- icon: ibexa.helpers.icon.getIconPath('search'),
- isHiddenOnList: true,
- },
- ],
- true,
-);
-
-export default SearchTabModule;
+const SearchTab = {
+ id: 'search',
+ component: SearchTabModule,
+ getLabel: () => getTranslator().trans(/*@Desc("Search")*/ 'search.label', {}, 'ibexa_universal_discovery_widget'),
+ getIcon: () => getIconPath('search'),
+ isHiddenOnList: true,
+};
+
+export { SearchTabModule as ValueTypeDefault, SearchTab };
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/services/universal.discovery.service.js b/src/bundle/ui-dev/src/modules/universal-discovery/services/universal.discovery.service.js
index 8b60864379..b62782dbb2 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/services/universal.discovery.service.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/services/universal.discovery.service.js
@@ -1,6 +1,8 @@
+import { getRequestHeaders, getRequestMode } from '../../../../../Resources/public/js/scripts/helpers/request.helper.js';
import { showErrorNotification } from '../../common/services/notification.service';
import { handleRequestResponse, handleRequestResponseStatus } from '../../common/helpers/request.helper.js';
+const DEFAULT_INSTANCE_URL = window.location.origin;
const HEADERS_CREATE_VIEW = {
Accept: 'application/vnd.ibexa.api.View+json; version=1.1',
'Content-Type': 'application/vnd.ibexa.api.ViewInput+json; version=1.1',
@@ -41,28 +43,33 @@ export const findLocationsByParentLocationId = (
{
token,
siteaccess,
+ accessToken,
parentLocationId,
limit = QUERY_LIMIT,
offset = 0,
sortClause = 'DatePublished',
sortOrder = 'ascending',
gridView = false,
+ instanceUrl = DEFAULT_INSTANCE_URL,
},
callback,
) => {
- let url = `${ENDPOINT_LOCATION}/${parentLocationId}`;
+ let url = `${instanceUrl}${ENDPOINT_LOCATION}/${parentLocationId}`;
if (gridView) {
url += '/gridview';
}
const request = new Request(`${url}?limit=${limit}&offset=${offset}&sortClause=${sortClause}&sortOrder=${sortOrder}`, {
method: 'GET',
- headers: {
- 'X-CSRF-Token': token,
- Accept: 'application/json',
- 'X-Siteaccess': siteaccess,
- },
- mode: 'same-origin',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/json',
+ },
+ }),
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -86,31 +93,37 @@ export const findLocationsByParentLocationId = (
.catch(showErrorNotificationAbortWrapper);
};
-export const loadAccordionData = (
+export const loadAccordionData = async (
{
token,
siteaccess,
+ accessToken,
parentLocationId,
limit = QUERY_LIMIT,
sortClause = 'DatePublished',
sortOrder = 'ascending',
gridView = false,
rootLocationId = 1,
+ instanceUrl = DEFAULT_INSTANCE_URL,
},
callback,
) => {
- let url = `${ENDPOINT_ACCORDION}/${parentLocationId}`;
+ let url = `${instanceUrl}${ENDPOINT_ACCORDION}/${parentLocationId}`;
if (gridView) {
url += '/gridview';
}
+
const request = new Request(`${url}?limit=${limit}&sortClause=${sortClause}&sortOrder=${sortOrder}&rootLocationId=${rootLocationId}`, {
method: 'GET',
- headers: {
- 'X-CSRF-Token': token,
- Accept: 'application/json',
- 'X-Siteaccess': siteaccess,
- },
- mode: 'same-origin',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/json',
+ },
+ }),
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -160,7 +173,18 @@ export const loadAccordionData = (
};
export const findLocationsBySearchQuery = (
- { token, siteaccess, query, aggregations, filters, limit = QUERY_LIMIT, offset = 0, languageCode = null },
+ {
+ token,
+ siteaccess,
+ accessToken,
+ query,
+ aggregations,
+ filters,
+ limit = QUERY_LIMIT,
+ offset = 0,
+ languageCode = null,
+ instanceUrl = DEFAULT_INSTANCE_URL,
+ },
callback,
) => {
const useAlwaysAvailable = true;
@@ -181,11 +205,16 @@ export const findLocationsBySearchQuery = (
},
},
});
- const request = new Request(ENDPOINT_CREATE_VIEW, {
+ const request = new Request(`${instanceUrl}${ENDPOINT_CREATE_VIEW}`, {
method: 'POST',
- headers: { ...HEADERS_CREATE_VIEW, 'X-Siteaccess': siteaccess, 'X-CSRF-Token': token },
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: HEADERS_CREATE_VIEW,
+ }),
body,
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -204,7 +233,10 @@ export const findLocationsBySearchQuery = (
.catch(showErrorNotificationAbortWrapper);
};
-export const findLocationsById = ({ token, siteaccess, id, limit = QUERY_LIMIT, offset = 0 }, callback) => {
+export const findLocationsById = (
+ { token, siteaccess, accessToken, id, limit = QUERY_LIMIT, offset = 0, instanceUrl = DEFAULT_INSTANCE_URL },
+ callback,
+) => {
const body = JSON.stringify({
ViewInput: {
identifier: `udw-locations-by-id-${id}`,
@@ -218,11 +250,17 @@ export const findLocationsById = ({ token, siteaccess, id, limit = QUERY_LIMIT,
},
},
});
- const request = new Request(ENDPOINT_CREATE_VIEW, {
+
+ const request = new Request(`${instanceUrl}${ENDPOINT_CREATE_VIEW}`, {
method: 'POST',
- headers: { ...HEADERS_CREATE_VIEW, 'X-Siteaccess': siteaccess, 'X-CSRF-Token': token },
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: HEADERS_CREATE_VIEW,
+ }),
body,
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -236,7 +274,10 @@ export const findLocationsById = ({ token, siteaccess, id, limit = QUERY_LIMIT,
.catch(showErrorNotificationAbortWrapper);
};
-export const findContentInfo = ({ token, siteaccess, contentId, limit = QUERY_LIMIT, offset = 0 }, callback) => {
+export const findContentInfo = (
+ { token, siteaccess, accessToken, contentId, limit = QUERY_LIMIT, offset = 0, instanceUrl = DEFAULT_INSTANCE_URL },
+ callback,
+) => {
const body = JSON.stringify({
ViewInput: {
identifier: `udw-load-content-info-${contentId}`,
@@ -250,11 +291,16 @@ export const findContentInfo = ({ token, siteaccess, contentId, limit = QUERY_LI
},
},
});
- const request = new Request(ENDPOINT_CREATE_VIEW, {
+ const request = new Request(`${instanceUrl}${ENDPOINT_CREATE_VIEW}`, {
method: 'POST',
- headers: { ...HEADERS_CREATE_VIEW, 'X-Siteaccess': siteaccess, 'X-CSRF-Token': token },
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: HEADERS_CREATE_VIEW,
+ }),
body,
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -268,15 +314,18 @@ export const findContentInfo = ({ token, siteaccess, contentId, limit = QUERY_LI
.catch(showErrorNotificationAbortWrapper);
};
-export const loadBookmarks = ({ token, siteaccess, limit, offset }, callback) => {
- const request = new Request(`${ENDPOINT_BOOKMARK}?limit=${limit}&offset=${offset}`, {
+export const loadBookmarks = ({ token, siteaccess, accessToken, limit, offset, instanceUrl = DEFAULT_INSTANCE_URL }, callback) => {
+ const request = new Request(`${instanceUrl}${ENDPOINT_BOOKMARK}?limit=${limit}&offset=${offset}`, {
method: 'GET',
- headers: {
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
- Accept: 'application/vnd.ibexa.api.ContentTypeInfoList+json',
- },
- mode: 'same-origin',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/vnd.ibexa.api.ContentTypeInfoList+json',
+ },
+ }),
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -291,14 +340,11 @@ export const loadBookmarks = ({ token, siteaccess, limit, offset }, callback) =>
.catch(showErrorNotificationAbortWrapper);
};
-const toggleBookmark = ({ siteaccess, token, locationId }, callback, method) => {
- const request = new Request(`${ENDPOINT_BOOKMARK}/${locationId}`, {
+const toggleBookmark = ({ siteaccess, token, accessToken, locationId, instanceUrl = DEFAULT_INSTANCE_URL }, callback, method) => {
+ const request = new Request(`${instanceUrl}${ENDPOINT_BOOKMARK}/${locationId}`, {
method,
- headers: {
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
- },
- mode: 'same-origin',
+ headers: getRequestHeaders({ token, siteaccess, accessToken }),
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -313,37 +359,46 @@ export const removeBookmark = (options, callback) => {
toggleBookmark(options, callback, 'DELETE');
};
-export const loadContentTypes = ({ token, siteaccess }, callback) => {
- const request = new Request('/api/ibexa/v2/content/types', {
+export const loadContentTypes = ({ token, siteaccess, accessToken, instanceUrl = DEFAULT_INSTANCE_URL }, callback) => {
+ const request = new Request(`${instanceUrl}/api/ibexa/v2/content/types`, {
method: 'GET',
- headers: {
- Accept: 'application/vnd.ibexa.api.ContentTypeInfoList+json',
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
- },
- mode: 'same-origin',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/vnd.ibexa.api.ContentTypeInfoList+json',
+ },
+ }),
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
fetch(request).then(handleRequestResponse).then(callback).catch(showErrorNotificationAbortWrapper);
};
-export const createDraft = ({ token, siteaccess, contentId }, callback) => {
- const request = new Request(`/api/ibexa/v2/content/objects/${contentId}/currentversion`, {
+export const createDraft = ({ token, siteaccess, accessToken, contentId, instanceUrl = DEFAULT_INSTANCE_URL }, callback) => {
+ const request = new Request(`${instanceUrl}/api/ibexa/v2/content/objects/${contentId}/currentversion`, {
method: 'COPY',
- headers: {
- Accept: 'application/vnd.ibexa.api.VersionUpdate+json',
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
- },
- mode: 'same-origin',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/vnd.ibexa.api.VersionUpdate+json',
+ },
+ }),
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
fetch(request).then(handleRequestResponse).then(callback).catch(showErrorNotificationAbortWrapper);
};
-export const loadContentInfo = ({ token, siteaccess, contentId, limit = QUERY_LIMIT, offset = 0, signal }, callback) => {
+export const loadContentInfo = (
+ { token, siteaccess, accessToken, contentId, limit = QUERY_LIMIT, offset = 0, signal, instanceUrl = DEFAULT_INSTANCE_URL },
+ callback,
+) => {
const body = JSON.stringify({
ViewInput: {
identifier: `udw-load-content-info-${contentId}`,
@@ -357,11 +412,16 @@ export const loadContentInfo = ({ token, siteaccess, contentId, limit = QUERY_LI
},
},
});
- const request = new Request(ENDPOINT_CREATE_VIEW, {
+ const request = new Request(`${instanceUrl}${ENDPOINT_CREATE_VIEW}`, {
method: 'POST',
- headers: { ...HEADERS_CREATE_VIEW, 'X-Siteaccess': siteaccess, 'X-CSRF-Token': token },
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: HEADERS_CREATE_VIEW,
+ }),
body,
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
@@ -375,17 +435,44 @@ export const loadContentInfo = ({ token, siteaccess, contentId, limit = QUERY_LI
.catch(showErrorNotificationAbortWrapper);
};
-export const loadLocationsWithPermissions = ({ token, siteaccess, locationIds, signal }, callback) => {
- const request = new Request(`${ENDPOINT_LOCATION_LIST}?locationIds=${locationIds}`, {
- headers: {
- Accept: 'application/vnd.ibexa.api.VersionUpdate+json',
- 'X-Siteaccess': siteaccess,
- 'X-CSRF-Token': token,
- },
+export const loadLocationsWithPermissions = (
+ { token, siteaccess, accessToken, locationIds, signal, instanceUrl = DEFAULT_INSTANCE_URL },
+ callback,
+) => {
+ const request = new Request(`${instanceUrl}${ENDPOINT_LOCATION_LIST}?locationIds=${locationIds}`, {
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/vnd.ibexa.api.VersionUpdate+json',
+ },
+ }),
method: 'GET',
- mode: 'same-origin',
+ mode: getRequestMode({ instanceUrl }),
credentials: 'same-origin',
});
fetch(request, { signal }).then(handleRequestResponse).then(callback).catch(showErrorNotificationAbortWrapper);
};
+
+export const fetchAdminConfig = async ({ token, siteaccess, accessToken, instanceUrl = DEFAULT_INSTANCE_URL }) => {
+ const request = new Request(`${instanceUrl}/api/ibexa/v2/application-config`, {
+ method: 'GET',
+ headers: getRequestHeaders({
+ token,
+ siteaccess,
+ accessToken,
+ extraHeaders: {
+ Accept: 'application/json',
+ },
+ }),
+ mode: getRequestMode({ instanceUrl }),
+ credentials: 'same-origin',
+ });
+
+ const adminUiData = await fetch(request);
+ const adminUiConfig = await adminUiData.json();
+
+ return adminUiConfig.ApplicationConfig;
+};
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.global.loader.js b/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.global.loader.js
new file mode 100644
index 0000000000..11f6ed8721
--- /dev/null
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.global.loader.js
@@ -0,0 +1,13 @@
+import React from 'react';
+
+const UniversalDiscoveryModuleGlobalLoader = () => {
+ return (
+
+ );
+};
+
+export default UniversalDiscoveryModuleGlobalLoader;
diff --git a/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js b/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js
index d7e7eaaad2..c8bc6eeecc 100644
--- a/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js
+++ b/src/bundle/ui-dev/src/modules/universal-discovery/universal.discovery.module.js
@@ -14,97 +14,101 @@ import {
loadLocationsWithPermissions,
} from './services/universal.discovery.service';
-const { Translator, ibexa, document } = window;
+import {
+ parse as parseTooltips,
+ hideAll as hideAllTooltips,
+} from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/tooltips.helper';
+import { getAdminUiConfig, getTranslator } from '@ibexa-admin-ui/src/bundle/Resources/public/js/scripts/helpers/context.helper';
+
+const { document } = window;
const CLASS_SCROLL_DISABLED = 'ibexa-scroll-disabled';
export const SORTING_OPTIONS = [
{
value: 'date:asc',
- label: (
-
- {Translator.trans(/*@Desc("Date")*/ 'sorting.date.label', {}, 'ibexa_universal_discovery_widget')}
-
-
- ),
- selectedLabel: (
-
- {Translator.trans(/*@Desc("Sort by date")*/ 'sorting.date.selected_label', {}, 'ibexa_universal_discovery_widget')}
-
-
- ),
+ getLabel: () => {
+ return (
+
+ {getTranslator().trans(/*@Desc("Date")*/ 'sorting.date.label', {}, 'ibexa_universal_discovery_widget')}
+
+
+ );
+ },
+ selectedLabel: () => {
+ return (
+
+ {getTranslator().trans(/*@Desc("Sort by date")*/ 'sorting.date.selected_label', {}, 'ibexa_universal_discovery_widget')}
+
+
+ );
+ },
sortClause: 'DatePublished',
sortOrder: 'ascending',
},
{
value: 'date:desc',
- label: (
-
- {Translator.trans(/*@Desc("Date")*/ 'sorting.date.label', {}, 'ibexa_universal_discovery_widget')}
-
-
- ),
- selectedLabel: (
-
- {Translator.trans(/*@Desc("Sort by date")*/ 'sorting.date.selected_label', {}, 'ibexa_universal_discovery_widget')}
-
-
- ),
+ getLabel: () => {
+ return (
+
+ {getTranslator().trans(/*@Desc("Date")*/ 'sorting.date.label', {}, 'ibexa_universal_discovery_widget')}
+
+
+ );
+ },
+ selectedLabel: () => {
+ return (
+
+ {getTranslator().trans(/*@Desc("Sort by date")*/ 'sorting.date.selected_label', {}, 'ibexa_universal_discovery_widget')}
+
+
+ );
+ },
sortClause: 'DatePublished',
sortOrder: 'descending',
},
{
value: 'name:asc',
- label: Translator.trans(/*@Desc("Name A-Z")*/ 'sorting.name.asc.label', {}, 'ibexa_universal_discovery_widget'),
- selectedLabel: Translator.trans(
- /*@Desc("Sort by name A-Z")*/ 'sorting.name.asc.selected_label',
- {},
- 'ibexa_universal_discovery_widget',
- ),
+ getLabel: () => getTranslator().trans(/*@Desc("Name A-Z")*/ 'sorting.name.asc.label', {}, 'ibexa_universal_discovery_widget'),
+ selectedLabel: () =>
+ getTranslator().trans(/*@Desc("Sort by name A-Z")*/ 'sorting.name.asc.selected_label', {}, 'ibexa_universal_discovery_widget'),
sortClause: 'ContentName',
sortOrder: 'ascending',
},
{
value: 'name:desc',
- label: Translator.trans(/*@Desc("Name Z-A")*/ 'sorting.name.desc.label', {}, 'ibexa_universal_discovery_widget'),
- selectedLabel: Translator.trans(
- /*@Desc("Sort by name Z-A")*/ 'sorting.name.desc.selected_label',
- {},
- 'ibexa_universal_discovery_widget',
- ),
+ getLabel: () => getTranslator().trans(/*@Desc("Name Z-A")*/ 'sorting.name.desc.label', {}, 'ibexa_universal_discovery_widget'),
+ selectedLabel: () =>
+ getTranslator().trans(/*@Desc("Sort by name Z-A")*/ 'sorting.name.desc.selected_label', {}, 'ibexa_universal_discovery_widget'),
sortClause: 'ContentName',
sortOrder: 'descending',
},
];
+
export const VIEWS = [
{
value: 'finder',
iconName: 'panels',
- label: Translator.trans(/*@Desc("Panels view")*/ 'sorting.panels.view', {}, 'ibexa_universal_discovery_widget'),
+ getLabel: () => getTranslator().trans(/*@Desc("Panels view")*/ 'sorting.panels.view', {}, 'ibexa_universal_discovery_widget'),
},
{
value: 'grid',
iconName: 'view-grid',
- label: Translator.trans(/*@Desc("Grid view")*/ 'sorting.grid.view', {}, 'ibexa_universal_discovery_widget'),
+ getLabel: () => getTranslator().trans(/*@Desc("Grid view")*/ 'sorting.grid.view', {}, 'ibexa_universal_discovery_widget'),
},
{
value: 'tree',
iconName: 'content-tree',
- label: Translator.trans(/*@Desc("Tree view")*/ 'sorting.tree.view', {}, 'ibexa_universal_discovery_widget'),
+ getLabel: () => getTranslator().trans(/*@Desc("Tree view")*/ 'sorting.tree.view', {}, 'ibexa_universal_discovery_widget'),
},
];
-const restInfo = {
- token: document.querySelector('meta[name="CSRF-Token"]').content,
- siteaccess: document.querySelector('meta[name="SiteAccess"]').content,
+const defaultRestInfo = {
+ accsessToken: null,
+ instanceUrl: window.location.origin,
+ token: document.querySelector('meta[name="CSRF-Token"]')?.content,
+ siteaccess: document.querySelector('meta[name="SiteAccess"]')?.content,
};
-const contentTypesMapGlobal = Object.values(ibexa.adminUiConfig.contentTypes).reduce((contentTypesMap, contentTypesGroup) => {
- contentTypesGroup.forEach((contentType) => {
- contentTypesMap[contentType.href] = contentType;
- });
-
- return contentTypesMap;
-}, {});
export const UDWContext = createContext();
export const RestInfoContext = createContext();
@@ -137,7 +141,9 @@ export const SearchTextContext = createContext();
export const DropdownPortalRefContext = createContext();
const UniversalDiscoveryModule = (props) => {
- const { tabs } = ibexa.adminUiConfig.universalDiscoveryWidget;
+ const { restInfo } = props;
+ const adminUiConfig = getAdminUiConfig();
+ const { tabs } = adminUiConfig.universalDiscoveryWidget;
const defaultMarkedLocationId = props.startingLocationId || props.rootLocationId;
const abortControllerRef = useRef();
const dropdownPortalRef = useRef();
@@ -195,6 +201,13 @@ const UniversalDiscoveryModule = (props) => {
loadContentInfo({ ...restInfo, contentId, signal }, (response) => resolve(response));
});
};
+ const contentTypesMapGlobal = Object.values(adminUiConfig.contentTypes).reduce((contentTypesMap, contentTypesGroup) => {
+ contentTypesGroup.forEach((contentType) => {
+ contentTypesMap[contentType.href] = contentType;
+ });
+
+ return contentTypesMap;
+ }, {});
const onConfirm = useCallback(
(selectedItems = selectedLocations) => {
loadVersions().then((locationsWithVersions) => {
@@ -241,17 +254,17 @@ const UniversalDiscoveryModule = (props) => {
addContentTypesInfo(contentTypesMap);
};
- window.ibexa.adminUiConfig.universalDiscoveryWidget.contentTypesLoaders?.forEach((contentTypesLoader) =>
+ adminUiConfig.universalDiscoveryWidget.contentTypesLoaders?.forEach((contentTypesLoader) =>
contentTypesLoader(addContentTypesInfo),
);
loadContentTypes(restInfo, handleLoadContentTypes);
document.body.dispatchEvent(new CustomEvent('ibexa-udw-opened'));
- ibexa.helpers.tooltips.parse(document.querySelector('.c-udw-tab'));
+ parseTooltips(document.querySelector('.c-udw-tab'));
return () => {
document.body.dispatchEvent(new CustomEvent('ibexa-udw-closed'));
- ibexa.helpers.tooltips.hideAll();
+ hideAllTooltips();
};
}, []);
@@ -371,7 +384,6 @@ const UniversalDiscoveryModule = (props) => {
dispatchLoadedLocationsAction({ type: 'SET_LOCATIONS', data: locationsMap });
}, [sorting, sortOrder]);
- /* eslint-disable max-len */
return (
@@ -516,6 +528,12 @@ UniversalDiscoveryModule.propTypes = {
selectedLocations: PropTypes.array,
allowRedirects: PropTypes.bool.isRequired,
allowConfirmation: PropTypes.bool.isRequired,
+ restInfo: PropTypes.shape({
+ token: PropTypes.string,
+ siteaccess: PropTypes.string,
+ accsessToken: PropTypes.string,
+ instanceUrl: PropTypes.string,
+ }),
};
UniversalDiscoveryModule.defaultProps = {
@@ -529,8 +547,7 @@ UniversalDiscoveryModule.defaultProps = {
activeSortOrder: 'ascending',
activeView: 'finder',
selectedLocations: [],
+ restInfo: defaultRestInfo,
};
-ibexa.addConfig('modules.UniversalDiscovery', UniversalDiscoveryModule);
-
export default UniversalDiscoveryModule;
diff --git a/src/contracts/REST/ApplicationConfigRestResolverInterface.php b/src/contracts/REST/ApplicationConfigRestResolverInterface.php
new file mode 100644
index 0000000000..ea96af5cc5
--- /dev/null
+++ b/src/contracts/REST/ApplicationConfigRestResolverInterface.php
@@ -0,0 +1,23 @@
+ $config
+ *
+ * @return mixed
+ */
+ public function resolve(array $config);
+}
diff --git a/src/contracts/REST/ApplicationConfigRestResolverRegistryInterface.php b/src/contracts/REST/ApplicationConfigRestResolverRegistryInterface.php
new file mode 100644
index 0000000000..53a51817c8
--- /dev/null
+++ b/src/contracts/REST/ApplicationConfigRestResolverRegistryInterface.php
@@ -0,0 +1,23 @@
+
+ */
+ public function getResolvers(string $namespace): iterable;
+}
diff --git a/src/lib/REST/Resolver/ApplicationConfigRestResolverRegistry.php b/src/lib/REST/Resolver/ApplicationConfigRestResolverRegistry.php
new file mode 100644
index 0000000000..47fe8cdfec
--- /dev/null
+++ b/src/lib/REST/Resolver/ApplicationConfigRestResolverRegistry.php
@@ -0,0 +1,79 @@
+ */
+ private iterable $resolvers;
+
+ /**
+ * @param iterable<\Ibexa\Contracts\AdminUi\REST\ApplicationConfigRestResolverInterface> $resolvers
+ */
+ public function __construct(iterable $resolvers)
+ {
+ $this->resolvers = $resolvers;
+ }
+
+ public function hasResolver(
+ string $namespace,
+ string $parameter
+ ): bool {
+ foreach ($this->resolvers as $mapper) {
+ if (
+ $mapper->supportsNamespace($namespace)
+ && $mapper->supportsParameter($parameter)
+ ) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function hasResolvers(string $namespace): bool
+ {
+ foreach ($this->resolvers as $mapper) {
+ if ($mapper->supportsNamespace($namespace)) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ public function getResolver(string $namespace, string $parameter): ?ApplicationConfigRestResolverInterface
+ {
+ foreach ($this->resolvers as $mapper) {
+ if (
+ $mapper->supportsNamespace($namespace)
+ && $mapper->supportsParameter($parameter)
+ ) {
+ return $mapper;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * @return iterable<\Ibexa\Contracts\AdminUi\REST\ApplicationConfigRestResolverInterface>
+ */
+ public function getResolvers(string $namespace): iterable
+ {
+ foreach ($this->resolvers as $mapper) {
+ if ($mapper->supportsNamespace($namespace)) {
+ yield $mapper;
+ }
+ }
+ }
+}
diff --git a/src/lib/REST/Resolver/ProfilePictureFieldConfigRestResolver.php b/src/lib/REST/Resolver/ProfilePictureFieldConfigRestResolver.php
new file mode 100644
index 0000000000..b58b5278eb
--- /dev/null
+++ b/src/lib/REST/Resolver/ProfilePictureFieldConfigRestResolver.php
@@ -0,0 +1,53 @@
+getContentType();
+ if (null === $config['profile_picture_field']) {
+ return null;
+ }
+
+ $fieldDefinition = $userContentType->getFieldDefinition(
+ $config['profile_picture_field']->fieldDefIdentifier
+ );
+
+ if (null === $fieldDefinition) {
+ return null;
+ }
+
+ return new RestFieldDefinition($userContentType, $fieldDefinition);
+ }
+}
diff --git a/src/lib/REST/Resolver/UserConfigRestResolver.php b/src/lib/REST/Resolver/UserConfigRestResolver.php
new file mode 100644
index 0000000000..610d6c78bb
--- /dev/null
+++ b/src/lib/REST/Resolver/UserConfigRestResolver.php
@@ -0,0 +1,33 @@
+