@shopgate/pwa-common 7.30.0-alpha.7 → 7.30.0-alpha.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/App.js +48 -6
- package/action-creators/app/index.js +75 -12
- package/action-creators/app/spec.js +96 -1
- package/action-creators/client/index.js +27 -5
- package/action-creators/client/spec.js +44 -1
- package/action-creators/error/index.js +15 -3
- package/action-creators/index.js +9 -1
- package/action-creators/menu/index.js +23 -4
- package/action-creators/menu/spec.js +37 -1
- package/action-creators/modal/index.js +15 -3
- package/action-creators/modal/spec.js +26 -1
- package/action-creators/page/index.js +24 -4
- package/action-creators/page/spec.js +38 -1
- package/action-creators/router/index.js +48 -7
- package/action-creators/url/index.js +24 -4
- package/action-creators/url/spec.js +45 -1
- package/action-creators/user/index.js +90 -13
- package/action-creators/user/spec.js +186 -2
- package/actions/app/handleDeepLink.js +11 -2
- package/actions/app/handleLink.js +62 -6
- package/actions/app/handlePushNotification.js +32 -4
- package/actions/app/handleUniversalLink.js +11 -2
- package/actions/app/registerLinkEvents.js +24 -3
- package/actions/client/fetchClientInformation.js +26 -2
- package/actions/menu/fetchMenu.js +23 -2
- package/actions/modal/closeModal.js +18 -2
- package/actions/modal/promiseMap.js +3 -1
- package/actions/modal/showModal.js +54 -8
- package/actions/page/fetchPageConfig.js +69 -2
- package/actions/page/getPageConfig.js +6 -2
- package/actions/page/index.js +1 -1
- package/actions/router/historyPop.js +12 -2
- package/actions/router/historyPopToRoute.js +27 -2
- package/actions/router/historyPush.js +12 -2
- package/actions/router/historyRedirect.js +21 -2
- package/actions/router/historyReplace.js +20 -3
- package/actions/router/historyReset.js +11 -2
- package/actions/router/historyResetTo.js +12 -2
- package/actions/router/index.js +17 -1
- package/actions/router/routeDidPop.js +11 -2
- package/actions/router/routeDidPush.js +13 -2
- package/actions/router/routeDidReplace.js +11 -2
- package/actions/router/routeDidReset.js +11 -2
- package/actions/router/routeDidUpdate.js +10 -2
- package/actions/router/routeWillPop.js +11 -2
- package/actions/router/routeWillPush.js +13 -2
- package/actions/router/routeWillReplace.js +11 -2
- package/actions/router/routeWillReset.js +11 -2
- package/actions/router/windowOpenOverride.js +10 -2
- package/actions/user/fetchRegisterUrl.js +36 -2
- package/actions/user/fetchUser.js +29 -3
- package/actions/user/getUser.js +6 -2
- package/actions/user/index.js +1 -1
- package/actions/user/login.js +76 -9
- package/actions/user/logout.js +30 -2
- package/collections/AuthRoutes.js +73 -14
- package/collections/Configuration.js +54 -7
- package/collections/EmbeddedMedia.js +84 -11
- package/collections/PersistedReducers.js +41 -6
- package/collections/Redirects.js +103 -17
- package/collections/index.js +5 -1
- package/collections/media-providers/MediaProvider.js +151 -26
- package/collections/media-providers/Vimeo.js +113 -19
- package/collections/media-providers/YouTube.js +74 -14
- package/collections/media-providers/index.js +3 -1
- package/collections/media-providers/style.js +52 -2
- package/components/Backdrop/index.js +95 -6
- package/components/Backdrop/spec.js +23 -1
- package/components/Backdrop/style.js +11 -2
- package/components/Button/index.js +47 -5
- package/components/Button/spec.js +36 -1
- package/components/Button/style.js +6 -1
- package/components/Checkbox/index.js +126 -32
- package/components/Checkbox/spec.js +94 -3
- package/components/Consume/helpers/buildParams.js +13 -2
- package/components/Consume/index.js +14 -2
- package/components/CountdownTimer/index.js +115 -17
- package/components/CountdownTimer/spec.js +126 -12
- package/components/Drawer/index.js +131 -16
- package/components/Drawer/spec.js +76 -1
- package/components/Drawer/style.js +37 -1
- package/components/Dropdown/index.js +65 -6
- package/components/Dropdown/style.js +4 -1
- package/components/Dropdown/transitions.js +34 -1
- package/components/Ellipsis/index.js +16 -2
- package/components/Ellipsis/spec.js +13 -1
- package/components/EmbeddedMedia/index.js +56 -6
- package/components/EmbeddedMedia/spec.js +52 -3
- package/components/ErrorBoundary/connector.js +9 -2
- package/components/ErrorBoundary/index.js +43 -7
- package/components/Grid/components/Item/index.js +40 -4
- package/components/Grid/components/Item/spec.js +23 -1
- package/components/Grid/components/Item/style.js +17 -3
- package/components/Grid/index.js +36 -4
- package/components/Grid/spec.js +23 -1
- package/components/Grid/style.js +11 -2
- package/components/HtmlSanitizer/connector.js +24 -3
- package/components/HtmlSanitizer/index.js +104 -12
- package/components/HtmlSanitizer/spec.js +207 -6
- package/components/I18n/components/FormatDate/index.js +26 -2
- package/components/I18n/components/FormatDate/spec.js +46 -1
- package/components/I18n/components/FormatNumber/index.js +34 -2
- package/components/I18n/components/FormatNumber/spec.js +41 -2
- package/components/I18n/components/FormatPrice/index.js +32 -2
- package/components/I18n/components/FormatPrice/spec.js +46 -1
- package/components/I18n/components/FormatTime/index.js +26 -2
- package/components/I18n/components/FormatTime/spec.js +43 -2
- package/components/I18n/components/I18nProvider/index.js +52 -9
- package/components/I18n/components/I18nProvider/spec.js +39 -1
- package/components/I18n/components/Placeholder/index.js +8 -2
- package/components/I18n/components/Placeholder/spec.js +30 -1
- package/components/I18n/components/Translate/index.js +68 -7
- package/components/I18n/components/Translate/spec.js +30 -1
- package/components/I18n/index.js +16 -1
- package/components/Icon/index.js +25 -2
- package/components/Icon/style.js +6 -1
- package/components/Image/Image.js +176 -19
- package/components/Image/ImageInner.js +48 -2
- package/components/Image/index.js +1 -1
- package/components/Image/style.js +29 -2
- package/components/InfiniteContainer/index.js +381 -49
- package/components/InfiniteContainer/spec.js +199 -10
- package/components/Input/components/DateInput.js +262 -6
- package/components/Input/components/MultiLineInput.js +98 -12
- package/components/Input/components/SimpleInput.js +207 -31
- package/components/Input/index.js +32 -3
- package/components/Input/spec.js +122 -1
- package/components/KeyboardConsumer/index.js +48 -7
- package/components/Link/connector.js +7 -1
- package/components/Link/index.js +96 -11
- package/components/Link/spec.js +56 -1
- package/components/Link/style.js +10 -1
- package/components/List/components/Item/index.js +35 -3
- package/components/List/components/Item/style.js +16 -1
- package/components/List/index.js +20 -2
- package/components/List/spec.js +31 -1
- package/components/Loading/index.js +6 -2
- package/components/Modal/index.js +38 -3
- package/components/Modal/style.js +36 -1
- package/components/ModalContainer/connector.js +17 -3
- package/components/ModalContainer/index.js +36 -3
- package/components/ModalContainer/spec.js +105 -5
- package/components/Picker/components/Button/index.js +34 -2
- package/components/Picker/components/Button/style.js +19 -1
- package/components/Picker/components/List/index.js +33 -2
- package/components/Picker/components/List/style.js +17 -1
- package/components/Picker/components/Modal/index.js +60 -7
- package/components/Picker/components/Modal/style.js +78 -1
- package/components/Picker/index.js +167 -21
- package/components/Picker/spec.js +83 -2
- package/components/Portal/index.js +130 -19
- package/components/ProductCharacteristics/connector.js +33 -4
- package/components/ProductCharacteristics/context.js +2 -1
- package/components/ProductCharacteristics/helpers/index.js +135 -21
- package/components/ProductCharacteristics/index.js +266 -31
- package/components/RangeSlider/components/Handle/index.js +25 -2
- package/components/RangeSlider/components/Handle/style.js +14 -1
- package/components/RangeSlider/helper.js +43 -8
- package/components/RangeSlider/index.js +228 -38
- package/components/RangeSlider/style.js +14 -1
- package/components/Route/RouteNotFound.js +46 -3
- package/components/Route/index.js +78 -10
- package/components/Router/connector.js +9 -2
- package/components/Router/index.js +237 -31
- package/components/ScannerContainer/connector.js +9 -2
- package/components/ScannerContainer/index.js +42 -6
- package/components/Select/components/Item/index.js +20 -4
- package/components/Select/components/Item/style.js +4 -1
- package/components/Select/index.js +149 -28
- package/components/Select/spec.js +86 -2
- package/components/Select/style.js +17 -1
- package/components/SelectBox/components/Item/index.js +47 -5
- package/components/SelectBox/components/Item/style.js +7 -1
- package/components/SelectBox/index.js +173 -17
- package/components/SelectBox/spec.js +59 -3
- package/components/SelectBox/style.js +18 -1
- package/components/Slider/index.js +6 -2
- package/components/SurroundPortals/index.js +26 -2
- package/components/Swiper/components/SwiperItem/index.js +28 -4
- package/components/Swiper/components/SwiperItem/spec.js +17 -1
- package/components/Swiper/components/SwiperItem/styles.js +5 -1
- package/components/Swiper/index.js +210 -18
- package/components/Swiper/styles.js +75 -7
- package/components/Toaster/index.js +10 -2
- package/components/Transition/index.js +89 -13
- package/components/Widgets/components/Widget/index.js +52 -4
- package/components/Widgets/components/Widget/spec.js +68 -3
- package/components/Widgets/components/Widget/style.js +21 -3
- package/components/Widgets/components/WidgetGrid/index.js +52 -7
- package/components/Widgets/components/WidgetGrid/spec.js +46 -2
- package/components/Widgets/components/WidgetGrid/style.js +8 -1
- package/components/Widgets/helpers/shouldShowWidget.js +44 -7
- package/components/Widgets/index.js +127 -15
- package/components/Widgets/spec.js +213 -6
- package/components/index.js +9 -1
- package/constants/ActionTypes.js +97 -19
- package/constants/Configuration.js +12 -2
- package/constants/Device.js +29 -2
- package/constants/DisplayOptions.js +8 -1
- package/constants/MenuIDs.js +2 -1
- package/constants/ModalTypes.js +1 -1
- package/constants/PageIDs.js +1 -1
- package/constants/Pipelines.js +7 -1
- package/constants/Portals.js +136 -3
- package/constants/Registration.js +3 -1
- package/constants/RoutePaths.js +13 -2
- package/constants/Tracking.js +3 -1
- package/constants/client.js +6 -1
- package/constants/ui.js +2 -1
- package/constants/user.js +6 -2
- package/context/index.js +33 -3
- package/helpers/config/index.js +139 -21
- package/helpers/config/mock.js +200 -8
- package/helpers/config/theme.js +50 -4
- package/helpers/data/index.js +204 -29
- package/helpers/data/spec.js +187 -7
- package/helpers/date/index.js +58 -6
- package/helpers/date/spec.js +92 -1
- package/helpers/dom/index.js +48 -11
- package/helpers/environment/index.js +14 -2
- package/helpers/html/decodeHTML.js +7 -1
- package/helpers/html/handleDOM.js +172 -21
- package/helpers/html/parseHTML.js +67 -12
- package/helpers/i18n/getDateFormatter.js +23 -4
- package/helpers/i18n/getNumberFormatter.js +32 -4
- package/helpers/i18n/getPriceFormatter.js +38 -4
- package/helpers/i18n/getTimeFormatter.js +23 -4
- package/helpers/i18n/getTranslator.js +62 -8
- package/helpers/i18n/index.js +5 -1
- package/helpers/i18n/mergeTranslations.js +36 -9
- package/helpers/i18n/messageCache.js +3 -1
- package/helpers/legacy/index.js +47 -9
- package/helpers/modal/withShowModal.js +13 -2
- package/helpers/portals/portalCollection.js +28 -6
- package/helpers/portals/routePortals.js +12 -1
- package/helpers/redux/compareObjects.js +7 -2
- package/helpers/redux/generateResultHash.js +36 -3
- package/helpers/redux/generateSortedHash.js +7 -2
- package/helpers/redux/hasExpired.js +10 -2
- package/helpers/redux/index.js +7 -1
- package/helpers/redux/mutable.js +143 -24
- package/helpers/redux/shouldFetchData.js +46 -10
- package/helpers/redux/shouldFetchFilters.js +17 -4
- package/helpers/router/index.js +49 -5
- package/helpers/style/index.js +43 -4
- package/helpers/style/spec.js +108 -2
- package/helpers/tracking/index.js +52 -9
- package/helpers/validation/index.js +39 -12
- package/helpers/validation/spec.js +10 -1
- package/package.json +3 -3
- package/providers/index.js +4 -1
- package/providers/loading/context.js +2 -1
- package/providers/loading/index.js +137 -22
- package/providers/toast/context.js +2 -1
- package/providers/toast/index.js +105 -11
- package/reducers/client/connectivity.js +22 -2
- package/reducers/client/index.js +7 -1
- package/reducers/client/info.js +27 -2
- package/reducers/index.js +23 -4
- package/reducers/menu/index.js +5 -1
- package/reducers/menu/menusById.js +41 -2
- package/reducers/modal/index.js +14 -2
- package/reducers/page/index.js +68 -5
- package/reducers/router/index.js +48 -2
- package/reducers/url/index.js +42 -3
- package/reducers/user/data.js +27 -2
- package/reducers/user/index.js +7 -1
- package/reducers/user/login.js +65 -2
- package/selectors/client.js +138 -21
- package/selectors/history.js +49 -11
- package/selectors/menu.js +34 -6
- package/selectors/modal.js +15 -4
- package/selectors/page.js +25 -4
- package/selectors/router.js +154 -30
- package/selectors/url.js +25 -4
- package/selectors/user.js +90 -13
- package/store/index.js +60 -6
- package/store/middelwares/logger.js +7 -1
- package/store/middelwares/streams.js +19 -2
- package/streams/app.js +60 -8
- package/streams/client.js +8 -2
- package/streams/error.js +14 -3
- package/streams/index.js +6 -1
- package/streams/interval.js +6 -2
- package/streams/main.js +27 -2
- package/streams/router.js +45 -8
- package/streams/user.js +89 -15
- package/streams/view.js +97 -25
- package/styles/reset/form.js +57 -5
- package/styles/reset/index.js +6 -1
- package/styles/reset/media.js +22 -1
- package/styles/reset/root.js +33 -1
- package/styles/reset/table.js +10 -1
- package/styles/reset/typography.js +26 -1
- package/subscriptions/app.js +148 -17
- package/subscriptions/error.js +292 -13
- package/subscriptions/helpers/buildRegisterUrl.js +25 -6
- package/subscriptions/helpers/clearUpInAppBrowser.js +14 -3
- package/subscriptions/helpers/handleLinks.js +267 -25
- package/subscriptions/helpers/pipeline.js +12 -1
- package/subscriptions/history.js +34 -6
- package/subscriptions/index.js +25 -4
- package/subscriptions/menu.js +22 -5
- package/subscriptions/mock.js +39 -7
- package/subscriptions/router.js +336 -23
- package/subscriptions/user.js +93 -3
package/helpers/date/spec.js
CHANGED
|
@@ -1 +1,92 @@
|
|
|
1
|
-
|
|
1
|
+
import { isBefore, isAfter, isBetween, parseDuration, addDuration } from '.';
|
|
2
|
+
describe('helpers/date', () => {
|
|
3
|
+
const date10Hours = new Date('2019-01-01T10:00:00.000Z');
|
|
4
|
+
const date12Hours = new Date('2019-01-01T12:00:00.000Z');
|
|
5
|
+
describe('isBefore', () => {
|
|
6
|
+
it('should be before', () => {
|
|
7
|
+
expect(isBefore(new Date('2019-01-01T09:59:59.000Z'), date10Hours)).toBeTruthy();
|
|
8
|
+
});
|
|
9
|
+
it('should be not before', () => {
|
|
10
|
+
expect(isBefore(new Date('2019-01-01T10:00:00.000Z'), date10Hours)).toBeFalsy();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
describe('isAfter', () => {
|
|
14
|
+
it('should be after', () => {
|
|
15
|
+
expect(isAfter(new Date('2019-01-01T10:00:01.000Z'), date10Hours)).toBeTruthy();
|
|
16
|
+
});
|
|
17
|
+
it('should be not after', () => {
|
|
18
|
+
expect(isAfter(new Date('2019-01-01T10:00:00.000Z'), date10Hours)).toBeFalsy();
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
describe('isBetween', () => {
|
|
22
|
+
it('should be between', () => {
|
|
23
|
+
expect(isBetween(new Date('2019-01-01T11:00:00.000Z'), date10Hours, date12Hours)).toBeTruthy();
|
|
24
|
+
});
|
|
25
|
+
it('should be not between', () => {
|
|
26
|
+
expect(isBetween(new Date('2019-01-01T09:00:00.000Z'), date10Hours, date12Hours)).toBeFalsy();
|
|
27
|
+
expect(isBetween(new Date('2019-01-01T13:00:00.000Z'), date10Hours, date12Hours)).toBeFalsy();
|
|
28
|
+
});
|
|
29
|
+
it('should be inclusively between', () => {
|
|
30
|
+
expect(isBetween(new Date('2019-01-01T10:00:00.000Z'), date10Hours, date12Hours)).toBeTruthy();
|
|
31
|
+
expect(isBetween(new Date('2019-01-01T12:00:00.000Z'), date10Hours, date12Hours)).toBeTruthy();
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
describe('parseDuration', () => {
|
|
35
|
+
const parsed = {
|
|
36
|
+
Year: undefined,
|
|
37
|
+
Month: undefined,
|
|
38
|
+
Week: undefined,
|
|
39
|
+
Day: undefined,
|
|
40
|
+
Hour: undefined,
|
|
41
|
+
Minute: undefined,
|
|
42
|
+
Second: undefined
|
|
43
|
+
};
|
|
44
|
+
it('should parse 10 second', () => {
|
|
45
|
+
expect(parseDuration('PT10S')).toEqual({
|
|
46
|
+
...parsed,
|
|
47
|
+
Second: 10
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
it('should parse 1 hour', () => {
|
|
51
|
+
expect(parseDuration('PT1H')).toEqual({
|
|
52
|
+
...parsed,
|
|
53
|
+
Hour: 1
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
it('should parse 5 day', () => {
|
|
57
|
+
expect(parseDuration('P5D')).toEqual({
|
|
58
|
+
...parsed,
|
|
59
|
+
Day: 5
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
it('should parse -5 day', () => {
|
|
63
|
+
expect(parseDuration('-P5D')).toEqual({
|
|
64
|
+
...parsed,
|
|
65
|
+
Day: -5
|
|
66
|
+
});
|
|
67
|
+
});
|
|
68
|
+
});
|
|
69
|
+
describe('addDuration', () => {
|
|
70
|
+
const dateStub = '2019-01-01T11:00:00.000Z';
|
|
71
|
+
let date;
|
|
72
|
+
beforeEach(() => {
|
|
73
|
+
date = new Date(dateStub);
|
|
74
|
+
});
|
|
75
|
+
it('should add 0sec', () => {
|
|
76
|
+
addDuration(date, 'PT0S');
|
|
77
|
+
expect(date).toEqual(date);
|
|
78
|
+
});
|
|
79
|
+
it('should add 1 hour', () => {
|
|
80
|
+
addDuration(date, 'PT1H');
|
|
81
|
+
expect(date).toEqual(new Date('2019-01-01T12:00:00.000Z'));
|
|
82
|
+
});
|
|
83
|
+
it('should add 5 day', () => {
|
|
84
|
+
addDuration(date, 'P5D');
|
|
85
|
+
expect(date).toEqual(new Date('2019-01-06T11:00:00.000Z'));
|
|
86
|
+
});
|
|
87
|
+
it('should subtract 5 day', () => {
|
|
88
|
+
addDuration(date, '-P5D');
|
|
89
|
+
expect(date).toEqual(new Date('2018-12-27T11:00:00.000Z'));
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
});
|
package/helpers/dom/index.js
CHANGED
|
@@ -1,32 +1,69 @@
|
|
|
1
|
+
import "core-js/modules/es.string.replace.js";
|
|
1
2
|
/**
|
|
2
3
|
* Checks if the given child is a descendant of the given parent.
|
|
3
4
|
* @param {Object} parent The parent element.
|
|
4
5
|
* @param {Object} child The child element.
|
|
5
6
|
* @return {boolean}
|
|
6
|
-
*/
|
|
7
|
+
*/
|
|
8
|
+
export const isDescendant = (parent, child) => {
|
|
9
|
+
let node = child.parentNode;
|
|
10
|
+
while (node !== null) {
|
|
11
|
+
if (node === parent) return true;
|
|
12
|
+
node = node.parentNode;
|
|
13
|
+
}
|
|
14
|
+
return false;
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
/**
|
|
7
18
|
* Retrieves the offset of a element.
|
|
8
19
|
* @param {Object} element The element to retrieve the offset for.
|
|
9
20
|
* @returns {Object} The offset of the element contain `top` and `left` position values.
|
|
10
|
-
*/
|
|
21
|
+
*/
|
|
22
|
+
export const getOffset = element => element.getBoundingClientRect();
|
|
23
|
+
|
|
24
|
+
/**
|
|
11
25
|
* Calculate the height of an element including it's y-axis margins.
|
|
12
26
|
* @param {HTMLElement} element The DOM element.
|
|
13
27
|
* @returns {number} The absolute height of the element.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
return
|
|
28
|
+
*/
|
|
29
|
+
export const getAbsoluteHeight = element => {
|
|
30
|
+
if (!element) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
// Get the styles of the element.
|
|
35
|
+
const styles = window.getComputedStyle(element);
|
|
36
|
+
// Isolate the y-axis margins.
|
|
37
|
+
const margins = parseFloat(styles.marginTop) + parseFloat(styles.marginBottom);
|
|
38
|
+
// Add the margins to the element's height and return it.
|
|
39
|
+
return Math.ceil(element.offsetHeight + margins);
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
/**
|
|
18
43
|
* Retrieves a style of an element.
|
|
19
44
|
* @param {HTMLElement} element The DOM element.
|
|
20
45
|
* @param {string} property The style property in camel case
|
|
21
46
|
* @returns {string}
|
|
22
|
-
*/
|
|
23
|
-
|
|
24
|
-
|
|
47
|
+
*/
|
|
48
|
+
export const getStyle = (element, property) => {
|
|
49
|
+
// Use computed styles if possible - doesn't work with elements which are not mounted to the DOM
|
|
50
|
+
if (window.getComputedStyle && document.body.contains(element)) {
|
|
51
|
+
// getPropertyValue expects the property in kebab case.
|
|
52
|
+
return window.getComputedStyle(element, null).getPropertyValue(property.replace(/([a-z])([A-Z])/g, '$1-$2').toLowerCase());
|
|
53
|
+
}
|
|
54
|
+
return element.style[property];
|
|
55
|
+
};
|
|
56
|
+
|
|
57
|
+
/**
|
|
25
58
|
* Check if element is relative.
|
|
26
59
|
* @param {Element} element The DOM element.
|
|
27
60
|
* @returns {boolean}
|
|
28
|
-
*/
|
|
61
|
+
*/
|
|
62
|
+
export const isRelativePosition = element => getStyle(element, 'position') === 'relative';
|
|
63
|
+
|
|
64
|
+
/**
|
|
29
65
|
* Check if element is relative.
|
|
30
66
|
* @param {Element} element The DOM element.
|
|
31
67
|
* @returns {boolean}
|
|
32
|
-
*/
|
|
68
|
+
*/
|
|
69
|
+
export const isAbsolutePosition = element => getStyle(element, 'position') === 'absolute';
|
|
@@ -1,2 +1,14 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
// Environment variables.
|
|
2
|
+
const ENV_KEY_DEVELOPMENT = 'development';
|
|
3
|
+
const ENV_KEY_TEST = 'test';
|
|
4
|
+
const ENV_KEY_STAGING = 'staging';
|
|
5
|
+
const ENV_KEY_PRODUCTION = 'production';
|
|
6
|
+
const env = process.env.NODE_ENV || ENV_KEY_DEVELOPMENT;
|
|
7
|
+
module.exports = {
|
|
8
|
+
env,
|
|
9
|
+
isDev: env === ENV_KEY_DEVELOPMENT || env === ENV_KEY_TEST,
|
|
10
|
+
isProd: env === ENV_KEY_PRODUCTION,
|
|
11
|
+
isStaging: env === ENV_KEY_STAGING,
|
|
12
|
+
isRemote: !!process.env.REMOTE,
|
|
13
|
+
isWindows: (window?.navigator?.userAgent ?? '').toLowerCase().includes('win')
|
|
14
|
+
};
|
|
@@ -2,4 +2,10 @@
|
|
|
2
2
|
* Unescape HTML entities.
|
|
3
3
|
* @param {string} input The escaped HTML.
|
|
4
4
|
* @returns {string} The unescaped HTML.
|
|
5
|
-
*/
|
|
5
|
+
*/
|
|
6
|
+
const decodeHTML = input => {
|
|
7
|
+
const e = document.createElement('div');
|
|
8
|
+
e.innerHTML = input;
|
|
9
|
+
return e.childNodes.length === 0 ? '' : e.childNodes[0].nodeValue;
|
|
10
|
+
};
|
|
11
|
+
export default decodeHTML;
|
|
@@ -1,54 +1,205 @@
|
|
|
1
|
-
import
|
|
1
|
+
import "core-js/modules/es.array.reduce.js";
|
|
2
|
+
import "core-js/modules/es.string.replace.js";
|
|
3
|
+
import event from '@shopgate/pwa-core/classes/Event/index';
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Parses a collection of DOM nodes for external script tags.
|
|
3
7
|
* @param {Array} nodes A collection of DOM nodes.
|
|
4
8
|
* @param {Function} callback Will be called when a single script is loaded.
|
|
5
9
|
* @param {boolean} isRoot Whether this is the root level of the given DOM tree.
|
|
6
10
|
* @return {Array} A collection of external script tags.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
|
|
11
|
+
*/
|
|
12
|
+
export const getExternalScripts = (nodes, callback, isRoot = true) => {
|
|
13
|
+
const nodesArray = [].slice.call(nodes);
|
|
14
|
+
const externalScripts = nodesArray.reduce((result, node) => {
|
|
15
|
+
// We only want external scripts.
|
|
16
|
+
if (node.tagName !== 'SCRIPT' || !node.src) {
|
|
17
|
+
if (node.childNodes && node.childNodes.length) {
|
|
18
|
+
return result.concat(getExternalScripts(node.childNodes, callback, false));
|
|
19
|
+
}
|
|
20
|
+
return result;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Create a new script tag.
|
|
24
|
+
const script = document.createElement('script');
|
|
25
|
+
script.type = node.type;
|
|
26
|
+
script.src = node.src;
|
|
27
|
+
script.async = node.async;
|
|
28
|
+
script.onload = callback;
|
|
29
|
+
script.onerror = callback;
|
|
30
|
+
result.push(script);
|
|
31
|
+
return result;
|
|
32
|
+
}, []);
|
|
33
|
+
if (!externalScripts.length && isRoot) {
|
|
34
|
+
return callback();
|
|
35
|
+
}
|
|
36
|
+
return externalScripts;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
/**
|
|
10
40
|
* Parses a collection of DOM nodes for inline script tags.
|
|
11
41
|
* @param {Array} nodes A collection of DOM nodes.
|
|
12
42
|
* @return {Array} A collection of inline script tags.
|
|
13
|
-
*/
|
|
14
|
-
|
|
15
|
-
|
|
43
|
+
*/
|
|
44
|
+
export const getInlineScripts = nodes => {
|
|
45
|
+
const nodesArray = [].slice.call(nodes);
|
|
46
|
+
return nodesArray.reduce((result, node) => {
|
|
47
|
+
// We only want scripts.
|
|
48
|
+
if (node.tagName !== 'SCRIPT' || node.src) {
|
|
49
|
+
if (node.childNodes && node.childNodes.length) {
|
|
50
|
+
return result.concat(getInlineScripts(node.childNodes));
|
|
51
|
+
}
|
|
52
|
+
return result;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Create a new script tag.
|
|
56
|
+
const script = document.createElement('script');
|
|
57
|
+
script.type = node.type;
|
|
58
|
+
script.textContent = node.innerText;
|
|
59
|
+
result.push(script);
|
|
60
|
+
return result;
|
|
61
|
+
}, []);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
/**
|
|
16
65
|
* Parses a collection of DOM nodes for non-script tags.
|
|
17
66
|
* @param {Array} nodes A collection of DOM nodes.
|
|
18
67
|
* @return {Object} A DOM node containing the HTML content.
|
|
19
|
-
*/
|
|
68
|
+
*/
|
|
69
|
+
export const getHTMLContent = nodes => {
|
|
70
|
+
const contents = document.createElement('div');
|
|
71
|
+
const nodesArray = [].slice.call(nodes);
|
|
72
|
+
|
|
73
|
+
/**
|
|
20
74
|
* Filters out unwanted nodes.
|
|
21
75
|
* @param {Object} nodeList A node list.
|
|
22
76
|
* @returns {Object}
|
|
23
|
-
*/
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
77
|
+
*/
|
|
78
|
+
const filterBlacklistedNodes = nodeList => nodeList.map(node => {
|
|
79
|
+
// We don't care about script tags.
|
|
80
|
+
if (node.tagName === 'SCRIPT') {
|
|
81
|
+
return null;
|
|
82
|
+
}
|
|
83
|
+
if (node.tagName === 'IMG') {
|
|
84
|
+
// Images with a relative path won't work so we will remove them here.
|
|
85
|
+
if (!node.getAttribute('src').startsWith('http')) {
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
if (node.childNodes.length > 0) {
|
|
90
|
+
const filteredNodes = filterBlacklistedNodes(Array.from(node.childNodes));
|
|
91
|
+
|
|
92
|
+
/* eslint-disable no-param-reassign */
|
|
93
|
+
// Resets / Clears all children so it can be replaced with the filtered ones.
|
|
94
|
+
node.innerHTML = '';
|
|
95
|
+
/* eslint-enable no-param-reassign */
|
|
96
|
+
|
|
97
|
+
filteredNodes.forEach(child => node.appendChild(child));
|
|
98
|
+
}
|
|
99
|
+
return node;
|
|
100
|
+
}).filter(node => node !== null);
|
|
101
|
+
filterBlacklistedNodes(nodesArray).forEach(node => {
|
|
102
|
+
contents.appendChild(node.cloneNode(true));
|
|
103
|
+
});
|
|
104
|
+
return contents;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
/**
|
|
27
108
|
* Checks if a DOM container already exist and creates a new one if it doesn't exist.
|
|
28
109
|
* @param {string} containerID The HTML id attribute of the container.
|
|
29
110
|
* @return {Object} The container DOM node.
|
|
30
|
-
*/
|
|
111
|
+
*/
|
|
112
|
+
export const getDOMContainer = containerID => {
|
|
113
|
+
let container = document.getElementById(containerID);
|
|
114
|
+
if (container) {
|
|
115
|
+
container.innerHTML = '';
|
|
116
|
+
} else {
|
|
117
|
+
container = document.createElement('div');
|
|
118
|
+
container.id = containerID;
|
|
119
|
+
document.body.appendChild(container);
|
|
120
|
+
}
|
|
121
|
+
return container;
|
|
122
|
+
};
|
|
123
|
+
|
|
124
|
+
/**
|
|
31
125
|
* Stops a NodeList of youtube players.
|
|
32
126
|
* @param {NodeList} players YouTube player iframes.
|
|
33
|
-
*/
|
|
127
|
+
*/
|
|
128
|
+
const stopPlayer = players => {
|
|
129
|
+
const cmdStop = '{"event":"command","func":"stopVideo","args":""}';
|
|
130
|
+
players.forEach((node, index) => {
|
|
131
|
+
const yt = players[index];
|
|
132
|
+
if (yt.contentWindow && yt.contentWindow.postMessage) {
|
|
133
|
+
yt.contentWindow.postMessage(cmdStop, '*');
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
/**
|
|
34
139
|
* Handles YouTube iframes so that we are able to controll when the video should be stopped.
|
|
35
140
|
* It should not play in the background when a tab/page has changed.
|
|
36
141
|
* @param {NodeList} container HTML widget container.
|
|
37
142
|
* @deprecated Replaced by the EmbeddedVideos collection system.
|
|
38
|
-
*/
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
143
|
+
*/
|
|
144
|
+
export const handleYouTube = container => {
|
|
145
|
+
const youtubeIframes = container.querySelectorAll('iframe[src*="youtube.com"]');
|
|
146
|
+
youtubeIframes.forEach((node, index) => {
|
|
147
|
+
let {
|
|
148
|
+
src
|
|
149
|
+
} = node;
|
|
150
|
+
|
|
151
|
+
// Is it really needed? We just queried for iframes WITH src attribute.
|
|
152
|
+
if (!src) {
|
|
153
|
+
return;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// Enable the js api
|
|
157
|
+
if (src.includes('enablejsapi=0')) {
|
|
158
|
+
src = src.replace('enablejsapi=0', 'enablejsapi=1');
|
|
159
|
+
}
|
|
160
|
+
if (!src.includes('enablejsapi')) {
|
|
161
|
+
const queryChar = src.includes('?') ? '&' : '?';
|
|
162
|
+
src += `${queryChar}enablejsapi=1`;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
// Set controls to avoid the iframe not being resumable because of controls=0 param on ios.
|
|
166
|
+
if (!src.includes('controls')) {
|
|
167
|
+
src += '&controls=1';
|
|
168
|
+
} else if (src.includes('controls=0')) {
|
|
169
|
+
src = src.replace('controls=0', 'controls=1');
|
|
170
|
+
}
|
|
171
|
+
youtubeIframes[index].src = src;
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
/**
|
|
42
175
|
* Stops the player when a native app event is triggered when a webview gets hidden or when the
|
|
43
176
|
* user navigated to some other page.
|
|
44
|
-
*/
|
|
177
|
+
*/
|
|
178
|
+
event.addCallback('routeDidChange', () => {
|
|
179
|
+
stopPlayer(youtubeIframes);
|
|
180
|
+
});
|
|
181
|
+
event.addCallback('viewDidDisappear', () => {
|
|
182
|
+
stopPlayer(youtubeIframes);
|
|
183
|
+
});
|
|
184
|
+
};
|
|
185
|
+
|
|
186
|
+
/**
|
|
45
187
|
* Gets all styles from DOM.
|
|
46
188
|
* Important: DOM parser might and probably will add <style> tags into <head> while parsing
|
|
47
189
|
* the html string.
|
|
48
190
|
* @param {HTMLDocument} dom DOM.
|
|
49
191
|
* @returns {NodeList}
|
|
50
|
-
*/
|
|
192
|
+
*/
|
|
193
|
+
export const getStyles = dom => dom.querySelectorAll('style');
|
|
194
|
+
|
|
195
|
+
/**
|
|
51
196
|
* Load image and notify on load.
|
|
52
197
|
* @param {string} src .
|
|
53
198
|
* @returns {Promise}
|
|
54
|
-
*/
|
|
199
|
+
*/
|
|
200
|
+
export const loadImage = src => new Promise((resolve, reject) => {
|
|
201
|
+
const image = new window.Image();
|
|
202
|
+
image.onload = () => resolve(src);
|
|
203
|
+
image.onerror = reject;
|
|
204
|
+
image.src = src;
|
|
205
|
+
});
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
|
|
1
|
+
import { logger } from '@shopgate/pwa-core/helpers';
|
|
2
|
+
import CryptoJs from 'crypto-js';
|
|
3
|
+
import { embeddedMedia } from "../../collections";
|
|
4
|
+
import { getExternalScripts, getInlineScripts, getHTMLContent, getDOMContainer, getStyles } from "./handleDOM";
|
|
5
|
+
import decodeHTML from "./decodeHTML";
|
|
6
|
+
|
|
7
|
+
/**
|
|
2
8
|
* Receives custom HTML from a widget configuration, parses possible
|
|
3
9
|
* script tags and executes them after loading external scripts.
|
|
4
10
|
* @param {string} html The HTML string. It might contain script tags.
|
|
@@ -11,18 +17,67 @@ function _extends(){_extends=Object.assign||function(target){for(var i=1;i<argum
|
|
|
11
17
|
* @param {boolean} [cookieConsentSettings.statisticsCookiesAccepted] Whether statistics cookies
|
|
12
18
|
* are accepted.
|
|
13
19
|
* @returns {string} The HTML without any script tags.
|
|
14
|
-
*/
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
+
*/
|
|
21
|
+
const parseHTML = (html, decode, settings, processStyles = false, cookieConsentSettings = {}) => {
|
|
22
|
+
const id = CryptoJs.MD5(JSON.stringify(settings)).toString();
|
|
23
|
+
const container = getDOMContainer(`html-sanitizer-${id}`);
|
|
24
|
+
const cookieConsent = {
|
|
25
|
+
comfortCookiesAccepted: false,
|
|
26
|
+
statisticsCookiesAccepted: false,
|
|
27
|
+
...cookieConsentSettings
|
|
28
|
+
};
|
|
29
|
+
try {
|
|
30
|
+
const parser = new DOMParser();
|
|
31
|
+
const unparsedHTML = decode ? decodeHTML(html) : html;
|
|
32
|
+
// Parse the html string to a DOM object.
|
|
33
|
+
const dom = parser.parseFromString(`<body>${unparsedHTML}</body>`, 'text/html');
|
|
34
|
+
|
|
35
|
+
// Run cookie consent logic from embedded media to remove markup that's not supposed to run
|
|
36
|
+
// when consent is not accepted.
|
|
37
|
+
embeddedMedia.handleCookieConsent(dom, cookieConsent);
|
|
38
|
+
// Optimize embedded media iframe markup before it's injected into the DOM.
|
|
39
|
+
embeddedMedia.applyIframeOptimizations(dom);
|
|
40
|
+
|
|
41
|
+
// How many onloads have been processed.
|
|
42
|
+
let onloads = 0;
|
|
43
|
+
let inlineScripts = [];
|
|
44
|
+
let externalScripts = [];
|
|
45
|
+
|
|
46
|
+
/**
|
|
20
47
|
* Handles the onload events for external scripts.
|
|
21
48
|
* @return {Array} The collection of external scripts.
|
|
22
|
-
*/
|
|
49
|
+
*/
|
|
50
|
+
const handleOnload = () => {
|
|
51
|
+
onloads += 1;
|
|
52
|
+
|
|
53
|
+
/**
|
|
23
54
|
* If there are no external scripts or all external
|
|
24
55
|
* scripts are loaded, handle the inline scripts.
|
|
25
|
-
*/
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
56
|
+
*/
|
|
57
|
+
if (!externalScripts.length || onloads === externalScripts.length) {
|
|
58
|
+
inlineScripts.forEach(scriptTag => {
|
|
59
|
+
container.appendChild(scriptTag);
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
return externalScripts;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
// A collection of all the inline script tags.
|
|
66
|
+
inlineScripts = getInlineScripts(dom.childNodes);
|
|
67
|
+
// A collection of all the external script tags.
|
|
68
|
+
externalScripts = getExternalScripts(dom.childNodes, handleOnload);
|
|
69
|
+
|
|
70
|
+
// Append the external scripts.
|
|
71
|
+
externalScripts.forEach(scriptTag => {
|
|
72
|
+
container.appendChild(scriptTag);
|
|
73
|
+
});
|
|
74
|
+
if (processStyles) {
|
|
75
|
+
getStyles(dom).forEach(style => container.appendChild(style));
|
|
76
|
+
}
|
|
77
|
+
return getHTMLContent(dom.body.childNodes).innerHTML;
|
|
78
|
+
} catch (err) {
|
|
79
|
+
logger.error(err);
|
|
80
|
+
return html;
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
export default parseHTML;
|
|
@@ -1,4 +1,8 @@
|
|
|
1
|
-
import IntlMessageFormat from'intl-messageformat';
|
|
1
|
+
import IntlMessageFormat from 'intl-messageformat';
|
|
2
|
+
import curry from 'lodash/curry';
|
|
3
|
+
import messageCache from "./messageCache";
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Returns an instance of IntlMessageFormat from cache based on a hash.
|
|
3
7
|
* The hash is generated from given language code and translation key.
|
|
4
8
|
* If no instance exists yet, a new instance will be created and returned.
|
|
@@ -6,12 +10,27 @@ import IntlMessageFormat from'intl-messageformat';import curry from'lodash/curry
|
|
|
6
10
|
* @param {string} format The date format.
|
|
7
11
|
* Possible values: 'short', 'medium' (default), 'long','full'
|
|
8
12
|
* @returns {IntlMessageFormat}
|
|
9
|
-
*/
|
|
10
|
-
|
|
13
|
+
*/
|
|
14
|
+
const getFormattedDateFromCache = (langCode, format) => {
|
|
15
|
+
const hash = `${langCode}_date_${format}`;
|
|
16
|
+
|
|
17
|
+
// Check if a cached instance already exists.
|
|
18
|
+
if (messageCache[hash]) {
|
|
19
|
+
return messageCache[hash];
|
|
20
|
+
}
|
|
21
|
+
messageCache[hash] = new IntlMessageFormat(`{timestamp, date, ${format}}`, langCode);
|
|
22
|
+
return messageCache[hash];
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
/**
|
|
11
26
|
* Get a formatted date from a timestamp.
|
|
12
27
|
* @param {string} langCode A language code.
|
|
13
28
|
* @param {number} timestamp The current date's timestamp.
|
|
14
29
|
* @param {string} [format='medium'] The date format.
|
|
15
30
|
* Possible values: 'short', 'medium', 'long','full'
|
|
16
31
|
* @returns {string}
|
|
17
|
-
*/
|
|
32
|
+
*/
|
|
33
|
+
const formatDate = (langCode, timestamp, format = 'medium') => getFormattedDateFromCache(langCode, format).format({
|
|
34
|
+
timestamp
|
|
35
|
+
});
|
|
36
|
+
export default curry(formatDate);
|
|
@@ -1,15 +1,43 @@
|
|
|
1
|
-
import IntlMessageFormat from'intl-messageformat';
|
|
1
|
+
import IntlMessageFormat from 'intl-messageformat';
|
|
2
|
+
import curry from 'lodash/curry';
|
|
3
|
+
import messageCache from "./messageCache";
|
|
4
|
+
|
|
5
|
+
/**
|
|
2
6
|
* Returns an instance of IntlMessageFormat from cache based on a hash.
|
|
3
7
|
* The hash is generated from given language code and translation key.
|
|
4
8
|
* If no instance exists yet, a new instance will be created and returned.
|
|
5
9
|
* @param {string} langCode A language code.
|
|
6
10
|
* @param {number} fractions With or without fraction digits.
|
|
7
11
|
* @returns {IntlMessageFormat}
|
|
8
|
-
*/
|
|
9
|
-
|
|
12
|
+
*/
|
|
13
|
+
const getFormattedNumberFromCache = (langCode, fractions) => {
|
|
14
|
+
const hash = `${langCode}_number_fr_${fractions}`;
|
|
15
|
+
|
|
16
|
+
// Check if a cached instance already exists.
|
|
17
|
+
if (messageCache[hash]) {
|
|
18
|
+
return messageCache[hash];
|
|
19
|
+
}
|
|
20
|
+
messageCache[hash] = new IntlMessageFormat('{value, number, decimal}', langCode, {
|
|
21
|
+
number: {
|
|
22
|
+
decimal: {
|
|
23
|
+
style: 'decimal',
|
|
24
|
+
minimumFractionDigits: fractions,
|
|
25
|
+
maximumFractionDigits: fractions
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
return messageCache[hash];
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
/**
|
|
10
33
|
* Get a formatted number by a language code.
|
|
11
34
|
* @param {string} langCode A language code.
|
|
12
35
|
* @param {number} value The number to format.
|
|
13
36
|
* @param {boolean} fractions Number of digits after dot.
|
|
14
37
|
* @returns {string}
|
|
15
|
-
*/
|
|
38
|
+
*/
|
|
39
|
+
const formatNumber = (langCode, value, fractions) => getFormattedNumberFromCache(langCode, fractions).format({
|
|
40
|
+
value
|
|
41
|
+
});
|
|
42
|
+
const getNumberFormatter = curry(formatNumber);
|
|
43
|
+
export default getNumberFormatter;
|