407b4c9c9 New calendar: first hour of day is now configurable. Tooltips.
41907bf51 WIP: BigCalendar -> Fullcalendar
5fff1f800 global.js: unused imports remove.
4a4e2086a global.js: merge/combine didn't work correct for some cases (e. g. Merlin plugin). AttachmentsService returns now empty array instead of null, if no attachments given (client is now able to clear the list of attachments after deletion of last attachment).
6bf735d24 global.js: combined much shorter.
407b4c9c9
New calendar: first hour of day is now configurable. Tooltips.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 -> Fullcalendar41907bf51150c1ad7299e66b8bb3ed1bb8534c0e
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: unused imports remove.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 didn't work correct for some cases (e. g. Merlin plugin). AttachmentsService returns now empty array instead of null, if no attachments given (client is now able to clear the list of attachments after deletion of last attachment).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;
+// Don't delete not given data properties while merging:
+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)) {
+ // If property exists, the use it: the value might be undefined.
+ set(combinedData, key, value);
+ }
+ });
+ return combinedData;
+};
+
// Combines two objects. Paths like user.rights[2].value are also supported in o2 fields.
-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: combined much shorter.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)) {
- // Don't merge arrays: replace existing array by src array.
- return srcValue;
- }
- return undefined;
-};
-
// Combines two objects. Paths like user.rights[2].value are also supported in o2 fields.
Object.combine = (o1, o2) => {
- const newValues = {};
- const specialProperties = {};
+ const combined = { ...o1 };
forIn(o2, (value, key) => {
- if (key.includes('.') || key.match(/\[(\d)\]/) || value === undefined) {
- // keys like user.name or user.rights[2].value or undefined values
- // need special treatment after merge.
- specialProperties[key] = value;
- } else {
- newValues[key] = value;
- }
- });
- const newState = mergeWith(o1, newValues, customizer);
- forIn(specialProperties, (value, key) => {
- // Sets value of new state by deep property path (like user.name or user.rights[2].value)
- // undefined values will also be set.
- set(newState, key, value);
+ set(combined, key, value);
});
- return newState;
+ return combined;
};
Array.findByField = (array, field, value) => array.reduce((accumulator, currentValue) => {