@pobuca/email-builder 1.0.0

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.
Files changed (150) hide show
  1. package/README.md +1 -0
  2. package/assets/icons/dribbble.png +0 -0
  3. package/assets/icons/facebook.png +0 -0
  4. package/assets/icons/github.png +0 -0
  5. package/assets/icons/instagram.png +0 -0
  6. package/assets/icons/linkedin.png +0 -0
  7. package/assets/icons/medium.png +0 -0
  8. package/assets/icons/pinterest.png +0 -0
  9. package/assets/icons/snapchat.png +0 -0
  10. package/assets/icons/soundcloud.png +0 -0
  11. package/assets/icons/tumblr.png +0 -0
  12. package/assets/icons/twitter.png +0 -0
  13. package/assets/icons/vimeo.png +0 -0
  14. package/assets/icons/web.png +0 -0
  15. package/assets/icons/xing.png +0 -0
  16. package/assets/icons/youtube.png +0 -0
  17. package/bundles/pobuca-email-builder.umd.js +4664 -0
  18. package/bundles/pobuca-email-builder.umd.js.map +1 -0
  19. package/bundles/pobuca-email-builder.umd.min.js +2 -0
  20. package/bundles/pobuca-email-builder.umd.min.js.map +1 -0
  21. package/esm2015/lib/classes/DefaultEmail.js +53 -0
  22. package/esm2015/lib/classes/Elements.js +229 -0
  23. package/esm2015/lib/classes/Structure.js +89 -0
  24. package/esm2015/lib/components/block/block.component.js +89 -0
  25. package/esm2015/lib/components/block-settings/block-settings.component.js +53 -0
  26. package/esm2015/lib/components/builder-container/builder-container.component.js +114 -0
  27. package/esm2015/lib/components/dialog.component.js +30 -0
  28. package/esm2015/lib/components/general-settings/general-settings.component.js +25 -0
  29. package/esm2015/lib/components/import-dialog/import-dialog.component.js +62 -0
  30. package/esm2015/lib/components/preview.component.js +89 -0
  31. package/esm2015/lib/components/structure/structure.component.js +163 -0
  32. package/esm2015/lib/components/structure-settings/structure-settings.component.js +31 -0
  33. package/esm2015/lib/components/template-list-dialog/template-list-dialog.component.js +45 -0
  34. package/esm2015/lib/directives/dynamic-component.directive.js +46 -0
  35. package/esm2015/lib/elements/abstract-block.js +23 -0
  36. package/esm2015/lib/elements/button/button.component.js +29 -0
  37. package/esm2015/lib/elements/divider/divider.component.js +30 -0
  38. package/esm2015/lib/elements/image/image.component.js +54 -0
  39. package/esm2015/lib/elements/social/social.component.js +42 -0
  40. package/esm2015/lib/elements/spacer/spacer.component.js +30 -0
  41. package/esm2015/lib/elements/text-element/text-element.component.js +80 -0
  42. package/esm2015/lib/groups/align.js +79 -0
  43. package/esm2015/lib/groups/back-repeat.js +55 -0
  44. package/esm2015/lib/groups/border.js +102 -0
  45. package/esm2015/lib/groups/color.js +139 -0
  46. package/esm2015/lib/groups/direction.js +63 -0
  47. package/esm2015/lib/groups/font-styles.js +112 -0
  48. package/esm2015/lib/groups/gaps.js +45 -0
  49. package/esm2015/lib/groups/line-height.js +68 -0
  50. package/esm2015/lib/groups/link.js +67 -0
  51. package/esm2015/lib/groups/margin.js +45 -0
  52. package/esm2015/lib/groups/padding.js +53 -0
  53. package/esm2015/lib/groups/upload-image.js +112 -0
  54. package/esm2015/lib/groups/width-height.js +94 -0
  55. package/esm2015/lib/interceptors/pb-interceptor.interceptor.js +51 -0
  56. package/esm2015/lib/interfaces/interfaces.js +13 -0
  57. package/esm2015/lib/pb-email-builder.component.js +246 -0
  58. package/esm2015/lib/pb-email-builder.module.js +291 -0
  59. package/esm2015/lib/pb-email-builder.service.js +134 -0
  60. package/esm2015/lib/pipes/slugify.pipe.js +39 -0
  61. package/esm2015/lib/services/internals/pb-email-object-store/pb-email-object-store.service.js +165 -0
  62. package/esm2015/lib/services/internals/user-interfaces/user-interface.service.js +122 -0
  63. package/esm2015/lib/services/pb-storage/FreeUsersStorage.class.js +11 -0
  64. package/esm2015/lib/services/pb-storage/index.js +7 -0
  65. package/esm2015/lib/services/pb-storage/pb-storage.service.js +79 -0
  66. package/esm2015/lib/services/user-image-uploader-service/free-users-image-uploader.service.js +26 -0
  67. package/esm2015/lib/services/user-image-uploader-service/index.js +8 -0
  68. package/esm2015/lib/services/user-image-uploader-service/paid-users-image-uploader.service.js +30 -0
  69. package/esm2015/lib/services/user-image-uploader-service/upload-bottom-sheet-dialog/upload-bottom-sheet-dialog.component.js +112 -0
  70. package/esm2015/lib/services/user-image-uploader-service/upload-image-gallery/upload-image-gallery.component.js +91 -0
  71. package/esm2015/lib/services/user-image-uploader-service/user-image-uploader.service.js +26 -0
  72. package/esm2015/lib/services/user-middleware-service/FreeUsersMiddleware.js +31 -0
  73. package/esm2015/lib/services/user-middleware-service/PaidUsersMiddleware.js +12 -0
  74. package/esm2015/lib/services/user-middleware-service/index.js +8 -0
  75. package/esm2015/lib/services/user-middleware-service/pb-middlewares.service.js +195 -0
  76. package/esm2015/lib/services/user-rest-api-service/free-users-rest-api.service.js +16 -0
  77. package/esm2015/lib/services/user-rest-api-service/index.js +7 -0
  78. package/esm2015/lib/services/user-rest-api-service/user-rest-api.service.js +116 -0
  79. package/esm2015/lib/tokens/private-tokens.js +17 -0
  80. package/esm2015/lib/tokens/tokens.js +159 -0
  81. package/esm2015/lib/utils.js +147 -0
  82. package/esm2015/pobuca-email-builder.js +43 -0
  83. package/esm2015/public_api.js +26 -0
  84. package/fesm2015/pobuca-email-builder.js +4335 -0
  85. package/fesm2015/pobuca-email-builder.js.map +1 -0
  86. package/lib/classes/DefaultEmail.d.ts +9 -0
  87. package/lib/classes/Elements.d.ts +62 -0
  88. package/lib/classes/Structure.d.ts +11 -0
  89. package/lib/components/block/block.component.d.ts +25 -0
  90. package/lib/components/block-settings/block-settings.component.d.ts +18 -0
  91. package/lib/components/builder-container/builder-container.component.d.ts +36 -0
  92. package/lib/components/dialog.component.d.ts +10 -0
  93. package/lib/components/general-settings/general-settings.component.d.ts +6 -0
  94. package/lib/components/import-dialog/import-dialog.component.d.ts +16 -0
  95. package/lib/components/preview.component.d.ts +18 -0
  96. package/lib/components/structure/structure.component.d.ts +43 -0
  97. package/lib/components/structure-settings/structure-settings.component.d.ts +9 -0
  98. package/lib/components/template-list-dialog/template-list-dialog.component.d.ts +15 -0
  99. package/lib/directives/dynamic-component.directive.d.ts +13 -0
  100. package/lib/elements/abstract-block.d.ts +8 -0
  101. package/lib/elements/button/button.component.d.ts +18 -0
  102. package/lib/elements/divider/divider.component.d.ts +10 -0
  103. package/lib/elements/image/image.component.d.ts +19 -0
  104. package/lib/elements/social/social.component.d.ts +21 -0
  105. package/lib/elements/spacer/spacer.component.d.ts +5 -0
  106. package/lib/elements/text-element/text-element.component.d.ts +52 -0
  107. package/lib/groups/align.d.ts +17 -0
  108. package/lib/groups/back-repeat.d.ts +8 -0
  109. package/lib/groups/border.d.ts +13 -0
  110. package/lib/groups/color.d.ts +26 -0
  111. package/lib/groups/direction.d.ts +13 -0
  112. package/lib/groups/font-styles.d.ts +17 -0
  113. package/lib/groups/gaps.d.ts +7 -0
  114. package/lib/groups/line-height.d.ts +12 -0
  115. package/lib/groups/link.d.ts +11 -0
  116. package/lib/groups/margin.d.ts +8 -0
  117. package/lib/groups/padding.d.ts +8 -0
  118. package/lib/groups/upload-image.d.ts +19 -0
  119. package/lib/groups/width-height.d.ts +19 -0
  120. package/lib/interceptors/pb-interceptor.interceptor.d.ts +10 -0
  121. package/lib/interfaces/interfaces.d.ts +422 -0
  122. package/lib/pb-email-builder.component.d.ts +67 -0
  123. package/lib/pb-email-builder.module.d.ts +51 -0
  124. package/lib/pb-email-builder.service.d.ts +83 -0
  125. package/lib/pipes/slugify.pipe.d.ts +9 -0
  126. package/lib/services/internals/pb-email-object-store/pb-email-object-store.service.d.ts +50 -0
  127. package/lib/services/internals/user-interfaces/user-interface.service.d.ts +46 -0
  128. package/lib/services/pb-storage/FreeUsersStorage.class.d.ts +6 -0
  129. package/lib/services/pb-storage/index.d.ts +2 -0
  130. package/lib/services/pb-storage/pb-storage.service.d.ts +54 -0
  131. package/lib/services/user-image-uploader-service/free-users-image-uploader.service.d.ts +12 -0
  132. package/lib/services/user-image-uploader-service/index.d.ts +3 -0
  133. package/lib/services/user-image-uploader-service/paid-users-image-uploader.service.d.ts +14 -0
  134. package/lib/services/user-image-uploader-service/upload-bottom-sheet-dialog/upload-bottom-sheet-dialog.component.d.ts +28 -0
  135. package/lib/services/user-image-uploader-service/upload-image-gallery/upload-image-gallery.component.d.ts +27 -0
  136. package/lib/services/user-image-uploader-service/user-image-uploader.service.d.ts +26 -0
  137. package/lib/services/user-middleware-service/FreeUsersMiddleware.d.ts +15 -0
  138. package/lib/services/user-middleware-service/PaidUsersMiddleware.d.ts +7 -0
  139. package/lib/services/user-middleware-service/index.d.ts +3 -0
  140. package/lib/services/user-middleware-service/pb-middlewares.service.d.ts +190 -0
  141. package/lib/services/user-rest-api-service/free-users-rest-api.service.d.ts +10 -0
  142. package/lib/services/user-rest-api-service/index.d.ts +2 -0
  143. package/lib/services/user-rest-api-service/user-rest-api.service.d.ts +82 -0
  144. package/lib/tokens/private-tokens.d.ts +5 -0
  145. package/lib/tokens/tokens.d.ts +70 -0
  146. package/lib/utils.d.ts +88 -0
  147. package/package.json +37 -0
  148. package/pobuca-email-builder.d.ts +42 -0
  149. package/pobuca-email-builder.metadata.json +1 -0
  150. package/public_api.d.ts +16 -0
@@ -0,0 +1,4335 @@
1
+ import * as i0 from '@angular/core';
2
+ import { InjectionToken, Injectable, Inject, Component, ChangeDetectionStrategy, ViewChild, ElementRef, ViewEncapsulation, ChangeDetectorRef, Input, HostBinding, HostListener, Pipe, EventEmitter, forwardRef, Renderer2, Output, Directive, ComponentFactoryResolver, ViewContainerRef, inject, NgModule } from '@angular/core';
3
+ import { defer, of, BehaviorSubject, Subject, combineLatest, EMPTY, ReplaySubject, animationFrameScheduler, iif, fromEvent, throwError } from 'rxjs';
4
+ import { map, shareReplay, pluck, withLatestFrom, switchMap, exhaustMap, take, catchError, distinct, distinctUntilKeyChanged, subscribeOn, distinctUntilChanged, tap, filter, finalize, takeUntil, mapTo, debounceTime } from 'rxjs/operators';
5
+ import { moveItemInArray, transferArrayItem, DragDropModule } from '@angular/cdk/drag-drop';
6
+ import { HttpClient, HttpEventType, HttpResponse, HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http';
7
+ import { MatSnackBar, MatSnackBarModule } from '@angular/material/snack-bar';
8
+ import { MatDialogRef, MAT_DIALOG_DATA, MatDialog, MatDialogModule } from '@angular/material/dialog';
9
+ import { MatBottomSheetRef, MatBottomSheet, MatBottomSheetModule } from '@angular/material/bottom-sheet';
10
+ import { DomSanitizer } from '@angular/platform-browser';
11
+ import { FlexLayoutModule } from '@angular/flex-layout';
12
+ import { MatButtonModule } from '@angular/material/button';
13
+ import { MatButtonToggleModule } from '@angular/material/button-toggle';
14
+ import { MatDividerModule } from '@angular/material/divider';
15
+ import { MatExpansionModule } from '@angular/material/expansion';
16
+ import { MatFormFieldModule } from '@angular/material/form-field';
17
+ import { MatIconModule } from '@angular/material/icon';
18
+ import { MatInputModule } from '@angular/material/input';
19
+ import { MatListModule } from '@angular/material/list';
20
+ import { MatMenuModule } from '@angular/material/menu';
21
+ import { MatProgressBarModule } from '@angular/material/progress-bar';
22
+ import { MatSelectModule } from '@angular/material/select';
23
+ import { MatSidenavModule } from '@angular/material/sidenav';
24
+ import { MatSlideToggleModule } from '@angular/material/slide-toggle';
25
+ import { MatSliderModule } from '@angular/material/slider';
26
+ import { MatTabsModule } from '@angular/material/tabs';
27
+ import { MatToolbarModule } from '@angular/material/toolbar';
28
+ import { MatTooltipModule } from '@angular/material/tooltip';
29
+ import { ResizableModule } from 'angular-resizable-element';
30
+ import { NG_VALUE_ACCESSOR, FormsModule } from '@angular/forms';
31
+ import { DOCUMENT, CommonModule } from '@angular/common';
32
+ import { ScrollingModule } from '@angular/cdk/scrolling';
33
+ import 'quill';
34
+ import { QuillModule, QUILL_CONFIG_TOKEN } from 'ngx-quill';
35
+ import { ColorChromeModule } from 'ngx-color/chrome';
36
+ import { CdkPortal, PortalModule } from '@angular/cdk/portal';
37
+ import { __awaiter } from 'tslib';
38
+ import '@angular/localize/init';
39
+
40
+ /*
41
+ * Copyright (c) 2024 Pobuca.
42
+ * All rights reserved.
43
+ */
44
+ /**
45
+ * Template Storage/Cache keys.
46
+ */
47
+ var ETemplatesStorage;
48
+ (function (ETemplatesStorage) {
49
+ ETemplatesStorage["LATEST_USED"] = "NGB_LATEST_USED_TEMPLATES";
50
+ ETemplatesStorage["STORAGE"] = "NGB_TEMP_TEMPLATES_STORAGE";
51
+ })(ETemplatesStorage || (ETemplatesStorage = {}));
52
+
53
+ /*
54
+ * Copyright (c) 2024 Pobuca.
55
+ * All rights reserved.
56
+ */
57
+ // import { getDiff } from 'recursive-diff';
58
+ /**
59
+ * An alternative lodash cloneDeep function. Use it on your own risk.
60
+ * @param obj Object to be cloned.
61
+ */
62
+ function cloneDeep(obj = {}) {
63
+ return JSON.parse(JSON.stringify(obj));
64
+ }
65
+ /**
66
+ * An alternative lodash isEqual function. Use it on your own risk.
67
+ * @param x Object to be compared
68
+ * @param y the second Object to be compared
69
+ */
70
+ function isEqual(x, y) {
71
+ // return !getDiff(x, y).length;
72
+ return JSON.stringify(x) === JSON.stringify(y);
73
+ }
74
+ /**
75
+ * An alternative lodash defaultsDeep function. Use it on your own risk.
76
+ * @param to The object with default properties
77
+ * @param sources An array of objects with default properties
78
+ */
79
+ function defaultsDeep(to = {}, ...sources) {
80
+ for (const source of sources) {
81
+ for (const key in source) {
82
+ if (to.hasOwnProperty(key)) {
83
+ continue;
84
+ }
85
+ if (!Array.isArray(source[key]) && typeof source[key] === 'object') {
86
+ to[key] = defaultsDeep(to[key], source[key]);
87
+ }
88
+ else {
89
+ to[key] = source[key];
90
+ }
91
+ }
92
+ }
93
+ return to;
94
+ }
95
+ /**
96
+ * Create CSS border styles based on {@link IBorder} object.
97
+ * @param border Border object.
98
+ * @param rule Most likely you won't need it, but for some cases, it can be changed. Default is: `border`.
99
+ *
100
+ * @return CSS Border styles.
101
+ */
102
+ function createBorder(border, rule = 'border') {
103
+ const { color = '#000000', style = 'solid', width = 4, radius = 0 } = border;
104
+ return {
105
+ [rule]: `${width}px ${style} ${color}`,
106
+ borderRadius: `${radius}px`
107
+ };
108
+ }
109
+ /**
110
+ * Create CSS padding styles based on {@link IPadding} object.
111
+ * @param padding Padding object.
112
+ * @param rule Most likely you won't need it, but for some cases, it can be changed. Default is: `padding`.
113
+ */
114
+ function createPadding(padding, rule = 'padding') {
115
+ const { top = 10, right = 25, bottom = 10, left = 25 } = padding;
116
+ return {
117
+ [rule]: `${top}px ${right}px ${bottom}px ${left}px`
118
+ };
119
+ }
120
+ /**
121
+ * Create CSS margin styles based on {@link IMargin} object.
122
+ * @param margin Margin object.
123
+ */
124
+ function createMargin(margin) {
125
+ const { top = 0, bottom = 0 } = margin;
126
+ return {
127
+ margin: `${top}px 0 ${bottom}px`
128
+ };
129
+ }
130
+ /**
131
+ * Create CSS font styles based on {@link IFont} object.
132
+ * @param font Font object.
133
+ */
134
+ function createFont(font) {
135
+ const { family = '', size = 13, style = 'normal', weight = 'normal' } = font;
136
+ return {
137
+ fontFamily: family,
138
+ fontSize: `${size}px`,
139
+ fontStyle: style,
140
+ fontWeight: weight
141
+ };
142
+ }
143
+ /**
144
+ * Create CSS line-height styles based on {@link ILineHeight} object.
145
+ * @param lineHeight Line-height object.
146
+ */
147
+ function createLineHeight(lineHeight) {
148
+ const { value = 22, unit = 'px' } = lineHeight;
149
+ return {
150
+ lineHeight: unit !== 'none' ? `${value}${unit}` : 'normal'
151
+ };
152
+ }
153
+ /**
154
+ * Create background styles based on {@link IBackground} object.
155
+ * @param background Background object.
156
+ */
157
+ function createBackground(background) {
158
+ const { url = '', color = 'white', repeat = 'no-repeat' } = background;
159
+ return `${color} ${url && `url(${url})`} ${repeat} top center`;
160
+ }
161
+ /**
162
+ * Create Width or Height styles based on {@link IWidthHeight} object.
163
+ * @param widthHeight Width or Height object.
164
+ */
165
+ function createWidthHeight(widthHeight) {
166
+ const { value = 100, unit = '%', auto = false } = widthHeight;
167
+ return (auto && 'auto') || (['%', 'px'].indexOf(unit) > -1 && `${value}${unit}`) || unit;
168
+ }
169
+ /**
170
+ * Convert bytes to KB-YB.
171
+ * @param bytes Bytes number.
172
+ * @param decimals How many decimals to be used. Default: 2.
173
+ */
174
+ function bytesToSize(bytes, decimals = 2) {
175
+ if (bytes === 0) {
176
+ return '0 Bytes';
177
+ }
178
+ const k = 1024;
179
+ const dm = decimals < 0 ? 0 : decimals;
180
+ const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB', 'PB', 'EB', 'ZB', 'YB'];
181
+ const i = Math.floor(Math.log(bytes) / Math.log(k));
182
+ return parseFloat((bytes / Math.pow(k, i)).toFixed(dm)) + sizes[i];
183
+ }
184
+ /**
185
+ * Get a Social Icon path.
186
+ * @param path Icon path. Ex: facebook.png
187
+ */
188
+ function getAssetByPath(path) {
189
+ return `https://www.mailjet.com/images/theme/v1/icons/ico-social/${path}`;
190
+ }
191
+ /**
192
+ * A simple and powerful function that allows to create an `Observable` only when it needs to be used.
193
+ * @param args Arguments to send to new Observable.
194
+ */
195
+ function deferOf(...args) {
196
+ return defer(() => of(...args));
197
+ }
198
+
199
+ /*
200
+ * Copyright (c) 2024 Pobuca.
201
+ * All rights reserved.
202
+ */
203
+ const defaultColumnsOptions = {
204
+ background: {
205
+ color: 'transparent'
206
+ },
207
+ border: {
208
+ width: 0,
209
+ color: '#cccccc',
210
+ radius: 0,
211
+ style: 'solid'
212
+ },
213
+ verticalAlign: 'top'
214
+ };
215
+ class Structure {
216
+ constructor(type = 'cols_1', elements = [], options) {
217
+ this.type = type;
218
+ this.elements = elements;
219
+ this.columns = 1;
220
+ this.id = Date.now();
221
+ this.options = {
222
+ fullWidth: false,
223
+ border: {
224
+ color: '#cccccc',
225
+ style: 'solid',
226
+ width: 0,
227
+ radius: 0
228
+ },
229
+ background: {
230
+ color: '#ffffff',
231
+ url: '',
232
+ repeat: 'repeat',
233
+ size: {
234
+ value: 100,
235
+ unit: 'px',
236
+ auto: true,
237
+ units: ['px', '%', 'cover', 'contain']
238
+ }
239
+ },
240
+ padding: {
241
+ top: 4,
242
+ right: 4,
243
+ bottom: 4,
244
+ left: 4
245
+ },
246
+ margin: {
247
+ top: 0,
248
+ bottom: 0
249
+ },
250
+ gaps: [4, 4]
251
+ };
252
+ if (!elements.length) {
253
+ if (['cols_2', 'cols_12', 'cols_21'].includes(type)) {
254
+ this.columns = 2;
255
+ }
256
+ else if (type === 'cols_3') {
257
+ this.columns = 3;
258
+ }
259
+ else if (type === 'cols_4') {
260
+ this.columns = 4;
261
+ }
262
+ }
263
+ const columns = Array.from({ length: this.columns }, () => defaultColumnsOptions);
264
+ let columnsWidth = [1];
265
+ if (type === 'cols_21') {
266
+ columnsWidth = [4, 6];
267
+ }
268
+ else if (type === 'cols_12') {
269
+ columnsWidth = [6, 4];
270
+ }
271
+ else if (type === 'cols_2') {
272
+ columnsWidth = [5, 5];
273
+ }
274
+ else if (type === 'cols_3') {
275
+ columnsWidth = [3.33, 3.33, 3.33];
276
+ }
277
+ else if (type === 'cols_4') {
278
+ columnsWidth = [2.5, 2.5, 2.5, 2.5];
279
+ }
280
+ this.options = defaultsDeep(options, this.options, {
281
+ columns,
282
+ columnsWidth
283
+ });
284
+ }
285
+ }
286
+
287
+ /*
288
+ * Copyright (c) 2024 Pobuca.
289
+ * All rights reserved.
290
+ */
291
+ class AIPBlock {
292
+ }
293
+ class TextBlock {
294
+ constructor(innerText, options, state = {
295
+ disabled: false,
296
+ message: ''
297
+ }) {
298
+ this.innerText = innerText;
299
+ this.state = state;
300
+ this.type = 'text';
301
+ this.icon = 'text_format';
302
+ this.options = {
303
+ color: '#000000',
304
+ font: {
305
+ fallback: 'Arial, Helvetica, sans-serif',
306
+ family: 'Roboto',
307
+ style: 'normal',
308
+ size: 16,
309
+ weight: 400
310
+ },
311
+ lineHeight: {
312
+ value: 40,
313
+ unit: 'none'
314
+ },
315
+ padding: {
316
+ top: 10,
317
+ right: 25,
318
+ bottom: 10,
319
+ left: 25
320
+ }
321
+ };
322
+ this.title = $localize `:@@text_block:Text`;
323
+ this.options = defaultsDeep(options, this.options);
324
+ }
325
+ }
326
+ class ImageBlock {
327
+ constructor(src = 'https://via.placeholder.com/600x200?text=CHANGE+ME', options, state = {
328
+ disabled: false,
329
+ message: ''
330
+ }) {
331
+ this.src = src;
332
+ this.state = state;
333
+ this.type = 'image';
334
+ this.icon = 'image';
335
+ this.options = {
336
+ border: {
337
+ color: '#cccccc',
338
+ style: 'solid',
339
+ width: 0,
340
+ radius: 0
341
+ },
342
+ width: {
343
+ value: 100,
344
+ unit: 'px',
345
+ auto: true,
346
+ units: ['px']
347
+ },
348
+ height: {
349
+ value: 100,
350
+ unit: 'px',
351
+ auto: true,
352
+ units: ['px']
353
+ },
354
+ link: {
355
+ href: '',
356
+ target: '_blank'
357
+ },
358
+ align: 'center',
359
+ title: '',
360
+ padding: {
361
+ top: 0,
362
+ right: 0,
363
+ bottom: 0,
364
+ left: 0
365
+ }
366
+ };
367
+ this.title = $localize `:@@image_block:Image`;
368
+ this.options = defaultsDeep(options, this.options);
369
+ }
370
+ }
371
+ class ButtonBlock {
372
+ constructor(innerText = 'Click on me', options, state = {
373
+ disabled: false,
374
+ message: ''
375
+ }) {
376
+ this.innerText = innerText;
377
+ this.state = state;
378
+ this.type = 'button';
379
+ this.icon = 'radio_button_checked';
380
+ this.options = {
381
+ backgroundColor: '#414141',
382
+ border: {
383
+ color: '#414141',
384
+ style: 'solid',
385
+ width: 0,
386
+ radius: 3
387
+ },
388
+ color: '#ffffff',
389
+ font: {
390
+ fallback: 'Arial, Helvetica, sans-serif',
391
+ family: 'Roboto',
392
+ size: 13,
393
+ style: 'normal',
394
+ weight: 400
395
+ },
396
+ align: 'center',
397
+ fullWidth: false,
398
+ // verticalAlign: 'middle',
399
+ lineHeight: {
400
+ value: 120,
401
+ unit: '%'
402
+ },
403
+ link: {
404
+ href: '',
405
+ target: '_blank'
406
+ },
407
+ innerPadding: {
408
+ top: 10,
409
+ right: 25,
410
+ bottom: 10,
411
+ left: 25
412
+ },
413
+ padding: {
414
+ top: 10,
415
+ right: 25,
416
+ bottom: 10,
417
+ left: 25
418
+ }
419
+ };
420
+ this.title = $localize `:@@button_block:Button`;
421
+ this.options = defaultsDeep(options, this.options);
422
+ }
423
+ }
424
+ class DividerBlock {
425
+ constructor(options, state = {
426
+ disabled: false,
427
+ message: ''
428
+ }) {
429
+ this.state = state;
430
+ this.type = 'divider';
431
+ this.icon = 'remove';
432
+ this.options = {
433
+ border: {
434
+ color: '#000000',
435
+ style: 'solid',
436
+ width: 4
437
+ },
438
+ padding: {
439
+ top: 10,
440
+ right: 25,
441
+ bottom: 10,
442
+ left: 25
443
+ }
444
+ };
445
+ this.title = $localize `:@@divider_block:Divider`;
446
+ this.options = defaultsDeep(options, this.options);
447
+ }
448
+ }
449
+ class SpacerBlock {
450
+ constructor(options, state = {
451
+ disabled: false,
452
+ message: ''
453
+ }) {
454
+ this.state = state;
455
+ this.type = 'spacer';
456
+ this.icon = 'vertical_align_center';
457
+ this.title = $localize `:@@spacer_block:Spacer`;
458
+ this.options = {
459
+ height: {
460
+ value: 20,
461
+ unit: 'px',
462
+ units: ['px']
463
+ }
464
+ };
465
+ this.options = defaultsDeep(options, this.options);
466
+ }
467
+ }
468
+ class SocialBlock {
469
+ // https://mjml.io/documentation/#mjml-social
470
+ constructor(networks = [], options, state = {
471
+ disabled: false,
472
+ message: ''
473
+ }) {
474
+ this.networks = networks;
475
+ this.state = state;
476
+ this.type = 'social';
477
+ this.icon = 'share';
478
+ this.title = $localize `:@@share_block:Social`;
479
+ this.options = {
480
+ align: 'center',
481
+ mode: 'horizontal',
482
+ font: {
483
+ fallback: 'Arial, Helvetica, sans-serif',
484
+ family: 'Roboto',
485
+ style: 'normal',
486
+ size: 16,
487
+ weight: 400
488
+ },
489
+ iconSize: {
490
+ value: 30,
491
+ unit: 'px'
492
+ },
493
+ lineHeight: {
494
+ value: 16,
495
+ unit: 'px'
496
+ },
497
+ color: '#333333',
498
+ innerPadding: {
499
+ top: 4,
500
+ right: 4,
501
+ bottom: 4,
502
+ left: 4
503
+ },
504
+ padding: {
505
+ top: 10,
506
+ right: 25,
507
+ bottom: 10,
508
+ left: 25
509
+ }
510
+ };
511
+ this.options = defaultsDeep(options, this.options);
512
+ }
513
+ }
514
+
515
+ /*
516
+ * Copyright (c) 2024 Pobuca.
517
+ * All rights reserved.
518
+ */
519
+ /**
520
+ * Some top documentation
521
+ */
522
+ /**
523
+ * The default social networks list provided by builder. This list is injected by {@link PB_SOCIAL_NETWORKS}.
524
+ */
525
+ const PB_DEFAULT_SOCIAL_NETWORKS = [
526
+ 'github',
527
+ 'instagram',
528
+ 'web',
529
+ 'snapchat',
530
+ 'youtube',
531
+ 'vimeo',
532
+ 'medium',
533
+ 'soundcloud',
534
+ 'dribbble',
535
+ 'facebook',
536
+ 'twitter',
537
+ 'pinterest',
538
+ 'linkedin',
539
+ 'tumblr',
540
+ 'xing',
541
+ 'tiktok'
542
+ ];
543
+ /**
544
+ * The token that injects [default social networks list]{@link PB_DEFAULT_SOCIAL_NETWORKS}.
545
+ * Use it to add or remove social networks within list.
546
+ *
547
+ * @example
548
+ * {provide: PB_SOCIAL_NETWORKS, useValue: PB_DEFAULT_SOCIAL_NETWORKS.filter(network => !['github', 'instagram'].includes(network)}
549
+ */
550
+ const PB_SOCIAL_NETWORKS = new InjectionToken('PB Social Networks', {
551
+ providedIn: 'any',
552
+ factory: () => PB_DEFAULT_SOCIAL_NETWORKS
553
+ });
554
+ /**
555
+ * The default [Google Fonts]{@link https://fonts.google.com} list provided by builder.
556
+ * This list is injected by {@link PB_GOOGLE_FONTS} token.
557
+ */
558
+ const PB_DEFAULT_GOOGLE_FONTS = [
559
+ 'Open+Sans:300,400,500,700',
560
+ 'Droid+Sans:300,400,500,700',
561
+ 'Lato:300,400,500,700',
562
+ 'Roboto:300,400,700,900',
563
+ 'Ubuntu:300,400,500,700',
564
+ 'Fira+Sans:300,400,500,700',
565
+ 'Mansalva:400'
566
+ ];
567
+ /**
568
+ * The token that injects [default google fonts]{@link PB_DEFAULT_GOOGLE_FONTS} list.
569
+ */
570
+ const PB_GOOGLE_FONTS = new InjectionToken('PB Google Fonts', {
571
+ providedIn: 'any',
572
+ factory: () => PB_DEFAULT_GOOGLE_FONTS
573
+ });
574
+ /**
575
+ * The default Fallback Fonts list provided by builder. This list is injected by {@link PB_FALLBACK_FONTS} token.
576
+ *
577
+ * A fallback font is a font that takes effect in case a [Google Font]{@link PB_DEFAULT_GOOGLE_FONTS} can't be loaded by some email
578
+ * providers.
579
+ */
580
+ const PB_DEFAULT_FALLBACK_FONTS = [
581
+ 'Palatino Linotype, Book Antiqua, Palatino, serif',
582
+ 'Times New Roman, Times, serif',
583
+ 'Arial, Helvetica, sans-serif',
584
+ 'Arial Black, Gadget, sans-serif',
585
+ 'Comic Sans MS, cursive, sans-serif',
586
+ 'Impact, Charcoal, sans-serif',
587
+ 'Lucida Sans Unicode, Lucida Grande, sans-serif',
588
+ 'Tahoma, Geneva, sans-serif',
589
+ 'Trebuchet MS, Helvetica, sans-serif',
590
+ 'Verdana, Geneva, sans-serif',
591
+ 'Courier New, Courier, monospace',
592
+ 'Lucida Console, Monaco, monospace'
593
+ ];
594
+ /**
595
+ * The token that injects {@link PB_DEFAULT_FALLBACK_FONTS} list.
596
+ */
597
+ const PB_FALLBACK_FONTS = new InjectionToken('PB Fallback Fonts', {
598
+ providedIn: 'any',
599
+ factory: () => PB_DEFAULT_FALLBACK_FONTS
600
+ });
601
+ /**
602
+ * The default [Structures]{@link IStructure} list. This list is injected by {@link PB_STRUCTURES} token.
603
+ */
604
+ const PB_DEFAULT_STRUCTURES = [
605
+ new Structure('cols_1'),
606
+ new Structure('cols_2'),
607
+ new Structure('cols_3'),
608
+ new Structure('cols_4'),
609
+ new Structure('cols_12'),
610
+ new Structure('cols_21')
611
+ ];
612
+ /**
613
+ * The token that injects {@link PB_DEFAULT_STRUCTURES} list.
614
+ */
615
+ const PB_STRUCTURES = new InjectionToken('PB Structures', {
616
+ providedIn: 'any',
617
+ factory: () => PB_DEFAULT_STRUCTURES
618
+ });
619
+ /**
620
+ * The default [Blocks]{@link TBlocks} list. This list is injected by {@link PB_BLOCKS} token.
621
+ */
622
+ const PB_DEFAULT_BLOCKS = [
623
+ new TextBlock(),
624
+ new ImageBlock(),
625
+ new ButtonBlock(),
626
+ new DividerBlock(),
627
+ new SpacerBlock(),
628
+ new SocialBlock()
629
+ ];
630
+ /**
631
+ * The token that injects {@link PB_BLOCKS} list.
632
+ */
633
+ const PB_BLOCKS = new InjectionToken('PB Blocks', {
634
+ providedIn: 'any',
635
+ factory: () => PB_DEFAULT_BLOCKS
636
+ });
637
+ /**
638
+ * Default builder configuration, injected by {@link PB_CONFIG} token. See {@link IForRootConf} for more info.
639
+ */
640
+ const PB_DEFAULT_CONFIG = Object.freeze({
641
+ xApiKey: 't7HdQfZjGp6R96fOV4P8v18ggf6LLTQZ1puUI2tz',
642
+ // apiPath: 'https://ngb-api.wlocalhost.org/v1',
643
+ useSaveButton: true,
644
+ usePreviewButton: true,
645
+ useDownloadButton: true,
646
+ templateListIfEmpty: true,
647
+ uploadImageName: 'image'
648
+ });
649
+ /**
650
+ * The token that injects [default builder configurations]{@link PB_DEFAULT_CONFIG}.
651
+ */
652
+ const PB_CONFIG = new InjectionToken('PB Builder Configuration', {
653
+ providedIn: 'root',
654
+ factory: () => PB_DEFAULT_CONFIG
655
+ });
656
+ /**
657
+ * The default Storage used by builder. It can be either `localStorage` or `sessionStorage`.
658
+ */
659
+ const PB_STORAGE_FACTORY = new InjectionToken('PB Storage factory token', {
660
+ providedIn: 'any',
661
+ factory: () => sessionStorage
662
+ });
663
+ /**
664
+ * The default storage to cache the templates list. It can be either `localStorage` or `sessionStorage`.
665
+ */
666
+ const PB_TEMPLATES_TEMPORARY_STORAGE = new InjectionToken('PB Token that stores temporary templates cache', {
667
+ providedIn: 'any',
668
+ factory: () => sessionStorage
669
+ });
670
+
671
+ /*
672
+ * Copyright (c) 2024 Pobuca.
673
+ * All rights reserved.
674
+ */
675
+ // import { Structure } from './Structure';
676
+ class Defaults {
677
+ constructor(structures = [], general = {
678
+ name: '',
679
+ previewText: '',
680
+ width: {
681
+ value: 600,
682
+ unit: 'px',
683
+ units: ['px']
684
+ },
685
+ background: {
686
+ // url: '',
687
+ color: '#f1f1f1',
688
+ // repeat: 'repeat',
689
+ size: {
690
+ value: 100,
691
+ unit: '%',
692
+ auto: true,
693
+ units: ['px', '%', 'cover', 'contain']
694
+ }
695
+ },
696
+ padding: {
697
+ top: 16,
698
+ right: 10,
699
+ bottom: 10,
700
+ left: 10
701
+ },
702
+ direction: 'ltr',
703
+ global: {
704
+ // TODO Add more global configurations
705
+ // fonts: [],
706
+ padding: {
707
+ top: 0,
708
+ right: 0,
709
+ bottom: 0,
710
+ left: 0
711
+ }
712
+ }
713
+ }) {
714
+ this.structures = structures;
715
+ this.general = general;
716
+ }
717
+ }
718
+ class PBEmail extends Defaults {
719
+ constructor({ structures, general } = {}) {
720
+ super(structures, general);
721
+ }
722
+ }
723
+
724
+ /*
725
+ * Copyright (c) 2024 Pobuca.
726
+ * All rights reserved.
727
+ */
728
+ /**
729
+ * This service allows you to control all your users' abilities within this builder. Lets say you want to implement user Roles or just
730
+ * need to disable some functionality for certain users based on purchase plan or on something else. You can allow or disallow almost
731
+ * everything.
732
+ *
733
+ * All the methods must return an Observable, so, in my opinion, that's the best part of this service, you can either return an
734
+ * [EMPTY Observable]{@link https://rxjs.dev/api/index/const/EMPTY}, a modified object or an (Info Modal).pipe(mapTo(EMPTY)) - I think you
735
+ * got the idea.
736
+ *
737
+ * I recommend always using a Modal or a Toast for forbidden actions.
738
+ *
739
+ * It won't work if you have a Regular/Free License - you'll get an error on running the project,
740
+ * you need either an [Extended or Commercial License]{@link https://wlocalhost.org} key for this purpose.
741
+ *
742
+ * @example
743
+ * // Create a custom service
744
+ * class YourOwnMiddlewareService extends PbUserMiddlewaresService {}
745
+ *
746
+ * // Rewrite it into AppModule
747
+ * { provide: PbUserMiddlewaresService, useClass: YourOwnMiddlewareService }
748
+ */
749
+ class PbUserMiddlewaresService {
750
+ /**
751
+ * This method is called before sending the request to MJML Convertor. Use it to add some additional blocks or anything else to
752
+ * the PBEmail object.
753
+ * @param email PBEmail object that's being sent to MJML Convertor.
754
+ */
755
+ createHTMLTemplate(email) {
756
+ return deferOf(email);
757
+ }
758
+ /**
759
+ * Allow or Disallow preview window.
760
+ * @param state Coming Preview state
761
+ */
762
+ togglePreview(state) {
763
+ return deferOf(state);
764
+ }
765
+ /**
766
+ * Allow or Disallow preview devices.
767
+ * @param button Device's button that has been clicked
768
+ */
769
+ togglePreviewDevice(button) {
770
+ return deferOf(button.value);
771
+ }
772
+ /**
773
+ * Allow or disallow users to select certain templates based either on category or template object.
774
+ * @param category Template's category user has selected
775
+ * @param template Template user has selected
776
+ */
777
+ chooseTemplate(category, template) {
778
+ return deferOf({ category, template });
779
+ }
780
+ /**
781
+ * Allow, disallow or return the same path for all user's uploaded images.
782
+ * @param path Path of uploaded image
783
+ *
784
+ * @TODO Check if this middleware is being called before image has been uploaded
785
+ */
786
+ uploadImage(path) {
787
+ return deferOf(path);
788
+ }
789
+ /**
790
+ * Allow or disallow users to add blocks within email structures.
791
+ * @param event Event of dropped block
792
+ * @param column Column that block has been dropped
793
+ *
794
+ * @TODO add parent structure as a parameter
795
+ */
796
+ addBlock(event, column) {
797
+ return deferOf({ event, column });
798
+ }
799
+ /**
800
+ * Prevent user to edit blocks within email body.
801
+ * @param block Block that user intends to edit
802
+ */
803
+ editBlock(block) {
804
+ return deferOf(block);
805
+ }
806
+ /**
807
+ * Prevent user to remove blocks within email body.
808
+ * @param index Block's Index
809
+ * @param column Block's parent column
810
+ * @param block Block that user intends to remove
811
+ */
812
+ removeBlock(index, column, block) {
813
+ return deferOf({ index, column });
814
+ }
815
+ /**
816
+ * Prevent user to duplicate blocks within email body.
817
+ * @param index Block's Index
818
+ * @param column Block's parent column
819
+ * @param block Block that user intends to duplicate
820
+ */
821
+ duplicateBlock(index, column, block) {
822
+ return deferOf({ index, column, block });
823
+ }
824
+ /**
825
+ * Disable Drag and Drop certain blocks from Blocks list to Email body.
826
+ * Return TRUE to disable all blocks - no matter on block's data.
827
+ * @param block Block to allow or disallow from being dragged
828
+ */
829
+ disableBlockDragFromList(block) {
830
+ return deferOf(false);
831
+ }
832
+ /**
833
+ * Prevent users to sort blocks within email body.
834
+ * @param block Block that user intends to change the order
835
+ */
836
+ disableBlockDragWithinEmailBody(block) {
837
+ return deferOf(false);
838
+ }
839
+ /**
840
+ * Prevent user to add new structure.
841
+ * @param event Event of dropped structure
842
+ */
843
+ addStructure(event) {
844
+ return deferOf(event);
845
+ }
846
+ /**
847
+ * Prevent user to edit the structure.
848
+ * @param structure Structure that user intends to edit
849
+ */
850
+ editStructure(structure) {
851
+ return deferOf(structure);
852
+ }
853
+ /**
854
+ * Prevent user to remove the structure.
855
+ * @param index Index of the structure
856
+ * @param structure Structure that user intends to remove
857
+ */
858
+ removeStructure(index, structure) {
859
+ return deferOf(index);
860
+ }
861
+ /**
862
+ * Prevent user to duplicate the structure within email body.
863
+ * @param index Index of structure
864
+ * @param structure Structure that user intends to duplicate
865
+ */
866
+ duplicateStructure(index, structure) {
867
+ return deferOf(index);
868
+ }
869
+ /**
870
+ * Disable Drag and Drop certain structures from Structures list to Email body.
871
+ * Return TRUE to disable all structures.
872
+ * @param structure Structure to prevent from being dragged
873
+ */
874
+ disableStructureDragFromList(structure) {
875
+ return deferOf(false);
876
+ }
877
+ /**
878
+ * Allow or disallow users to sort structures within email body.
879
+ * @param structure Structure that user intends to change the order
880
+ */
881
+ disableStructureDragWithinEmailBody(structure) {
882
+ return deferOf(false);
883
+ }
884
+ /**
885
+ * I don't know why would you do that, but you can disable OnExit confirm modal.
886
+ * @param event Window [BeforeUnloadEvent]{@link https://developer.mozilla.org/en-US/docs/Web/API/BeforeUnloadEvent}
887
+ */
888
+ preventWindowExit(event) {
889
+ return deferOf(event);
890
+ }
891
+ /**
892
+ * Allow or disallow user to export certain types of file
893
+ * @param type Type that user intends to download
894
+ */
895
+ exportFile(type) {
896
+ return deferOf(type);
897
+ }
898
+ /**
899
+ * Allow or disallow user to import certain types of file
900
+ * @param file Web APIs [FILE]{@link https://developer.mozilla.org/en-US/docs/Web/API/File}
901
+ */
902
+ importFile(file) {
903
+ return deferOf(file);
904
+ }
905
+ /**
906
+ * Catch all errors within email editor, it might not work 100%, it's still on working process.
907
+ * @param error Throwable Error
908
+ */
909
+ catchError(error) {
910
+ return deferOf(error);
911
+ }
912
+ }
913
+ PbUserMiddlewaresService.decorators = [
914
+ { type: Injectable }
915
+ ];
916
+
917
+ /*
918
+ * Copyright (c) 2024 Pobuca.
919
+ * All rights reserved.
920
+ */
921
+ /**
922
+ * Default NGB ROOT API Path
923
+ */
924
+ const NGB_HOST = 'https://ngb-api.wlocalhost.org/v1';
925
+ /**
926
+ * The abstract service that must extend the user's custom REST API service.
927
+ * Contains all required properties needed within project.
928
+ *
929
+ * Rewrite the default methods/properties to get the desired data.
930
+ * We recommend using `shareReplay()` operator if it's just a simple static data.
931
+ *
932
+ * @example
933
+ * // Create a custom service
934
+ * class YourOwnRestApiService extends PbUserRestApiService {}
935
+ *
936
+ * // Rewrite it into AppModule
937
+ * { provide: PbUserRestApiService, useClass: YourOwnRestApiService }
938
+ */
939
+ class PbUserRestApiService {
940
+ constructor(http) {
941
+ this.http = http;
942
+ /**
943
+ * Get all user merge fields to inject into text editor.
944
+ */
945
+ this.getAllUserMergeFields$ = deferOf([]);
946
+ /**
947
+ * Get all Custom Modules to be included into Modules List.
948
+ * We're looking for someone who could create many modules to be included by default, if you feel you can help us, please leave a message!
949
+ */
950
+ this.getAllUserModules$ = deferOf([]);
951
+ /**
952
+ * Get all Predefined Templates and categories.
953
+ * You can leave it to get all default templates from NGB API
954
+ */
955
+ this.getAllUserTemplates$ = this.http
956
+ .get(NGB_HOST.concat('/templates'))
957
+ .pipe(map(list => list.map(({ category, templates }) => ({
958
+ category,
959
+ templates: templates.map(title => ({
960
+ thumbPath: `https://ngb-templates.s3.amazonaws.com/${category}-${title}.jpg`,
961
+ title,
962
+ templateData: null
963
+ }))
964
+ }))), shareReplay());
965
+ }
966
+ /**
967
+ * This method must return the chosen template from Template Gallery List PBEmail object,
968
+ * see {@link PbUserRestApiService#getAllUserTemplates$|getAllUserTemplates$}.
969
+ *
970
+ * Sometimes it can contain 'templateData' property - in this case, just return it.
971
+ *
972
+ * @param category Selected Category from Template Gallery.
973
+ * @param template Selected Template from Template Gallery.
974
+ *
975
+ * @example
976
+ * if (template.templateData) { return template }
977
+ */
978
+ getUserTemplateData$(category, template) {
979
+ if (template.templateData) {
980
+ return deferOf(template);
981
+ }
982
+ return this.http
983
+ .get(NGB_HOST.concat('/templates'), {
984
+ params: { category, template: template.title }
985
+ })
986
+ .pipe(map(email => (Object.assign(Object.assign({}, template), { templateData: email }))));
987
+ }
988
+ /**
989
+ * Handle all uploaded images.
990
+ * FormData 'csrf' is deprecated in favor of [HttpClientXsrfModule]{@link https://angular.io/api/common/http/HttpClientXsrfModule}.
991
+ *
992
+ * @param body A FormData that contains 'image' and 'csrf' data.
993
+ * @param uploadImagePath Define a path where NGB have to send the upload request.
994
+ */
995
+ userImageUpload$(body, uploadImagePath) {
996
+ return this.http.request('POST', uploadImagePath, {
997
+ body,
998
+ reportProgress: true,
999
+ responseType: 'json',
1000
+ observe: 'events'
1001
+ });
1002
+ }
1003
+ /**
1004
+ * Get all images to include into Image Gallery.
1005
+ */
1006
+ getUserImages$() {
1007
+ return deferOf([]);
1008
+ }
1009
+ /**
1010
+ * Rewrite the default request which converts PBEmail to HTML, if you have a paid License,
1011
+ * this method allows you to rewrite the default Convertor API Path to yours.
1012
+ *
1013
+ * You can still use the default Convertor API Path, since you have a valid and active License Key.
1014
+ *
1015
+ * @param emailAndFonts PBEmail plus Google Fonts List object.
1016
+ * @param url Your own Convertor API Path, or leave it empty to use NGB servers.
1017
+ */
1018
+ createHTMLTemplate$(emailAndFonts, url = NGB_HOST) {
1019
+ return this.http.post(url, emailAndFonts);
1020
+ }
1021
+ }
1022
+ PbUserRestApiService.decorators = [
1023
+ { type: Injectable }
1024
+ ];
1025
+ PbUserRestApiService.ctorParameters = () => [
1026
+ { type: HttpClient }
1027
+ ];
1028
+
1029
+ /*
1030
+ * Copyright (c) 2024 Pobuca.
1031
+ * All rights reserved.
1032
+ */
1033
+ /**
1034
+ * This service allow you rewrite the default Builder Storage methods. It contains all methods builder needs to cache or store objects.
1035
+ * Alternatively you can rewrite the [PB_TEMPLATES_TEMPORARY_STORAGE]{@link PB_TEMPLATES_TEMPORARY_STORAGE}
1036
+ * or [PB_STORAGE_FACTORY]{@link PB_STORAGE_FACTORY} tokens.
1037
+ *
1038
+ * In next major updates, it can have some limitations for Regular License.
1039
+ *
1040
+ * @example
1041
+ * // Create a custom service
1042
+ * class YourOwnStorageService extends IpStorageService {}
1043
+ *
1044
+ * // Rewrite it into AppModule
1045
+ * { provide: IpStorageService, useClass: YourOwnStorageService }
1046
+ */
1047
+ class PbStorageService {
1048
+ constructor(
1049
+ /**
1050
+ * Storage for templates defined by [PB_TEMPLATES_TEMPORARY_STORAGE]{@link PB_TEMPLATES_TEMPORARY_STORAGE} token.
1051
+ */
1052
+ templateStorage) {
1053
+ this.templateStorage = templateStorage;
1054
+ }
1055
+ /**
1056
+ * Get the latest used templates end user has chosen from templates list.
1057
+ * @return Latest used templates by end user.
1058
+ */
1059
+ getLatestUsedTemplates() {
1060
+ return JSON.parse(this.templateStorage.getItem(ETemplatesStorage.LATEST_USED)) || [];
1061
+ }
1062
+ /**
1063
+ * Add a template to end user's chosen templates list.
1064
+ * @param template Template end user chosen.
1065
+ */
1066
+ addTemplateToLatestUsed(template) {
1067
+ const latest = this.getLatestUsedTemplates().filter(({ title }) => title !== template.title);
1068
+ latest.unshift(template);
1069
+ this.templateStorage.setItem(ETemplatesStorage.LATEST_USED, JSON.stringify(latest));
1070
+ }
1071
+ /**
1072
+ * Clear all latest used templates cache.
1073
+ */
1074
+ clearLatestUsed() {
1075
+ this.templateStorage.removeItem(ETemplatesStorage.LATEST_USED);
1076
+ }
1077
+ /**
1078
+ * Cache a fully templates list.
1079
+ * @param list Template list to cache
1080
+ */
1081
+ cacheTemplateList(list) {
1082
+ this.templateStorage.setItem(ETemplatesStorage.STORAGE, JSON.stringify(list));
1083
+ }
1084
+ /**
1085
+ * Get a cached templates list if exists.
1086
+ * @return Either a cached templates list or an empty array.
1087
+ */
1088
+ getCachedTemplateList() {
1089
+ return JSON.parse(this.templateStorage.getItem(ETemplatesStorage.STORAGE)) || [];
1090
+ }
1091
+ /**
1092
+ * Clear all templates list cache.
1093
+ */
1094
+ clearCachedTemplateList() {
1095
+ this.templateStorage.removeItem(ETemplatesStorage.STORAGE);
1096
+ }
1097
+ }
1098
+ PbStorageService.decorators = [
1099
+ { type: Injectable }
1100
+ ];
1101
+ PbStorageService.ctorParameters = () => [
1102
+ { type: Storage, decorators: [{ type: Inject, args: [PB_TEMPLATES_TEMPORARY_STORAGE,] }] }
1103
+ ];
1104
+
1105
+ /*
1106
+ * Copyright (c) 2024 Pobuca.
1107
+ * All rights reserved.
1108
+ */
1109
+ // https://www.npmjs.com/package/recursive-diff
1110
+ /**
1111
+ * @internal
1112
+ */
1113
+ class PbEmailObjectStoreService {
1114
+ constructor(userRestApi, pbStorage, userMiddleware, googleFonts, config) {
1115
+ this.userRestApi = userRestApi;
1116
+ this.pbStorage = pbStorage;
1117
+ this.userMiddleware = userMiddleware;
1118
+ this.googleFonts = googleFonts;
1119
+ this.config = config;
1120
+ this.Email = new PBEmail();
1121
+ this.clonedEmail = cloneDeep(this.Email);
1122
+ this._Email$ = new BehaviorSubject(this.Email);
1123
+ this.emailAsObservable$ = this._Email$.asObservable();
1124
+ this.emailStructuresAsObservable$ = this.emailAsObservable$.pipe(pluck('structures'));
1125
+ this.generalEmailOptionsAsObservable$ = this.emailAsObservable$.pipe(pluck('general'));
1126
+ this.currentEmailHasChanges$ = this.emailAsObservable$.pipe(map(current => !isEqual(current, this.clonedEmail))
1127
+ // shareReplay(),
1128
+ // tap((isDirty) => console.log('IsDirty', isDirty)),
1129
+ );
1130
+ this.builderContainerStyles$ = this.generalEmailOptionsAsObservable$.pipe(map(({ background, padding, direction }) => (Object.assign({ direction, backgroundRepeat: background.repeat, backgroundColor: background.color, backgroundSize: createWidthHeight(background.size), backgroundPosition: 'top center' }, createPadding(padding)))));
1131
+ // public readonly emailBodyWidth$ = this.generalEmailOptionsAsObservable$.pipe(map(({ width }) => createWidthHeight(width)));
1132
+ this._Mjml$ = new BehaviorSubject('');
1133
+ this.mjmlAsObservable$ = this._Mjml$.asObservable();
1134
+ this._Template$ = new BehaviorSubject('');
1135
+ this.templateAsObservable$ = this._Template$.asObservable();
1136
+ this._onTemplateCreated$ = new Subject();
1137
+ this.onTemplateCreated$ = this._onTemplateCreated$.pipe(withLatestFrom(this._Email$, this._Template$, this._Mjml$), map(([_, ...rest]) => rest));
1138
+ }
1139
+ createHTMLTemplate$() {
1140
+ return this.emailAsObservable$.pipe(switchMap(email => {
1141
+ if (!email.structures.length) {
1142
+ throw new Error('Please add some structures and blocks to perform this action.');
1143
+ }
1144
+ return deferOf(email);
1145
+ }), withLatestFrom(combineLatest([this.currentEmailHasChanges$, this.templateAsObservable$])), exhaustMap(([email, [hasChanges, currentHtml]]) => {
1146
+ if (hasChanges || !currentHtml) {
1147
+ return this.userMiddleware.createHTMLTemplate(email).pipe(exhaustMap(em => this.userRestApi.createHTMLTemplate$(Object.assign(Object.assign({}, em), { googleFonts: this.googleFonts }), this.config.apiPath)), map(res => {
1148
+ if (res.errors.length) {
1149
+ const error = res.errors.map(({ message, tagName }) => `${tagName} > ${message}`).join('\n');
1150
+ throw new Error(error);
1151
+ }
1152
+ this._Mjml$.next(res.mjml);
1153
+ this._Template$.next(res.html);
1154
+ this.clonedEmail = cloneDeep(this.Email);
1155
+ this._onTemplateCreated$.next();
1156
+ return res;
1157
+ }));
1158
+ }
1159
+ return combineLatest([this._Mjml$, this._Template$]).pipe(map(([mjml, html]) => ({ html, mjml, errors: [] })));
1160
+ }));
1161
+ }
1162
+ markForCheck() {
1163
+ this._Email$.next(this.Email);
1164
+ if (this.Email.structures.length) {
1165
+ this.pbStorage.addTemplateToLatestUsed(cloneDeep({
1166
+ templateData: this.Email,
1167
+ title: 'last-edited',
1168
+ thumbPath: 'https://via.placeholder.com/200x300?text=LAST+EDITED'
1169
+ }));
1170
+ }
1171
+ // console.log(getDiff(this.clonedEmail, this.Email));
1172
+ }
1173
+ setEmail(newEmail) {
1174
+ if (!newEmail.structures || !newEmail.general) {
1175
+ throw new Error('Injected object is not a valid PBEmail');
1176
+ }
1177
+ this.Email = newEmail;
1178
+ this.reset();
1179
+ }
1180
+ addStructure({ currentIndex = 0, item }) {
1181
+ const { structures = [] } = this.Email;
1182
+ let isModule = true;
1183
+ if (!item.data.elements.length) {
1184
+ isModule = false;
1185
+ item.data.elements = Array.from({ length: item.data.columns }, () => []);
1186
+ }
1187
+ const newStructure = Object.assign(Object.assign({ id: Date.now() }, cloneDeep(item.data)), { isModule });
1188
+ structures.splice(currentIndex, 0, newStructure);
1189
+ this.markForCheck();
1190
+ return newStructure;
1191
+ }
1192
+ changeStructureOrder({ previousIndex = 0, currentIndex = 0 }) {
1193
+ moveItemInArray(this.Email.structures, previousIndex, currentIndex);
1194
+ this.markForCheck();
1195
+ }
1196
+ duplicateStructure(index) {
1197
+ const { structures = [] } = this.Email;
1198
+ const newStructure = cloneDeep(Object.assign(Object.assign({}, structures[index]), { id: Date.now() }));
1199
+ structures.splice(index, 0, newStructure);
1200
+ this.markForCheck();
1201
+ return newStructure;
1202
+ }
1203
+ removeStructure(index) {
1204
+ const { structures = [] } = this.Email;
1205
+ structures.splice(index, 1);
1206
+ this.markForCheck();
1207
+ }
1208
+ addBlock({ previousIndex = 0, currentIndex = 0, item, previousContainer: { id, data } }, column) {
1209
+ // console.log(id);
1210
+ // console.log(item);
1211
+ if (id === 'block-elements') {
1212
+ column.splice(currentIndex, 0, cloneDeep(item.data));
1213
+ }
1214
+ else {
1215
+ transferArrayItem(data, column, previousIndex, currentIndex);
1216
+ }
1217
+ this.markForCheck();
1218
+ }
1219
+ changeBlockOrder({ previousIndex = 0, currentIndex = 0 }, column) {
1220
+ moveItemInArray(column, previousIndex, currentIndex);
1221
+ this.markForCheck();
1222
+ }
1223
+ duplicateBlock(key, column, block) {
1224
+ const newBlock = cloneDeep(block);
1225
+ column.splice(key, 0, newBlock);
1226
+ this.markForCheck();
1227
+ return newBlock;
1228
+ }
1229
+ removeBlock(key, column) {
1230
+ column.splice(key, 1);
1231
+ this.markForCheck();
1232
+ }
1233
+ reset() {
1234
+ this._Mjml$.next(null);
1235
+ this._Template$.next(null);
1236
+ this.clonedEmail = cloneDeep(this.Email);
1237
+ this.markForCheck();
1238
+ }
1239
+ }
1240
+ PbEmailObjectStoreService.ɵprov = i0.ɵɵdefineInjectable({ factory: function PbEmailObjectStoreService_Factory() { return new PbEmailObjectStoreService(i0.ɵɵinject(PbUserRestApiService), i0.ɵɵinject(PbStorageService), i0.ɵɵinject(PbUserMiddlewaresService), i0.ɵɵinject(PB_GOOGLE_FONTS), i0.ɵɵinject(PB_CONFIG)); }, token: PbEmailObjectStoreService, providedIn: "root" });
1241
+ PbEmailObjectStoreService.decorators = [
1242
+ { type: Injectable, args: [{
1243
+ providedIn: 'root'
1244
+ },] }
1245
+ ];
1246
+ PbEmailObjectStoreService.ctorParameters = () => [
1247
+ { type: PbUserRestApiService },
1248
+ { type: PbStorageService },
1249
+ { type: PbUserMiddlewaresService },
1250
+ { type: Array, decorators: [{ type: Inject, args: [PB_GOOGLE_FONTS,] }] },
1251
+ { type: undefined, decorators: [{ type: Inject, args: [PB_CONFIG,] }] }
1252
+ ];
1253
+
1254
+ /*
1255
+ * Copyright (c) 2024 Pobuca.
1256
+ * All rights reserved.
1257
+ */
1258
+ class TemplateListDialogComponent {
1259
+ constructor(matDialogRef, templateList) {
1260
+ this.matDialogRef = matDialogRef;
1261
+ this.templateList = templateList;
1262
+ this.chooseCategory$ = new BehaviorSubject('latest');
1263
+ this.currentCategoryTemplates$ = this.chooseCategory$.pipe(map(category => this.templateList.find(list => list.category === category) || { templates: [] }), pluck('templates'), map(templates => (templates.length > 0 ? templates : null))
1264
+ // map(tmpl => Array.from({ length: 1000 }).map((_, i) => tmpl[0]))
1265
+ );
1266
+ }
1267
+ chooseTemplate(template) {
1268
+ this.csdTemplate = template;
1269
+ }
1270
+ chageCategory(category) {
1271
+ this.chooseCategory$.next(category);
1272
+ }
1273
+ getTemplatesList() {
1274
+ return this.templateList.filter(({ category }) => category !== 'latest');
1275
+ }
1276
+ startBuilding() {
1277
+ this.chooseCategory$.pipe(take(1)).subscribe(category => {
1278
+ this.matDialogRef.close({ category, template: this.csdTemplate });
1279
+ });
1280
+ }
1281
+ }
1282
+ TemplateListDialogComponent.decorators = [
1283
+ { type: Component, args: [{
1284
+ selector: 'pb-template-list-dialog',
1285
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<div fxLayout=\"column\" style=\"height: 100%;\">\n <h2 mat-dialog-title i18n=\"templates|Modal template header\">Custom Templates</h2>\n <div class=\"mat-typography template-list-wrapper\" fxLayout fxLayoutGap=\"1rem\" fxFlex>\n <mat-list fxFlex=\"200px\" dense>\n <mat-list-item (click)=\"chageCategory('latest')\" [ngClass]=\"{active: (chooseCategory$ | async) === 'latest'}\"\n i18n=\"templates|category name\">\n Latest\n </mat-list-item>\n <mat-divider></mat-divider>\n <mat-list-item *ngFor=\"let list of getTemplatesList()\" (click)=\"chageCategory(list.category)\"\n [ngClass]=\"{active: (chooseCategory$ | async) === list.category}\" i18n=\"templates|category name\">\n {{list.category}}\n </mat-list-item>\n </mat-list>\n\n <ng-container *ngIf=\"currentCategoryTemplates$ | async as templates;else emptyCategory\">\n <cdk-virtual-scroll-viewport itemSize=\"150\" [maxBufferPx]=\"150\" fxFlex>\n <div class=\"template-list\">\n <div *cdkVirtualFor=\"let template of templates\" class=\"template-list-item\" (click)=\"chooseTemplate(template)\"\n i18n-matTooltip=\"templates|Click to choose message\" matTooltip=\"Click to choose\">\n <img [src]=\"template.thumbPath\" [alt]=\"template.title\" />\n <div class=\"description\">\n <h3>{{template.title}}</h3>\n </div>\n </div>\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container>\n </div>\n <mat-dialog-actions align=\"end\">\n <button mat-button mat-dialog-close i18n=\"actions|Undo\">Undo</button>\n <button mat-button (click)=\"startBuilding()\" [disabled]=\"!csdTemplate\" i18n=\"actions|Start\">\n Start\n </button>\n </mat-dialog-actions>\n</div>\n\n\n<ng-template #emptyCategory>\n <div fxFlex fxLayout=\"column\" fxLayoutAlign=\"center center\" class=\"empty-category-notification\">\n <mat-icon>notifications</mat-icon>\n <h2 i18n=\"templates|No templates in current category message\">This category is empty!</h2>\n </div>\n</ng-template>\n",
1286
+ changeDetection: ChangeDetectionStrategy.OnPush,
1287
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */:host{display:block;height:inherit}.template-list-wrapper mat-list{position:sticky;top:0}.template-list-wrapper mat-list mat-list-item{text-transform:capitalize;cursor:pointer;border-radius:3px;transition:all .3s linear}.template-list-wrapper mat-list mat-list-item.active,.template-list-wrapper mat-list mat-list-item:hover{background-color:#f3f3f3}.template-list-wrapper .template-list{display:grid;gap:1rem;grid-template:150px/repeat(3,1fr)}@media screen and (max-width:699px){.template-list-wrapper .template-list{grid-template:150px/repeat(2,1fr)}}.template-list-wrapper .template-list-item{border-radius:3px;overflow:hidden;border:1px solid #ccc;padding:.5rem;position:relative;background-color:#f3f3f3}.template-list-wrapper .template-list-item img{-o-object-fit:cover;object-fit:cover;-o-object-position:top;object-position:top;height:calc(200px - 1rem);width:100%;cursor:pointer;animation:objectPosition 3s linear infinite alternate;animation-play-state:paused}.template-list-wrapper .template-list-item .description{position:absolute;bottom:0;right:0;left:0;background-color:#fff;padding:.5rem;opacity:1;transition:all .3s linear;text-transform:capitalize}.template-list-wrapper .template-list-item .description h3{margin:0}.template-list-wrapper .template-list-item:hover img{animation-play-state:running}.template-list-wrapper .template-list-item:hover .description{bottom:-44px;opacity:.6}.empty-category-notification mat-icon{height:50px;width:50px;font-size:50px}.empty-category-notification h2{text-transform:uppercase}@keyframes objectPosition{to{-o-object-position:bottom;object-position:bottom}}"]
1288
+ },] }
1289
+ ];
1290
+ TemplateListDialogComponent.ctorParameters = () => [
1291
+ { type: MatDialogRef },
1292
+ { type: Array, decorators: [{ type: Inject, args: [MAT_DIALOG_DATA,] }] }
1293
+ ];
1294
+
1295
+ /*
1296
+ * Copyright (c) 2024 Pobuca.
1297
+ * All rights reserved.
1298
+ */
1299
+ // @dynamic
1300
+ class ConfirmDialogComponent {
1301
+ constructor(dialogRef, data) {
1302
+ this.dialogRef = dialogRef;
1303
+ this.data = data;
1304
+ }
1305
+ }
1306
+ ConfirmDialogComponent.decorators = [
1307
+ { type: Component, args: [{
1308
+ selector: 'pb-confirm-dialog',
1309
+ template: `
1310
+ <h2 mat-dialog-title>Are you sure?</h2>
1311
+ <mat-dialog-actions fxLayout fxLayoutAlign="space-between center" fxLayoutGap="1rem">
1312
+ <button mat-stroked-button mat-dialog-close="0">No</button>
1313
+ <button mat-stroked-button color="warn" mat-dialog-close="1">Yes</button>
1314
+ </mat-dialog-actions>
1315
+ `
1316
+ },] }
1317
+ ];
1318
+ ConfirmDialogComponent.ctorParameters = () => [
1319
+ { type: MatDialogRef },
1320
+ { type: undefined, decorators: [{ type: Inject, args: [MAT_DIALOG_DATA,] }] }
1321
+ ];
1322
+
1323
+ /*
1324
+ * Copyright (c) 2024 Pobuca.
1325
+ * All rights reserved.
1326
+ */
1327
+ class ImportDialogComponent {
1328
+ constructor(pbMiddlewares, bottomSheetRef) {
1329
+ this.pbMiddlewares = pbMiddlewares;
1330
+ this.bottomSheetRef = bottomSheetRef;
1331
+ this.importing = false;
1332
+ this.fileReader = new FileReader();
1333
+ }
1334
+ openBrowserModal(event) {
1335
+ event.preventDefault();
1336
+ this.uploadInput.nativeElement.click();
1337
+ }
1338
+ startImporting() {
1339
+ this.importing = true;
1340
+ this.pbMiddlewares
1341
+ .importFile(this.uploadInput.nativeElement.files.item(0))
1342
+ .pipe(take(1), catchError(error => this.pbMiddlewares.catchError(error).pipe(switchMap(() => {
1343
+ this.bottomSheetRef.dismiss(error);
1344
+ return EMPTY;
1345
+ }))))
1346
+ .subscribe(file => {
1347
+ this.fileReader.readAsText(file, 'utf-8');
1348
+ });
1349
+ }
1350
+ ngOnInit() {
1351
+ this.fileReader.addEventListener('loadend', () => {
1352
+ this.importing = false;
1353
+ try {
1354
+ const email = JSON.parse(this.fileReader.result);
1355
+ this.bottomSheetRef.dismiss(email);
1356
+ }
1357
+ catch (error) {
1358
+ this.bottomSheetRef.dismiss(null);
1359
+ throw new Error(error);
1360
+ }
1361
+ });
1362
+ }
1363
+ ngOnDestroy() { }
1364
+ }
1365
+ ImportDialogComponent.decorators = [
1366
+ { type: Component, args: [{
1367
+ selector: 'pb-import-dialog',
1368
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<mat-nav-list>\n <mat-list-item (click)=\"openBrowserModal($event)\">\n <div *ngIf=\"!importing\">\n <span mat-line i18n=\"import|Import JSON file\">Import JSON file</span>\n </div>\n <ng-container *ngIf=\"importing\">\n <span mat-line i18n=\"import|Importing in progress\">Importing in progress ...</span>\n <!-- <span mat-line>{{ imageInfo }}</span> -->\n </ng-container>\n </mat-list-item>\n <mat-progress-bar *ngIf=\"importing\" mode=\"buffer\" value=\"100\"></mat-progress-bar>\n</mat-nav-list>\n<input type=\"file\" accept=\"application/json\" fxHide #uploadInput (change)=\"startImporting()\" />\n",
1369
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */"]
1370
+ },] }
1371
+ ];
1372
+ ImportDialogComponent.ctorParameters = () => [
1373
+ { type: PbUserMiddlewaresService },
1374
+ { type: MatBottomSheetRef }
1375
+ ];
1376
+ ImportDialogComponent.propDecorators = {
1377
+ uploadInput: [{ type: ViewChild, args: ['uploadInput', { read: ElementRef, static: true },] }]
1378
+ };
1379
+
1380
+ /*
1381
+ * Copyright (c) 2024 Pobuca.
1382
+ * All rights reserved.
1383
+ */
1384
+ /**
1385
+ * @internal
1386
+ */
1387
+ class PbUserInterfaceService {
1388
+ constructor(emailObjectStore, matDialog, bottomSheet, snackBar) {
1389
+ this.emailObjectStore = emailObjectStore;
1390
+ this.matDialog = matDialog;
1391
+ this.bottomSheet = bottomSheet;
1392
+ this.snackBar = snackBar;
1393
+ this.activeMatProgress$ = new ReplaySubject();
1394
+ this.cdkDropListConnectedTo$ = this.emailObjectStore.emailStructuresAsObservable$.pipe(
1395
+ // tap(structures => console.log('Structures Length', structures.length)),
1396
+ map(structures => structures.reduce((prev, { elements }, structureKey) => {
1397
+ prev.push(...elements.map((_, columnKey) => `column-droplist-${columnKey}-${structureKey}`));
1398
+ return prev;
1399
+ }, [])), distinct(), distinctUntilKeyChanged('length'),
1400
+ // tap(dropList => console.log('Drop List', dropList)),
1401
+ shareReplay());
1402
+ this._currentEditingStructure$ = new BehaviorSubject(null);
1403
+ this.currentEditingStructure$ = this._currentEditingStructure$.pipe(subscribeOn(animationFrameScheduler), distinctUntilChanged(), catchError(() => of(null)),
1404
+ // tap(editStructure => console.log(editStructure)),
1405
+ shareReplay());
1406
+ this._currentEditingBlock$ = new BehaviorSubject(null);
1407
+ this.currentEditingBlock$ = this._currentEditingBlock$.pipe(subscribeOn(animationFrameScheduler), distinctUntilChanged(), catchError(() => of(null)), shareReplay());
1408
+ this._editGeneralSettings$ = new Subject();
1409
+ this.editGeneralSettings$ = this._editGeneralSettings$.pipe(subscribeOn(animationFrameScheduler), tap(() => this.changeTabIndex(2)), distinctUntilChanged(), shareReplay());
1410
+ this._currentTabIndex$ = new BehaviorSubject(0);
1411
+ this.currentTabIndex$ = this._currentTabIndex$.pipe(subscribeOn(animationFrameScheduler), distinctUntilChanged());
1412
+ }
1413
+ editBlock(block) {
1414
+ this._currentEditingStructure$.next(null);
1415
+ this._currentEditingBlock$.next(block);
1416
+ this._editGeneralSettings$.next('block');
1417
+ }
1418
+ editStructure(structure) {
1419
+ this._currentEditingBlock$.next(null);
1420
+ this._editGeneralSettings$.next('structure');
1421
+ this._currentEditingStructure$.next(structure);
1422
+ }
1423
+ editGeneralSettings() {
1424
+ this.resetElements();
1425
+ this._editGeneralSettings$.next('general');
1426
+ }
1427
+ changeTabIndex(index) {
1428
+ this._currentTabIndex$.next(index);
1429
+ }
1430
+ confirmDialog$() {
1431
+ return this.matDialog
1432
+ .open(ConfirmDialogComponent)
1433
+ .afterClosed()
1434
+ .pipe(map(res => res === '1'));
1435
+ }
1436
+ templatesListDialog$(templateList) {
1437
+ return this.matDialog
1438
+ .open(TemplateListDialogComponent, {
1439
+ data: templateList,
1440
+ width: '60vw',
1441
+ maxWidth: '800px',
1442
+ height: '70vh',
1443
+ maxHeight: '900px'
1444
+ })
1445
+ .afterClosed()
1446
+ .pipe(filter(tmpl => Boolean(tmpl)));
1447
+ }
1448
+ importDialog$() {
1449
+ return this.bottomSheet
1450
+ .open(ImportDialogComponent, {
1451
+ ariaLabel: 'Browse media'
1452
+ })
1453
+ .afterDismissed();
1454
+ }
1455
+ notify(msg, close = 'dismiss', duration = 3000) {
1456
+ return this.snackBar.open(msg, close, { duration });
1457
+ }
1458
+ currentEditingBlock() {
1459
+ return this._currentEditingBlock$.getValue();
1460
+ }
1461
+ currentEditingStructure() {
1462
+ return this._currentEditingStructure$.getValue();
1463
+ }
1464
+ currentStructureEqualWith(structure) {
1465
+ return this.currentEditingStructure() === structure;
1466
+ }
1467
+ currentBlockEqualWith(block) {
1468
+ return this.currentEditingBlock() === block;
1469
+ }
1470
+ currentStructureContainsActiveBlock(structure) {
1471
+ return structure.elements.some(elems => elems.some(block => block === this.currentEditingBlock()));
1472
+ }
1473
+ resetElements() {
1474
+ this._currentEditingStructure$.next(null);
1475
+ this._currentEditingBlock$.next(null);
1476
+ }
1477
+ reset() {
1478
+ this.resetElements();
1479
+ this.changeTabIndex(0);
1480
+ }
1481
+ }
1482
+ PbUserInterfaceService.decorators = [
1483
+ { type: Injectable }
1484
+ ];
1485
+ PbUserInterfaceService.ctorParameters = () => [
1486
+ { type: PbEmailObjectStoreService },
1487
+ { type: MatDialog },
1488
+ { type: MatBottomSheet },
1489
+ { type: MatSnackBar }
1490
+ ];
1491
+
1492
+ /*
1493
+ * Copyright (c) 2024 Pobuca.
1494
+ * All rights reserved.
1495
+ */
1496
+ /**
1497
+ * @deprecated Soon it will be removed
1498
+ * @internal
1499
+ */
1500
+ class PbEmailBuilderService {
1501
+ constructor(config,
1502
+ // @Inject(PB_GOOGLE_FONTS) private googleFonts: string[],
1503
+ emailObjectStore, pbMiddleWares, pbUserInterface // private _http: HttpClient,
1504
+ ) {
1505
+ this.config = config;
1506
+ this.emailObjectStore = emailObjectStore;
1507
+ this.pbMiddleWares = pbMiddleWares;
1508
+ this.pbUserInterface = pbUserInterface;
1509
+ // private _template = new BehaviorSubject<string>('');
1510
+ // private _mjml = new BehaviorSubject<string>('');
1511
+ // private readonly _onSave$ = new Subject();
1512
+ /**
1513
+ * @deprecated Please use the new service "UserRestApiService" instead
1514
+ */
1515
+ this.modules = new Set();
1516
+ /**
1517
+ * @deprecated Please use the new service "UserRestApiService" instead
1518
+ */
1519
+ this.customTemplates = new Set();
1520
+ /**
1521
+ * @deprecated Please use the new service "UserRestApiService" instead
1522
+ */
1523
+ this._mergeTags = new Set();
1524
+ this.onTemplateCreated$ = this.emailObjectStore.onTemplateCreated$.pipe(shareReplay());
1525
+ /**
1526
+ * @deprecated Use onTemplateCreated$ instead
1527
+ */
1528
+ this.onSave$ = this.onTemplateCreated$;
1529
+ /**
1530
+ * @deprecated Use isLoading$ instead
1531
+ */
1532
+ this.isLoading = this.pbUserInterface.activeMatProgress$.asObservable();
1533
+ this.isLoading$ = this.pbUserInterface.activeMatProgress$.asObservable();
1534
+ this.config = Object.assign(Object.assign({}, PB_DEFAULT_CONFIG), this.config);
1535
+ }
1536
+ /**
1537
+ * Save current Email Template
1538
+ */
1539
+ createHTMLTemplate$() {
1540
+ this.pbUserInterface.activeMatProgress$.next(true);
1541
+ return this.emailObjectStore.createHTMLTemplate$().pipe(tap(() => this.pbUserInterface.activeMatProgress$.next(false)), catchError((error) => this.pbMiddleWares.catchError(error).pipe(switchMap(() => {
1542
+ this.pbUserInterface.notify(error.message);
1543
+ this.pbUserInterface.activeMatProgress$.next(false);
1544
+ return EMPTY;
1545
+ }))), finalize(() => this.pbUserInterface.activeMatProgress$.next(false)));
1546
+ }
1547
+ /**
1548
+ * @deprecated Please use ngb.createHTMLTemplate$() instead
1549
+ */
1550
+ saveEmail() {
1551
+ return this.createHTMLTemplate$();
1552
+ }
1553
+ /**
1554
+ * Get Email as object
1555
+ */
1556
+ get Email() {
1557
+ return this.emailObjectStore.Email;
1558
+ }
1559
+ /**
1560
+ * Set Email saved from database or created with new PBEmail()
1561
+ */
1562
+ set Email(newEmail) {
1563
+ this.emailObjectStore.setEmail(newEmail);
1564
+ }
1565
+ /**
1566
+ * @deprecated Use getTemplateAsObservable$() instead
1567
+ */
1568
+ get Template() {
1569
+ return null;
1570
+ }
1571
+ /**
1572
+ * Set HTML output
1573
+ */
1574
+ // set Template(template: string) {
1575
+ // this._template.next(template);
1576
+ // }
1577
+ /**
1578
+ * @deprecated Use getMjmlAsObservable$() instead
1579
+ */
1580
+ get Mjml() {
1581
+ return null;
1582
+ }
1583
+ /**
1584
+ * Listen Email changes
1585
+ */
1586
+ getEmailAsObservable$() {
1587
+ return this.emailObjectStore.emailAsObservable$;
1588
+ }
1589
+ /**
1590
+ * Listen Template changes
1591
+ */
1592
+ getTemplateAsObservable$() {
1593
+ return this.emailObjectStore.templateAsObservable$;
1594
+ }
1595
+ /**
1596
+ * Listen MJML changes
1597
+ */
1598
+ getMjmlAsObservable$() {
1599
+ return this.emailObjectStore.mjmlAsObservable$;
1600
+ }
1601
+ /**
1602
+ * Listen Email and Template changes
1603
+ * @deprecated Use onTemplateCreated$ instead
1604
+ */
1605
+ onChanges$() {
1606
+ return this.onTemplateCreated$;
1607
+ }
1608
+ }
1609
+ PbEmailBuilderService.decorators = [
1610
+ { type: Injectable }
1611
+ ];
1612
+ PbEmailBuilderService.ctorParameters = () => [
1613
+ { type: undefined, decorators: [{ type: Inject, args: [PB_CONFIG,] }] },
1614
+ { type: PbEmailObjectStoreService },
1615
+ { type: PbUserMiddlewaresService },
1616
+ { type: PbUserInterfaceService }
1617
+ ];
1618
+
1619
+ /*
1620
+ * Copyright (c) 2024 Pobuca.
1621
+ * All rights reserved.
1622
+ */
1623
+ class UploadBottomSheetDialogComponent {
1624
+ constructor(sanitizer, ngb, userRestApi, userInterface, middlewares, bottomSheetRef) {
1625
+ this.sanitizer = sanitizer;
1626
+ this.ngb = ngb;
1627
+ this.userRestApi = userRestApi;
1628
+ this.userInterface = userInterface;
1629
+ this.middlewares = middlewares;
1630
+ this.bottomSheetRef = bottomSheetRef;
1631
+ this.uploading = false;
1632
+ this.progress = new Subject();
1633
+ }
1634
+ get imageInfo() {
1635
+ if (this.choosedImage) {
1636
+ const { lastModified, size } = this.choosedImage;
1637
+ const modTime = new Date(lastModified);
1638
+ return `${modTime.toLocaleString()}, ${bytesToSize(size)}.`;
1639
+ }
1640
+ return '';
1641
+ }
1642
+ previewLink() {
1643
+ return this.sanitizer.bypassSecurityTrustResourceUrl(this.objectUrl);
1644
+ }
1645
+ openBrowserModal(event) {
1646
+ event.preventDefault();
1647
+ const { uploadImagePath } = this.ngb.config;
1648
+ if (!this.uploading && uploadImagePath) {
1649
+ this.uploadInput.nativeElement.click();
1650
+ }
1651
+ else if (!uploadImagePath) {
1652
+ this.userInterface.notify(`Hm ... this isn't a bug, it seems 'uploadImagePath' is empty!`);
1653
+ }
1654
+ }
1655
+ uploadInputChanged() {
1656
+ const { nativeElement } = this.uploadInput;
1657
+ if (nativeElement.files.length) {
1658
+ this._startUploading(nativeElement.files.item(0));
1659
+ }
1660
+ }
1661
+ _startUploading(image) {
1662
+ if (this.objectUrl) {
1663
+ URL.revokeObjectURL(this.objectUrl);
1664
+ }
1665
+ this.objectUrl = URL.createObjectURL(image);
1666
+ this.uploading = true;
1667
+ const { uploadImagePath, csrf } = this.ngb.config;
1668
+ const formData = new FormData();
1669
+ if (csrf) {
1670
+ formData.append(csrf.name, csrf.token);
1671
+ }
1672
+ formData.append('image', image);
1673
+ return this.userRestApi
1674
+ .userImageUpload$(formData, uploadImagePath)
1675
+ .pipe(catchError((error) => this.middlewares.catchError(error).pipe(switchMap(() => {
1676
+ this.userInterface.notify(error.message);
1677
+ return EMPTY;
1678
+ }))), finalize(() => this.progress.complete()))
1679
+ .subscribe((event) => {
1680
+ if (event.type === HttpEventType.UploadProgress) {
1681
+ const percentDone = Math.round((100 * event.loaded) / event.total);
1682
+ this.progress.next(percentDone);
1683
+ }
1684
+ else if (event instanceof HttpResponse) {
1685
+ if (!event.body.success) {
1686
+ this.userInterface.notify(event.body.message, 'Dismiss', null);
1687
+ }
1688
+ else {
1689
+ this.bottomSheetRef.dismiss(event.body.path);
1690
+ this.userInterface.notify('Successfully uploaded.', null, 1000);
1691
+ }
1692
+ }
1693
+ });
1694
+ }
1695
+ ngOnDestroy() {
1696
+ if (this.objectUrl) {
1697
+ URL.revokeObjectURL(this.objectUrl);
1698
+ }
1699
+ }
1700
+ }
1701
+ UploadBottomSheetDialogComponent.decorators = [
1702
+ { type: Component, args: [{
1703
+ selector: 'pb-upload-bottom-sheet-dialog',
1704
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<mat-nav-list>\n <mat-list-item (click)=\"openBrowserModal($event)\">\n <div *ngIf=\"!uploading\">\n <span mat-line i18n=\"upload|Browse images from computer\">Browse images from computer</span>\n </div>\n <ng-container *ngIf=\"uploading\">\n <img matListAvatar [src]=\"previewLink()\" />\n <span mat-line i18n=\"upload|Uploading Message\">Uploading ...</span>\n <span mat-line>{{ imageInfo }}</span>\n </ng-container>\n </mat-list-item>\n <mat-progress-bar *ngIf=\"uploading\" mode=\"buffer\" [value]=\"progress | async\"></mat-progress-bar>\n</mat-nav-list>\n<input type=\"file\" accept=\"image/*\" fxHide #uploadInput (change)=\"uploadInputChanged()\" />\n",
1705
+ styles: [""]
1706
+ },] }
1707
+ ];
1708
+ UploadBottomSheetDialogComponent.ctorParameters = () => [
1709
+ { type: DomSanitizer },
1710
+ { type: PbEmailBuilderService },
1711
+ { type: PbUserRestApiService },
1712
+ { type: PbUserInterfaceService },
1713
+ { type: PbUserMiddlewaresService },
1714
+ { type: MatBottomSheetRef }
1715
+ ];
1716
+ UploadBottomSheetDialogComponent.propDecorators = {
1717
+ uploadInput: [{ type: ViewChild, args: ['uploadInput', { static: true },] }]
1718
+ };
1719
+
1720
+ /*
1721
+ * Copyright (c) 2024 Pobuca.
1722
+ * All rights reserved.
1723
+ */
1724
+ /**
1725
+ * A service that must be extended in case you want to rewrite the default
1726
+ * uploading process. In case you have a Regular License, you'll get a simple upload
1727
+ * service, for any other paid Licenses - you get an Image Gallery.
1728
+ *
1729
+ * It won't work if you have a Regular/Free License - you'll get an error on running the project,
1730
+ * you need either an [Extended or Commercial License]{@link https://wlocalhost.org} key for this purpose.
1731
+ *
1732
+ * @example
1733
+ * // Create a custom service
1734
+ * class YourOwnUploaderService extends PbUserImageUploaderService {}
1735
+ *
1736
+ * // Rewrite it into AppModule
1737
+ * { provide: PbUserImageUploaderService, useClass: YourOwnUploaderService }
1738
+ */
1739
+ class PbUserImageUploaderService {
1740
+ }
1741
+ PbUserImageUploaderService.decorators = [
1742
+ { type: Injectable }
1743
+ ];
1744
+
1745
+ /*
1746
+ * Copyright (c) 2024 Pobuca.
1747
+ * All rights reserved.
1748
+ */
1749
+ /**
1750
+ * @internal
1751
+ */
1752
+ class ImageUploader extends PbUserImageUploaderService {
1753
+ constructor(matBottomSheet, userMiddlewaresService) {
1754
+ super();
1755
+ this.matBottomSheet = matBottomSheet;
1756
+ this.userMiddlewaresService = userMiddlewaresService;
1757
+ }
1758
+ browse$() {
1759
+ return this.matBottomSheet
1760
+ .open(UploadBottomSheetDialogComponent, {
1761
+ ariaLabel: 'Browse media'
1762
+ })
1763
+ .afterDismissed()
1764
+ .pipe(switchMap(path => this.userMiddlewaresService.uploadImage(path)));
1765
+ }
1766
+ }
1767
+
1768
+ /*
1769
+ * Copyright (c) 2024 Pobuca.
1770
+ * All rights reserved.
1771
+ */
1772
+ class UploadImageGalleryComponent {
1773
+ constructor(imageCategoryList, userConfig, matDialogRef, sanitizer, userRestApi, middlewares, userInterface) {
1774
+ this.imageCategoryList = imageCategoryList;
1775
+ this.userConfig = userConfig;
1776
+ this.matDialogRef = matDialogRef;
1777
+ this.sanitizer = sanitizer;
1778
+ this.userRestApi = userRestApi;
1779
+ this.middlewares = middlewares;
1780
+ this.userInterface = userInterface;
1781
+ this.currentMenuItem = 'gallery';
1782
+ }
1783
+ changeCurrentMenuItem(item) {
1784
+ this.currentMenuItem = item;
1785
+ }
1786
+ addImageToTemplate(imagePath = this.choseImage) {
1787
+ this.matDialogRef.close(imagePath);
1788
+ }
1789
+ previewImage({ target }) {
1790
+ this.uploadImageFile = target.files.item(0);
1791
+ if (this.imagePreviewObjectUrl) {
1792
+ URL.revokeObjectURL(this.imagePreviewObjectUrl);
1793
+ }
1794
+ this.imagePreviewObjectUrl = URL.createObjectURL(this.uploadImageFile);
1795
+ this.uploadImagePreview = this.sanitizer.bypassSecurityTrustResourceUrl(this.imagePreviewObjectUrl);
1796
+ }
1797
+ startUploading() {
1798
+ const { csrf, uploadImagePath } = this.userConfig;
1799
+ const formData = new FormData();
1800
+ if (csrf) {
1801
+ formData.append(csrf.name, csrf.token);
1802
+ }
1803
+ formData.append('image', this.uploadImageFile);
1804
+ return this.userRestApi
1805
+ .userImageUpload$(formData, uploadImagePath)
1806
+ .pipe(catchError((error) => this.middlewares.catchError(error).pipe(switchMap(() => {
1807
+ this.userInterface.notify(error.message);
1808
+ return EMPTY;
1809
+ }))))
1810
+ .subscribe((event) => {
1811
+ if (event.type === HttpEventType.UploadProgress) {
1812
+ // const percentDone = Math.round((100 * event.loaded) / event.total);
1813
+ // this.progress.next(percentDone);
1814
+ }
1815
+ else if (event instanceof HttpResponse) {
1816
+ if (!event.body.success) {
1817
+ this.userInterface.notify(event.body.message, 'Dismiss', null);
1818
+ }
1819
+ else {
1820
+ this.addImageToTemplate(event.body.path);
1821
+ this.userInterface.notify('Successfully uploaded.', null, 1000);
1822
+ }
1823
+ }
1824
+ });
1825
+ }
1826
+ ngOnDestroy() {
1827
+ if (this.imagePreviewObjectUrl) {
1828
+ URL.revokeObjectURL(this.imagePreviewObjectUrl);
1829
+ }
1830
+ }
1831
+ }
1832
+ UploadImageGalleryComponent.decorators = [
1833
+ { type: Component, args: [{
1834
+ selector: 'pb-upload-image-gallery',
1835
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<div fxLayout=\"column\" style=\"height: 100%;\">\n <h2 mat-dialog-title i18n=\"image-gallery|Modal Image gallery header\">Image Gallery</h2>\n <div class=\"mat-typography gallery-list-wrapper\" fxLayout fxLayoutGap=\"1rem\" fxFlex>\n <mat-list fxFlex=\"200px\">\n <mat-list-item (click)=\"changeCurrentMenuItem('gallery')\" [class.active]=\"currentMenuItem === 'gallery'\"\n i18n=\"image-gallery|Image list\">\n Gallery Image list\n </mat-list-item>\n <mat-list-item (click)=\"changeCurrentMenuItem('upload')\" [class.active]=\"currentMenuItem === 'upload'\"\n i18n=\"image-gallery|Upload an image\">\n Upload an image\n </mat-list-item>\n </mat-list>\n\n <ng-container *ngIf=\"currentMenuItem === 'gallery'\">\n <ng-container *ngIf=\"imageCategoryList.length;else emptyImageList\">\n <cdk-virtual-scroll-viewport itemSize=\"150\" [minBufferPx]=\"150 * 10\" fxFlex\n class=\"gallery-list\">\n <div *cdkVirtualFor=\"let imagePath of imageCategoryList\" class=\"gallery-list-item\"\n (click)=\"choseImage = imagePath\" i18n-matTooltip=\"image-gallery|Click to choose message\"\n matTooltip=\"Click to choose\">\n <img [src]=\"imagePath\" />\n </div>\n </cdk-virtual-scroll-viewport>\n </ng-container>\n </ng-container>\n <ng-container *ngIf=\"currentMenuItem === 'upload'\">\n <div class=\"upload-image\" fxLayout=\"column\" fxLayoutAlign=\"center center\" fxFlex fxLayoutGap=\"1rem\">\n <label class=\"upload-image-item\" [class.empty]=\"!uploadImagePreview\">\n <div class=\"upload-image-item-overview\" fxLayout=\"column\" fxLayoutAlign=\"center center\">\n <mat-icon>backup</mat-icon>\n </div>\n <img class=\"upload-image-item-preview\" *ngIf=\"uploadImagePreview\" [src]=\"uploadImagePreview\" />\n <input type=\"file\" fxHide pattern=\"image/*\" (change)=\"previewImage($event)\">\n </label>\n <button mat-flat-button color=\"primary\" (click)=\"startUploading()\" i18n=\"image-gallery|Upload and insert into template\">\n Upload and insert into template\n </button>\n </div>\n </ng-container>\n </div>\n <mat-dialog-actions align=\"end\">\n <button mat-button mat-dialog-close i18n=\"actions|Undo\">Cancel</button>\n <button mat-stroked-button color=\"primary\" [disabled]=\"!choseImage\" (click)=\"addImageToTemplate()\"\n i18n=\"actions|Start\">\n Add to template\n </button>\n </mat-dialog-actions>\n</div>\n\n\n<ng-template #emptyImageList>\n <div fxFlex fxLayout=\"column\" fxLayoutAlign=\"center center\" class=\"empty-category-notification\">\n <mat-icon>notifications</mat-icon>\n <h2 i18n=\"image-gallery|Image list is empty message\">Image list is empty!</h2>\n </div>\n</ng-template>\n",
1836
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */mat-list{background-color:#fff}mat-list mat-list-item{cursor:pointer}mat-list mat-list-item.active{background-color:#ccc}.gallery-list ::ng-deep .cdk-virtual-scroll-content-wrapper{display:grid;gap:.3rem;grid-template:auto/repeat(4,1fr)}.gallery-list-item{height:120px;background-color:#ccc;cursor:pointer}.gallery-list-item img{width:100%;height:100%;-o-object-fit:contain;object-fit:contain;-o-object-position:center;object-position:center}.upload-image-item{width:80%;height:200px;background-color:#ccc;position:relative;border-radius:3px;padding:1em;text-align:center}.upload-image-item.empty .upload-image-item-overview,.upload-image-item:hover .upload-image-item-overview{opacity:1}.upload-image-item-overview{opacity:0;position:absolute;top:0;bottom:0;left:0;right:0;cursor:pointer;transition:opacity .5s linear}.upload-image-item-overview mat-icon{height:50px;width:50px;font-size:50px}.upload-image-item-preview{max-height:100%}"]
1837
+ },] }
1838
+ ];
1839
+ UploadImageGalleryComponent.ctorParameters = () => [
1840
+ { type: Array, decorators: [{ type: Inject, args: [MAT_DIALOG_DATA,] }] },
1841
+ { type: undefined, decorators: [{ type: Inject, args: [PB_CONFIG,] }] },
1842
+ { type: MatDialogRef },
1843
+ { type: DomSanitizer },
1844
+ { type: PbUserRestApiService },
1845
+ { type: PbUserMiddlewaresService },
1846
+ { type: PbUserInterfaceService }
1847
+ ];
1848
+
1849
+ /*
1850
+ * Copyright (c) 2024 Pobuca.
1851
+ * All rights reserved.
1852
+ */
1853
+ /**
1854
+ * @internal
1855
+ */
1856
+ class PaidUsersImageUploaderServiceService extends PbUserImageUploaderService {
1857
+ constructor(matDialog, userMiddleware, userRestApi) {
1858
+ super();
1859
+ this.matDialog = matDialog;
1860
+ this.userMiddleware = userMiddleware;
1861
+ this.userRestApi = userRestApi;
1862
+ }
1863
+ browse$() {
1864
+ return this.userRestApi.getUserImages$().pipe(exhaustMap(imageCategoryList => this.matDialog
1865
+ .open(UploadImageGalleryComponent, {
1866
+ data: imageCategoryList,
1867
+ width: '60vw',
1868
+ maxWidth: '800px',
1869
+ height: '60vh',
1870
+ maxHeight: '800px'
1871
+ })
1872
+ .afterClosed()), filter(path => !!path.length), switchMap(path => this.userMiddleware.uploadImage(path)));
1873
+ }
1874
+ }
1875
+
1876
+ /*
1877
+ * Copyright (c) 2024 Pobuca.
1878
+ * All rights reserved.
1879
+ */
1880
+
1881
+ /*
1882
+ * Copyright (c) 2024 Pobuca.
1883
+ * All rights reserved.
1884
+ */
1885
+ class StructureComponent {
1886
+ constructor(userInterfaceService, emailObjectStore, chRef, pbMiddlewaresService) {
1887
+ this.userInterfaceService = userInterfaceService;
1888
+ this.emailObjectStore = emailObjectStore;
1889
+ this.chRef = chRef;
1890
+ this.pbMiddlewaresService = pbMiddlewaresService;
1891
+ this.structure = new Structure();
1892
+ this.cdkDropListConnectedTo$ = this.userInterfaceService.cdkDropListConnectedTo$;
1893
+ this.validate = function ({ rectangle }) {
1894
+ const colFr = +(rectangle.width / this.fr).toFixed(2);
1895
+ return colFr > 1 && colFr <= 10 - this.structure.columns;
1896
+ }.bind(this);
1897
+ // sectionWidth$ = this.userInterfaceService.currentEditingStructure$.pipe(
1898
+ // withLatestFrom(this.emailObjectStore.emailBodyWidth$),
1899
+ // map(([{ options }, width]) => {
1900
+ // return options.fullWidth ? '100%' : width;
1901
+ // })
1902
+ // );
1903
+ this.componentIsDestroyed$ = new Subject();
1904
+ }
1905
+ get isStructureActive() {
1906
+ return this.isActive;
1907
+ }
1908
+ // @HostBinding('style.width') get sectionWidth(): string | number {
1909
+ // console.log(this.emailObjectStore.Email.general.width.value);
1910
+ // return this.structure.options.fullWidth ? '100%' : this.emailObjectStore.Email.general.width.value;
1911
+ // }
1912
+ // Don't close right panel on structure click
1913
+ onHostClick(event) {
1914
+ event.stopImmediatePropagation();
1915
+ this.editStructure();
1916
+ }
1917
+ removeStructure(event) {
1918
+ event.stopPropagation();
1919
+ this.pbMiddlewaresService
1920
+ .removeStructure(this.index, this.structure)
1921
+ .pipe(exhaustMap(() => this.userInterfaceService.confirmDialog$()), filter(removeAllowed => removeAllowed), take(1))
1922
+ .subscribe(() => {
1923
+ this.emailObjectStore.removeStructure(this.index);
1924
+ this.userInterfaceService.resetElements();
1925
+ });
1926
+ }
1927
+ duplicateStructure(event) {
1928
+ event.stopPropagation();
1929
+ this.pbMiddlewaresService
1930
+ .duplicateStructure(this.index, this.structure)
1931
+ .pipe(map(() => this.emailObjectStore.duplicateStructure(this.index)), take(1))
1932
+ .subscribe(newStructure => {
1933
+ this.editStructure(newStructure);
1934
+ });
1935
+ }
1936
+ dropNewBlock(event, column) {
1937
+ if (event.previousContainer === event.container) {
1938
+ this.emailObjectStore.addBlock(event, column);
1939
+ }
1940
+ else {
1941
+ this.pbMiddlewaresService
1942
+ .addBlock(event, column)
1943
+ .pipe(map(newData => this.emailObjectStore.addBlock(newData.event, newData.column)))
1944
+ .subscribe(() => {
1945
+ // this.userInterfaceService.editBlock(newBlock);
1946
+ this.chRef.markForCheck();
1947
+ });
1948
+ }
1949
+ }
1950
+ disableBlockDrag$(block) {
1951
+ return this.pbMiddlewaresService.disableBlockDragWithinEmailBody(block).pipe(take(1));
1952
+ }
1953
+ editStructure(structure = this.structure) {
1954
+ this.pbMiddlewaresService
1955
+ .editStructure(structure)
1956
+ .pipe(take(1))
1957
+ .subscribe(strctr => {
1958
+ this.userInterfaceService.editStructure(strctr);
1959
+ });
1960
+ }
1961
+ getResizeEdges(columnKey) {
1962
+ return {
1963
+ right: columnKey + 1 !== this.structure.columns,
1964
+ left: columnKey !== 0
1965
+ };
1966
+ }
1967
+ createColumnId(columnKey) {
1968
+ return `column-droplist-${columnKey}-${this.index}`;
1969
+ }
1970
+ getColumnStyles(columnKey) {
1971
+ const { options: { gaps = [4, 4], columns = [] } } = this.structure;
1972
+ const column = columns[columnKey] || defaultColumnsOptions;
1973
+ let verticalAlign = 'center';
1974
+ if (column.verticalAlign === 'bottom') {
1975
+ verticalAlign = 'flex-end';
1976
+ }
1977
+ else if (column.verticalAlign === 'top') {
1978
+ verticalAlign = 'flex-start';
1979
+ }
1980
+ return Object.assign({ padding: gaps.map(gap => `${gap}px`).join(' '), backgroundColor: column.background.color, placeSelf: `${verticalAlign} stretch` }, createBorder(column.border)
1981
+ // ...createBackground(column.background)
1982
+ );
1983
+ }
1984
+ onResizeEnd({ rectangle }, key) {
1985
+ this.structure.options.columnsWidth[key] = +(rectangle.width / this.fr).toFixed(2);
1986
+ }
1987
+ ngDoCheck() {
1988
+ if (this.isActive || this.userInterfaceService.currentStructureContainsActiveBlock(this.structure)) {
1989
+ this.chRef.markForCheck();
1990
+ }
1991
+ }
1992
+ ngOnInit() {
1993
+ // Add columns options in case of old template
1994
+ const { columns, columnsWidth } = this.structure.options;
1995
+ if (!columns || !columnsWidth) {
1996
+ const { type, elements, options } = this.structure;
1997
+ this.editStructure(new Structure(type, elements, options));
1998
+ }
1999
+ const width = this.emailObjectStore.Email.general.width.value;
2000
+ const [, horizontalGap] = this.structure.options.gaps;
2001
+ this.fr = (width - horizontalGap * this.structure.columns) / 10;
2002
+ this.userInterfaceService.currentEditingStructure$
2003
+ .pipe(map(currentEditingStructure => currentEditingStructure === this.structure), takeUntil(this.componentIsDestroyed$))
2004
+ .subscribe(isActive => {
2005
+ this.isActive = isActive;
2006
+ });
2007
+ }
2008
+ ngOnDestroy() {
2009
+ this.componentIsDestroyed$.next('');
2010
+ this.componentIsDestroyed$.complete();
2011
+ }
2012
+ }
2013
+ StructureComponent.decorators = [
2014
+ { type: Component, args: [{
2015
+ selector: 'pb-structure',
2016
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<div class=\"column\" *ngFor=\"let column of structure.elements; let index = index\" cdkDropList mwlResizable\n [enableGhostResize]=\"false\" [resizeSnapGrid]=\"{ left: fr, right: fr }\" [resizeEdges]=\"getResizeEdges(index)\"\n [validateResize]=\"validate\" (resizing)=\"onResizeEnd($event, index)\"\n (cdkDropListDropped)=\"dropNewBlock($event, column)\" [class.empty]=\"!column.length\" [ngStyle]=\"getColumnStyles(index)\"\n [cdkDropListConnectedTo]=\"cdkDropListConnectedTo$ | async\" [cdkDropListData]=\"column\" [id]=\"createColumnId(index)\">\n\n <div *ngIf=\"!column.length\" class=\"empty-block\" i18n=\"structure|Inside empty block\">DnD blocks</div>\n\n <pb-block *ngFor=\"let block of column; let index = index\" cdkDrag [cdkDragData]=\"block\" [block]=\"block\"\n [index]=\"index\" [column]=\"column\" [cdkDragDisabled]=\"disableBlockDrag$(block) | async\">\n <button mat-icon-button class=\"move\" cdkDragHandle i18n-matTooltip=\"block|Change Block order\"\n matTooltip=\"Change Block order\" *ngIf=\"!(disableBlockDrag$(block) | async)\">\n <mat-icon i18n-aria-label=\"block|Move block\" aria-label=\"Move block\" inline>pan_tool</mat-icon>\n </button>\n </pb-block>\n</div>\n\n<ng-content select=\".move\"></ng-content>\n<div class=\"tools\" fxLayoutGap=\"0.25rem\">\n <button mat-icon-button class=\"edit\" color=\"primary\" i18n-matTooltip=\"structure|Change structure settings\"\n matTooltip=\"Change structure settings\">\n <mat-icon i18n-aria-label=\"structure|Edit structure\" aria-label=\"Edit structure\" inline>edit</mat-icon>\n </button>\n <button mat-icon-button (click)=\"duplicateStructure($event)\" i18n-matTooltip=\"structure|Duplicate structure\"\n matTooltip=\"Duplicate structure\">\n <mat-icon i18n-aria-label=\"structure|Duplicate structure\" aria-label=\"Duplicate structure\" inline>file_copy\n </mat-icon>\n </button>\n <button mat-icon-button color=\"warn\" (click)=\"removeStructure($event)\" i18n-matTooltip=\"structure|Delete structure\"\n matTooltip=\"Delete structure\">\n <mat-icon i18n-aria-label=\"structure|Remove Structure\" aria-label=\"Remove Structure\" inline>delete_forever\n </mat-icon>\n </button>\n</div>\n",
2017
+ changeDetection: ChangeDetectionStrategy.OnPush,
2018
+ encapsulation: ViewEncapsulation.Emulated,
2019
+ exportAs: 'structure',
2020
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */pb-block>.cdk-drag-handle{position:absolute;top:-30px;right:0;cursor:move;background-color:rgba(63,81,181,.5);color:#fff;border-radius:50% 50% 0 0;opacity:0;height:30px;width:30px;font-size:smaller}pb-block>.cdk-drag-handle mat-icon{margin-top:-8px}pb-block>.cdk-drag-handle:hover{background-color:#3f51b5}pb-block.cdk-drag-preview .cdk-drag-handle,pb-block:hover .cdk-drag-handle{opacity:1}:host{display:grid;border:1px solid #ccc;position:relative;grid-template-columns:1fr}:host>.tools{direction:ltr;position:absolute;opacity:0;left:0;bottom:-25px;color:#ff4081}:host>.tools button{background-color:#fff;border-radius:0 0 3px 3px;height:25px;width:25px;line-height:0}:host.active,:host.cdk-drag-placeholder,:host.cdk-drag-preview,:host:hover{box-shadow:0 0 1px 2px #ff4081;z-index:1}:host:hover>.tools{opacity:1}:host:hover>.tools button{background-color:#ff4081;color:#fff}:host.active>.tools>.edit{display:none}:host.cols_2{grid-template-columns:repeat(2,6fr)}:host.cols_3{grid-template-columns:repeat(3,4fr)}:host.cols_4{grid-template-columns:repeat(4,3fr)}:host.cols_12{grid-template-columns:7fr 5fr}:host.cols_21{grid-template-columns:5fr 7fr}:host .cdk-drop-list-dragging,:host .cdk-drop-list-receiving{height:100%}:host>.column{box-sizing:border-box}:host>.column.empty{height:60px}:host>.column.empty .empty-block{background-color:rgba(101,99,99,.21);height:100%;display:flex;justify-content:center;place-items:center;flex-direction:column;color:rgba(101,99,99,.3);font-size:small}:host>.column.empty.cdk-drop-list-dragging .empty-block{display:none}:host>.column.empty>.cdk-drag-placeholder{min-height:60px!important}"]
2021
+ },] }
2022
+ ];
2023
+ StructureComponent.ctorParameters = () => [
2024
+ { type: PbUserInterfaceService },
2025
+ { type: PbEmailObjectStoreService },
2026
+ { type: ChangeDetectorRef },
2027
+ { type: PbUserMiddlewaresService }
2028
+ ];
2029
+ StructureComponent.propDecorators = {
2030
+ structure: [{ type: Input }],
2031
+ index: [{ type: Input }],
2032
+ isStructureActive: [{ type: HostBinding, args: ['class.active',] }],
2033
+ onHostClick: [{ type: HostListener, args: ['click', ['$event'],] }]
2034
+ };
2035
+
2036
+ /*
2037
+ * Copyright (c) 2024 Pobuca.
2038
+ * All rights reserved.
2039
+ */
2040
+ /**
2041
+ * @ignore
2042
+ *
2043
+ * Soon will be removed.
2044
+ */
2045
+ class SlugifyPipe {
2046
+ transform(input) {
2047
+ const trChars = {
2048
+ áÁ: 'a',
2049
+ éÉ: 'e',
2050
+ íÍ: 'i',
2051
+ óÓ: 'o',
2052
+ úÚ: 'u',
2053
+ ñÑ: 'n'
2054
+ };
2055
+ for (const key of Object.keys(trChars)) {
2056
+ input = input.replace(new RegExp('[' + key + ']', 'g'), trChars[key]);
2057
+ }
2058
+ return input
2059
+ .toString()
2060
+ .toLowerCase()
2061
+ .replace(/\s+/g, '-') // Replace spaces with -
2062
+ .replace(/[^\w\-]+/g, '') // Remove all non-word chars
2063
+ .replace(/\-\-+/g, '-') // Replace multiple - with single -
2064
+ .replace(/^-+/, '') // Trim - from start of text
2065
+ .replace(/-+$/, ''); // Trim - from end of text
2066
+ }
2067
+ }
2068
+ SlugifyPipe.decorators = [
2069
+ { type: Pipe, args: [{
2070
+ name: 'slugify'
2071
+ },] }
2072
+ ];
2073
+
2074
+ /*
2075
+ * Copyright (c) 2024 Pobuca.
2076
+ * All rights reserved.
2077
+ */
2078
+ class PbEmailBuilderComponent {
2079
+ constructor(ngb, userRestApiService, userInterfaceService, emailObjectStore, renderer2, slugifyPipe, middlewares, changeDetectorRef, structures, blocks, googleFonts, doc) {
2080
+ this.ngb = ngb;
2081
+ this.userRestApiService = userRestApiService;
2082
+ this.userInterfaceService = userInterfaceService;
2083
+ this.emailObjectStore = emailObjectStore;
2084
+ this.renderer2 = renderer2;
2085
+ this.slugifyPipe = slugifyPipe;
2086
+ this.middlewares = middlewares;
2087
+ this.changeDetectorRef = changeDetectorRef;
2088
+ this.structures = structures;
2089
+ this.blocks = blocks;
2090
+ this.doc = doc;
2091
+ this.emailChange = new EventEmitter();
2092
+ this.previewTemplate = false;
2093
+ this.showGeneralSettings$ = this.userInterfaceService.editGeneralSettings$;
2094
+ this.currentTabIndex$ = this.userInterfaceService.currentTabIndex$;
2095
+ this.cdkDropListConnectedTo$ = this.userInterfaceService.cdkDropListConnectedTo$;
2096
+ this.getBuilderContainerStyles$ = this.emailObjectStore.builderContainerStyles$;
2097
+ this.currentHTMLTemplate$ = this.emailObjectStore.templateAsObservable$;
2098
+ this.activeMatProgress$ = this.userInterfaceService.activeMatProgress$.asObservable();
2099
+ this.customModuleList$ = this.userRestApiService.getAllUserModules$;
2100
+ this._onDestroy$ = new Subject();
2101
+ this.includedFonts = new Set();
2102
+ if (this.doc) {
2103
+ for (const font of googleFonts) {
2104
+ const link = this.doc.createElement('link');
2105
+ link.href = `https://fonts.googleapis.com/css?family=${font}`;
2106
+ link.rel = 'stylesheet';
2107
+ this.includedFonts.add(link);
2108
+ this.doc.head.appendChild(link);
2109
+ }
2110
+ }
2111
+ }
2112
+ writeValue(email) {
2113
+ try {
2114
+ this.emailObjectStore.setEmail(email);
2115
+ this.previewTemplate = false;
2116
+ this.changeDetectorRef.markForCheck();
2117
+ }
2118
+ catch (error) {
2119
+ this.userInterfaceService.notify(error.message);
2120
+ }
2121
+ }
2122
+ registerOnChange(fn) {
2123
+ this.onChange = fn;
2124
+ }
2125
+ registerOnTouched(fn) {
2126
+ this.onTouched = fn;
2127
+ }
2128
+ /**
2129
+ * Not implemented yet
2130
+ * @param isDisabled The state of builder
2131
+ */
2132
+ setDisabledState(isDisabled) {
2133
+ // tslint:disable-next-line: no-console
2134
+ console.info('[IpEmailBuilderComponent] Method [setDisabledState] is not implemented.');
2135
+ }
2136
+ saveEmail() {
2137
+ return this.emailObjectStore.currentEmailHasChanges$
2138
+ .pipe(exhaustMap(hasChanges => {
2139
+ return iif(() => hasChanges, this.ngb.createHTMLTemplate$(), this.userInterfaceService.notify('No changes were detected to be save!').afterDismissed());
2140
+ }), take(1))
2141
+ .subscribe();
2142
+ }
2143
+ disableBlocksList$(block) {
2144
+ return iif(() => { var _a; return !((_a = block.state) === null || _a === void 0 ? void 0 : _a.disabled); }, this.emailObjectStore.emailStructuresAsObservable$.pipe(map(({ length }) => length > 0), exhaustMap(hasStructures => (hasStructures ? this.middlewares.disableBlockDragFromList(block) : deferOf(true))))).pipe(take(1));
2145
+ }
2146
+ disableStructureList$(structure) {
2147
+ return this.middlewares.disableStructureDragFromList(structure).pipe(take(1));
2148
+ }
2149
+ trackByFn(block) {
2150
+ return block.type;
2151
+ }
2152
+ changeTabIndex(index) {
2153
+ this.userInterfaceService.changeTabIndex(index);
2154
+ }
2155
+ download(source) {
2156
+ return this.middlewares
2157
+ .exportFile(source)
2158
+ .pipe(exhaustMap(() => this.ngb.createHTMLTemplate$().pipe(map(serverResponse => (Object.assign(Object.assign({}, serverResponse), { type: source }))))), catchError(error => this.middlewares.catchError(error).pipe(switchMap(() => {
2159
+ this.userInterfaceService.notify(error.message);
2160
+ return EMPTY;
2161
+ }))), take(1))
2162
+ .subscribe(({ type, html, mjml }) => {
2163
+ const anchor = this.renderer2.createElement('a');
2164
+ let download = html;
2165
+ if (type === 'mjml') {
2166
+ download = mjml;
2167
+ }
2168
+ else if (type === 'json') {
2169
+ download = JSON.stringify(this.ngb.Email, null, 1);
2170
+ }
2171
+ const href = URL.createObjectURL(new Blob([download], {
2172
+ type: type === 'json' ? 'text/json' : 'text/html'
2173
+ }));
2174
+ const fileName = this.slugifyPipe.transform(this.ngb.Email.general.name || 'ngb-template');
2175
+ anchor.href = href;
2176
+ anchor.target = '_blank';
2177
+ anchor.download = `${fileName}.${type}`;
2178
+ anchor.click();
2179
+ URL.revokeObjectURL(href);
2180
+ });
2181
+ }
2182
+ importFile() {
2183
+ this.userInterfaceService
2184
+ .importDialog$()
2185
+ .pipe(switchMap(emailOrError => {
2186
+ if (emailOrError instanceof Error) {
2187
+ throw emailOrError;
2188
+ }
2189
+ return deferOf(emailOrError);
2190
+ }), catchError(error => this.middlewares.catchError(error).pipe(switchMap(() => {
2191
+ this.userInterfaceService.notify(error.message);
2192
+ return EMPTY;
2193
+ }))), take(1), filter(email => !!email))
2194
+ .subscribe(email => {
2195
+ this.writeValue(email);
2196
+ this.userInterfaceService.notify('Email has been imported successfully.');
2197
+ });
2198
+ }
2199
+ // getBackgroundImage(): SafeStyle {
2200
+ // const {
2201
+ // background: { url }
2202
+ // } = this.email.general;
2203
+ // return this.sanitizer.bypassSecurityTrustStyle(url && `url(${url})`);
2204
+ // }
2205
+ // getBuilderContainerStyles() {
2206
+ // const { background, padding, direction } = this.emailObjectStore.Email.general;
2207
+ // return {
2208
+ // direction,
2209
+ // backgroundRepeat: background.repeat,
2210
+ // backgroundColor: background.color,
2211
+ // backgroundSize: createWidthHeight(background.size),
2212
+ // backgroundPosition: 'top center',
2213
+ // ...createPadding(padding)
2214
+ // };
2215
+ // }
2216
+ createArrayFromStructureColumns({ columns }) {
2217
+ return new Array(columns).fill('');
2218
+ }
2219
+ togglePreview() {
2220
+ return this.emailObjectStore
2221
+ .createHTMLTemplate$()
2222
+ .pipe(exhaustMap(() => this.middlewares.togglePreview(!this.previewTemplate)), catchError(error => this.middlewares.catchError(error).pipe(switchMap(() => {
2223
+ this.userInterfaceService.notify(error.message);
2224
+ return EMPTY;
2225
+ }))), take(1))
2226
+ .subscribe(nextState => {
2227
+ this.previewTemplate = nextState;
2228
+ this.changeDetectorRef.markForCheck();
2229
+ });
2230
+ }
2231
+ ngOnInit() {
2232
+ fromEvent(window, 'beforeunload')
2233
+ .pipe(withLatestFrom(this.emailObjectStore.currentEmailHasChanges$), filter(([_, emailIsDirty]) => emailIsDirty), switchMap(([event]) => this.middlewares.preventWindowExit(event)), takeUntil(this._onDestroy$))
2234
+ .subscribe(ev => {
2235
+ ev.preventDefault();
2236
+ ev.returnValue = '';
2237
+ });
2238
+ this.emailObjectStore.emailAsObservable$.pipe(takeUntil(this._onDestroy$)).subscribe(email => {
2239
+ var _a, _b;
2240
+ (_a = this.onTouched) === null || _a === void 0 ? void 0 : _a.call(this);
2241
+ (_b = this.onChange) === null || _b === void 0 ? void 0 : _b.call(this, email);
2242
+ this.emailChange.next(email);
2243
+ });
2244
+ }
2245
+ ngOnChanges(changes) {
2246
+ if (changes.email) {
2247
+ this.writeValue(changes.email.currentValue);
2248
+ }
2249
+ }
2250
+ // private setEmail(email: PBEmail) {
2251
+ // try {
2252
+ // this.emailObjectStore.setEmail(email);
2253
+ // this.previewTemplate = false;
2254
+ // this.changeDetectorRef.markForCheck();
2255
+ // } catch (error) {
2256
+ // this.userInterfaceService.notify(error.message);
2257
+ // }
2258
+ // }
2259
+ ngOnDestroy() {
2260
+ this._onDestroy$.next();
2261
+ this._onDestroy$.complete();
2262
+ // Reset the builder state
2263
+ this.userInterfaceService.reset();
2264
+ if (this.doc) {
2265
+ this.includedFonts.forEach(font => font.remove());
2266
+ }
2267
+ this.includedFonts.clear();
2268
+ }
2269
+ }
2270
+ PbEmailBuilderComponent.decorators = [
2271
+ { type: Component, args: [{
2272
+ selector: 'pb-email-builder',
2273
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<mat-sidenav-container>\n <div class=\"pb-builder-container\" fxLayout=\"column\" fxFlex>\n <mat-progress-bar *ngIf=\"activeMatProgress$ | async\" mode=\"buffer\"></mat-progress-bar>\n <mat-toolbar fxLayoutGap=\"1rem\" fxLayoutAlign=\"space-between center\">\n <ng-content fxLayout fxLayoutGap=\"0.5rem\" select=\".top-actions\"></ng-content>\n\n <div fxFlexlayout fxLayoutGap=\"0.5rem\">\n <button *ngIf=\"ngb.config.useSaveButton\" type=\"button\" (click)=\"saveEmail()\" mat-stroked-button color=\"primary\"\n i18n=\"actions|Save Email\">\n Save Email\n </button>\n <button *ngIf=\"ngb.config.usePreviewButton\" type=\"button\" (click)=\"togglePreview()\" mat-stroked-button>\n <ng-container [ngSwitch]=\"previewTemplate\">\n <span *ngSwitchDefault i18n=\"actions|Preview\">Preview</span>\n <span *ngSwitchCase=\"true\" i18n=\"actions|Close Preview\">Close Preview</span>\n </ng-container>\n </button>\n\n <button mat-button mat-stroked-button i18n=\"actions|Import\" (click)=\"importFile()\">\n Import\n </button>\n\n <ng-container *ngIf=\"ngb.config.useDownloadButton\">\n <button mat-button [matMenuTriggerFor]=\"downloadMenu\" mat-stroked-button i18n=\"actions|Export\">\n Export\n </button>\n <mat-menu #downloadMenu=\"matMenu\">\n <button mat-menu-item (click)=\"download('html')\" i18n=\"actions|Export HTML\">\n Export HTML\n </button>\n <button mat-menu-item (click)=\"download('mjml')\" i18n=\"actions|Export MJML\">\n Export MJML\n </button>\n <button mat-menu-item (click)=\"download('json')\" i18n=\"actions|Export JSON\">\n Export JSON\n </button>\n </mat-menu>\n </ng-container>\n\n </div>\n <!-- <div class=\"history-actions\" style=\"margin-inline-start: auto;\">\n <span>Last saved Now</span>\n <button type=\"button\" mat-icon-button>\n <mat-icon>undo</mat-icon>\n </button>\n <button type=\"button\" mat-icon-button>\n <mat-icon>redo</mat-icon>\n </button>\n </div> -->\n </mat-toolbar>\n <ng-container [ngSwitch]=\"previewTemplate\">\n <pb-builder-container *ngSwitchDefault [ngStyle]=\"getBuilderContainerStyles$ | async\">\n <ng-content select=\".rewrited-empty-email\"></ng-content>\n </pb-builder-container>\n\n <pb-preview-template fxLayout fxFlex=\"auto\" fxLayoutAlign=\"center\" [template]=\"currentHTMLTemplate$ | async\"\n *ngSwitchCase=\"true\">\n </pb-preview-template>\n </ng-container>\n </div>\n <mat-sidenav mode=\"side\" fxFlex=\"0 0 310px\" [opened]=\"!previewTemplate\" position=\"end\" class=\"pb-builder-content\">\n <mat-tab-group [selectedIndex]=\"currentTabIndex$ | async\" (selectedIndexChange)=\"changeTabIndex($event)\">\n <mat-tab i18n-label=\"Content\" label=\"Content\">\n <div class=\"main-padding\">\n <cdk-drop-list class=\"elements\" [cdkDropListConnectedTo]=\"cdkDropListConnectedTo$ | async\"\n [cdkDropListData]=\"blocks\" [cdkDropListSortingDisabled]=\"true\" id=\"block-elements\">\n <div cdkDrag *ngFor=\"let block of blocks; trackBy: trackByFn\" [cdkDragData]=\"block\"\n [cdkDragDisabled]=\"disableBlocksList$(block) | async\" class=\"drag-element\"\n [matTooltip]=\"block.state.message\">\n <mat-icon>{{ block.icon }}</mat-icon>\n <div class=\"drag-element-title\">{{ block.title }}</div>\n </div>\n </cdk-drop-list>\n\n <mat-divider style=\"margin: 1em 0;\"></mat-divider>\n <!-- <h3 class=\"divider\"><span>Structures</span></h3> -->\n <cdk-drop-list class=\"elements structure-elements\" cdkDropListConnectedTo=\"structures-drop-list\"\n [cdkDropListSortingDisabled]=\"true\" [cdkDropListData]=\"structures\">\n <div cdkDrag *ngFor=\"let structure of structures; trackBy: trackByFn\" [cdkDragData]=\"structure\"\n [cdkDragDisabled]=\"disableStructureList$(structure) | async\" class=\"drag-element structure-element\"\n [ngClass]=\"structure.type\">\n <div *ngFor=\"let column of createArrayFromStructureColumns(structure)\"></div>\n </div>\n </cdk-drop-list>\n <ng-content fxLayout fxLayoutGap=\"0.5rem\" select=\".after-structure-blocks\"></ng-content>\n </div>\n </mat-tab>\n <mat-tab i18n-label=\"Modules\" label=\"Modules\" class=\"modules-tab\">\n <cdk-virtual-scroll-viewport itemSize=\"54\" [minBufferPx]=\"54 * 10\" [maxBufferPx]=\"54 * 20\"\n style=\"height: inherit;\"\n *ngIf=\"customModuleList$ | async as modules; else emptyModuleList\">\n <div class=\"main-padding\">\n <div class=\"custom-modules\" cdkDropList cdkDropListConnectedTo=\"structures-drop-list\"\n [cdkDropListData]=\"modules\" [cdkDropListSortingDisabled]=\"true\">\n <div fxLayout=\"column\" fxLayoutGap=\"1rem\">\n <ng-container *cdkVirtualFor=\"let module of modules\">\n <div cdkDrag [cdkDragData]=\"module.module\"\n [cdkDragDisabled]=\"disableStructureList$(module.module) | async\" class=\"drag-element\"\n style=\"padding: 1em;text-transform: uppercase;height: 54px;\">\n <span *ngIf=\"module.name\">{{module.name}}</span>\n <!-- <img *ngIf=\"module.thumb\" [src]=\"module.thumb\" /> -->\n </div>\n </ng-container>\n </div>\n </div>\n <ng-content fxLayout fxLayoutGap=\"0.5rem\" select=\".after-content-blocks\"></ng-content>\n </div>\n </cdk-virtual-scroll-viewport>\n <ng-template #emptyModuleList>\n <h4 class=\"main-padding\" style=\"text-align: center;\" i18n=\"modules|empty list message\">\n Module list is empty\n </h4>\n </ng-template>\n </mat-tab>\n <mat-tab i18n-label=\"Settings\" label=\"Settings\">\n <div class=\"pb-builder-options\" [ngSwitch]=\"showGeneralSettings$ | async\">\n <pb-general-settings *ngSwitchDefault></pb-general-settings>\n <pb-block-settings *ngSwitchCase=\"'block'\"></pb-block-settings>\n <pb-structure-settings *ngSwitchCase=\"'structure'\" fxLayout=\"column\"></pb-structure-settings>\n </div>\n </mat-tab>\n </mat-tab-group>\n </mat-sidenav>\n</mat-sidenav-container>\n",
2274
+ exportAs: 'pbEmailBuilder',
2275
+ changeDetection: ChangeDetectionStrategy.OnPush,
2276
+ providers: [
2277
+ {
2278
+ provide: NG_VALUE_ACCESSOR,
2279
+ useExisting: forwardRef(() => PbEmailBuilderComponent),
2280
+ multi: true
2281
+ },
2282
+ SlugifyPipe
2283
+ ],
2284
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */:host{display:block;height:100vh}.hide{display:none}::ng-deep mat-sidenav-container{height:100%}::ng-deep mat-sidenav-container mat-sidenav-content{width:100%;z-index:unset!important;overflow:unset!important}::ng-deep h3.divider{text-align:center;display:block;overflow:hidden;margin:0 0 1rem}::ng-deep h3.divider span{font-weight:100;position:relative;display:inline-block}::ng-deep h3.divider span:after,::ng-deep h3.divider span:before{content:\"\";position:absolute;top:50%;height:1px;background:#ccc;width:99999px}::ng-deep h3.divider span:before{left:100%;margin-left:10px}::ng-deep h3.divider span:after{right:100%;margin-right:10px}::ng-deep .pb-builder-content{border-right:1px solid rgba(0,0,0,.12)}::ng-deep .pb-builder-content .overflow{position:absolute;top:0;bottom:0;left:0;right:0;background-color:#fff;opacity:.5;display:none;z-index:3}::ng-deep .pb-builder-content.disabled .overflow{display:block}::ng-deep .pb-builder-content .mat-tab-label{width:50%;min-width:auto;height:64px;font-size:medium;text-transform:uppercase;padding:0 12px}::ng-deep .pb-builder-content .mat-tab-body-wrapper,::ng-deep .pb-builder-content .mat-tab-group{height:100%}::ng-deep .pb-builder-content .mat-tab-body-wrapper .mat-tab-body{padding:0}::ng-deep .pb-builder-content .mat-tab-body-wrapper .mat-tab-body .elements{display:grid;grid-gap:.5rem;margin-bottom:1rem;grid-template:repeat(2,1fr)/repeat(3,1fr)}::ng-deep .pb-builder-content .mat-tab-body-wrapper .mat-tab-body .elements.structure-elements{grid-template:repeat(4,1fr)/1fr}::ng-deep .pb-builder-content .mat-tab-body-wrapper .mat-tab-body .elements.cdk-drop-list-dragging .cdk-drag{transform:none!important}::ng-deep .pb-builder-content .mat-tab-body-wrapper .mat-tab-body input{height:auto;border:none}::ng-deep .pb-builder-content .mat-tab-body-wrapper .mat-tab-body .custom-modules .drag-element img{max-width:100%}::ng-deep .pb-builder-container{position:relative;height:100%}::ng-deep .pb-builder-container mat-progress-bar{position:absolute}::ng-deep .pb-builder-container mat-toolbar{background-color:#fff}::ng-deep .pb-builder-options .mat-expansion-panel{box-shadow:none!important}::ng-deep .pb-builder-options .mat-expansion-panel.mat-expanded{overflow:visible}::ng-deep .pb-builder-options mat-expansion-panel-header:not(.mat-expanded){background:rgba(0,0,0,.04)}::ng-deep .pb-builder-options ::ng-deep .group{display:grid;grid-template:auto/repeat(2,1fr);grid-gap:1rem}::ng-deep .pb-builder-options ::ng-deep .group>*{align-self:center}::ng-deep .pb-builder-options ::ng-deep .group+.group{margin-top:1em}::ng-deep .pb-builder-options ::ng-deep .group.four{grid-template-columns:repeat(4,1fr)}::ng-deep .pb-builder-options ::ng-deep .group.f-large{grid-template-columns:2fr 1fr}::ng-deep .pb-builder-options ::ng-deep .group.l-large{grid-template-columns:1fr 2fr}::ng-deep .pb-builder-options ::ng-deep .group.three{grid-template-columns:repeat(3,1fr)}::ng-deep .pb-builder-options ::ng-deep .group.three.f-small{grid-template-columns:1fr repeat(2,2fr)}::ng-deep .pb-builder-options ::ng-deep .group.three.f-large{grid-template-columns:2fr repeat(2,1fr)}::ng-deep .pb-builder-options ::ng-deep .group.three.l-large{grid-template-columns:repeat(2,1fr) 2fr}::ng-deep .pb-builder-options ::ng-deep .group .mat-form-field-infix{width:auto!important}::ng-deep .drag-element{text-align:center;border:1px solid #ccc;box-sizing:border-box;background:#fff;color:#7b7b7b;cursor:move;transition:box-shadow .3s ease-in-out;will-change:box-shadow;border-radius:3px}::ng-deep .drag-element.cdk-drag-disabled,::ng-deep .drag-element.cdk-drag-placeholder{cursor:not-allowed;opacity:.6}::ng-deep .drag-element:hover{box-shadow:0 3px 1px -2px rgba(0,0,0,.2),0 2px 2px 0 rgba(0,0,0,.14),0 1px 5px 0 rgba(0,0,0,.12)}::ng-deep .drag-element .mat-icon{font-size:40px!important;padding:.5rem;width:auto;height:auto}::ng-deep .drag-element img{max-width:100%}::ng-deep .drag-element-title{font-size:.9em;text-transform:uppercase;margin-bottom:.5rem}::ng-deep .drag-element.structure-element{height:60px;position:relative;padding:4px;display:grid;grid-template:1fr/1fr}::ng-deep .drag-element.structure-element>div{background:#ccc;border:4px solid #bbb}::ng-deep .drag-element.structure-element.cols_2{grid-template-columns:repeat(2,5fr)}::ng-deep .drag-element.structure-element.cols_3{grid-template-columns:repeat(3,3.33fr)}::ng-deep .drag-element.structure-element.cols_4{grid-template-columns:repeat(4,2.5fr)}::ng-deep .drag-element.structure-element.cols_12{grid-template-columns:6fr 4fr}::ng-deep .drag-element.structure-element.cols_21{grid-template-columns:4fr 6fr}::ng-deep .main-padding{padding:1rem}::ng-deep .cdk-drop-list-receiving>:not(.cdk-drag){opacity:.6}::ng-deep .cdk-drop-list-dragging>*{pointer-events:none}@keyframes drag-animation{0%{opacity:0;height:0}to{opacity:1}}::ng-deep .cdk-drag-animating{animation:drag-animation 1s cubic-bezier(0,0,.2,1) infinite}::ng-deep .cdk-drag-preview{border-radius:4px;box-shadow:0 0 0 2px rgba(63,81,181,.5);min-height:60px;min-width:100px;background-color:#fff}::ng-deep .cdk-drag.structure-element.cdk-drag-placeholder{box-shadow:0 0 1px 2px #ff4081;width:100%;pointer-events:none}"]
2285
+ },] }
2286
+ ];
2287
+ PbEmailBuilderComponent.ctorParameters = () => [
2288
+ { type: PbEmailBuilderService },
2289
+ { type: PbUserRestApiService },
2290
+ { type: PbUserInterfaceService },
2291
+ { type: PbEmailObjectStoreService },
2292
+ { type: Renderer2 },
2293
+ { type: SlugifyPipe },
2294
+ { type: PbUserMiddlewaresService },
2295
+ { type: ChangeDetectorRef },
2296
+ { type: Array, decorators: [{ type: Inject, args: [PB_STRUCTURES,] }] },
2297
+ { type: Array, decorators: [{ type: Inject, args: [PB_BLOCKS,] }] },
2298
+ { type: Array, decorators: [{ type: Inject, args: [PB_GOOGLE_FONTS,] }] },
2299
+ { type: Document, decorators: [{ type: Inject, args: [DOCUMENT,] }] }
2300
+ ];
2301
+ PbEmailBuilderComponent.propDecorators = {
2302
+ email: [{ type: Input }],
2303
+ emailChange: [{ type: Output }]
2304
+ };
2305
+
2306
+ /*
2307
+ * Copyright (c) 2024 Pobuca.
2308
+ * All rights reserved.
2309
+ */
2310
+ // tslint:disable-next-line:no-shadowed-variable directive-class-suffix
2311
+ class AbstractBlock {
2312
+ ngOnInit() {
2313
+ // if (!this.portal) {
2314
+ // throw new Error(`Each element should have an options' portal, add *cdkPortal inside of HTML block.`);
2315
+ // }
2316
+ }
2317
+ }
2318
+ AbstractBlock.decorators = [
2319
+ { type: Directive }
2320
+ ];
2321
+ AbstractBlock.propDecorators = {
2322
+ portal: [{ type: ViewChild, args: [CdkPortal, { static: true },] }]
2323
+ };
2324
+ class AbstractEntityBlock {
2325
+ }
2326
+
2327
+ /*
2328
+ * Copyright (c) 2024 Pobuca.
2329
+ * All rights reserved.
2330
+ */
2331
+ class TextElementComponent extends AbstractBlock {
2332
+ constructor(userRestApi, emailObject, internalService) {
2333
+ super();
2334
+ this.userRestApi = userRestApi;
2335
+ this.emailObject = emailObject;
2336
+ this.internalService = internalService;
2337
+ // @Input() block: TextBlock;
2338
+ this.setAsReadOnly$ = this.internalService.currentEditingBlock$.pipe(map(editingBlock => editingBlock !== this.block));
2339
+ this.staticQuillConfig = {
2340
+ toolbar: {
2341
+ container: [
2342
+ ['bold', 'italic', 'underline', 'strike'],
2343
+ [{ header: [1, 2, 3, 4, 5, 6, false] }, { size: ['small', false, 'large', 'huge'] }],
2344
+ [{ align: [] }, 'link'],
2345
+ [{ list: 'ordered' }, { list: 'bullet' }],
2346
+ [{ color: [] }, { background: [] }],
2347
+ ['clean']
2348
+ ],
2349
+ handlers: {
2350
+ placeholder(selector) {
2351
+ const range = this.quill.getSelection();
2352
+ const format = this.quill.getFormat();
2353
+ const text = this.quill.getText(range.index, range.length);
2354
+ this.quill.deleteText(range.index, text.length);
2355
+ this.quill.insertText(range.index, selector, format);
2356
+ this.quill.setSelection(range.index, selector.length);
2357
+ }
2358
+ }
2359
+ }
2360
+ };
2361
+ this.quillInit$ = this.userRestApi.getAllUserMergeFields$.pipe(map(placeholder => {
2362
+ // @ts-ignore
2363
+ this.staticQuillConfig.toolbar.container.splice(-1, 0, [{ placeholder }]);
2364
+ }), mapTo(true), take(1));
2365
+ this.textChanged$ = new Subject();
2366
+ this.componentDestroyed$ = new Subject();
2367
+ }
2368
+ getTextStyles() {
2369
+ const { color, font, lineHeight, padding } = this.block.options;
2370
+ return Object.assign(Object.assign(Object.assign({ color, 'word-break': 'break-all' }, createLineHeight(lineHeight)), createFont(font)), createPadding(padding));
2371
+ }
2372
+ contentChanged() {
2373
+ this.textChanged$.next();
2374
+ }
2375
+ ngOnInit() {
2376
+ this.textChanged$.pipe(debounceTime(600), takeUntil(this.componentDestroyed$)).subscribe(() => {
2377
+ this.emailObject.markForCheck();
2378
+ });
2379
+ }
2380
+ ngOnDestroy() {
2381
+ this.componentDestroyed$.next();
2382
+ this.componentDestroyed$.complete();
2383
+ }
2384
+ }
2385
+ TextElementComponent.decorators = [
2386
+ { type: Component, args: [{
2387
+ selector: 'pb-text-element',
2388
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<div [ngStyle]=\"getTextStyles()\">\n <quill-editor *ngIf=\"quillInit$ | async; else loadingModules\" i18n-placeholder=\"text-element|placeholder\"\n placeholder=\"Insert text here ...\" [modules]=\"staticQuillConfig\" [readOnly]=\"setAsReadOnly$ |async\"\n [(ngModel)]=\"block.innerText\" (onContentChanged)=\"contentChanged()\">\n </quill-editor>\n</div>\n\n<ng-template #loadingModules>\n <span i18n=\"text-element|loading message\">Please wait ...</span>\n</ng-template>\n",
2389
+ encapsulation: ViewEncapsulation.None,
2390
+ styles: ["@charset \"UTF-8\";\n/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */\n/*!\n * Quill Editor v1.3.7\n * https://quilljs.com/\n * Copyright (c) 2014, Jason Chen\n * Copyright (c) 2013, salesforce.com\n */.ql-container{box-sizing:border-box;font-family:Helvetica,Arial,sans-serif;font-size:13px;height:100%;margin:0;position:relative}.ql-container.ql-disabled .ql-tooltip{visibility:hidden}.ql-container.ql-disabled .ql-editor ul[data-checked]>li:before{pointer-events:none}.ql-clipboard{left:-100000px;height:1px;overflow-y:hidden;position:absolute;top:50%}.ql-clipboard p{margin:0;padding:0}.ql-editor{box-sizing:border-box;line-height:1.42;height:100%;outline:none;overflow-y:auto;padding:12px 15px;-o-tab-size:4;tab-size:4;-moz-tab-size:4;text-align:left;white-space:pre-wrap;word-wrap:break-word}.ql-editor>*{cursor:text}.ql-editor blockquote,.ql-editor h1,.ql-editor h2,.ql-editor h3,.ql-editor h4,.ql-editor h5,.ql-editor h6,.ql-editor ol,.ql-editor p,.ql-editor pre,.ql-editor ul{margin:0;padding:0;counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol,.ql-editor ul{padding-left:1.5em}.ql-editor ol>li,.ql-editor ul>li{list-style-type:none}.ql-editor ul>li:before{content:\"\u2022\"}.ql-editor ul[data-checked=false],.ql-editor ul[data-checked=true]{pointer-events:none}.ql-editor ul[data-checked=false]>li *,.ql-editor ul[data-checked=true]>li *{pointer-events:all}.ql-editor ul[data-checked=false]>li:before,.ql-editor ul[data-checked=true]>li:before{color:#777;cursor:pointer;pointer-events:all}.ql-editor ul[data-checked=true]>li:before{content:\"\u2611\"}.ql-editor ul[data-checked=false]>li:before{content:\"\u2610\"}.ql-editor li:before{display:inline-block;white-space:nowrap;width:1.2em}.ql-editor li:not(.ql-direction-rtl):before{margin-left:-1.5em;margin-right:.3em;text-align:right}.ql-editor li.ql-direction-rtl:before{margin-left:.3em;margin-right:-1.5em}.ql-editor ol li:not(.ql-direction-rtl),.ql-editor ul li:not(.ql-direction-rtl){padding-left:1.5em}.ql-editor ol li.ql-direction-rtl,.ql-editor ul li.ql-direction-rtl{padding-right:1.5em}.ql-editor ol li{counter-reset:list-1 list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9;counter-increment:list-0}.ql-editor ol li:before{content:counter(list-0,decimal) \". \"}.ql-editor ol li.ql-indent-1{counter-increment:list-1}.ql-editor ol li.ql-indent-1:before{content:counter(list-1,lower-alpha) \". \"}.ql-editor ol li.ql-indent-1{counter-reset:list-2 list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-2{counter-increment:list-2}.ql-editor ol li.ql-indent-2:before{content:counter(list-2,lower-roman) \". \"}.ql-editor ol li.ql-indent-2{counter-reset:list-3 list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-3{counter-increment:list-3}.ql-editor ol li.ql-indent-3:before{content:counter(list-3,decimal) \". \"}.ql-editor ol li.ql-indent-3{counter-reset:list-4 list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-4{counter-increment:list-4}.ql-editor ol li.ql-indent-4:before{content:counter(list-4,lower-alpha) \". \"}.ql-editor ol li.ql-indent-4{counter-reset:list-5 list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-5{counter-increment:list-5}.ql-editor ol li.ql-indent-5:before{content:counter(list-5,lower-roman) \". \"}.ql-editor ol li.ql-indent-5{counter-reset:list-6 list-7 list-8 list-9}.ql-editor ol li.ql-indent-6{counter-increment:list-6}.ql-editor ol li.ql-indent-6:before{content:counter(list-6,decimal) \". \"}.ql-editor ol li.ql-indent-6{counter-reset:list-7 list-8 list-9}.ql-editor ol li.ql-indent-7{counter-increment:list-7}.ql-editor ol li.ql-indent-7:before{content:counter(list-7,lower-alpha) \". \"}.ql-editor ol li.ql-indent-7{counter-reset:list-8 list-9}.ql-editor ol li.ql-indent-8{counter-increment:list-8}.ql-editor ol li.ql-indent-8:before{content:counter(list-8,lower-roman) \". \"}.ql-editor ol li.ql-indent-8{counter-reset:list-9}.ql-editor ol li.ql-indent-9{counter-increment:list-9}.ql-editor ol li.ql-indent-9:before{content:counter(list-9,decimal) \". \"}.ql-editor .ql-indent-1:not(.ql-direction-rtl){padding-left:3em}.ql-editor li.ql-indent-1:not(.ql-direction-rtl){padding-left:4.5em}.ql-editor .ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:3em}.ql-editor li.ql-indent-1.ql-direction-rtl.ql-align-right{padding-right:4.5em}.ql-editor .ql-indent-2:not(.ql-direction-rtl){padding-left:6em}.ql-editor li.ql-indent-2:not(.ql-direction-rtl){padding-left:7.5em}.ql-editor .ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:6em}.ql-editor li.ql-indent-2.ql-direction-rtl.ql-align-right{padding-right:7.5em}.ql-editor .ql-indent-3:not(.ql-direction-rtl){padding-left:9em}.ql-editor li.ql-indent-3:not(.ql-direction-rtl){padding-left:10.5em}.ql-editor .ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:9em}.ql-editor li.ql-indent-3.ql-direction-rtl.ql-align-right{padding-right:10.5em}.ql-editor .ql-indent-4:not(.ql-direction-rtl){padding-left:12em}.ql-editor li.ql-indent-4:not(.ql-direction-rtl){padding-left:13.5em}.ql-editor .ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:12em}.ql-editor li.ql-indent-4.ql-direction-rtl.ql-align-right{padding-right:13.5em}.ql-editor .ql-indent-5:not(.ql-direction-rtl){padding-left:15em}.ql-editor li.ql-indent-5:not(.ql-direction-rtl){padding-left:16.5em}.ql-editor .ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:15em}.ql-editor li.ql-indent-5.ql-direction-rtl.ql-align-right{padding-right:16.5em}.ql-editor .ql-indent-6:not(.ql-direction-rtl){padding-left:18em}.ql-editor li.ql-indent-6:not(.ql-direction-rtl){padding-left:19.5em}.ql-editor .ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:18em}.ql-editor li.ql-indent-6.ql-direction-rtl.ql-align-right{padding-right:19.5em}.ql-editor .ql-indent-7:not(.ql-direction-rtl){padding-left:21em}.ql-editor li.ql-indent-7:not(.ql-direction-rtl){padding-left:22.5em}.ql-editor .ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:21em}.ql-editor li.ql-indent-7.ql-direction-rtl.ql-align-right{padding-right:22.5em}.ql-editor .ql-indent-8:not(.ql-direction-rtl){padding-left:24em}.ql-editor li.ql-indent-8:not(.ql-direction-rtl){padding-left:25.5em}.ql-editor .ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:24em}.ql-editor li.ql-indent-8.ql-direction-rtl.ql-align-right{padding-right:25.5em}.ql-editor .ql-indent-9:not(.ql-direction-rtl){padding-left:27em}.ql-editor li.ql-indent-9:not(.ql-direction-rtl){padding-left:28.5em}.ql-editor .ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:27em}.ql-editor li.ql-indent-9.ql-direction-rtl.ql-align-right{padding-right:28.5em}.ql-editor .ql-video{display:block;max-width:100%}.ql-editor .ql-video.ql-align-center{margin:0 auto}.ql-editor .ql-video.ql-align-right{margin:0 0 0 auto}.ql-editor .ql-bg-black{background-color:#000}.ql-editor .ql-bg-red{background-color:#e60000}.ql-editor .ql-bg-orange{background-color:#f90}.ql-editor .ql-bg-yellow{background-color:#ff0}.ql-editor .ql-bg-green{background-color:#008a00}.ql-editor .ql-bg-blue{background-color:#06c}.ql-editor .ql-bg-purple{background-color:#93f}.ql-editor .ql-color-white{color:#fff}.ql-editor .ql-color-red{color:#e60000}.ql-editor .ql-color-orange{color:#f90}.ql-editor .ql-color-yellow{color:#ff0}.ql-editor .ql-color-green{color:#008a00}.ql-editor .ql-color-blue{color:#06c}.ql-editor .ql-color-purple{color:#93f}.ql-editor .ql-font-serif{font-family:Georgia,Times New Roman,serif}.ql-editor .ql-font-monospace{font-family:Monaco,Courier New,monospace}.ql-editor .ql-size-small{font-size:.75em}.ql-editor .ql-size-large{font-size:1.5em}.ql-editor .ql-size-huge{font-size:2.5em}.ql-editor .ql-direction-rtl{direction:rtl;text-align:inherit}.ql-editor .ql-align-center{text-align:center}.ql-editor .ql-align-justify{text-align:justify}.ql-editor .ql-align-right{text-align:right}.ql-editor.ql-blank:before{color:rgba(0,0,0,.6);content:attr(data-placeholder);font-style:italic;left:15px;pointer-events:none;position:absolute;right:15px}.ql-bubble.ql-toolbar:after,.ql-bubble .ql-toolbar:after{clear:both;content:\"\";display:table}.ql-bubble.ql-toolbar button,.ql-bubble .ql-toolbar button{background:none;border:none;cursor:pointer;display:inline-block;float:left;height:24px;padding:3px 5px;width:28px}.ql-bubble.ql-toolbar button svg,.ql-bubble .ql-toolbar button svg{float:left;height:100%}.ql-bubble.ql-toolbar button:active:hover,.ql-bubble .ql-toolbar button:active:hover{outline:none}.ql-bubble.ql-toolbar input.ql-image[type=file],.ql-bubble .ql-toolbar input.ql-image[type=file]{display:none}.ql-bubble.ql-toolbar .ql-picker-item.ql-selected,.ql-bubble .ql-toolbar .ql-picker-item.ql-selected,.ql-bubble.ql-toolbar .ql-picker-item:hover,.ql-bubble .ql-toolbar .ql-picker-item:hover,.ql-bubble.ql-toolbar .ql-picker-label.ql-active,.ql-bubble .ql-toolbar .ql-picker-label.ql-active,.ql-bubble.ql-toolbar .ql-picker-label:hover,.ql-bubble .ql-toolbar .ql-picker-label:hover,.ql-bubble.ql-toolbar button.ql-active,.ql-bubble .ql-toolbar button.ql-active,.ql-bubble.ql-toolbar button:focus,.ql-bubble .ql-toolbar button:focus,.ql-bubble.ql-toolbar button:hover,.ql-bubble .ql-toolbar button:hover{color:#fff}.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-fill,.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke.ql-fill,.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-fill,.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-fill,.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke.ql-fill,.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-fill,.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke.ql-fill,.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-fill,.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-fill,.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke.ql-fill,.ql-bubble.ql-toolbar button.ql-active .ql-fill,.ql-bubble .ql-toolbar button.ql-active .ql-fill,.ql-bubble.ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-bubble .ql-toolbar button.ql-active .ql-stroke.ql-fill,.ql-bubble.ql-toolbar button:focus .ql-fill,.ql-bubble .ql-toolbar button:focus .ql-fill,.ql-bubble.ql-toolbar button:focus .ql-stroke.ql-fill,.ql-bubble .ql-toolbar button:focus .ql-stroke.ql-fill,.ql-bubble.ql-toolbar button:hover .ql-fill,.ql-bubble .ql-toolbar button:hover .ql-fill,.ql-bubble.ql-toolbar button:hover .ql-stroke.ql-fill,.ql-bubble .ql-toolbar button:hover .ql-stroke.ql-fill{fill:#fff}.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke,.ql-bubble.ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-bubble .ql-toolbar .ql-picker-item.ql-selected .ql-stroke-miter,.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke,.ql-bubble.ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-bubble .ql-toolbar .ql-picker-item:hover .ql-stroke-miter,.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke,.ql-bubble.ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-bubble .ql-toolbar .ql-picker-label.ql-active .ql-stroke-miter,.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke,.ql-bubble.ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-bubble .ql-toolbar .ql-picker-label:hover .ql-stroke-miter,.ql-bubble.ql-toolbar button.ql-active .ql-stroke,.ql-bubble .ql-toolbar button.ql-active .ql-stroke,.ql-bubble.ql-toolbar button.ql-active .ql-stroke-miter,.ql-bubble .ql-toolbar button.ql-active .ql-stroke-miter,.ql-bubble.ql-toolbar button:focus .ql-stroke,.ql-bubble .ql-toolbar button:focus .ql-stroke,.ql-bubble.ql-toolbar button:focus .ql-stroke-miter,.ql-bubble .ql-toolbar button:focus .ql-stroke-miter,.ql-bubble.ql-toolbar button:hover .ql-stroke,.ql-bubble .ql-toolbar button:hover .ql-stroke,.ql-bubble.ql-toolbar button:hover .ql-stroke-miter,.ql-bubble .ql-toolbar button:hover .ql-stroke-miter{stroke:#fff}@media (pointer:coarse){.ql-bubble.ql-toolbar button:hover:not(.ql-active),.ql-bubble .ql-toolbar button:hover:not(.ql-active){color:#ccc}.ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-fill,.ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill,.ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke.ql-fill{fill:#ccc}.ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke,.ql-bubble.ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter,.ql-bubble .ql-toolbar button:hover:not(.ql-active) .ql-stroke-miter{stroke:#ccc}}.ql-bubble,.ql-bubble *{box-sizing:border-box}.ql-bubble .ql-hidden{display:none}.ql-bubble .ql-out-bottom,.ql-bubble .ql-out-top{visibility:hidden}.ql-bubble .ql-tooltip{position:absolute;transform:translateY(10px)}.ql-bubble .ql-tooltip a{cursor:pointer;text-decoration:none}.ql-bubble .ql-tooltip.ql-flip{transform:translateY(-10px)}.ql-bubble .ql-formats{display:inline-block;vertical-align:middle}.ql-bubble .ql-formats:after{clear:both;content:\"\";display:table}.ql-bubble .ql-stroke{fill:none;stroke:#ccc;stroke-linecap:round;stroke-linejoin:round;stroke-width:2}.ql-bubble .ql-stroke-miter{fill:none;stroke:#ccc;stroke-miterlimit:10;stroke-width:2}.ql-bubble .ql-fill,.ql-bubble .ql-stroke.ql-fill{fill:#ccc}.ql-bubble .ql-empty{fill:none}.ql-bubble .ql-even{fill-rule:evenodd}.ql-bubble .ql-stroke.ql-thin,.ql-bubble .ql-thin{stroke-width:1}.ql-bubble .ql-transparent{opacity:.4}.ql-bubble .ql-direction svg:last-child{display:none}.ql-bubble .ql-direction.ql-active svg:last-child{display:inline}.ql-bubble .ql-direction.ql-active svg:first-child{display:none}.ql-bubble .ql-editor h1{font-size:2em}.ql-bubble .ql-editor h2{font-size:1.5em}.ql-bubble .ql-editor h3{font-size:1.17em}.ql-bubble .ql-editor h4{font-size:1em}.ql-bubble .ql-editor h5{font-size:.83em}.ql-bubble .ql-editor h6{font-size:.67em}.ql-bubble .ql-editor a{text-decoration:underline}.ql-bubble .ql-editor blockquote{border-left:4px solid #ccc;margin-bottom:5px;margin-top:5px;padding-left:16px}.ql-bubble .ql-editor code,.ql-bubble .ql-editor pre{background-color:#f0f0f0;border-radius:3px}.ql-bubble .ql-editor pre{white-space:pre-wrap;margin-bottom:5px;margin-top:5px;padding:5px 10px}.ql-bubble .ql-editor code{font-size:85%;padding:2px 4px}.ql-bubble .ql-editor pre.ql-syntax{background-color:#23241f;color:#f8f8f2;overflow:visible}.ql-bubble .ql-editor img{max-width:100%}.ql-bubble .ql-picker{color:#ccc;display:inline-block;float:left;font-size:14px;font-weight:500;height:24px;position:relative;vertical-align:middle}.ql-bubble .ql-picker-label{cursor:pointer;display:inline-block;height:100%;padding-left:8px;padding-right:2px;position:relative;width:100%}.ql-bubble .ql-picker-label:before{display:inline-block;line-height:22px}.ql-bubble .ql-picker-options{background-color:#444;display:none;min-width:100%;padding:4px 8px;position:absolute;white-space:nowrap}.ql-bubble .ql-picker-options .ql-picker-item{cursor:pointer;display:block;padding-bottom:5px;padding-top:5px}.ql-bubble .ql-picker.ql-expanded .ql-picker-label{color:#777;z-index:2}.ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-fill{fill:#777}.ql-bubble .ql-picker.ql-expanded .ql-picker-label .ql-stroke{stroke:#777}.ql-bubble .ql-picker.ql-expanded .ql-picker-options{display:block;margin-top:-1px;top:100%;z-index:1}.ql-bubble .ql-color-picker,.ql-bubble .ql-icon-picker{width:28px}.ql-bubble .ql-color-picker .ql-picker-label,.ql-bubble .ql-icon-picker .ql-picker-label{padding:2px 4px}.ql-bubble .ql-color-picker .ql-picker-label svg,.ql-bubble .ql-icon-picker .ql-picker-label svg{right:4px}.ql-bubble .ql-icon-picker .ql-picker-options{padding:4px 0}.ql-bubble .ql-icon-picker .ql-picker-item{height:24px;width:24px;padding:2px 4px}.ql-bubble .ql-color-picker .ql-picker-options{padding:3px 5px;width:152px}.ql-bubble .ql-color-picker .ql-picker-item{border:1px solid transparent;float:left;height:16px;margin:2px;padding:0;width:16px}.ql-bubble .ql-picker:not(.ql-color-picker):not(.ql-icon-picker) svg{position:absolute;margin-top:-9px;right:0;top:50%;width:18px}.ql-bubble .ql-picker.ql-font .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-bubble .ql-picker.ql-font .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-bubble .ql-picker.ql-header .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-label]:not([data-label=\"\"]):before,.ql-bubble .ql-picker.ql-size .ql-picker-item[data-label]:not([data-label=\"\"]):before,.ql-bubble .ql-picker.ql-size .ql-picker-label[data-label]:not([data-label=\"\"]):before{content:attr(data-label)}.ql-bubble .ql-picker.ql-header{width:98px}.ql-bubble .ql-picker.ql-header .ql-picker-item:before,.ql-bubble .ql-picker.ql-header .ql-picker-label:before{content:\"Normal\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value=\"1\"]:before{content:\"Heading 1\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value=\"2\"]:before{content:\"Heading 2\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value=\"3\"]:before{content:\"Heading 3\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value=\"4\"]:before{content:\"Heading 4\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value=\"5\"]:before{content:\"Heading 5\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before,.ql-bubble .ql-picker.ql-header .ql-picker-label[data-value=\"6\"]:before{content:\"Heading 6\"}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"1\"]:before{font-size:2em}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"2\"]:before{font-size:1.5em}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"3\"]:before{font-size:1.17em}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"4\"]:before{font-size:1em}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"5\"]:before{font-size:.83em}.ql-bubble .ql-picker.ql-header .ql-picker-item[data-value=\"6\"]:before{font-size:.67em}.ql-bubble .ql-picker.ql-font{width:108px}.ql-bubble .ql-picker.ql-font .ql-picker-item:before,.ql-bubble .ql-picker.ql-font .ql-picker-label:before{content:\"Sans Serif\"}.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]:before,.ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=serif]:before{content:\"Serif\"}.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before,.ql-bubble .ql-picker.ql-font .ql-picker-label[data-value=monospace]:before{content:\"Monospace\"}.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=serif]:before{font-family:Georgia,Times New Roman,serif}.ql-bubble .ql-picker.ql-font .ql-picker-item[data-value=monospace]:before{font-family:Monaco,Courier New,monospace}.ql-bubble .ql-picker.ql-size{width:98px}.ql-bubble .ql-picker.ql-size .ql-picker-item:before,.ql-bubble .ql-picker.ql-size .ql-picker-label:before{content:\"Normal\"}.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]:before,.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=small]:before{content:\"Small\"}.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]:before,.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=large]:before{content:\"Large\"}.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]:before,.ql-bubble .ql-picker.ql-size .ql-picker-label[data-value=huge]:before{content:\"Huge\"}.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=small]:before{font-size:10px}.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=large]:before{font-size:18px}.ql-bubble .ql-picker.ql-size .ql-picker-item[data-value=huge]:before{font-size:32px}.ql-bubble .ql-color-picker.ql-background .ql-picker-item{background-color:#fff}.ql-bubble .ql-color-picker.ql-color .ql-picker-item{background-color:#000}.ql-bubble .ql-toolbar .ql-formats{margin:8px 12px 8px 0}.ql-bubble .ql-toolbar .ql-formats:first-child{margin-left:12px}.ql-bubble .ql-color-picker svg{margin:1px}.ql-bubble .ql-color-picker .ql-picker-item.ql-selected,.ql-bubble .ql-color-picker .ql-picker-item:hover{border-color:#fff}.ql-bubble .ql-tooltip{background-color:#444;border-radius:25px;color:#fff}.ql-bubble .ql-tooltip-arrow{border-left:6px solid transparent;border-right:6px solid transparent;content:\" \";display:block;left:50%;margin-left:-6px;position:absolute}.ql-bubble .ql-tooltip:not(.ql-flip) .ql-tooltip-arrow{border-bottom:6px solid #444;top:-6px}.ql-bubble .ql-tooltip.ql-flip .ql-tooltip-arrow{border-top:6px solid #444;bottom:-6px}.ql-bubble .ql-tooltip.ql-editing .ql-tooltip-editor{display:block}.ql-bubble .ql-tooltip.ql-editing .ql-formats{visibility:hidden}.ql-bubble .ql-tooltip-editor{display:none}.ql-bubble .ql-tooltip-editor input[type=text]{background:transparent;border:none;color:#fff;font-size:13px;height:100%;outline:none;padding:10px 20px;position:absolute;width:100%}.ql-bubble .ql-tooltip-editor a{top:10px;position:absolute;right:20px}.ql-bubble .ql-tooltip-editor a:before{color:#ccc;content:\"\u00D7\";font-size:16px;font-weight:700}.ql-container.ql-bubble:not(.ql-disabled) a{position:relative;white-space:nowrap}.ql-container.ql-bubble:not(.ql-disabled) a:before{background-color:#444;border-radius:15px;top:-5px;font-size:12px;color:#fff;content:attr(href);font-weight:400;overflow:hidden;padding:5px 15px;text-decoration:none;z-index:1}.ql-container.ql-bubble:not(.ql-disabled) a:after{border-top:6px solid #444;border-left:6px solid transparent;border-right:6px solid transparent;top:0;content:\" \";height:0;width:0}.ql-container.ql-bubble:not(.ql-disabled) a:after,.ql-container.ql-bubble:not(.ql-disabled) a:before{left:0;margin-left:50%;position:absolute;transform:translate(-50%,-100%);transition:visibility 0s ease .2s;visibility:hidden}.ql-container.ql-bubble:not(.ql-disabled) a:hover:after,.ql-container.ql-bubble:not(.ql-disabled) a:hover:before{visibility:visible}quill-editor{display:block;word-break:break-word}quill-editor .ql-container{font-family:inherit;font-size:inherit}quill-editor .ql-container .ql-editor{padding:0!important;line-height:inherit;font:inherit;overflow:visible}quill-editor .ql-placeholder .ql-picker-label:before{display:block;content:\"Tags\";min-width:50px}quill-editor .ql-placeholder.ql-expanded .ql-picker-item:before{content:attr(data-value);width:-moz-min-content;width:min-content}quill-editor .ql-tooltip{z-index:10;line-height:normal}quill-editor .ql-tooltip .ql-picker-options{max-height:300px;overflow:auto}quill-editor .ql-toolbar{width:600px;width:-moz-max-content;width:max-content}quill-editor h1,quill-editor h2,quill-editor h3,quill-editor h4,quill-editor h5,quill-editor h6{font-weight:inherit;line-height:inherit}"]
2391
+ },] }
2392
+ ];
2393
+ TextElementComponent.ctorParameters = () => [
2394
+ { type: PbUserRestApiService },
2395
+ { type: PbEmailObjectStoreService },
2396
+ { type: PbUserInterfaceService }
2397
+ ];
2398
+
2399
+ /*
2400
+ * Copyright (c) 2024 Pobuca.
2401
+ * All rights reserved.
2402
+ */
2403
+ class ImageComponent extends AbstractBlock {
2404
+ constructor(imageUploader, chRef, ngb) {
2405
+ super();
2406
+ this.imageUploader = imageUploader;
2407
+ this.chRef = chRef;
2408
+ this.ngb = ngb;
2409
+ }
2410
+ // @Input() block = new ImageBlock();
2411
+ get align() {
2412
+ return this.block.options.align;
2413
+ }
2414
+ get src() {
2415
+ return this.block.src || 'https://via.placeholder.com/600x200?text=CHANGE+ME';
2416
+ }
2417
+ uploadImage() {
2418
+ return __awaiter(this, void 0, void 0, function* () {
2419
+ const src = yield this.imageUploader.browse$().toPromise();
2420
+ if (src) {
2421
+ this.block.src = src;
2422
+ this.chRef.markForCheck();
2423
+ }
2424
+ });
2425
+ }
2426
+ getImageStyles() {
2427
+ const { border, width, height, padding } = this.block.options;
2428
+ return Object.assign(Object.assign({ width: createWidthHeight(width), height: createWidthHeight(height) }, createPadding(padding)), createBorder(border));
2429
+ }
2430
+ }
2431
+ ImageComponent.decorators = [
2432
+ { type: Component, args: [{
2433
+ selector: 'pb-image',
2434
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<!-- <div\n class=\"overflow\"\n *ngIf=\"(ngb.currentEditingBlock$ | async) !== block\"\n (click)=\"uploadImage()\"\n>\n <mat-icon inline>cloud_upload</mat-icon>\n</div> -->\n<img [src]=\"src\" [title]=\"block.options.title\" [ngStyle]=\"getImageStyles()\" />\n",
2435
+ styles: [":host{display:block;line-height:0}:host:hover .overflow{opacity:1}.overflow{position:absolute;top:0;right:0;bottom:0;left:0;background-color:rgba(0,0,0,.3);opacity:0;will-change:opacity;transition:opacity .3s cubic-bezier(.075,.82,.165,1);cursor:pointer;color:#fff;display:flex;align-items:center;justify-content:center;font-size:3em}.overflow mat-icon{opacity:.8}img{max-width:100%;box-sizing:border-box}"]
2436
+ },] }
2437
+ ];
2438
+ ImageComponent.ctorParameters = () => [
2439
+ { type: PbUserImageUploaderService },
2440
+ { type: ChangeDetectorRef },
2441
+ { type: PbEmailBuilderService }
2442
+ ];
2443
+ ImageComponent.propDecorators = {
2444
+ align: [{ type: HostBinding, args: ['style.textAlign',] }]
2445
+ };
2446
+
2447
+ /*
2448
+ * Copyright (c) 2024 Pobuca.
2449
+ * All rights reserved.
2450
+ */
2451
+ class ButtonComponent extends AbstractBlock {
2452
+ // @Input() block: ButtonBlock;
2453
+ getButtonStyles() {
2454
+ const { backgroundColor, border, color, font, lineHeight, innerPadding, fullWidth } = this.block.options;
2455
+ return Object.assign(Object.assign(Object.assign(Object.assign({ color, width: fullWidth ? '100%' : 'auto', backgroundColor }, createFont(font)), createPadding(innerPadding)), createBorder(border)), createLineHeight(lineHeight));
2456
+ }
2457
+ getParentStyles() {
2458
+ const { align, padding } = this.block.options;
2459
+ return Object.assign({ justifyContent: (align === 'center' && 'center') ||
2460
+ (align === 'right' && 'flex-end') ||
2461
+ 'flex-start' }, createPadding(padding));
2462
+ }
2463
+ }
2464
+ ButtonComponent.decorators = [
2465
+ { type: Component, args: [{
2466
+ selector: 'pb-button',
2467
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<div fxLayout [ngStyle]=\"getParentStyles()\">\n <button type=\"button\" [class.full-width]=\"block.options.fullWidth\" [ngStyle]=\"getButtonStyles()\">\n {{ block.innerText }}\n </button>\n</div>\n",
2468
+ encapsulation: ViewEncapsulation.Emulated,
2469
+ styles: ["button{transition:all .5s cubic-bezier(.445,.05,.55,.95)}"]
2470
+ },] }
2471
+ ];
2472
+
2473
+ /*
2474
+ * Copyright (c) 2024 Pobuca.
2475
+ * All rights reserved.
2476
+ */
2477
+ class DividerComponent extends AbstractBlock {
2478
+ // @Input()
2479
+ // block: DividerBlock = new DividerBlock();
2480
+ getDividerStyles() {
2481
+ const { border, padding } = this.block.options;
2482
+ return Object.assign(Object.assign({}, createBorder(border, 'borderTop')), createPadding(padding, 'margin'));
2483
+ }
2484
+ ngOnInit() {
2485
+ }
2486
+ }
2487
+ DividerComponent.decorators = [
2488
+ { type: Component, args: [{
2489
+ selector: 'pb-divider',
2490
+ template: '<div [ngStyle]="getDividerStyles()"></div>',
2491
+ styles: [`
2492
+ :host {
2493
+ display: table;
2494
+ width: 100%;
2495
+ }
2496
+ `]
2497
+ },] }
2498
+ ];
2499
+
2500
+ /*
2501
+ * Copyright (c) 2024 Pobuca.
2502
+ * All rights reserved.
2503
+ */
2504
+ class SpacerComponent extends AbstractBlock {
2505
+ // @Input() block: SpacerBlock = new SpacerBlock();
2506
+ get height() {
2507
+ return createWidthHeight(this.block.options.height);
2508
+ }
2509
+ }
2510
+ SpacerComponent.decorators = [
2511
+ { type: Component, args: [{
2512
+ selector: 'pb-spacer',
2513
+ template: '',
2514
+ styles: [`
2515
+ :host {
2516
+ display: table;
2517
+ width: 100%;
2518
+ transition: all 500ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
2519
+ }
2520
+ `]
2521
+ },] }
2522
+ ];
2523
+ SpacerComponent.propDecorators = {
2524
+ height: [{ type: HostBinding, args: ['style.height',] }]
2525
+ };
2526
+
2527
+ /*
2528
+ * Copyright (c) 2024 Pobuca.
2529
+ * All rights reserved.
2530
+ */
2531
+ class SocialComponent extends AbstractBlock {
2532
+ // @Input()
2533
+ // block: SocialBlock;
2534
+ getParentStyles() {
2535
+ const { color, font, lineHeight, padding } = this.block.options;
2536
+ return Object.assign(Object.assign(Object.assign({ color }, createLineHeight(lineHeight)), createFont(font)), createPadding(padding));
2537
+ }
2538
+ getLabelStyles() {
2539
+ const { innerPadding } = this.block.options;
2540
+ return Object.assign(Object.assign({}, createPadding(innerPadding)), { lineHeight: 0 });
2541
+ }
2542
+ getSocialListStyles() {
2543
+ const { align } = this.block.options;
2544
+ return {
2545
+ display: 'flex',
2546
+ placeContent: (align === 'left' && 'flex-start') ||
2547
+ (align === 'right' && 'flex-end') ||
2548
+ align
2549
+ };
2550
+ }
2551
+ getSocialListClasses() {
2552
+ return `social-list ${this.block.options.mode}`;
2553
+ }
2554
+ getSocialNetworkIcon(network) {
2555
+ return getAssetByPath(`${network}.png`);
2556
+ }
2557
+ }
2558
+ SocialComponent.decorators = [
2559
+ { type: Component, args: [{
2560
+ selector: 'pb-social',
2561
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<div fxLayout [ngStyle]=\"getParentStyles()\">\n <div [class]=\"getSocialListClasses()\" [ngStyle]=\"getSocialListStyles()\">\n <ng-container *ngIf=\"block.networks.length; else noSocialNetworks\">\n <div class=\"social-list-item\" *ngFor=\"let network of block.networks\">\n <div [ngStyle]=\"getLabelStyles()\">\n <img [src]=\"getSocialNetworkIcon(network.name)\" [width]=\"block.options.iconSize.value\"\n [height]=\"block.options.iconSize.value\" [classList]=\"network.name\" [alt]=\"network.name\" />\n </div>\n <span *ngIf=\"network.label\">{{ network.label }}</span>\n </div>\n </ng-container>\n </div>\n</div>\n\n<ng-template #noSocialNetworks>\n <p i18n=\"social block|Empty social list message\">Please add some social networks.</p>\n</ng-template>\n",
2562
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */:host{display:block}p{margin:0}.social-list{display:flex;width:100%;flex-wrap:wrap}.social-list.horizontal{flex-direction:row}.social-list.vertical{flex-direction:column}.social-list-item{display:flex;flex-direction:row;align-items:center}.social-list-item img{border-radius:3px}.social-list-item img.facebook{background-color:#3a5898}.social-list-item img.twitter{background-color:#d95988}.social-list-item img.github{background-color:#000}.social-list-item img.instagram{background-color:#3f729b}.social-list-item img.web{background-color:#4bade9}.social-list-item img.snapchat{background-color:#fffa54}.social-list-item img.youtube{background-color:#ea3323}.social-list-item img.vimeo{background-color:#53b4e7}.social-list-item img.medium{background-color:#000}.social-list-item img.soundcloud{background-color:#ef7f31}.social-list-item img.dribbble{background-color:#d95988}.social-list-item img.pinterest{background-color:#bd071c}.social-list-item img.linkedin{background-color:#0077b5}.social-list-item img.tumblr{background-color:#334356}.social-list-item img.xing{background-color:#296365}.social-list-item img.tiktok{background-color:#000}"]
2563
+ },] }
2564
+ ];
2565
+
2566
+ /*
2567
+ * Copyright (c) 2024 Pobuca.
2568
+ * All rights reserved.
2569
+ */
2570
+ const cStore = new Map();
2571
+ /**
2572
+ * @internal
2573
+ *
2574
+ * Soon it must be optimized, and load all components lazily.
2575
+ */
2576
+ class DynamicComponentDirective {
2577
+ constructor(cResolver, viewContainerRef) {
2578
+ this.cResolver = cResolver;
2579
+ this.viewContainerRef = viewContainerRef;
2580
+ cStore.set('text', TextElementComponent);
2581
+ cStore.set('image', ImageComponent);
2582
+ cStore.set('button', ButtonComponent);
2583
+ cStore.set('divider', DividerComponent);
2584
+ cStore.set('spacer', SpacerComponent);
2585
+ cStore.set('social', SocialComponent);
2586
+ }
2587
+ set pbDynamicComponent(block) {
2588
+ const component = this.cResolver.resolveComponentFactory(cStore.get(block.type));
2589
+ this.viewContainerRef.createComponent(component).instance.block = block;
2590
+ }
2591
+ }
2592
+ DynamicComponentDirective.decorators = [
2593
+ { type: Directive, args: [{
2594
+ selector: '[pbDynamicComponent]'
2595
+ },] }
2596
+ ];
2597
+ DynamicComponentDirective.ctorParameters = () => [
2598
+ { type: ComponentFactoryResolver },
2599
+ { type: ViewContainerRef }
2600
+ ];
2601
+ DynamicComponentDirective.propDecorators = {
2602
+ pbDynamicComponent: [{ type: Input }]
2603
+ };
2604
+
2605
+ /*
2606
+ * Copyright (c) 2024 Pobuca.
2607
+ * All rights reserved.
2608
+ */
2609
+ // import { IpUserRestApiProvider } from '../providers';
2610
+ class BuilderContainerComponent {
2611
+ constructor(userInterfaceService, emailObjectStore, userRestApi, pbStorage, pbMiddlewaresService, sanitizer, userConfig) {
2612
+ var _a;
2613
+ this.userInterfaceService = userInterfaceService;
2614
+ this.emailObjectStore = emailObjectStore;
2615
+ this.userRestApi = userRestApi;
2616
+ this.pbStorage = pbStorage;
2617
+ this.pbMiddlewaresService = pbMiddlewaresService;
2618
+ this.sanitizer = sanitizer;
2619
+ this.userConfig = userConfig;
2620
+ this.showTemplateList = (_a = this.userConfig.templateListIfEmpty) !== null && _a !== void 0 ? _a : true;
2621
+ this.getStructures$ = this.emailObjectStore.emailStructuresAsObservable$;
2622
+ this.activeMatProgress$ = this.userInterfaceService.activeMatProgress$;
2623
+ }
2624
+ onHostClick() {
2625
+ this.userInterfaceService.editGeneralSettings();
2626
+ }
2627
+ trackBy(structure) {
2628
+ return structure.id;
2629
+ }
2630
+ disableStructureDrag$(structure) {
2631
+ return this.pbMiddlewaresService.disableStructureDragWithinEmailBody(structure).pipe(take(1));
2632
+ }
2633
+ openTemplateDialog(ev) {
2634
+ ev.stopImmediatePropagation();
2635
+ this.userInterfaceService.activeMatProgress$.next(true);
2636
+ const cachedTemplates = this.pbStorage.getCachedTemplateList();
2637
+ return iif(() => cachedTemplates.length > 0, deferOf(cachedTemplates), this.userRestApi.getAllUserTemplates$.pipe(tap(list => this.pbStorage.cacheTemplateList(list))))
2638
+ .pipe(
2639
+ // map(() => []),
2640
+ map(templates => {
2641
+ return [...templates, { category: 'latest', templates: this.pbStorage.getLatestUsedTemplates() }];
2642
+ }), finalize(() => this.userInterfaceService.activeMatProgress$.next(false)), exhaustMap(list => (list === null || list === void 0 ? void 0 : list.length) > 0 ? this.userInterfaceService.templatesListDialog$(list) : throwError(new Error('The template list is empty'))), switchMap(({ category, template }) => this.pbMiddlewaresService.chooseTemplate(category, template)), exhaustMap(({ category, template }) => this.userRestApi.getUserTemplateData$(category, template).pipe(tap(choosedTemplate => {
2643
+ if (category !== 'latest') {
2644
+ this.pbStorage.addTemplateToLatestUsed(choosedTemplate);
2645
+ }
2646
+ }))), catchError((error) => this.pbMiddlewaresService.catchError(error).pipe(switchMap(() => {
2647
+ this.userInterfaceService.notify(error.message);
2648
+ return EMPTY;
2649
+ }))), take(1))
2650
+ .subscribe((result) => {
2651
+ if (result) {
2652
+ this.emailObjectStore.setEmail(new PBEmail(result.templateData));
2653
+ }
2654
+ else {
2655
+ this.userInterfaceService.notify('No template was chosen');
2656
+ }
2657
+ });
2658
+ }
2659
+ dropNewStructure(event) {
2660
+ if (event.previousContainer === event.container) {
2661
+ this.emailObjectStore.changeStructureOrder(event);
2662
+ }
2663
+ else {
2664
+ this.pbMiddlewaresService
2665
+ .addStructure(event)
2666
+ .pipe(tap(newEvent => this.emailObjectStore.addStructure(newEvent)), take(1))
2667
+ .subscribe();
2668
+ }
2669
+ }
2670
+ getStructureStyles(structure) {
2671
+ const { border, background, padding, margin, columnsWidth, fullWidth } = structure.options;
2672
+ return Object.assign(Object.assign(Object.assign({
2673
+ // direction,
2674
+ width: fullWidth ? '100%' : `${this.emailObjectStore.Email.general.width.value}px`, backgroundRepeat: background.repeat, backgroundColor: background.color, backgroundSize: createWidthHeight(background.size), backgroundPosition: 'top center', gridTemplateColumns: columnsWidth.map(fr => `${fr}fr`).join(' ') }, createBorder(border)), createPadding(padding)), createMargin(margin));
2675
+ }
2676
+ getBackgroundImage(structure) {
2677
+ const { background: { url } } = structure.options;
2678
+ return this.sanitizer.bypassSecurityTrustStyle(url && `url(${url})`);
2679
+ }
2680
+ }
2681
+ BuilderContainerComponent.decorators = [
2682
+ { type: Component, args: [{
2683
+ selector: 'pb-builder-container',
2684
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<ng-container *ngIf=\"getStructures$ | async as structures\">\n <div cdkDropList [cdkDropListData]=\"structures\"\n cdkDropListConnectedTo=\"structures-drop-list\" id=\"structures-drop-list\"\n (cdkDropListDropped)=\"dropNewStructure($event)\" fxFlex fxLayout=\"column\" fxLayoutAlign=\"start center\">\n <pb-structure cdkDrag\n *ngFor=\"let structure of structures; trackBy: trackBy; let index = index\" [id]=\"structure.id\"\n [index]=\"index\" [ngClass]=\"structure.type\" [structure]=\"structure\"\n [ngStyle]=\"getStructureStyles(structure)\"\n [style.backgroundImage]=\"getBackgroundImage(structure)\"\n [cdkDragDisabled]=\"disableStructureDrag$(structure) | async\">\n <button cdkDragHandle mat-icon-button class=\"move\" *ngIf=\"!(disableStructureDrag$(structure) | async)\"\n i18n-matTooltip=\"structure|Move Structure\" matTooltip=\"Move Structure\">\n <mat-icon i18n-aria-label=\"structure|Move Structure\" aria-label=\"Move structure\" inline>pan_tool</mat-icon>\n </button>\n </pb-structure>\n\n <div class=\"empty-email mat-typography\" *ngIf=\"!structures.length\">\n <ng-content></ng-content>\n <div class=\"default-empty-email\" *ngIf=\"showTemplateList\">\n <h1 i18n=\"templates|First header\">Choose template from list</h1>\n <p i18n=\"templates|Description\">Or create one from scratch by dragging structures and blocks here!</p>\n <button type=\"button\" color=\"primary\" [disabled]=\"activeMatProgress$ | async\"\n (click)=\"openTemplateDialog($event)\" mat-flat-button i18n=\"templates|Choose a template button\">\n Choose template\n </button>\n </div>\n </div>\n </div>\n</ng-container>\n",
2685
+ providers: [
2686
+ // IpUserRestApiProvider
2687
+ ],
2688
+ changeDetection: ChangeDetectionStrategy.OnPush
2689
+ // encapsulation: ViewEncapsulation.None
2690
+ ,
2691
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */pb-structure>.cdk-drag-handle{position:absolute;cursor:move;border-radius:50% 50% 0 0;height:30px;width:30px;font-size:smaller;line-height:0;top:-30px;right:0;background-color:#ff4081;color:#fff;opacity:0}pb-structure.cdk-drag-preview>.cdk-drag-handle,pb-structure:hover>.cdk-drag-handle{opacity:.8}pb-structure.cdk-drag-preview>.cdk-drag-handle:hover,pb-structure:hover>.cdk-drag-handle:hover{opacity:1}pb-structure ::ng-deep .cdk-drag-placeholder{background-color:#3f51b5;opacity:.6;cursor:move;border-radius:0}pb-structure ::ng-deep .cdk-drag-placeholder ::ng-deep :not(mat-icon){display:none}pb-structure ::ng-deep .cdk-drag-placeholder ::ng-deep mat-icon{padding:5px;color:#fff}:host{background-color:#f2f2f2;overflow-x:hidden;overflow-y:auto;position:relative;height:100%}:host #structures-drop-list{height:-moz-fit-content;height:fit-content;max-width:100%;padding-bottom:3rem;will-change:box-shadow}:host #structures-drop-list .empty-email{display:flex;justify-content:center;align-items:center;flex-direction:column;flex:1 1 100%;margin-top:10%}:host #structures-drop-list .empty-email .default-empty-email{text-align:center}:host #structures-drop-list.cdk-drop-list-dragging .empty-email{display:none}"]
2692
+ },] }
2693
+ ];
2694
+ BuilderContainerComponent.ctorParameters = () => [
2695
+ { type: PbUserInterfaceService },
2696
+ { type: PbEmailObjectStoreService },
2697
+ { type: PbUserRestApiService },
2698
+ { type: PbStorageService },
2699
+ { type: PbUserMiddlewaresService },
2700
+ { type: DomSanitizer },
2701
+ { type: undefined, decorators: [{ type: Inject, args: [PB_CONFIG,] }] }
2702
+ ];
2703
+ BuilderContainerComponent.propDecorators = {
2704
+ onHostClick: [{ type: HostListener, args: ['click',] }]
2705
+ };
2706
+
2707
+ /*
2708
+ * Copyright (c) 2024 Pobuca.
2709
+ * All rights reserved.
2710
+ */
2711
+ class FontStylesComponent {
2712
+ constructor(pbEmailObject, googleFonts, fallbackFonts) {
2713
+ this.pbEmailObject = pbEmailObject;
2714
+ this.fallbackFonts = fallbackFonts;
2715
+ this.fontsMap = new Map();
2716
+ this.stylesMap = new Map([
2717
+ ['normal', $localize `:@@font_style_normal:Normal`],
2718
+ ['italic', $localize `:@@font_style_italic:Italic`],
2719
+ ['oblique', $localize `:@@font_style_oblique:Oblique`]
2720
+ ]);
2721
+ googleFonts.forEach(font => {
2722
+ const [family, ...weights] = font.match(/[^\d:,]{2,}|\d{3}/g);
2723
+ this.fontsMap.set(family.replace('+', ' '), [...new Set(weights.map(Number))]);
2724
+ });
2725
+ }
2726
+ get fontWeightList() {
2727
+ return this.isGoogleFont() ? this.fontsMap.get(this.font.family) : [100, 400, 500, 700, 900];
2728
+ }
2729
+ get fontFamilyList() {
2730
+ return [...this.fontsMap.keys(), ...this.fallbackFonts];
2731
+ }
2732
+ get styles() {
2733
+ return [...this.stylesMap.keys()];
2734
+ }
2735
+ markForCheck() {
2736
+ this.pbEmailObject.markForCheck();
2737
+ }
2738
+ isGoogleFont() {
2739
+ return this.fontsMap.has(this.font.family);
2740
+ }
2741
+ getStyleLabel(style) {
2742
+ // tslint:disable-next-line:no-non-null-assertion
2743
+ return this.stylesMap.get(style);
2744
+ }
2745
+ hasProperty(property) {
2746
+ return this.font.hasOwnProperty(property);
2747
+ }
2748
+ }
2749
+ FontStylesComponent.decorators = [
2750
+ { type: Component, args: [{
2751
+ selector: 'pb-font-styles',
2752
+ template: `
2753
+ <div class="group two">
2754
+ <mat-form-field appearance="outline" *ngIf="hasProperty('family')">
2755
+ <mat-label i18n="settings|Font Family">Family</mat-label>
2756
+ <mat-select [(value)]="font.family" disableRipple (selectionChange)="markForCheck()">
2757
+ <mat-option *ngFor="let name of fontFamilyList" [ngStyle]="{ fontFamily: name }" [value]="name">
2758
+ {{ name }}
2759
+ </mat-option>
2760
+ </mat-select>
2761
+ <mat-hint *ngIf="isGoogleFont()" i18n="settings|Partial support">Partial support.</mat-hint>
2762
+ <mat-hint *ngIf="!isGoogleFont()" i18n="settings|Full support">Full support.</mat-hint>
2763
+ </mat-form-field>
2764
+ <mat-form-field appearance="outline" *ngIf="hasProperty('fallback')">
2765
+ <mat-label i18n="settings|Font Fallback">Fallback</mat-label>
2766
+ <mat-select [(value)]="font.fallback" [disabled]="!isGoogleFont()" disableRipple (selectionChange)="markForCheck()">
2767
+ <mat-option *ngFor="let name of fallbackFonts" [ngStyle]="{ fontFamily: name }" [value]="name">
2768
+ {{ name }}
2769
+ </mat-option>
2770
+ </mat-select>
2771
+ <mat-hint i18n="settings|Full support">Full support.</mat-hint>
2772
+ </mat-form-field>
2773
+ </div>
2774
+
2775
+ <div class="group three">
2776
+ <mat-form-field appearance="outline" *ngIf="hasProperty('size')">
2777
+ <mat-label i18n="settings|Font Size">Size</mat-label>
2778
+ <input matInput type="number" max="30" min="10" step="1" (input)="markForCheck()" [(ngModel)]="font.size" />
2779
+ </mat-form-field>
2780
+ <mat-form-field appearance="outline" *ngIf="hasProperty('weight')">
2781
+ <mat-label i18n="settings|Font Weight">Weight</mat-label>
2782
+ <mat-select placeholder="Weight" [(value)]="font.weight" disableRipple (selectionChange)="markForCheck()">
2783
+ <mat-option *ngFor="let weight of fontWeightList" [value]="weight">
2784
+ {{ weight }}
2785
+ </mat-option>
2786
+ </mat-select>
2787
+ </mat-form-field>
2788
+ <mat-form-field appearance="outline" style="min-width: 90px;">
2789
+ <mat-label i18n="settings|Font Style">Style</mat-label>
2790
+ <mat-select placeholder="Style" [(value)]="font.style" disableRipple (selectionChange)="markForCheck()">
2791
+ <mat-option *ngFor="let style of styles" [value]="style" i18n>
2792
+ {{ getStyleLabel(style) }}
2793
+ </mat-option>
2794
+ </mat-select>
2795
+ </mat-form-field>
2796
+ </div>
2797
+ `,
2798
+ changeDetection: ChangeDetectionStrategy.OnPush,
2799
+ styles: [`
2800
+ :host {
2801
+ display: block;
2802
+ width: 100%;
2803
+ }
2804
+ `]
2805
+ },] }
2806
+ ];
2807
+ FontStylesComponent.ctorParameters = () => [
2808
+ { type: PbEmailObjectStoreService },
2809
+ { type: Array, decorators: [{ type: Inject, args: [PB_GOOGLE_FONTS,] }] },
2810
+ { type: Array, decorators: [{ type: Inject, args: [PB_FALLBACK_FONTS,] }] }
2811
+ ];
2812
+ FontStylesComponent.propDecorators = {
2813
+ font: [{ type: Input }]
2814
+ };
2815
+
2816
+ /*
2817
+ * Copyright (c) 2024 Pobuca.
2818
+ * All rights reserved.
2819
+ */
2820
+ class PaddingComponent {
2821
+ constructor(emailObject) {
2822
+ this.emailObject = emailObject;
2823
+ }
2824
+ markForCheck() {
2825
+ this.emailObject.markForCheck();
2826
+ }
2827
+ }
2828
+ PaddingComponent.decorators = [
2829
+ { type: Component, args: [{
2830
+ selector: 'pb-padding',
2831
+ template: `
2832
+ <div class="group four">
2833
+ <mat-form-field appearance="outline">
2834
+ <mat-label i18n="Padding Settings|Padding Top">Top</mat-label>
2835
+ <input matInput type="number" min="0" step="1" (input)="markForCheck()" [(ngModel)]="padding.top" />
2836
+ </mat-form-field>
2837
+ <mat-form-field appearance="outline">
2838
+ <mat-label i18n="Padding Settings|Padding Right">Right</mat-label>
2839
+ <input matInput type="number" min="0" step="1" (input)="markForCheck()" [(ngModel)]="padding.right" />
2840
+ </mat-form-field>
2841
+ <mat-form-field appearance="outline">
2842
+ <mat-label i18n="Padding Settings|Padding Bottom">Bottom</mat-label>
2843
+ <input matInput type="number" min="0" step="1" (input)="markForCheck()" [(ngModel)]="padding.bottom" />
2844
+ </mat-form-field>
2845
+ <mat-form-field appearance="outline">
2846
+ <mat-label i18n="Padding Settings|Padding Left">Left</mat-label>
2847
+ <input matInput type="number" min="0" step="1" (input)="markForCheck()" [(ngModel)]="padding.left" />
2848
+ </mat-form-field>
2849
+ </div>
2850
+ `,
2851
+ changeDetection: ChangeDetectionStrategy.OnPush,
2852
+ styles: [`
2853
+ :host {
2854
+ display: block;
2855
+ width: 100%;
2856
+ }
2857
+ `]
2858
+ },] }
2859
+ ];
2860
+ PaddingComponent.ctorParameters = () => [
2861
+ { type: PbEmailObjectStoreService }
2862
+ ];
2863
+ PaddingComponent.propDecorators = {
2864
+ padding: [{ type: Input }]
2865
+ };
2866
+
2867
+ /*
2868
+ * Copyright (c) 2024 Pobuca.
2869
+ * All rights reserved.
2870
+ */
2871
+ class LineHeightComponent {
2872
+ constructor(emailObject) {
2873
+ this.emailObject = emailObject;
2874
+ this.label = $localize `:@@line_height_label:Line Height`;
2875
+ this.units = ['%', 'px', 'none'];
2876
+ this.unitsLabels = new Map([
2877
+ ['%', $localize `:@@unit_percent:Percent`],
2878
+ ['px', $localize `:@@unit_pixels:Pixels`],
2879
+ ['none', $localize `:@@unit_none:None`]
2880
+ ]);
2881
+ }
2882
+ markForCheck() {
2883
+ this.emailObject.markForCheck();
2884
+ }
2885
+ getUnitLabel(unit) {
2886
+ return this.unitsLabels.get(unit);
2887
+ }
2888
+ }
2889
+ LineHeightComponent.decorators = [
2890
+ { type: Component, args: [{
2891
+ selector: 'pb-line-height',
2892
+ template: `
2893
+ <div class="group">
2894
+ <mat-form-field appearance="outline">
2895
+ <mat-label>{{ label }}</mat-label>
2896
+ <input
2897
+ matInput
2898
+ [(ngModel)]="lineHeight.value"
2899
+ type="number"
2900
+ step="1"
2901
+ (input)="markForCheck()"
2902
+ [disabled]="lineHeight.unit === 'none'"
2903
+ />
2904
+ </mat-form-field>
2905
+ <mat-form-field appearance="outline">
2906
+ <mat-label i18n="Line Height Settings|Change Line Height Unit">Unit</mat-label>
2907
+ <mat-select placeholder="Unit" [(value)]="lineHeight.unit" (selectionChange)="markForCheck()" disableRipple>
2908
+ <mat-option *ngFor="let unit of units" [value]="unit" i18n>
2909
+ {{ getUnitLabel(unit) }}
2910
+ </mat-option>
2911
+ </mat-select>
2912
+ </mat-form-field>
2913
+ </div>
2914
+ `,
2915
+ changeDetection: ChangeDetectionStrategy.OnPush,
2916
+ styles: [`
2917
+ :host {
2918
+ display: block;
2919
+ width: 100%;
2920
+ }
2921
+ `]
2922
+ },] }
2923
+ ];
2924
+ LineHeightComponent.ctorParameters = () => [
2925
+ { type: PbEmailObjectStoreService }
2926
+ ];
2927
+ LineHeightComponent.propDecorators = {
2928
+ lineHeight: [{ type: Input }],
2929
+ label: [{ type: Input }],
2930
+ units: [{ type: Input }]
2931
+ };
2932
+
2933
+ /*
2934
+ * Copyright (c) 2024 Pobuca.
2935
+ * All rights reserved.
2936
+ */
2937
+ class WidthHeightComponent {
2938
+ constructor(emailObject) {
2939
+ this.emailObject = emailObject;
2940
+ this.disabled = false;
2941
+ this.units = new Map([
2942
+ ['%', $localize `:@@unit_percent:Percent`],
2943
+ ['px', $localize `:@@unit_pixels:Pixels`],
2944
+ ['contain', $localize `:@@unit_contain:Contain`],
2945
+ ['cover', $localize `:@@unit_cover:Cover`]
2946
+ ]);
2947
+ }
2948
+ markForCheck() {
2949
+ this.emailObject.markForCheck();
2950
+ }
2951
+ getLabel() {
2952
+ return this.label;
2953
+ }
2954
+ toggleChange({ checked }) {
2955
+ this.model.auto = checked;
2956
+ this.markForCheck();
2957
+ }
2958
+ getUnits() {
2959
+ return this.model.units || ['%', 'px'];
2960
+ }
2961
+ disableValueField() {
2962
+ return this.model.auto || ['%', 'px'].indexOf(this.model.unit) === -1;
2963
+ }
2964
+ showAutoSlider() {
2965
+ return this.model.hasOwnProperty('auto');
2966
+ }
2967
+ getUnitLabel(unit) {
2968
+ return this.units.get(unit);
2969
+ }
2970
+ }
2971
+ WidthHeightComponent.decorators = [
2972
+ { type: Component, args: [{
2973
+ selector: 'pb-width-height',
2974
+ template: `
2975
+ <div class="group" [ngClass]="{ three: showAutoSlider() }">
2976
+ <mat-form-field appearance="outline">
2977
+ <mat-label>{{ getLabel() }}</mat-label>
2978
+ <input
2979
+ matInput
2980
+ [(ngModel)]="model.value"
2981
+ [disabled]="disableValueField() || disabled"
2982
+ type="number"
2983
+ [placeholder]="getLabel()"
2984
+ (input)="markForCheck()"
2985
+ />
2986
+ </mat-form-field>
2987
+ <mat-form-field appearance="outline">
2988
+ <mat-label i18n="Size Settings|Size Unit">Unit</mat-label>
2989
+ <mat-select [disabled]="model.auto || disabled" [(value)]="model.unit" (selectionChange)="markForCheck()" disableRipple>
2990
+ <mat-option *ngFor="let unit of getUnits()" [value]="unit" i18n>
2991
+ {{ getUnitLabel(unit) }}
2992
+ </mat-option>
2993
+ </mat-select>
2994
+ </mat-form-field>
2995
+ <mat-slide-toggle
2996
+ style="margin-top: -20px;"
2997
+ *ngIf="showAutoSlider()"
2998
+ [checked]="model.auto"
2999
+ (change)="toggleChange($event)"
3000
+ [disabled]="disabled"
3001
+ i18n="Size Settings|Size Auto"
3002
+ >
3003
+ Auto
3004
+ </mat-slide-toggle>
3005
+ </div>
3006
+ `,
3007
+ changeDetection: ChangeDetectionStrategy.OnPush,
3008
+ styles: [`
3009
+ :host {
3010
+ display: block;
3011
+ width: 100%;
3012
+ }
3013
+ `]
3014
+ },] }
3015
+ ];
3016
+ WidthHeightComponent.ctorParameters = () => [
3017
+ { type: PbEmailObjectStoreService }
3018
+ ];
3019
+ WidthHeightComponent.propDecorators = {
3020
+ model: [{ type: Input }],
3021
+ label: [{ type: Input }],
3022
+ disabled: [{ type: Input }]
3023
+ };
3024
+
3025
+ /*
3026
+ * Copyright (c) 2024 Pobuca.
3027
+ * All rights reserved.
3028
+ */
3029
+ class BorderComponent {
3030
+ constructor(emailObject) {
3031
+ this.emailObject = emailObject;
3032
+ this._styleLabels = new Map([
3033
+ ['solid', $localize `:@@border_style_solid:Solid`],
3034
+ ['dotted', $localize `:@@border_style_dotted:Dotted`],
3035
+ ['dashed', $localize `:@@border_style_dashed:Dashed`],
3036
+ ['double', $localize `:@@border_style_double:Double`],
3037
+ ['groove', $localize `:@@border_style_groove:Groove`]
3038
+ ]);
3039
+ }
3040
+ get styleLabels() {
3041
+ return [...this._styleLabels.keys()];
3042
+ }
3043
+ getStyleLabel(style) {
3044
+ // tslint:disable-next-line:no-non-null-assertion
3045
+ return this._styleLabels.get(style);
3046
+ }
3047
+ markForCheck() {
3048
+ this.emailObject.markForCheck();
3049
+ }
3050
+ isEven() {
3051
+ return Object.keys(this.border).length % 2 === 0;
3052
+ }
3053
+ hasOwnProperty(property) {
3054
+ return this.border.hasOwnProperty(property);
3055
+ }
3056
+ }
3057
+ BorderComponent.decorators = [
3058
+ { type: Component, args: [{
3059
+ selector: 'pb-border',
3060
+ template: `
3061
+ <div class="group" [class.three]="isEven()">
3062
+ <mat-form-field appearance="outline" *ngIf="hasOwnProperty('width')">
3063
+ <mat-label i18n="Border Settings|Change Border Width">Width</mat-label>
3064
+ <input
3065
+ matInput
3066
+ [(ngModel)]="border.width"
3067
+ type="number"
3068
+ min="0"
3069
+ step="1"
3070
+ (input)="markForCheck()"
3071
+ i18n-placeholder
3072
+ placeholder="Border Settings|Change Border Width"
3073
+ />
3074
+ </mat-form-field>
3075
+ <mat-form-field appearance="outline" *ngIf="hasOwnProperty('radius')">
3076
+ <mat-label i18n="Border Settings|Change Border Radius">Radius</mat-label>
3077
+ <input
3078
+ matInput
3079
+ [(ngModel)]="border.radius"
3080
+ type="number"
3081
+ min="0"
3082
+ step="1"
3083
+ (input)="markForCheck()"
3084
+ i18n-placeholder
3085
+ placeholder="Border Settings|Change Border Radius"
3086
+ />
3087
+ </mat-form-field>
3088
+ <mat-form-field appearance="outline" *ngIf="hasOwnProperty('style')" style="min-width: 90px">
3089
+ <mat-label i18n="Border Settings|Change Border Style">Style</mat-label>
3090
+ <mat-select
3091
+ placeholder="Style"
3092
+ [disabled]="!border.width"
3093
+ [(value)]="border.style"
3094
+ (selectionChange)="markForCheck()"
3095
+ disableRipple
3096
+ >
3097
+ <mat-option *ngFor="let style of styleLabels" [value]="style">
3098
+ {{ getStyleLabel(style) }}
3099
+ </mat-option>
3100
+ </mat-select>
3101
+ </mat-form-field>
3102
+ </div>
3103
+ <pb-color [options]="border" [disabled]="!border.width" *ngIf="hasOwnProperty('color')" key="color"></pb-color>
3104
+ `,
3105
+ changeDetection: ChangeDetectionStrategy.OnPush,
3106
+ styles: [`
3107
+ :host {
3108
+ display: block;
3109
+ width: 100%;
3110
+ }
3111
+
3112
+ mat-form-field {
3113
+ width: 100%;
3114
+ }
3115
+ `]
3116
+ },] }
3117
+ ];
3118
+ BorderComponent.ctorParameters = () => [
3119
+ { type: PbEmailObjectStoreService }
3120
+ ];
3121
+ BorderComponent.propDecorators = {
3122
+ border: [{ type: Input }]
3123
+ };
3124
+
3125
+ /*
3126
+ * Copyright (c) 2024 Pobuca.
3127
+ * All rights reserved.
3128
+ */
3129
+ // import { PbEmailBuilderService } from '../pb-email-builder.service';
3130
+ // import { parseColor } from '../utils';
3131
+ class ColorComponent {
3132
+ constructor(emailObject) {
3133
+ this.emailObject = emailObject;
3134
+ this.disabled = false;
3135
+ this.key = 'backgroundColor';
3136
+ this.transparent = false;
3137
+ this.showColorPicker = false;
3138
+ }
3139
+ get currentColorModel() {
3140
+ return this.options[this.key];
3141
+ }
3142
+ set currentColorModel(hex) {
3143
+ this.options[this.key] = hex;
3144
+ }
3145
+ get currentColor() {
3146
+ return this.transparent ? this.oldValue : this.currentColorModel;
3147
+ }
3148
+ set currentColor(hex) {
3149
+ this.currentColorModel = hex;
3150
+ }
3151
+ onHostMouseLeave() {
3152
+ this.showColorPicker = false;
3153
+ }
3154
+ changeColor(event) {
3155
+ this.currentColor = event.color.hex;
3156
+ this.emailObject.markForCheck();
3157
+ }
3158
+ makeTransparentColor() {
3159
+ this.showColorPicker = false;
3160
+ if (this.transparent) {
3161
+ this.oldValue = this.currentColorModel;
3162
+ this.currentColor = 'transparent';
3163
+ }
3164
+ else {
3165
+ this.currentColor = this.oldValue;
3166
+ }
3167
+ this.emailObject.markForCheck();
3168
+ }
3169
+ ngOnInit() {
3170
+ if (this.currentColor === 'transparent') {
3171
+ this.transparent = true;
3172
+ this.oldValue = '#ffffff';
3173
+ }
3174
+ // this.changeContrastColor();
3175
+ }
3176
+ }
3177
+ ColorComponent.decorators = [
3178
+ { type: Component, args: [{
3179
+ selector: 'pb-color',
3180
+ template: `
3181
+ <div class="group" *ngIf="showTransparent">
3182
+ <mat-slide-toggle
3183
+ [disabled]="disabled"
3184
+ [(ngModel)]="transparent"
3185
+ (change)="makeTransparentColor()"
3186
+ i18n="Color settings|Make color transparent"
3187
+ >
3188
+ Transparent
3189
+ </mat-slide-toggle>
3190
+ </div>
3191
+ <div class="group two">
3192
+ <mat-form-field appearance="outline">
3193
+ <mat-label i18n="Color settings|Change color">Color</mat-label>
3194
+ <input matInput [disabled]="transparent || disabled" (focus)="showColorPicker = false" [(ngModel)]="currentColor" type="text" />
3195
+ </mat-form-field>
3196
+ <div class="choose-color" [class.transparent]="transparent || disabled">
3197
+ <div class="current-color" (mouseover)="showColorPicker = !transparent" [style.backgroundColor]="currentColor"></div>
3198
+ <color-chrome
3199
+ [disableAlpha]="true"
3200
+ *ngIf="showColorPicker"
3201
+ (onChangeComplete)="changeColor($event)"
3202
+ [color]="currentColor"
3203
+ ></color-chrome>
3204
+ </div>
3205
+ </div>
3206
+ `,
3207
+ changeDetection: ChangeDetectionStrategy.OnPush,
3208
+ styles: [`
3209
+ :host {
3210
+ display: block;
3211
+ position: relative;
3212
+ }
3213
+
3214
+ mat-form-field {
3215
+ width: 100%;
3216
+ }
3217
+
3218
+ .choose-color {
3219
+ display: block;
3220
+ height: 100%;
3221
+ width: 100%;
3222
+ }
3223
+
3224
+ .current-color {
3225
+ width: 100%;
3226
+ height: 48px;
3227
+ border-radius: 5px;
3228
+ margin: 0.25em 0;
3229
+ cursor: pointer;
3230
+ display: flex;
3231
+ align-items: center;
3232
+ justify-content: center;
3233
+ border: 1px solid rgba(0, 0, 0, 0.12);
3234
+ transition: background-color 500ms cubic-bezier(0.445, 0.05, 0.55, 0.95);
3235
+ }
3236
+
3237
+ .choose-color.transparent .current-color {
3238
+ opacity: 0.5;
3239
+ pointer-events: none;
3240
+ }
3241
+
3242
+ color-chrome {
3243
+ position: absolute;
3244
+ top: calc(100% - 1em);
3245
+ right: 0;
3246
+ z-index: 9;
3247
+ }
3248
+ `]
3249
+ },] }
3250
+ ];
3251
+ ColorComponent.ctorParameters = () => [
3252
+ { type: PbEmailObjectStoreService }
3253
+ ];
3254
+ ColorComponent.propDecorators = {
3255
+ options: [{ type: Input }],
3256
+ showTransparent: [{ type: Input }],
3257
+ disabled: [{ type: Input }],
3258
+ key: [{ type: Input }],
3259
+ onHostMouseLeave: [{ type: HostListener, args: ['mouseleave',] }]
3260
+ };
3261
+
3262
+ /*
3263
+ * Copyright (c) 2024 Pobuca.
3264
+ * All rights reserved.
3265
+ */
3266
+ class LinkComponent {
3267
+ constructor(emailObject) {
3268
+ this.emailObject = emailObject;
3269
+ this.targetLabels = new Map([
3270
+ ['_blank', $localize `:@@link_target_blank:Blank`],
3271
+ ['_self', $localize `:@@link_target_self:Self`],
3272
+ ['_parent', $localize `:@@link_target_parent:Parent`],
3273
+ ['_top', $localize `:@@link_target_top:Top`]
3274
+ ]);
3275
+ }
3276
+ markForCheck() {
3277
+ this.emailObject.markForCheck();
3278
+ }
3279
+ getTargets() {
3280
+ return ['_blank', '_self', '_parent', '_top'];
3281
+ }
3282
+ getTargetLabel(target) {
3283
+ return this.targetLabels.get(target);
3284
+ }
3285
+ }
3286
+ LinkComponent.decorators = [
3287
+ { type: Component, args: [{
3288
+ selector: 'pb-link',
3289
+ template: `
3290
+ <div class="group f-large">
3291
+ <mat-form-field appearance="outline">
3292
+ <mat-label i18n="Link Settings|Link">Link</mat-label>
3293
+ <input matInput [(ngModel)]="link.href" type="url" placeholder="Link" (blur)="markForCheck()" />
3294
+ </mat-form-field>
3295
+ <mat-form-field appearance="outline">
3296
+ <mat-label i18n="Link Settings|Target">Target</mat-label>
3297
+ <mat-select
3298
+ placeholder="Target"
3299
+ i18n-placeholder="Link Settings|Target"
3300
+ [(value)]="link.target"
3301
+ disableRipple
3302
+ (selectionChange)="markForCheck()"
3303
+ >
3304
+ <mat-option *ngFor="let target of getTargets()" [value]="target">
3305
+ {{ getTargetLabel(target) }}
3306
+ </mat-option>
3307
+ </mat-select>
3308
+ </mat-form-field>
3309
+ </div>
3310
+ `,
3311
+ changeDetection: ChangeDetectionStrategy.OnPush,
3312
+ styles: [`
3313
+ :host {
3314
+ display: block;
3315
+ width: 100%;
3316
+ }
3317
+ `]
3318
+ },] }
3319
+ ];
3320
+ LinkComponent.ctorParameters = () => [
3321
+ { type: PbEmailObjectStoreService }
3322
+ ];
3323
+ LinkComponent.propDecorators = {
3324
+ link: [{ type: Input }]
3325
+ };
3326
+
3327
+ /*
3328
+ * Copyright (c) 2024 Pobuca.
3329
+ * All rights reserved.
3330
+ */
3331
+ class AlignComponent {
3332
+ constructor(emailObject) {
3333
+ this.emailObject = emailObject;
3334
+ this.mode = 'horizontal';
3335
+ this.labels = new Map([
3336
+ ['left', $localize `:@@horizontal_align_left:Left`],
3337
+ ['center', $localize `:@@horizontal_align_center:Center`],
3338
+ ['right', $localize `:@@horizontal_align_right:Right`],
3339
+ ['top', $localize `:@@vertical_align_top:Top`],
3340
+ ['middle', $localize `:@@vertical_align_middle:Middle`],
3341
+ ['bottom', $localize `:@@vertical_align_bottom:Bottom`]
3342
+ ]);
3343
+ }
3344
+ get currentModel() {
3345
+ return this.model.align || this.model.verticalAlign;
3346
+ }
3347
+ set currentModel(value) {
3348
+ if (this.model.align) {
3349
+ this.model.align = value;
3350
+ }
3351
+ else {
3352
+ this.model.verticalAlign = value;
3353
+ }
3354
+ this.emailObject.markForCheck();
3355
+ }
3356
+ getLabel(key) {
3357
+ return this.labels.get(key);
3358
+ }
3359
+ getPositions() {
3360
+ if (this.mode === 'vertical') {
3361
+ return ['top', 'middle', 'bottom'];
3362
+ }
3363
+ return ['left', 'center', 'right'];
3364
+ }
3365
+ }
3366
+ AlignComponent.decorators = [
3367
+ { type: Component, args: [{
3368
+ selector: 'pb-align',
3369
+ template: `
3370
+ <mat-form-field appearance="outline">
3371
+ <mat-label [ngSwitch]="mode">
3372
+ <ng-container *ngSwitchCase="'vertical'" i18n="Align Settings|Vertical Align">Vertical Align</ng-container>
3373
+ <ng-container *ngSwitchDefault i18n="Align Settings|Align">Align</ng-container>
3374
+ </mat-label>
3375
+ <mat-select [(ngModel)]="currentModel" disableRipple [disabled]="disabled">
3376
+ <mat-option *ngFor="let position of getPositions()" [value]="position">
3377
+ {{ getLabel(position) }}
3378
+ </mat-option>
3379
+ </mat-select>
3380
+ </mat-form-field>
3381
+ `,
3382
+ changeDetection: ChangeDetectionStrategy.OnPush,
3383
+ styles: [`
3384
+ :host {
3385
+ display: block;
3386
+ width: 100%;
3387
+ }
3388
+
3389
+ mat-form-field {
3390
+ width: 100%;
3391
+ }
3392
+ `]
3393
+ },] }
3394
+ ];
3395
+ AlignComponent.ctorParameters = () => [
3396
+ { type: PbEmailObjectStoreService }
3397
+ ];
3398
+ AlignComponent.propDecorators = {
3399
+ model: [{ type: Input }],
3400
+ mode: [{ type: Input }],
3401
+ disabled: [{ type: Input }]
3402
+ };
3403
+
3404
+ /*
3405
+ * Copyright (c) 2024 Pobuca.
3406
+ * All rights reserved.
3407
+ */
3408
+ class DirectionComponent {
3409
+ constructor(emailObject) {
3410
+ this.emailObject = emailObject;
3411
+ this.dirLabels = new Map([
3412
+ ['ltr', $localize `:@@direction_ltr:Left to right`],
3413
+ ['rtl', $localize `:@@direction_rtl:Right to left`]
3414
+ ]);
3415
+ }
3416
+ markForCheck() {
3417
+ this.emailObject.markForCheck();
3418
+ }
3419
+ getDirections() {
3420
+ return ['ltr', 'rtl'];
3421
+ }
3422
+ getDirectionLabel(dir) {
3423
+ return this.dirLabels.get(dir);
3424
+ }
3425
+ }
3426
+ DirectionComponent.decorators = [
3427
+ { type: Component, args: [{
3428
+ selector: 'pb-direction',
3429
+ template: `
3430
+ <mat-form-field appearance="outline">
3431
+ <mat-label i18n="settings|Direction">Direction</mat-label>
3432
+ <mat-select
3433
+ i18n-placeholder="settings|Direction"
3434
+ placeholder="Direction"
3435
+ [(value)]="model.direction"
3436
+ (selectionChange)="markForCheck()"
3437
+ disableRipple
3438
+ >
3439
+ <mat-option *ngFor="let dir of getDirections()" [value]="dir">
3440
+ {{ getDirectionLabel(dir) }}
3441
+ </mat-option>
3442
+ </mat-select>
3443
+ </mat-form-field>
3444
+ `,
3445
+ changeDetection: ChangeDetectionStrategy.OnPush,
3446
+ styles: [`
3447
+ :host {
3448
+ display: block;
3449
+ width: 100%;
3450
+ }
3451
+
3452
+ mat-form-field {
3453
+ width: 100%;
3454
+ }
3455
+ `]
3456
+ },] }
3457
+ ];
3458
+ DirectionComponent.ctorParameters = () => [
3459
+ { type: PbEmailObjectStoreService }
3460
+ ];
3461
+ DirectionComponent.propDecorators = {
3462
+ model: [{ type: Input }]
3463
+ };
3464
+
3465
+ /*
3466
+ * Copyright (c) 2024 Pobuca.
3467
+ * All rights reserved.
3468
+ */
3469
+ class BackRepatComponent {
3470
+ constructor() {
3471
+ this.disabled = false;
3472
+ this.repeatLabels = new Map([
3473
+ ['no-repeat', $localize `:@@no_repeat:No`],
3474
+ ['repeat', $localize `:@@repeat:Repeat`],
3475
+ ['repeat-x', $localize `:@@repeat_x:X`],
3476
+ ['repeat-y', $localize `:@@repeat_y:Y`],
3477
+ ['round', $localize `:@@repeat_round:Round`],
3478
+ ['space', $localize `:@@repeat_space:Space`]
3479
+ ]);
3480
+ }
3481
+ getRepeats() {
3482
+ return ['no-repeat', 'repeat', 'repeat-x', 'repeat-y'];
3483
+ }
3484
+ getRepeatLabel(repeat) {
3485
+ return this.repeatLabels.get(repeat);
3486
+ }
3487
+ }
3488
+ BackRepatComponent.decorators = [
3489
+ { type: Component, args: [{
3490
+ selector: 'pb-back-repeat',
3491
+ template: `
3492
+ <mat-form-field appearance="outline">
3493
+ <mat-label i18n="settings|Background Repeat">Repeat</mat-label>
3494
+ <mat-select [(value)]="model.repeat" [disabled]="disabled" disableRipple>
3495
+ <mat-option *ngFor="let repeat of getRepeats()" [value]="repeat">
3496
+ {{ getRepeatLabel(repeat) }}
3497
+ </mat-option>
3498
+ </mat-select>
3499
+ </mat-form-field>
3500
+ `,
3501
+ changeDetection: ChangeDetectionStrategy.OnPush,
3502
+ styles: [`
3503
+ :host {
3504
+ display: block;
3505
+ width: 100%;
3506
+ }
3507
+
3508
+ mat-form-field {
3509
+ width: 100%;
3510
+ }
3511
+ `]
3512
+ },] }
3513
+ ];
3514
+ BackRepatComponent.propDecorators = {
3515
+ model: [{ type: Input }],
3516
+ disabled: [{ type: Input }]
3517
+ };
3518
+
3519
+ /*
3520
+ * Copyright (c) 2024 Pobuca.
3521
+ * All rights reserved.
3522
+ */
3523
+ const devicesMap = new Map([
3524
+ ['desktop', '1 1 100%'],
3525
+ ['smartphone', '1 1 360px'],
3526
+ ['tablet', '1 1 768px']
3527
+ ]);
3528
+ class PreviewTemplateComponent {
3529
+ constructor(middlewares, sanitizer) {
3530
+ this.middlewares = middlewares;
3531
+ this.sanitizer = sanitizer;
3532
+ this.device = 'desktop';
3533
+ }
3534
+ changeDevice(button) {
3535
+ return this.middlewares
3536
+ .togglePreviewDevice(button)
3537
+ .pipe(take(1))
3538
+ .subscribe(device => {
3539
+ this.device = device;
3540
+ });
3541
+ }
3542
+ getFlexWidth() {
3543
+ return devicesMap.get(this.device);
3544
+ }
3545
+ ngOnInit() {
3546
+ this.src = URL.createObjectURL(new Blob([this.template], { type: 'text/html' }));
3547
+ this.templateSrc = this.sanitizer.bypassSecurityTrustResourceUrl(this.src);
3548
+ }
3549
+ ngOnDestroy() {
3550
+ if (this.src) {
3551
+ URL.revokeObjectURL(this.src);
3552
+ }
3553
+ }
3554
+ }
3555
+ PreviewTemplateComponent.decorators = [
3556
+ { type: Component, args: [{
3557
+ selector: 'pb-preview-template',
3558
+ template: `
3559
+ <iframe [src]="templateSrc" [fxFlex]="getFlexWidth()"></iframe>
3560
+ <mat-button-toggle-group value="desktop" (change)="changeDevice($event)" vertical>
3561
+ <mat-button-toggle value="desktop" matTooltip="Desktop / 100%" matTooltipPosition="left">
3562
+ <mat-icon>desktop_windows</mat-icon>
3563
+ </mat-button-toggle>
3564
+ <mat-button-toggle value="tablet" matTooltip="Tablet / 768px" matTooltipPosition="left">
3565
+ <mat-icon>tablet</mat-icon>
3566
+ </mat-button-toggle>
3567
+ <mat-button-toggle value="smartphone" matTooltip="Smartphone / 360px" matTooltipPosition="left">
3568
+ <mat-icon>smartphone</mat-icon>
3569
+ </mat-button-toggle>
3570
+ </mat-button-toggle-group>
3571
+ `,
3572
+ changeDetection: ChangeDetectionStrategy.OnPush,
3573
+ styles: [`
3574
+ iframe {
3575
+ border: 0;
3576
+ will-change: width;
3577
+ transition: all 500ms ease-in-out;
3578
+ }
3579
+
3580
+ /* iframe a[href] {
3581
+ pointer-events: none;
3582
+ } */
3583
+
3584
+ /* iframe.active {
3585
+ opacity: 1;
3586
+ } */
3587
+
3588
+ mat-button-toggle-group {
3589
+ position: absolute;
3590
+ right: 0;
3591
+ background: white;
3592
+ }
3593
+ `]
3594
+ },] }
3595
+ ];
3596
+ PreviewTemplateComponent.ctorParameters = () => [
3597
+ { type: PbUserMiddlewaresService },
3598
+ { type: DomSanitizer }
3599
+ ];
3600
+ PreviewTemplateComponent.propDecorators = {
3601
+ template: [{ type: Input }]
3602
+ };
3603
+
3604
+ /*
3605
+ * Copyright (c) 2024 Pobuca.
3606
+ * All rights reserved.
3607
+ */
3608
+ class BlockComponent {
3609
+ constructor(pbMiddlewaresService, userInterfaceService, emailObjectStore, chRef) {
3610
+ this.pbMiddlewaresService = pbMiddlewaresService;
3611
+ this.userInterfaceService = userInterfaceService;
3612
+ this.emailObjectStore = emailObjectStore;
3613
+ this.chRef = chRef;
3614
+ this.isActive = false;
3615
+ this.componentIsDestroyed$ = new Subject();
3616
+ }
3617
+ onHostClick(event) {
3618
+ event.stopImmediatePropagation();
3619
+ this.editBlock();
3620
+ }
3621
+ get isBlockActive() {
3622
+ return this.isActive;
3623
+ }
3624
+ removeBlock() {
3625
+ this.pbMiddlewaresService
3626
+ .removeBlock(this.index, this.column, this.block)
3627
+ .pipe(exhaustMap(() => this.userInterfaceService.confirmDialog$()), filter(removeAllowed => removeAllowed), take(1))
3628
+ .subscribe(() => {
3629
+ this.emailObjectStore.removeBlock(this.index, this.column);
3630
+ });
3631
+ }
3632
+ duplicateBlock() {
3633
+ this.pbMiddlewaresService
3634
+ .duplicateBlock(this.index, this.column, this.block)
3635
+ .pipe(map(data => this.emailObjectStore.duplicateBlock(data.index, data.column, data.block)), take(1))
3636
+ .subscribe(() => {
3637
+ // this.chRef.markForCheck();
3638
+ });
3639
+ }
3640
+ editBlock() {
3641
+ this.pbMiddlewaresService
3642
+ .editBlock(this.block)
3643
+ .pipe(take(1))
3644
+ .subscribe(block => {
3645
+ this.userInterfaceService.editBlock(block);
3646
+ });
3647
+ }
3648
+ ngOnInit() {
3649
+ this.userInterfaceService.currentEditingBlock$
3650
+ .pipe(map(currentEditingBlock => currentEditingBlock === this.block), takeUntil(this.componentIsDestroyed$))
3651
+ .subscribe(isActive => {
3652
+ this.isActive = isActive;
3653
+ });
3654
+ }
3655
+ ngDoCheck() {
3656
+ if (this.isActive) {
3657
+ this.chRef.markForCheck();
3658
+ }
3659
+ }
3660
+ ngOnDestroy() {
3661
+ this.componentIsDestroyed$.next('');
3662
+ this.componentIsDestroyed$.complete();
3663
+ }
3664
+ }
3665
+ BlockComponent.decorators = [
3666
+ { type: Component, args: [{
3667
+ selector: 'pb-block',
3668
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<ng-content select=\".move\"></ng-content>\n<div class=\"tools\" fxLayout fxLayoutGap=\"0.25rem\">\n <button mat-icon-button (click)=\"duplicateBlock()\" i18n-matTooltip=\"block|Duplicate Block\"\n matTooltip=\"Duplicate Block\">\n <mat-icon i18n-aria-label=\"block|Duplicate Block\" aria-label=\"Duplicate block\" inline>file_copy</mat-icon>\n </button>\n <button mat-icon-button (click)=\"removeBlock()\" i18n-matTooltip=\"block|Remove Block\" class=\"delete\"\n matTooltip=\"Remove Block\">\n <mat-icon i18n-aria-label=\"block|Remove Block\" aria-label=\"Delete block\" inline>delete_forever</mat-icon>\n </button>\n</div>\n<ng-content *pbDynamicComponent=\"block\"></ng-content>\n",
3669
+ changeDetection: ChangeDetectionStrategy.OnPush,
3670
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */:host{display:block;position:relative}:host.active:not(.cdk-drag-preview)>.tools{opacity:1;display:flex!important}:host.active,:host.cdk-drag-placeholder,:host.cdk-drag-preview{z-index:3;box-shadow:0 0 0 2px #3f51b5}:host:hover:not(.active){box-shadow:0 0 0 2px rgba(63,81,181,.5)}:host>.tools{direction:ltr;opacity:0;z-index:4;position:absolute;max-width:100%;bottom:-25px;right:0;display:none!important;transition:all .5s ease-in-out}:host>.tools>button{background:#3f51b5;border-radius:3px;color:#fff;line-height:0;width:25px;height:25px}:host>.tools>button mat-icon{font-size:14px;margin-top:-3px}:host>.tools ::ng-deep+*>*{transition:all .5s cubic-bezier(.445,.05,.55,.95)}"]
3671
+ },] }
3672
+ ];
3673
+ BlockComponent.ctorParameters = () => [
3674
+ { type: PbUserMiddlewaresService },
3675
+ { type: PbUserInterfaceService },
3676
+ { type: PbEmailObjectStoreService },
3677
+ { type: ChangeDetectorRef }
3678
+ ];
3679
+ BlockComponent.propDecorators = {
3680
+ block: [{ type: Input }],
3681
+ column: [{ type: Input }],
3682
+ index: [{ type: Input }],
3683
+ onHostClick: [{ type: HostListener, args: ['click', ['$event'],] }],
3684
+ isBlockActive: [{ type: HostBinding, args: ['class.active',] }]
3685
+ };
3686
+
3687
+ /*
3688
+ * Copyright (c) 2024 Pobuca.
3689
+ * All rights reserved.
3690
+ */
3691
+ class ImageUploadComponent {
3692
+ constructor(imageUpload, emailObject) {
3693
+ this.imageUpload = imageUpload;
3694
+ this.emailObject = emailObject;
3695
+ this.key = 'src';
3696
+ this.browsing = new Subject();
3697
+ }
3698
+ get source() {
3699
+ return this.block[this.key];
3700
+ }
3701
+ set source(value) {
3702
+ this.block[this.key] = value;
3703
+ }
3704
+ markForCheck() {
3705
+ this.emailObject.markForCheck();
3706
+ }
3707
+ browse() {
3708
+ return __awaiter(this, void 0, void 0, function* () {
3709
+ this.browsing.next(true);
3710
+ try {
3711
+ const path = yield this.imageUpload.browse$().toPromise();
3712
+ if (path) {
3713
+ this.source = path;
3714
+ this.emailObject.markForCheck();
3715
+ }
3716
+ }
3717
+ finally {
3718
+ this.browsing.next(false);
3719
+ }
3720
+ });
3721
+ }
3722
+ ngOnInit() {
3723
+ this.source = this.block.src || this.block.url;
3724
+ }
3725
+ }
3726
+ ImageUploadComponent.decorators = [
3727
+ { type: Component, args: [{
3728
+ selector: 'pb-image-upload',
3729
+ template: `
3730
+ <div fxLayout fxLayoutAlign="space-between center">
3731
+ <div class="image-info" [fxFlex]="source ? '30%' : '60%'" fxLayout fxLayoutGap="0.5em" fxLayoutAlign="center center">
3732
+ <div *ngIf="source" class="chose-image">
3733
+ <img [src]="source" alt="image source" />
3734
+ </div>
3735
+ <span *ngIf="!source" style="width: 100%;" i18n="Upload Image Settings|Upload an image"> Upload an image </span>
3736
+ </div>
3737
+ <button
3738
+ type="button"
3739
+ (click)="browse()"
3740
+ [disabled]="browsing | async"
3741
+ color="primary"
3742
+ mat-stroked-button
3743
+ i18n="Upload Image Settings|Browse"
3744
+ >
3745
+ Browse
3746
+ </button>
3747
+ </div>
3748
+ <mat-form-field appearance="outline" style="width: 100%">
3749
+ <mat-label i18n="Upload Image Settings|Image Source">Image Source</mat-label>
3750
+ <input matInput [(ngModel)]="source" type="url" (input)="markForCheck()" />
3751
+ </mat-form-field>
3752
+ `,
3753
+ changeDetection: ChangeDetectionStrategy.OnPush,
3754
+ styles: [`
3755
+ :host {
3756
+ display: block;
3757
+ }
3758
+
3759
+ .chose-image {
3760
+ width: 100%;
3761
+ max-height: 60px;
3762
+ overflow: hidden;
3763
+ border-radius: 3px;
3764
+ line-height: 0;
3765
+ }
3766
+
3767
+ .chose-image img {
3768
+ width: 100%;
3769
+ height: 60px;
3770
+ object-fit: cover;
3771
+ object-position: center;
3772
+ }
3773
+
3774
+ .size {
3775
+ font-size: 80%;
3776
+ color: #ccc;
3777
+ }
3778
+
3779
+ mat-form-field {
3780
+ margin-top: 0.5rem;
3781
+ }
3782
+ `]
3783
+ },] }
3784
+ ];
3785
+ ImageUploadComponent.ctorParameters = () => [
3786
+ { type: PbUserImageUploaderService },
3787
+ { type: PbEmailObjectStoreService }
3788
+ ];
3789
+ ImageUploadComponent.propDecorators = {
3790
+ block: [{ type: Input }],
3791
+ key: [{ type: Input }]
3792
+ };
3793
+
3794
+ /*
3795
+ * Copyright (c) 2024 Pobuca.
3796
+ * All rights reserved.
3797
+ */
3798
+ class BlockSettingsComponent {
3799
+ constructor(internalService, emailObject, networks) {
3800
+ this.internalService = internalService;
3801
+ this.emailObject = emailObject;
3802
+ this.networks = networks;
3803
+ this.block$ = this.internalService.currentEditingBlock$;
3804
+ }
3805
+ hasProperty(options, property) {
3806
+ return options.hasOwnProperty(property);
3807
+ }
3808
+ markForCheck() {
3809
+ this.emailObject.markForCheck();
3810
+ }
3811
+ socialNetworks(block) {
3812
+ return this.networks.filter(link => !block.networks.find(({ name }) => name === link)).sort();
3813
+ }
3814
+ addSocialNetwork({ value, source }, block) {
3815
+ block.networks.push({ name: value, href: '', label: '' });
3816
+ source.value = '';
3817
+ this.markForCheck();
3818
+ }
3819
+ removeSocialNetwork(network, block) {
3820
+ block.networks = block.networks.filter(n => n !== network);
3821
+ this.markForCheck();
3822
+ }
3823
+ getSocialIcon(network) {
3824
+ return getAssetByPath(`${network}.png`);
3825
+ }
3826
+ }
3827
+ BlockSettingsComponent.decorators = [
3828
+ { type: Component, args: [{
3829
+ selector: 'pb-block-settings',
3830
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<ng-container *ngIf=\"block$ | async as currentBlock\">\n <mat-accordion>\n <mat-expansion-panel expanded *ngIf=\"hasProperty(currentBlock.options, 'font')\">\n <mat-expansion-panel-header i18n=\"settings|Font\">\n Font\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-color [options]=\"currentBlock.options\" key=\"color\"></pb-color>\n <pb-font-styles [font]=\"currentBlock.options.font\"></pb-font-styles>\n <pb-line-height *ngIf=\"currentBlock.type !== 'social'\" [lineHeight]=\"currentBlock.options.lineHeight\">\n </pb-line-height>\n </ng-template>\n </mat-expansion-panel>\n\n <ng-container *ngIf=\"currentBlock.type === 'image'\">\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header i18n=\"settings|Image\">\n Image\n </mat-expansion-panel-header>\n <pb-image-upload [block]=\"currentBlock\"></pb-image-upload>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"settings|Image Attributes\">\n Attributes\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <div class=\"group f-large\">\n <mat-form-field appearance=\"outline\">\n <mat-label i18n=\"settings|Image Alt\">Alt</mat-label>\n <input matInput [(ngModel)]=\"currentBlock.options.title\" type=\"text\" i18n-placeholder\n placeholder=\"settings|Image Alt\" (input)=\"markForCheck()\" />\n </mat-form-field>\n <pb-align [model]=\"currentBlock.options\"></pb-align>\n </div>\n <pb-link [link]=\"currentBlock.options.link\"></pb-link>\n </ng-template>\n </mat-expansion-panel>\n </ng-container>\n\n <ng-container *ngIf=\"currentBlock.type === 'button'\">\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"settings|Button Text\">\n Button Text\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <mat-form-field appearance=\"outline\" style=\"width: 100%\">\n <mat-label i18n=\"settings|Button Text\">Button Text</mat-label>\n <input matInput [(ngModel)]=\"currentBlock.innerText\" type=\"text\" i18n-placeholder\n placeholder=\"settings|Button Text\" (input)=\"markForCheck()\" />\n </mat-form-field>\n </ng-template>\n </mat-expansion-panel>\n\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"settings|Background\">\n Background\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-color [options]=\"currentBlock.options\"></pb-color>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"settings|Button Attributes\">\n Attributes\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <div class=\"group two\" style=\"padding-bottom: 0\">\n <pb-align [model]=\"currentBlock.options\" [disabled]=\"currentBlock.options.fullWidth\"></pb-align>\n <mat-slide-toggle style=\"margin-top: -24px\" [(ngModel)]=\"currentBlock.options.fullWidth\"\n (change)=\"markForCheck()\">\n <ng-container i18n=\"settings|Button Full Width\">Full Width</ng-container>\n </mat-slide-toggle>\n </div>\n <pb-link [link]=\"currentBlock.options.link\"></pb-link>\n <pb-padding [padding]=\"currentBlock.options.innerPadding\"></pb-padding>\n </ng-template>\n </mat-expansion-panel>\n </ng-container>\n\n <mat-expansion-panel [expanded]=\"currentBlock.type === 'spacer'\"\n *ngIf=\"hasProperty(currentBlock.options, 'width') || hasProperty(currentBlock.options, 'height')\">\n <mat-expansion-panel-header i18n=\"settings|Sizes\">\n Sizes\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-width-height *ngIf=\"hasProperty(currentBlock.options, 'width')\" [model]=\"currentBlock.options.width\"\n label=\"width\"></pb-width-height>\n <pb-width-height *ngIf=\"hasProperty(currentBlock.options, 'height')\" [model]=\"currentBlock.options.height\"\n label=\"height\"></pb-width-height>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel *ngIf=\"hasProperty(currentBlock.options, 'background')\">\n <mat-expansion-panel-header i18n=\"settings|Background\">\n Background\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-color [options]=\"currentBlock.options.background\"></pb-color>\n </ng-template>\n backgroundColor\n </mat-expansion-panel>\n\n <mat-expansion-panel [expanded]=\"currentBlock.type === 'divider'\"\n *ngIf=\"hasProperty(currentBlock.options, 'border')\">\n <mat-expansion-panel-header>\n <ng-container i18n=\"settings|Divider Styles\" *ngIf=\"currentBlock.type === 'divider'\">Styles</ng-container>\n <ng-container i18n=\"settings|Border\" *ngIf=\"currentBlock.type !== 'divider'\">Border</ng-container>\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-border [border]=\"currentBlock.options.border\"></pb-border>\n </ng-template>\n </mat-expansion-panel>\n\n <ng-container *ngIf=\"currentBlock.type === 'social'\">\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"settings|Icons\">\n Icons\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <mat-form-field appearance=\"outline\" style=\"width: 100%\">\n <mat-label i18n=\"settings|Add new Network\">Add new Network</mat-label>\n <mat-select (selectionChange)=\"addSocialNetwork($event, currentBlock)\" [disabled]=\"!socialNetworks.length\">\n <mat-option style=\"text-transform: capitalize\" *ngFor=\"let link of socialNetworks(currentBlock)\"\n [value]=\"link\">\n {{ link }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel class=\"networks-list\" *ngFor=\"let network of currentBlock.networks\">\n <mat-expansion-panel-header style=\"text-transform: capitalize\">\n <img [class]=\"network.name\" [src]=\"getSocialIcon(network.name)\" [alt]=\"network.name\" />\n {{ network.name }}\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <div class=\"networks-list-item\">\n <div class=\"item-info\">\n <mat-form-field matLine appearance=\"outline\">\n <mat-label i18n=\"settings|Social Network Label\">Label</mat-label>\n <input matInput autocomplete=\"off\" [(ngModel)]=\"network.label\"\n i18n-placeholder=\"settings|Social Network Label\" placeholder=\"Label\" type=\"text\"\n (input)=\"markForCheck()\" />\n </mat-form-field>\n <button mat-stroked-button color=\"warn\" (click)=\"removeSocialNetwork(network, currentBlock)\">\n <mat-icon>delete_forever</mat-icon>\n </button>\n </div>\n <mat-form-field matLine appearance=\"outline\">\n <mat-label style=\"text-transform: capitalize\">\n {{ network.name }} <ng-container i18n=\"settings|Social Network Link\">Link</ng-container>\n </mat-label>\n <input autocomplete=\"off\" matInput [(ngModel)]=\"network.href\" type=\"url\" (input)=\"markForCheck()\" />\n </mat-form-field>\n </div>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"settings|Social Styles\">\n Styles\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <div class=\"group two\" style=\"padding-bottom: 0\">\n <mat-form-field appearance=\"outline\">\n <mat-label i18n=\"settings|Social Model\">Mode</mat-label>\n <mat-select (selectionChange)=\"markForCheck()\" i18n-placeholder=\"settings|Social Model\" placeholder=\"Mode\"\n [(value)]=\"currentBlock.options.mode\" disableRipple>\n <mat-option *ngFor=\"let mode of ['horizontal', 'vertical']\" [value]=\"mode\">\n {{ mode }}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <pb-align [model]=\"currentBlock.options\"></pb-align>\n </div>\n <pb-line-height [units]=\"['px']\" [lineHeight]=\"currentBlock.options.iconSize\" label=\"Icon Size\">\n </pb-line-height>\n <pb-padding [padding]=\"currentBlock.options.innerPadding\"></pb-padding>\n </ng-template>\n </mat-expansion-panel>\n </ng-container>\n\n <mat-expansion-panel *ngIf=\"hasProperty(currentBlock.options, 'padding')\">\n <mat-expansion-panel-header i18n=\"settings|Padding\">\n Padding\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-padding [padding]=\"currentBlock.options.padding\"></pb-padding>\n </ng-template>\n </mat-expansion-panel>\n </mat-accordion>\n</ng-container>\n",
3831
+ changeDetection: ChangeDetectionStrategy.OnPush,
3832
+ encapsulation: ViewEncapsulation.None,
3833
+ styles: ["/*!\n * Copyright (c) 2024 Pobuca.\n * All rights reserved.\n */.networks-list mat-expansion-panel-header .mat-content{place-items:center}.networks-list mat-expansion-panel-header img{width:20px;margin:0 .5rem 0 0;border-radius:3px}.networks-list mat-expansion-panel-header img.facebook{background-color:#3a5898}.networks-list mat-expansion-panel-header img.twitter{background-color:#d95988}.networks-list mat-expansion-panel-header img.github{background-color:#000}.networks-list mat-expansion-panel-header img.instagram{background-color:#3f729b}.networks-list mat-expansion-panel-header img.web{background-color:#4bade9}.networks-list mat-expansion-panel-header img.snapchat{background-color:#fffa54}.networks-list mat-expansion-panel-header img.youtube{background-color:#ea3323}.networks-list mat-expansion-panel-header img.vimeo{background-color:#53b4e7}.networks-list mat-expansion-panel-header img.medium{background-color:#000}.networks-list mat-expansion-panel-header img.soundcloud{background-color:#ef7f31}.networks-list mat-expansion-panel-header img.dribbble{background-color:#d95988}.networks-list mat-expansion-panel-header img.pinterest{background-color:#bd071c}.networks-list mat-expansion-panel-header img.linkedin{background-color:#0077b5}.networks-list mat-expansion-panel-header img.tumblr{background-color:#334356}.networks-list mat-expansion-panel-header img.xing{background-color:#296365}.networks-list mat-expansion-panel-header img.tiktok{background-color:#000}.networks-list-item{width:100%;display:grid;row-gap:.5rem}.networks-list-item .item-info{display:grid;grid-template-columns:2fr 1fr;-moz-column-gap:.5rem;column-gap:.5rem}.networks-list-item .item-info button{align-self:baseline;margin:.25rem 0;height:50px}.networks-list-item .item-info ::ng-deep .mat-form-field-wrapper{padding-bottom:0;margin-bottom:0}"]
3834
+ },] }
3835
+ ];
3836
+ BlockSettingsComponent.ctorParameters = () => [
3837
+ { type: PbUserInterfaceService },
3838
+ { type: PbEmailObjectStoreService },
3839
+ { type: Array, decorators: [{ type: Inject, args: [PB_SOCIAL_NETWORKS,] }] }
3840
+ ];
3841
+
3842
+ /*
3843
+ * Copyright (c) 2024 Pobuca.
3844
+ * All rights reserved.
3845
+ */
3846
+ class StructureSettingsComponent {
3847
+ constructor(pbInternalService, emailObject) {
3848
+ this.pbInternalService = pbInternalService;
3849
+ this.emailObject = emailObject;
3850
+ this.currentStructure$ = this.pbInternalService.currentEditingStructure$;
3851
+ }
3852
+ markForCheck() {
3853
+ this.emailObject.markForCheck();
3854
+ }
3855
+ }
3856
+ StructureSettingsComponent.decorators = [
3857
+ { type: Component, args: [{
3858
+ selector: 'pb-structure-settings',
3859
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<mat-accordion *ngIf=\"currentStructure$ | async as structure\">\n <mat-expansion-panel expanded>\n <mat-expansion-panel-header i18n=\"Structure settings|Change structure Background\">\n Background\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-color [options]=\"structure.options.background\" key=\"color\"></pb-color>\n <pb-image-upload [block]=\"structure.options.background\" key=\"url\" style=\"margin-bottom: 1em\"></pb-image-upload>\n <pb-back-repeat [disabled]=\"!structure.options.background.url\"\n [model]=\"structure.options.background\"></pb-back-repeat>\n <pb-width-height [disabled]=\"!structure.options.background.url\" [model]=\"structure.options.background.size\"\n label=\"size\">\n </pb-width-height>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"Structure settings|Change structure border\">\n Border\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-border [border]=\"structure.options.border\"></pb-border>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"Structure settings|Change structure padding\">\n Padding\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-padding [padding]=\"structure.options.padding\"></pb-padding>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"Structure settings|Change structure margin\">\n Margin\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-margin [margin]=\"structure.options.margin\"></pb-margin>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"Structure settings|Change structure layout\">\n Layout\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-gaps [gaps]=\"structure.options.gaps\"></pb-gaps>\n <mat-slide-toggle [disabled]=\"structure.type === 'cols_1'\" style=\"margin-top: -24px;\"\n [(ngModel)]=\"structure.options.disableResponsive\" i18n=\"Structure settings|Disable Responsive\"\n (change)=\"markForCheck()\">\n Disable Responsive\n </mat-slide-toggle>\n <mat-slide-toggle\n [(ngModel)]=\"structure.options.fullWidth\" i18n=\"Structure settings|Full Width\"\n (change)=\"markForCheck()\">\n Make section full width\n </mat-slide-toggle>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel *ngFor=\"let column of structure.options.columns; let key = index\">\n <mat-expansion-panel-header>\n <ng-container i18n=\"Structure settings|Structure Column\">Column</ng-container>\n {{ key + 1 }}\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <h3 class=\"divider\">\n <span i18n=\"Structure settings|Column Background\">Column Background</span>\n </h3>\n <pb-color [options]=\"column.background\" [showTransparent]=\"true\" key=\"color\"></pb-color>\n <h3 class=\"divider\">\n <span i18n=\"Structure settings|Column Border\">Column Border</span>\n </h3>\n <pb-border [border]=\"column.border\"></pb-border>\n <h3 class=\"divider\">\n <span i18n=\"Structure settings|Column Vertical Align\">Vertical Align</span>\n </h3>\n <pb-align [model]=\"column\" mode=\"vertical\"></pb-align>\n </ng-template>\n </mat-expansion-panel>\n</mat-accordion>\n",
3860
+ changeDetection: ChangeDetectionStrategy.OnPush,
3861
+ encapsulation: ViewEncapsulation.None,
3862
+ styles: [":host{display:block}"]
3863
+ },] }
3864
+ ];
3865
+ StructureSettingsComponent.ctorParameters = () => [
3866
+ { type: PbUserInterfaceService },
3867
+ { type: PbEmailObjectStoreService }
3868
+ ];
3869
+
3870
+ /*
3871
+ * Copyright (c) 2024 Pobuca.
3872
+ * All rights reserved.
3873
+ */
3874
+ class GeneralSettingsComponent {
3875
+ constructor(pbEmailObject) {
3876
+ this.pbEmailObject = pbEmailObject;
3877
+ this.generalOptions$ = this.pbEmailObject.generalEmailOptionsAsObservable$;
3878
+ }
3879
+ }
3880
+ GeneralSettingsComponent.decorators = [
3881
+ { type: Component, args: [{
3882
+ selector: 'pb-general-settings',
3883
+ template: "<!--\n ~ Copyright (c) 2024 Pobuca.\n ~ All rights reserved.\n -->\n\n<ng-container *ngIf=\"generalOptions$ | async as general\">\n <div class=\"mat-expansion-panel-body\" style=\"margin: 24px 0\">\n <mat-form-field appearance=\"outline\" style=\"width: 100%\">\n <mat-label i18n=\"General Settings|Email Name\">Email Name</mat-label>\n <input matInput [(ngModel)]=\"general.name\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"width: 100%\">\n <mat-label i18n=\"General Settings|Email Preview Text\">Preview Text</mat-label>\n <textarea matInput [(ngModel)]=\"general.previewText\"></textarea>\n <mat-hint i18n=\"General Settings|Email Preview Text Hint\">\n This text is displayed in the inbox of the recipient.\n </mat-hint>\n </mat-form-field>\n </div>\n\n <mat-accordion>\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"General Settings|Email Background\">\n Background\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-color [options]=\"general.background\" key=\"color\"></pb-color>\n <!-- <pb-image-upload [block]=\"structure.options.background\" key=\"url\" style=\"margin-bottom: 1em\"></pb-image-upload>\n <pb-back-repeat [disabled]=\"!structure.options.background.url\" [model]=\"structure.options.background\">\n </pb-back-repeat>\n <pb-width-height [model]=\"structure.options.background.size\" label=\"Background Size\"></pb-width-height> -->\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"General Settings|Email Attributes\">\n Attributes\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-width-height [model]=\"general.width\" label=\"width\"></pb-width-height>\n <pb-direction [model]=\"general\"></pb-direction>\n </ng-template>\n </mat-expansion-panel>\n\n <mat-expansion-panel>\n <mat-expansion-panel-header i18n=\"General Settings|Email Padding\">\n Padding\n </mat-expansion-panel-header>\n <ng-template matExpansionPanelContent>\n <pb-padding [padding]=\"general.padding\"></pb-padding>\n </ng-template>\n </mat-expansion-panel>\n </mat-accordion>\n</ng-container>\n",
3884
+ changeDetection: ChangeDetectionStrategy.OnPush,
3885
+ encapsulation: ViewEncapsulation.None,
3886
+ styles: [""]
3887
+ },] }
3888
+ ];
3889
+ GeneralSettingsComponent.ctorParameters = () => [
3890
+ { type: PbEmailObjectStoreService }
3891
+ ];
3892
+
3893
+ /*
3894
+ * Copyright (c) 2024 Pobuca.
3895
+ * All rights reserved.
3896
+ */
3897
+ class MarginComponent {
3898
+ constructor(emailObject) {
3899
+ this.emailObject = emailObject;
3900
+ }
3901
+ markForCheck() {
3902
+ this.emailObject.markForCheck();
3903
+ }
3904
+ }
3905
+ MarginComponent.decorators = [
3906
+ { type: Component, args: [{
3907
+ selector: 'pb-margin',
3908
+ template: `
3909
+ <div class="group">
3910
+ <mat-form-field appearance="outline">
3911
+ <mat-label i18n="Margin settings|Margin Top">Margin Top</mat-label>
3912
+ <input matInput type="number" min="0" step="1" [(ngModel)]="margin.top" (input)="markForCheck()" />
3913
+ </mat-form-field>
3914
+ <mat-form-field appearance="outline">
3915
+ <mat-label i18n="Margin settings|Margin Bottom">Margin Bottom</mat-label>
3916
+ <input matInput type="number" min="0" step="1" [(ngModel)]="margin.bottom" (input)="markForCheck()" />
3917
+ </mat-form-field>
3918
+ </div>
3919
+ `,
3920
+ changeDetection: ChangeDetectionStrategy.OnPush,
3921
+ styles: [`
3922
+ :host {
3923
+ display: block;
3924
+ width: 100%;
3925
+ }
3926
+ `]
3927
+ },] }
3928
+ ];
3929
+ MarginComponent.ctorParameters = () => [
3930
+ { type: PbEmailObjectStoreService }
3931
+ ];
3932
+ MarginComponent.propDecorators = {
3933
+ margin: [{ type: Input }]
3934
+ };
3935
+
3936
+ /*
3937
+ * Copyright (c) 2024 Pobuca.
3938
+ * All rights reserved.
3939
+ */
3940
+ class GapsComponent {
3941
+ constructor(emailObject) {
3942
+ this.emailObject = emailObject;
3943
+ }
3944
+ markForCheck() {
3945
+ this.emailObject.markForCheck();
3946
+ }
3947
+ }
3948
+ GapsComponent.decorators = [
3949
+ { type: Component, args: [{
3950
+ selector: 'pb-gaps',
3951
+ template: `
3952
+ <div class="group">
3953
+ <mat-form-field appearance="outline">
3954
+ <mat-label i18n="Gaps settings|Vertical Gaps">Vertical Gaps</mat-label>
3955
+ <input matInput type="number" min="0" step="1" [(ngModel)]="gaps[0]" (input)="markForCheck()" />
3956
+ </mat-form-field>
3957
+ <mat-form-field appearance="outline">
3958
+ <mat-label i18n="Gaps settings|Horizontal Gaps">Horizontal Gaps</mat-label>
3959
+ <input matInput type="number" min="0" step="1" [(ngModel)]="gaps[1]" (input)="markForCheck()" />
3960
+ </mat-form-field>
3961
+ </div>
3962
+ `,
3963
+ changeDetection: ChangeDetectionStrategy.OnPush,
3964
+ styles: [`
3965
+ :host {
3966
+ display: block;
3967
+ width: 100%;
3968
+ }
3969
+ `]
3970
+ },] }
3971
+ ];
3972
+ GapsComponent.ctorParameters = () => [
3973
+ { type: PbEmailObjectStoreService }
3974
+ ];
3975
+ GapsComponent.propDecorators = {
3976
+ gaps: [{ type: Input }]
3977
+ };
3978
+
3979
+ /*
3980
+ * Copyright (c) 2024 Pobuca.
3981
+ * All rights reserved.
3982
+ */
3983
+ /**
3984
+ * @ignore
3985
+ */
3986
+ const NOT_ALLOWED = 'This feature is disabled in free version.';
3987
+ /**
3988
+ * @internal
3989
+ */
3990
+ class FreeUsersMiddleware extends PbUserMiddlewaresService {
3991
+ constructor() {
3992
+ super();
3993
+ // tslint:disable-next-line: no-console
3994
+ console.warn('You use the Regular License of Angular Email Builder, some limitations are applied. More info on https://wlocalhost.org');
3995
+ }
3996
+ chooseTemplate() {
3997
+ throw new Error(NOT_ALLOWED);
3998
+ }
3999
+ exportFile(type) {
4000
+ return iif(() => type === 'json', deferOf(type), throwError(new Error(NOT_ALLOWED)));
4001
+ }
4002
+ importFile(file) {
4003
+ return iif(() => file.type === 'application/json', deferOf(file), throwError(new Error(NOT_ALLOWED)));
4004
+ }
4005
+ }
4006
+
4007
+ /*
4008
+ * Copyright (c) 2024 Pobuca.
4009
+ * All rights reserved.
4010
+ */
4011
+ /**
4012
+ * @internal
4013
+ * No limitations are applied for Paid users
4014
+ */
4015
+ class PaidUsersMiddleware extends PbUserMiddlewaresService {
4016
+ }
4017
+
4018
+ /*
4019
+ * Copyright (c) 2024 Pobuca.
4020
+ * All rights reserved.
4021
+ */
4022
+
4023
+ /*
4024
+ * Copyright (c) 2024 Pobuca.
4025
+ * All rights reserved.
4026
+ */
4027
+ class IpInterceptorInterceptor {
4028
+ constructor(userConfig, userInterface) {
4029
+ this.userConfig = userConfig;
4030
+ this.userInterface = userInterface;
4031
+ }
4032
+ intercept(request, next) {
4033
+ if (request.url.startsWith('https://ngb-api.wlocalhost.org')) {
4034
+ const notify = this.userInterface.notify('Loading, please wait ...', null, null);
4035
+ const { xApiKey } = Object.assign(Object.assign({}, PB_DEFAULT_CONFIG), this.userConfig);
4036
+ return next
4037
+ .handle(request.clone({
4038
+ setHeaders: {
4039
+ 'Content-Type': 'application/json',
4040
+ 'X-Api-Key': xApiKey
4041
+ },
4042
+ responseType: 'json'
4043
+ }))
4044
+ .pipe(tap((res) => {
4045
+ if (res.type === HttpEventType.Response) {
4046
+ notify.dismiss();
4047
+ }
4048
+ }));
4049
+ }
4050
+ else {
4051
+ return next.handle(request);
4052
+ }
4053
+ }
4054
+ }
4055
+ IpInterceptorInterceptor.ɵprov = i0.ɵɵdefineInjectable({ factory: function IpInterceptorInterceptor_Factory() { return new IpInterceptorInterceptor(i0.ɵɵinject(PB_CONFIG), i0.ɵɵinject(PbUserInterfaceService)); }, token: IpInterceptorInterceptor, providedIn: "root" });
4056
+ IpInterceptorInterceptor.decorators = [
4057
+ { type: Injectable, args: [{
4058
+ providedIn: 'root'
4059
+ },] }
4060
+ ];
4061
+ IpInterceptorInterceptor.ctorParameters = () => [
4062
+ { type: undefined, decorators: [{ type: Inject, args: [PB_CONFIG,] }] },
4063
+ { type: PbUserInterfaceService }
4064
+ ];
4065
+
4066
+ /*
4067
+ * Copyright (c) 2024 Pobuca.
4068
+ * All rights reserved.
4069
+ */
4070
+ /**
4071
+ * @internal
4072
+ */
4073
+ const LIBRARY_IS_PRO = new InjectionToken('Library environment', {
4074
+ providedIn: 'any',
4075
+ factory: () => {
4076
+ const { xApiKey } = inject(PB_CONFIG);
4077
+ return !(!xApiKey || xApiKey.length < 40 || xApiKey === PB_DEFAULT_CONFIG.xApiKey);
4078
+ }
4079
+ });
4080
+
4081
+ /*
4082
+ * Copyright (c) 2024 Pobuca.
4083
+ * All rights reserved.
4084
+ */
4085
+ /**
4086
+ * @internal
4087
+ * The free User Rest API service for Regular license.
4088
+ * No differences between other licenses for now, but might be in the future.
4089
+ */
4090
+ class FreeUsersRestApi extends PbUserRestApiService {
4091
+ constructor(http) {
4092
+ super(http);
4093
+ }
4094
+ }
4095
+
4096
+ /*
4097
+ * Copyright (c) 2024 Pobuca.
4098
+ * All rights reserved.
4099
+ */
4100
+
4101
+ /*
4102
+ * Copyright (c) 2024 Pobuca.
4103
+ * All rights reserved.
4104
+ */
4105
+ /**
4106
+ * @internal
4107
+ */
4108
+ class FreeUsersPbStorage extends PbStorageService {
4109
+ }
4110
+
4111
+ /*
4112
+ * Copyright (c) 2024 Pobuca.
4113
+ * All rights reserved.
4114
+ */
4115
+
4116
+ /*
4117
+ * Copyright (c) 2024 Pobuca.
4118
+ * All rights reserved.
4119
+ */
4120
+ /**
4121
+ * @internal
4122
+ * @param http
4123
+ */
4124
+ function createCustomRestApiService(http) {
4125
+ return new FreeUsersRestApi(http);
4126
+ }
4127
+ /**
4128
+ * @internal
4129
+ * @param libraryIsProEnv
4130
+ */
4131
+ function createUserMiddlewareService(libraryIsProEnv) {
4132
+ if (!libraryIsProEnv) {
4133
+ return new FreeUsersMiddleware();
4134
+ }
4135
+ else {
4136
+ return new PaidUsersMiddleware();
4137
+ }
4138
+ }
4139
+ /**
4140
+ * @internal
4141
+ * @param templateStorage
4142
+ */
4143
+ function createUsersIpStorage(templateStorage) {
4144
+ return new FreeUsersPbStorage(templateStorage);
4145
+ }
4146
+ /**
4147
+ * @internal
4148
+ * @param libraryIsProEnv
4149
+ * @param matBottomSheet
4150
+ * @param matDialog
4151
+ * @param userMiddleware
4152
+ * @param userRestApi
4153
+ */
4154
+ function createUserUploaderService(libraryIsProEnv, matBottomSheet, matDialog, userMiddleware, userRestApi) {
4155
+ if (!libraryIsProEnv) {
4156
+ return new ImageUploader(matBottomSheet, userMiddleware);
4157
+ }
4158
+ else {
4159
+ return new PaidUsersImageUploaderServiceService(matDialog, userMiddleware, userRestApi);
4160
+ }
4161
+ }
4162
+ const ɵ0 = {
4163
+ bounds: 'pb-builder-container',
4164
+ theme: 'bubble',
4165
+ format: 'html',
4166
+ trackChanges: 'all',
4167
+ suppressGlobalRegisterWarning: true
4168
+ };
4169
+ class PbEmailBuilderModule {
4170
+ constructor(pbMiddlewaresService, userImageUploader, libraryIsPro) {
4171
+ if (!libraryIsPro && !(pbMiddlewaresService instanceof FreeUsersMiddleware)) {
4172
+ throw new Error('Upgrade to an Extended or Commercial License to use Custom Middlewares.');
4173
+ }
4174
+ if (!libraryIsPro && !(userImageUploader instanceof ImageUploader)) {
4175
+ throw new Error('Upgrade to an Extended or Commercial License to use Custom Image Uploader.');
4176
+ }
4177
+ }
4178
+ /**
4179
+ * @deprecated use PbEmailBuilderModule.withConfig(userConfig) instead
4180
+ * @internal
4181
+ */
4182
+ static forRoot(userConfig = {}) {
4183
+ return PbEmailBuilderModule.withConfig(userConfig);
4184
+ }
4185
+ /**
4186
+ * Import module with configurations
4187
+ * @param userConfig Configurations
4188
+ */
4189
+ static withConfig(userConfig = {}) {
4190
+ return {
4191
+ ngModule: PbEmailBuilderModule,
4192
+ providers: [
4193
+ PbEmailBuilderService,
4194
+ PbEmailObjectStoreService,
4195
+ PbUserInterfaceService,
4196
+ { provide: PB_CONFIG, useValue: userConfig },
4197
+ {
4198
+ provide: PbUserMiddlewaresService,
4199
+ useFactory: createUserMiddlewareService,
4200
+ deps: [LIBRARY_IS_PRO]
4201
+ },
4202
+ {
4203
+ provide: PbStorageService,
4204
+ useFactory: createUsersIpStorage,
4205
+ deps: [PB_TEMPLATES_TEMPORARY_STORAGE]
4206
+ },
4207
+ {
4208
+ provide: PbUserImageUploaderService,
4209
+ useFactory: createUserUploaderService,
4210
+ deps: [LIBRARY_IS_PRO, MatBottomSheet, MatDialog, PbUserMiddlewaresService, PbUserRestApiService]
4211
+ },
4212
+ {
4213
+ provide: PbUserRestApiService,
4214
+ useFactory: createCustomRestApiService,
4215
+ deps: [HttpClient]
4216
+ }
4217
+ ]
4218
+ };
4219
+ }
4220
+ }
4221
+ PbEmailBuilderModule.decorators = [
4222
+ { type: NgModule, args: [{
4223
+ imports: [
4224
+ CommonModule,
4225
+ HttpClientModule,
4226
+ QuillModule,
4227
+ FlexLayoutModule,
4228
+ DragDropModule,
4229
+ FormsModule,
4230
+ ColorChromeModule,
4231
+ MatButtonModule,
4232
+ MatIconModule,
4233
+ MatFormFieldModule,
4234
+ MatInputModule,
4235
+ MatTabsModule,
4236
+ MatSliderModule,
4237
+ MatSelectModule,
4238
+ MatSlideToggleModule,
4239
+ MatButtonToggleModule,
4240
+ MatDividerModule,
4241
+ MatTooltipModule,
4242
+ MatDialogModule,
4243
+ MatSnackBarModule,
4244
+ MatProgressBarModule,
4245
+ MatMenuModule,
4246
+ MatSidenavModule,
4247
+ MatToolbarModule,
4248
+ MatListModule,
4249
+ MatBottomSheetModule,
4250
+ MatDividerModule,
4251
+ MatExpansionModule,
4252
+ ResizableModule,
4253
+ ScrollingModule,
4254
+ PortalModule
4255
+ ],
4256
+ declarations: [
4257
+ PbEmailBuilderComponent,
4258
+ StructureComponent,
4259
+ BlockComponent,
4260
+ DynamicComponentDirective,
4261
+ PreviewTemplateComponent,
4262
+ TextElementComponent,
4263
+ ImageComponent,
4264
+ ButtonComponent,
4265
+ DividerComponent,
4266
+ SpacerComponent,
4267
+ SocialComponent,
4268
+ BuilderContainerComponent,
4269
+ FontStylesComponent,
4270
+ PaddingComponent,
4271
+ MarginComponent,
4272
+ GapsComponent,
4273
+ LineHeightComponent,
4274
+ WidthHeightComponent,
4275
+ BorderComponent,
4276
+ ColorComponent,
4277
+ LinkComponent,
4278
+ AlignComponent,
4279
+ DirectionComponent,
4280
+ BackRepatComponent,
4281
+ ConfirmDialogComponent,
4282
+ ImageUploadComponent,
4283
+ BlockSettingsComponent,
4284
+ StructureSettingsComponent,
4285
+ GeneralSettingsComponent,
4286
+ UploadBottomSheetDialogComponent,
4287
+ UploadImageGalleryComponent,
4288
+ TemplateListDialogComponent,
4289
+ SlugifyPipe,
4290
+ ImportDialogComponent
4291
+ ],
4292
+ exports: [PbEmailBuilderComponent, PreviewTemplateComponent, SlugifyPipe],
4293
+ entryComponents: [
4294
+ TextElementComponent,
4295
+ ImageComponent,
4296
+ ButtonComponent,
4297
+ DividerComponent,
4298
+ SpacerComponent,
4299
+ SocialComponent,
4300
+ ConfirmDialogComponent,
4301
+ UploadBottomSheetDialogComponent,
4302
+ UploadImageGalleryComponent,
4303
+ TemplateListDialogComponent,
4304
+ ImportDialogComponent
4305
+ ],
4306
+ providers: [
4307
+ {
4308
+ provide: QUILL_CONFIG_TOKEN,
4309
+ useValue: ɵ0
4310
+ },
4311
+ { provide: HTTP_INTERCEPTORS, useClass: IpInterceptorInterceptor, multi: true },
4312
+ // { provide: PB_BLOCK_ELEMENT, useClass: TextBlock, multi: true },
4313
+ PbEmailBuilderService,
4314
+ PbEmailObjectStoreService,
4315
+ PbUserInterfaceService
4316
+ ]
4317
+ },] }
4318
+ ];
4319
+ PbEmailBuilderModule.ctorParameters = () => [
4320
+ { type: PbUserMiddlewaresService },
4321
+ { type: PbUserImageUploaderService },
4322
+ { type: Boolean, decorators: [{ type: Inject, args: [LIBRARY_IS_PRO,] }] }
4323
+ ];
4324
+
4325
+ /*
4326
+ * Copyright (c) 2024 Pobuca.
4327
+ * All rights reserved.
4328
+ */
4329
+
4330
+ /**
4331
+ * Generated bundle index. Do not edit.
4332
+ */
4333
+
4334
+ export { AIPBlock, ButtonBlock, Defaults, DividerBlock, ETemplatesStorage, ImageUploader as FreeUsersImageUploader, ImageBlock, PBEmail, PB_BLOCKS, PB_CONFIG, PB_DEFAULT_BLOCKS, PB_DEFAULT_CONFIG, PB_DEFAULT_FALLBACK_FONTS, PB_DEFAULT_GOOGLE_FONTS, PB_DEFAULT_SOCIAL_NETWORKS, PB_DEFAULT_STRUCTURES, PB_FALLBACK_FONTS, PB_GOOGLE_FONTS, PB_SOCIAL_NETWORKS, PB_STORAGE_FACTORY, PB_STRUCTURES, PB_TEMPLATES_TEMPORARY_STORAGE, PbEmailBuilderComponent, PbEmailBuilderModule, PbEmailBuilderService, PbStorageService, PbUserImageUploaderService, PbUserMiddlewaresService, PbUserRestApiService, PreviewTemplateComponent, SlugifyPipe, SocialBlock, SpacerBlock, Structure, TextBlock, bytesToSize, cloneDeep, createBackground, createBorder, createCustomRestApiService, createFont, createLineHeight, createMargin, createPadding, createUserMiddlewareService, createUserUploaderService, createUsersIpStorage, createWidthHeight, defaultColumnsOptions, defaultsDeep, deferOf, getAssetByPath, isEqual, ɵ0, PbEmailObjectStoreService as ɵa, PbUserInterfaceService as ɵb, BackRepatComponent as ɵba, ConfirmDialogComponent as ɵbb, ImageUploadComponent as ɵbc, BlockSettingsComponent as ɵbd, StructureSettingsComponent as ɵbe, GeneralSettingsComponent as ɵbf, UploadBottomSheetDialogComponent as ɵbg, UploadImageGalleryComponent as ɵbh, TemplateListDialogComponent as ɵbi, ImportDialogComponent as ɵbj, IpInterceptorInterceptor as ɵbk, LIBRARY_IS_PRO as ɵbl, FreeUsersRestApi as ɵc, FreeUsersPbStorage as ɵd, StructureComponent as ɵe, BlockComponent as ɵf, DynamicComponentDirective as ɵg, TextElementComponent as ɵh, AbstractBlock as ɵi, ImageComponent as ɵj, ButtonComponent as ɵk, DividerComponent as ɵl, SpacerComponent as ɵm, SocialComponent as ɵn, BuilderContainerComponent as ɵo, FontStylesComponent as ɵp, PaddingComponent as ɵq, MarginComponent as ɵr, GapsComponent as ɵs, LineHeightComponent as ɵt, WidthHeightComponent as ɵu, BorderComponent as ɵv, ColorComponent as ɵw, LinkComponent as ɵx, AlignComponent as ɵy, DirectionComponent as ɵz };
4335
+ //# sourceMappingURL=pobuca-email-builder.js.map