@social-mail/social-mail-client 1.8.332 → 1.8.334

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 (29) hide show
  1. package/dist/site-editor/editor/HtmlPageEditor.d.ts +1 -1
  2. package/dist/site-editor/editor/HtmlPageEditor.d.ts.map +1 -1
  3. package/dist/site-editor/editor/HtmlPageEditor.js.map +1 -1
  4. package/dist/site-editor/editor/ui/SelectionUI.d.ts.map +1 -1
  5. package/dist/site-editor/editor/ui/SelectionUI.js +52 -21
  6. package/dist/site-editor/editor/ui/SelectionUI.js.map +1 -1
  7. package/dist/site-editor/tools/ToolService.d.ts +21 -0
  8. package/dist/site-editor/tools/ToolService.d.ts.map +1 -0
  9. package/dist/site-editor/tools/ToolService.js +35 -0
  10. package/dist/site-editor/tools/ToolService.js.map +1 -0
  11. package/dist/site-editor/tools/basic/BasicShapes.d.ts +5 -4
  12. package/dist/site-editor/tools/basic/BasicShapes.d.ts.map +1 -1
  13. package/dist/site-editor/tools/basic/BasicShapes.js +23 -41
  14. package/dist/site-editor/tools/basic/BasicShapes.js.map +1 -1
  15. package/dist/site-editor/tools/designs/Designs.d.ts +5 -4
  16. package/dist/site-editor/tools/designs/Designs.d.ts.map +1 -1
  17. package/dist/site-editor/tools/designs/Designs.js +23 -41
  18. package/dist/site-editor/tools/designs/Designs.js.map +1 -1
  19. package/dist/site-editor-app/SiteEditorApp.pack.js +137 -104
  20. package/dist/site-editor-app/SiteEditorApp.pack.js.map +1 -1
  21. package/dist/site-editor-app/SiteEditorApp.pack.min.js +1 -1
  22. package/dist/site-editor-app/SiteEditorApp.pack.min.js.map +1 -1
  23. package/dist/tsconfig.tsbuildinfo +1 -1
  24. package/package.json +1 -1
  25. package/src/site-editor/editor/HtmlPageEditor.tsx +2 -1
  26. package/src/site-editor/editor/ui/SelectionUI.tsx +75 -32
  27. package/src/site-editor/tools/ToolService.ts +32 -0
  28. package/src/site-editor/tools/basic/BasicShapes.tsx +15 -38
  29. package/src/site-editor/tools/designs/Designs.tsx +15 -38
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@social-mail/social-mail-client",
3
- "version": "1.8.332",
3
+ "version": "1.8.334",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -95,6 +95,8 @@ export default class HtmlPageEditor extends AtomControl {
95
95
 
96
96
  public maxWidth = desktopWidth;
97
97
 
98
+ public contentEditor: HTMLIFrameElement;
99
+
98
100
 
99
101
  public get modifiedDocument() {
100
102
  if (!this.undoRedo.changed) {
@@ -231,7 +233,6 @@ export default class HtmlPageEditor extends AtomControl {
231
233
  private lastInit: Promise<void>;
232
234
  private initCT: CancelToken;
233
235
 
234
- private contentEditor: HTMLIFrameElement;
235
236
 
236
237
 
237
238
  private readonly dropTarget: SelectedElement = new SelectedElement(this);
@@ -43,6 +43,9 @@ const setCapture = (editor: HtmlPageEditor, element: HTMLElement, e: PointerEven
43
43
  const selectedElement = selection.element;
44
44
  const selectedParent = selectedElement.parentElement;
45
45
 
46
+ const frameDocument = selectedElement.ownerDocument;
47
+ const frame = editor.contentEditor;
48
+
46
49
 
47
50
  const insetAttribute = `${prefix}-inset`;
48
51
  const widthAttribute = `${prefix}-width`;
@@ -52,15 +55,10 @@ const setCapture = (editor: HtmlPageEditor, element: HTMLElement, e: PointerEven
52
55
  const oldHeight = selectedElement.getAttribute(heightAttribute);
53
56
  const oldInset = selectedElement.getAttribute(insetAttribute);
54
57
 
55
- let newInset;
56
- let newHeight;
57
- let newWidth;
58
-
59
58
  const records = [] as MutationRecord[];
60
59
 
61
60
 
62
61
  const style = selectedElement.ownerDocument.defaultView.getComputedStyle(selectedElement);
63
- const { left = "0", top = "0", right = "0", bottom = "0" } = style;
64
62
  const width = selectedParent.offsetWidth;
65
63
  const height = selectedParent.offsetHeight;
66
64
 
@@ -70,39 +68,51 @@ const setCapture = (editor: HtmlPageEditor, element: HTMLElement, e: PointerEven
70
68
 
71
69
  const d = undoRedo.beginPause();
72
70
 
71
+ const left = parseFloat(style.left || "0");
72
+ const top = parseFloat(style.top || "0");
73
+ const bottom = parseFloat(style.bottom || "0");
74
+ const right = parseFloat(style.right || "0");
75
+
76
+ let moved = false;
77
+
78
+ let changed = false;
79
+
73
80
  const captureMove = (evt: PointerEvent) => {
74
81
  const dx = evt.clientX - sx;
75
82
  const dy = evt.clientY - sy;
83
+ if (dx === 0 && dy === 0) {
84
+ return;
85
+ }
76
86
  const ri = {
77
- left: parseFloat(left),
78
- top: parseFloat(top),
79
- right: parseFloat(right),
80
- bottom: parseFloat(bottom),
87
+ left,
88
+ top,
89
+ right,
90
+ bottom,
81
91
  sx,
82
92
  sy,
83
93
  dx,
84
94
  dy
85
95
  };
96
+ changed = true;
86
97
  const r = fx(ri);
87
- newInset = `${ps(r.top, height)}% ${ps(r.right, width)}% ${ps(r.bottom, height)}% ${ps(r.left, width)}%`;
88
- selectedElement.setAttribute(insetAttribute, newInset);
89
- // if (/^img$/i.test(selectedElement.tagName)) {
90
- // image needs width/height as well...
91
- if (!r.move) {
92
- let widthDiff = -r.left;
93
- let heightDiff = -r.top;
94
- if (ri.bottom === r.bottom) {
95
- heightDiff -= r.bottom;
96
- }
97
- if (ri.right === r.right) {
98
- widthDiff -= r.right;
99
- }
100
- newWidth = ps(width + widthDiff, width) + "%";
101
- selectedElement.setAttribute(widthAttribute, newWidth);
102
- newHeight = ps(height + heightDiff, height) + "%";
103
- selectedElement.setAttribute(heightAttribute, newHeight);
98
+ const inset = `${ps(r.top, height)}% ${ps(r.right, width)}% ${ps(r.bottom, height)}% ${ps(r.left, width)}%`;
99
+ selectedElement.setAttribute(insetAttribute, inset);
100
+
101
+ if (!r.move) {
102
+ moved = true;
103
+ let widthDiff = -r.left;
104
+ let heightDiff = -r.top;
105
+ if (ri.bottom === r.bottom) {
106
+ heightDiff -= r.bottom;
107
+ }
108
+ if (ri.right === r.right) {
109
+ widthDiff -= r.right;
104
110
  }
105
- // }
111
+ const newWidth = ps(width + widthDiff, width) + "%";
112
+ selectedElement.setAttribute(widthAttribute, newWidth);
113
+ const newHeight = ps(height + heightDiff, height) + "%";
114
+ selectedElement.setAttribute(heightAttribute, newHeight);
115
+ }
106
116
 
107
117
  setTimeout(() => {
108
118
  selection.updateRect();
@@ -112,13 +122,47 @@ const setCapture = (editor: HtmlPageEditor, element: HTMLElement, e: PointerEven
112
122
 
113
123
  element.addEventListener("pointermove", captureMove);
114
124
  element.setPointerCapture(e.pointerId);
115
- const release = (e1) => {
125
+ const release = (e1: PointerEvent) => {
116
126
  element.releasePointerCapture(e.pointerId);
117
127
  element.removeEventListener("pointermove", captureMove);
118
128
  element.removeEventListener("pointerup", release);
119
129
  captureMove(e1);
120
130
  d.resume();
121
131
 
132
+ if (!changed) {
133
+
134
+ // try to select an element...
135
+ const frameRect = frame.getBoundingClientRect();
136
+ let { clientX, clientY } = e1;
137
+ clientX -= frameRect.left;
138
+ clientY -= frameRect.top;
139
+
140
+ const elementAtPoint = frameDocument.elementFromPoint(clientX, clientY);
141
+ if (!elementAtPoint) {
142
+ return;
143
+ }
144
+
145
+ if (elementAtPoint === selectedElement) {
146
+ return;
147
+ }
148
+
149
+ const body = frameDocument.body;
150
+
151
+ let start = elementAtPoint;
152
+ while(start) {
153
+ if (start === selectedParent) {
154
+ // we need to select different child
155
+ editor.selection.update(elementAtPoint as any);
156
+ break;
157
+ }
158
+ start = start.parentElement;
159
+ if (start === body) {
160
+ return;
161
+ }
162
+ }
163
+
164
+ return;
165
+ }
122
166
  // push records...
123
167
  records.push({
124
168
  type: "attributes",
@@ -128,7 +172,7 @@ const setCapture = (editor: HtmlPageEditor, element: HTMLElement, e: PointerEven
128
172
  attributeNamespace: "",
129
173
  } as MutationRecord);
130
174
 
131
- if (newWidth) {
175
+ if (moved) {
132
176
  records.push({
133
177
  type: "attributes",
134
178
  oldValue: oldWidth,
@@ -136,8 +180,6 @@ const setCapture = (editor: HtmlPageEditor, element: HTMLElement, e: PointerEven
136
180
  attributeName: widthAttribute,
137
181
  attributeNamespace: "",
138
182
  } as MutationRecord);
139
- }
140
- if (newHeight) {
141
183
  records.push({
142
184
  type: "attributes",
143
185
  oldValue: oldHeight,
@@ -222,7 +264,8 @@ const eventPointerDown = (editor: HtmlPageEditor, e: PointerEvent) => {
222
264
 
223
265
  export function SelectionUI() {
224
266
  return <selected-element data-element="selection"
225
- data-edit={BindEditor.oneWay((e) => /absolute|fixed/i.test(e.selection.currentStyle.position) ? "1" : null)}
267
+ data-edit={BindEditor.oneWay((e) => /relative/i.test(e.selection.parentStyle.position)
268
+ && /absolute|fixed/i.test(e.selection.currentStyle.position) ? "1" : null)}
226
269
  event-pointerdown={BindEditor.event(eventPointerDown as any)}
227
270
  style-left={BindEditor.oneWay((e) => e.selection.left)}
228
271
  style-top={BindEditor.oneWay((e) => e.selection.top)}
@@ -0,0 +1,32 @@
1
+ import DISingleton from "@web-atoms/core/dist/di/DISingleton";
2
+ import FetchBuilder from "@web-atoms/core/dist/services/FetchBuilder";
3
+ import IPagedList from "@web-atoms/entity/dist/models/IPagedList";
4
+
5
+ export interface ISiteTemplate {
6
+ id: any;
7
+ tags: string[];
8
+ name: string;
9
+ host: string;
10
+ preview: string;
11
+ previewMobile: string;
12
+ template: string;
13
+ url: string;
14
+ }
15
+
16
+ @DISingleton()
17
+ export default class ToolService {
18
+
19
+
20
+ designs({ search, tags, start = 0, size = 50, cancelToken }) {
21
+ return FetchBuilder.get(`https://tools.esocialmail.com/social-mail/site/list/designs`)
22
+ .queries({
23
+ search,
24
+ tags,
25
+ start,
26
+ size
27
+ })
28
+ .cancelToken(cancelToken)
29
+ .asJson<IPagedList<ISiteTemplate>>();
30
+ }
31
+
32
+ }
@@ -1,59 +1,33 @@
1
1
  import FetchBuilder from "@web-atoms/core/dist/services/FetchBuilder";
2
2
  import { CacheTTL } from "../../../common/cache/CacheTTL";
3
3
  import { packageVersion } from "../../../common/PackageInfo";
4
- import { Sql } from "../../../common/Sql";
5
- import { ChannelEmail, IChannelEmail } from "../../../model/model";
6
4
  import ToolSection, { IToolItem } from "../section/ToolSection";
5
+ import ToolService, { ISiteTemplate } from "../ToolService";
6
+ import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
7
7
 
8
8
  const cacheVersion = packageVersion;
9
9
  const cacheSeconds = CacheTTL.seconds.oneDay;
10
10
 
11
11
 
12
- export default class BasicShapes extends ToolSection<IChannelEmail> {
12
+ export default class BasicShapes extends ToolSection<ISiteTemplate> {
13
+
14
+ @InjectProperty
15
+ tools: ToolService;
13
16
 
14
17
  get headerName() {
15
18
  return "Shapes";
16
19
  }
17
20
 
18
21
  async searchItems({ start, search, cancelToken }) {
19
- const contentTypes = ["image/%", "text/html"];
20
- const shape = "shape";
21
- let q = this.entityService.query(ChannelEmail, "libraryEmails")
22
- .where({ contentTypes, shape }, (p) => (x) => x.email.attachments.some((e) =>
23
- Sql.text.iLikeAny(e.contentType, p.contentTypes)
24
- && e.email.emailTags.some((t) => t.tag.parent.lowerCaseName === p.shape)
25
- ))
26
- ;
27
- if(search) {
28
- search += "%";
29
- q = q.where({ search }, (p) => (x) => Sql.text.iLike(x.email.subject, p.search));
30
- }
31
- return q
32
- .include((x) => [x.email.attachments, x.email.emailTags.forEach((t) => t.tag)])
33
- .toPagedList({
34
- start,
35
- cancelToken,
36
- size: 25,
37
- cacheSeconds,
38
- cacheVersion
39
- });
22
+ return this.tools.designs({ search, tags: "Shape", start, cancelToken, size: 50 });
40
23
  }
41
24
 
42
- asToolItem(x: IChannelEmail): IToolItem {
43
-
44
- const { email, emailID: id } = x;
45
- const { attachments: files, subject: title } = email;
25
+ asToolItem(x: ISiteTemplate): IToolItem {
46
26
 
47
- const preview = this.getFileType("preview.", ... files);
48
- const { src, href } = this.getFileType("template.", ... files);
27
+ const { id, preview, name: title, template: templateUrl } = x;
49
28
 
50
29
  const template = async () => {
51
- if (src) {
52
- const img = document.createElement("img");
53
- img.src = src;
54
- return img;
55
- }
56
- const text = await FetchBuilder.get(href).asText();
30
+ const text = await FetchBuilder.get(templateUrl).asText();
57
31
  const parser = new DOMParser();
58
32
  const d = parser.parseFromString(text, "text/html");
59
33
  const t = d.body.querySelector("template");
@@ -64,10 +38,13 @@ export default class BasicShapes extends ToolSection<IChannelEmail> {
64
38
 
65
39
  return {
66
40
  title,
67
- files,
41
+ files: [],
68
42
  id,
69
43
  copyAssets: true,
70
- preview,
44
+ preview: {
45
+ src: preview,
46
+ href: void 0
47
+ },
71
48
  template
72
49
  };
73
50
  }
@@ -1,59 +1,33 @@
1
1
  import FetchBuilder from "@web-atoms/core/dist/services/FetchBuilder";
2
2
  import { CacheTTL } from "../../../common/cache/CacheTTL";
3
3
  import { packageVersion } from "../../../common/PackageInfo";
4
- import { Sql } from "../../../common/Sql";
5
- import { ChannelEmail, IChannelEmail } from "../../../model/model";
6
4
  import ToolSection, { IToolItem } from "../section/ToolSection";
5
+ import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
6
+ import ToolService, { ISiteTemplate } from "../ToolService";
7
7
 
8
8
  const cacheVersion = packageVersion;
9
9
  const cacheSeconds = CacheTTL.seconds.oneDay;
10
10
 
11
11
 
12
- export default class Designs extends ToolSection<IChannelEmail> {
12
+ export default class Designs extends ToolSection<ISiteTemplate> {
13
+
14
+ @InjectProperty
15
+ tools: ToolService;
13
16
 
14
17
  get headerName() {
15
18
  return "Designs";
16
19
  }
17
20
 
18
21
  async searchItems({ start, search, cancelToken }) {
19
- const contentTypes = ["image/%", "text/html"];
20
- const shape = "design";
21
- let q = this.entityService.query(ChannelEmail, "libraryEmails")
22
- .where({ contentTypes, shape }, (p) => (x) => x.email.attachments.some((e) =>
23
- Sql.text.iLikeAny(e.contentType, p.contentTypes)
24
- && e.email.emailTags.some((t) => t.tag.lowerCaseName === p.shape)
25
- ))
26
- ;
27
- if(search) {
28
- search += "%";
29
- q = q.where({ search }, (p) => (x) => Sql.text.iLike(x.email.subject, p.search));
30
- }
31
- return q
32
- .include((x) => [x.email.attachments, x.email.emailTags.forEach((t) => t.tag)])
33
- .toPagedList({
34
- start,
35
- cancelToken,
36
- size: 25,
37
- cacheSeconds,
38
- cacheVersion
39
- });
22
+ return this.tools.designs({ search, tags: "Shape", start, cancelToken, size: 50 });
40
23
  }
41
24
 
42
- asToolItem(x: IChannelEmail): IToolItem {
43
-
44
- const { email, emailID: id } = x;
45
- const { attachments: files, subject: title } = email;
25
+ asToolItem(x: ISiteTemplate): IToolItem {
46
26
 
47
- const preview = this.getFileType("preview.", ... files);
48
- const { src, href } = this.getFileType("template.", ... files);
27
+ const { id, preview, name: title, template: templateUrl } = x;
49
28
 
50
29
  const template = async () => {
51
- if (src) {
52
- const img = document.createElement("img");
53
- img.src = src;
54
- return img;
55
- }
56
- const text = await FetchBuilder.get(href).asText();
30
+ const text = await FetchBuilder.get(templateUrl).asText();
57
31
  const parser = new DOMParser();
58
32
  const d = parser.parseFromString(text, "text/html");
59
33
  const t = d.body.querySelector("template");
@@ -64,10 +38,13 @@ export default class Designs extends ToolSection<IChannelEmail> {
64
38
 
65
39
  return {
66
40
  title,
67
- files,
41
+ files: [],
68
42
  id,
69
43
  copyAssets: true,
70
- preview,
44
+ preview: {
45
+ src: preview,
46
+ href: void 0
47
+ },
71
48
  template
72
49
  };
73
50
  }