407b4c9c9 Новый календарь: первый час дня теперь настраивается. Подсказки.
41907bf51 WIP: BigCalendar -> Fullcalendar
5fff1f800 global.js: удалены неиспользуемые импорты.
4a4e2086a global.js: merge/combine работали некорректно в некоторых случаях (например, плагин Merlin). AttachmentsService теперь возвращает пустой массив вместо null, если вложения не предоставлены (клиент теперь может очистить список вложений после удаления последнего вложения).
6bf735d24 global.js: объединение стало намного короче.
407b4c9c9
Новый календарь: первый час дня теперь настраивается. Подсказки.
407b4c9c917150e84635867ae2e8918629ae9636
diff --git a/projectforge-webapp/src/utilities/global.js b/projectforge-webapp/src/utilities/global.js
index aad75bcfa..bfe602d12 100644
--- a/projectforge-webapp/src/utilities/global.js
+++ b/projectforge-webapp/src/utilities/global.js
@@ -57,6 +57,13 @@ String.idify = (string) => string.replace(/[.#*, >+~/[\]=|^$:()]/g, '-');
String.truncate = (str, length) => (str?.length > length ? str.substring(0, length) : str);
+Number.as2Digits = (number) => {
+ if (number < 10) {
+ return `0${number.toString()}`;
+ }
+ return number.toString();
+};
+
Object.getResponseHeaderFilename = (contentDisposition) => {
// attachment; filename*=UTF-8''document.pdf; filename=document.pdf
const matches = /filename[^;=\n]*=(UTF-8(['"]*))?([^;=\n]*)*/.exec(contentDisposition);
41907bf51
WIP: BigCalendar -> Fullcalendar
41907bf51150c1ad7299e66b8bb3ed1bb8534c0e
diff --git a/projectforge-webapp/src/utilities/global.js b/projectforge-webapp/src/utilities/global.js
index ab0ed3509..aad75bcfa 100644
--- a/projectforge-webapp/src/utilities/global.js
+++ b/projectforge-webapp/src/utilities/global.js
@@ -62,3 +62,8 @@ Object.getResponseHeaderFilename = (contentDisposition) => {
const matches = /filename[^;=\n]*=(UTF-8(['"]*))?([^;=\n]*)*/.exec(contentDisposition);
return matches && matches.length >= 3 && matches[3] ? decodeURI(matches[3].replace(/['"]/g, '')) : 'download';
};
+
+Date.toIsoDateString = (date) => {
+ const offset = date.getTimezoneOffset();
+ return new Date(date.getTime() - (offset * 60 * 1000)).toISOString().split('T')[0];
+};
5fff1f800
global.js: удалены неиспользуемые импорты.
5fff1f8001d869654577e33ec32513b63e70bca1
diff --git a/projectforge-webapp/src/utilities/global.js b/projectforge-webapp/src/utilities/global.js
index 7cbe32c7b..ab0ed3509 100644
--- a/projectforge-webapp/src/utilities/global.js
+++ b/projectforge-webapp/src/utilities/global.js
@@ -1,6 +1,4 @@
-import { forIn, get, merge, set } from 'lodash/object';
-import { mergeWith } from 'lodash';
-import { cloneDeep, isArray } from 'lodash/lang';
+import { forIn, get, set } from 'lodash/object';
// https://stackoverflow.com/a/6491621
Object.getByString = (object, multiKey) => {
4a4e2086a
global.js: merge/combine работали некорректно в некоторых случаях (например, плагин Merlin). AttachmentsService теперь возвращает пустой массив вместо null, если вложения не предоставлены (клиент теперь может очистить список вложений после удаления последнего вложения).
4a4e2086aced8e2fa6608da4b65e087028b6138a
diff --git a/projectforge-webapp/src/utilities/global.js b/projectforge-webapp/src/utilities/global.js
index 6ddc999f8..7cbe32c7b 100644
--- a/projectforge-webapp/src/utilities/global.js
+++ b/projectforge-webapp/src/utilities/global.js
@@ -1,4 +1,6 @@
-import { forIn, get, set } from 'lodash/object';
+import { forIn, get, merge, set } from 'lodash/object';
+import { mergeWith } from 'lodash';
+import { cloneDeep, isArray } from 'lodash/lang';
// https://stackoverflow.com/a/6491621
Object.getByString = (object, multiKey) => {
@@ -15,11 +17,31 @@ Object.getByString = (object, multiKey) => {
Object.isEmpty = (object) => Object.keys(object).length === 0;
+// Не удалять отсутствующие свойства данных при слиянии:
+const mergeDataProps = (src, combined) => {
+ const srcData = src.data;
+ const combinedData = combined.data;
+ if (!combinedData) {
+ return srcData;
+ }
+ forIn(srcData, (value, key) => {
+ if (Object.prototype.hasOwnProperty.call(srcData, key)) {
+ // Если свойство существует, используем его: значение может быть undefined.
+ set(combinedData, key, value);
+ }
+ });
+ return combinedData;
+};
+
// Объединяет два объекта. Пути вида user.rights[2].value также поддерживаются в полях o2.
-Object.combine = (o1, o2) => {
- const combined = { ...o1 };
- forIn(o2, (value, key) => {
- set(combined, key, value);
+Object.combine = (src, obj) => {
+ const combined = { ...src };
+ forIn(obj, (value, key) => {
+ if (key === 'data') {
+ set(combined, key, mergeDataProps(obj, combined));
+ } else {
+ set(combined, key, value);
+ }
});
return combined;
};
6bf735d24
global.js: объединение стало намного короче.
6bf735d24dd5a4f5ff8d89c7dfe714aa8753cdaa
diff --git a/projectforge-webapp/src/utilities/global.js b/projectforge-webapp/src/utilities/global.js
index d1608283f..6ddc999f8 100644
--- a/projectforge-webapp/src/utilities/global.js
+++ b/projectforge-webapp/src/utilities/global.js
@@ -1,5 +1,4 @@
-import { forIn, get, mergeWith, set } from 'lodash/object';
-import { isArray } from 'lodash/lang';
+import { forIn, get, set } from 'lodash/object';
// https://stackoverflow.com/a/6491621
Object.getByString = (object, multiKey) => {
@@ -16,34 +15,13 @@ Object.getByString = (object, multiKey) => {
Object.isEmpty = (object) => Object.keys(object).length === 0;
-const customizer = (objValue, srcValue) => {
- if (isArray(objValue)) {
- // Не объединять массивы: заменять существующий массив исходным массивом.
- return srcValue;
- }
- return undefined;
-};
-
// Объединяет два объекта. Пути вида user.rights[2].value также поддерживаются в полях o2.
Object.combine = (o1, o2) => {
- const newValues = {};
- const specialProperties = {};
+ const combined = { ...o1 };
forIn(o2, (value, key) => {
- if (key.includes('.') || key.match(/\[(\d)\]/) || value === undefined) {
- // ключи вида user.name или user.rights[2].value или undefined значения
- // требуют специальной обработки после слияния.
- specialProperties[key] = value;
- } else {
- newValues[key] = value;
- }
- });
- const newState = mergeWith(o1, newValues, customizer);
- forIn(specialProperties, (value, key) => {
- // Устанавливает значение нового состояния по глубокому пути свойства (например, user.name или user.rights[2].value)
- // undefined значения также будут установлены.
- set(newState, key, value);
+ set(combined, key, value);
});
- return newState;
+ return combined;
};
Array.findByField = (array, field, value) => array.reduce((accumulator, currentValue) => {