@social-mail/social-mail-client 1.2.237 → 1.2.239

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 (32) hide show
  1. package/dist/admin/AdminAppIndex.pack.js +212 -28
  2. package/dist/admin/AdminAppIndex.pack.js.map +1 -1
  3. package/dist/admin/AdminAppIndex.pack.min.js +3 -3
  4. package/dist/admin/AdminAppIndex.pack.min.js.map +1 -1
  5. package/dist/common/SocialMailApp.d.ts +1 -0
  6. package/dist/common/SocialMailApp.d.ts.map +1 -1
  7. package/dist/common/SocialMailApp.js.map +1 -1
  8. package/dist/common/fileUrl.d.ts.map +1 -1
  9. package/dist/common/fileUrl.js +3 -2
  10. package/dist/common/fileUrl.js.map +1 -1
  11. package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.d.ts +3 -1
  12. package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.d.ts.map +1 -1
  13. package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.js +7 -23
  14. package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.js.map +1 -1
  15. package/dist/common/pages/websites/templates/TemplateService.d.ts +14 -1
  16. package/dist/common/pages/websites/templates/TemplateService.d.ts.map +1 -1
  17. package/dist/common/pages/websites/templates/TemplateService.js +200 -3
  18. package/dist/common/pages/websites/templates/TemplateService.js.map +1 -1
  19. package/dist/site-editor/editor/WebSitePageEditor.d.ts.map +1 -1
  20. package/dist/site-editor/editor/WebSitePageEditor.js +2 -0
  21. package/dist/site-editor/editor/WebSitePageEditor.js.map +1 -1
  22. package/dist/tsconfig.tsbuildinfo +1 -1
  23. package/dist/web/AppIndex.pack.js +212 -28
  24. package/dist/web/AppIndex.pack.js.map +1 -1
  25. package/dist/web/AppIndex.pack.min.js +3 -3
  26. package/dist/web/AppIndex.pack.min.js.map +1 -1
  27. package/package.json +1 -1
  28. package/src/common/SocialMailApp.ts +1 -0
  29. package/src/common/fileUrl.ts +3 -2
  30. package/src/common/pages/websites/templates/ChooseWebSiteTemplatePage.tsx +8 -33
  31. package/src/common/pages/websites/templates/TemplateService.ts +238 -2
  32. package/src/site-editor/editor/WebSitePageEditor.tsx +2 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@social-mail/social-mail-client",
3
- "version": "1.2.237",
3
+ "version": "1.2.239",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -3,6 +3,7 @@ import type { IUser } from "../model/model";
3
3
  interface ISocialMailConfig {
4
4
  path: string,
5
5
  name: string,
6
+ cdn: string,
6
7
  externalLogin: string
7
8
  }
8
9
 
@@ -2,10 +2,11 @@ import { IAppFile } from "../model/model";
2
2
  import { apiPath } from "./apiPath";
3
3
 
4
4
  export const imageUrl = (site: IAppFile, file: IAppFile, size?: number) => {
5
+ const name = encodeURIComponent(file.name);
5
6
  if (!size) {
6
- return apiPath(`/api/site/asset/webp/${site.appFileID}/${file.appFileID}/${file.fileContentID}/${file.name}.webp`);
7
+ return apiPath(`/api/site/asset/webp/${site.appFileID}/${file.appFileID}/${file.fileContentID}/${name}.webp`);
7
8
  }
8
- return apiPath(`/api/site/asset/webp(${size})/${site.appFileID}/${file.appFileID}/${file.fileContentID}/${file.name}.${size}.webp`);
9
+ return apiPath(`/api/site/asset/webp(${size})/${site.appFileID}/${file.appFileID}/${file.fileContentID}/${name}.${size}.webp`);
9
10
  };
10
11
 
11
12
  export const srcSetUrl = (site: IAppFile, file: IAppFile) => {
@@ -1,5 +1,5 @@
1
1
  import { PopupWindowPage } from "@web-atoms/web-controls/dist/mobile-app/MobileApp";
2
- import { IAppFile, IWebSiteFolder } from "../../../../model/model";
2
+ import { AppFile, IAppFile, IWebSiteFolder } from "../../../../model/model";
3
3
  import XNode from "@web-atoms/core/dist/core/XNode";
4
4
  import Action from "@web-atoms/core/dist/view-model/Action";
5
5
  import { UMD } from "@web-atoms/core/dist/core/types";
@@ -14,6 +14,8 @@ import TemplateService from "./TemplateService";
14
14
  import styled from "@web-atoms/core/dist/style/styled";
15
15
  import Bind from "@web-atoms/core/dist/core/Bind";
16
16
  import { AddIconTextButton } from "../../../controls/buttons/IconButton";
17
+ import SocialMailApp from "../../../SocialMailApp";
18
+ import EntityService from "../../../../services/EntityService";
17
19
 
18
20
  const css = styled.css `
19
21
  & .site {
@@ -71,6 +73,9 @@ export default class ChooseWebSiteTemplatePage extends PopupWindowPage {
71
73
  @InjectProperty
72
74
  cloudFileService: CloudFileService;
73
75
 
76
+ @InjectProperty
77
+ entityService: EntityService;
78
+
74
79
  @InjectProperty
75
80
  mimeTypeService: MimeTypeService;
76
81
 
@@ -136,38 +141,8 @@ export default class ChooseWebSiteTemplatePage extends PopupWindowPage {
136
141
 
137
142
  @Action({ onEvent: "use-template", close: true })
138
143
  async useTemplate(item: IWebSiteFolder) {
139
- // get vars....
140
- const host = `/api/site/draft/${item.folderID}`;
141
-
142
- let html = await FetchBuilder.get(`${host}/index.html`)
143
- .responseAsText();
144
-
145
- const parser = new DOMParser();
146
- const doc = parser.parseFromString(html, "text/html");
147
-
148
- // add all stylesheets
149
- let modified = false;
150
-
151
- for (const iterator of Array.from(doc.querySelectorAll(`link[rel="stylesheet"]`))) {
152
- const href = iterator.getAttribute("href");
153
- if( /vars\.css/i.test(href)) {
154
- continue;
155
- }
156
- modified = true;
157
- // upload all styles...
158
- const path = href.split("#")[0].split("?")[0];
159
- const name = path.split("/").pop();
160
- const style = await this.upload(void 0, name, "styles", void 0, href);
161
- iterator.setAttribute("href", `/api/site/asset/download/${this.parameters.appFileID}/${style.appFileID}/${style.fileContentID}/${name}`);
162
- }
163
-
164
- if (modified) {
165
- html = doc.documentElement.outerHTML;
166
- }
167
-
168
- await this.upload(host, "index.html", void 0, html);
169
- await this.upload(host, "vars.css", "styles");
170
-
144
+ await this.templateService.copyTemplate(item.folderID, this.parameters.appFileID);
145
+ return true;
171
146
  }
172
147
 
173
148
  // @Action({ onEvent: "create-template", close: true})
@@ -1,15 +1,26 @@
1
1
  import DITransient from "@web-atoms/core/dist/di/DITransient";
2
2
  import { Inject } from "@web-atoms/core/dist/di/Inject";
3
3
  import EntityService from "../../../../services/EntityService";
4
- import { AppFile, WebSiteFolder } from "../../../../model/model";
4
+ import { AppFile, IAppFile, WebSiteFolder } from "../../../../model/model";
5
5
  import { Sql } from "../../../Sql";
6
+ import FetchBuilder from "@web-atoms/core/dist/services/FetchBuilder";
7
+ import CloudFileService from "../../../../web/page/files/service/CloudFileService";
8
+ import TaskManager from "@web-atoms/entity/dist/models/TaskManager";
6
9
 
7
10
  @DITransient()
8
- export default class TemplateService {
11
+ export default class TemplateService extends TaskManager {
9
12
 
10
13
  @Inject
11
14
  private entityService: EntityService;
12
15
 
16
+ @Inject
17
+ private cloudFileService: CloudFileService;
18
+
19
+ private fileMap: Map<any, IAppFile>;
20
+ private fcMap: Map<any, IAppFile>;
21
+ private absolutePaths: Map<IAppFile, string>;
22
+ private root: IAppFile;
23
+
13
24
  async search({
14
25
  search = "",
15
26
  start = 0,
@@ -29,4 +40,229 @@ export default class TemplateService {
29
40
  });
30
41
  }
31
42
 
43
+ async copyTemplate(templateFolderID, destFolderID, siteRoot = "/") {
44
+
45
+ // all files
46
+ const allFiles = await this.entityService.query(AppFile, "templateSnapshot", templateFolderID)
47
+ .toArray();
48
+
49
+ const fileMap = this.fileMap = new Map();
50
+ const fcMap = this.fcMap = new Map();
51
+ this.absolutePaths = new Map();
52
+
53
+ for (const iterator of allFiles) {
54
+ fileMap.set(iterator.appFileID, iterator);
55
+ if (iterator.fileContentID) {
56
+ fcMap.set(iterator.fileContentID, iterator);
57
+ }
58
+ if (iterator.contentType === "snapshot" && !iterator.parent) {
59
+ this.root = iterator;
60
+ continue;
61
+ }
62
+ }
63
+
64
+ for (const iterator of this.root.children) {
65
+ await this.copyFile(iterator, destFolderID, siteRoot);
66
+ }
67
+
68
+ this.fcMap = null;
69
+ this.fileMap = null;
70
+ this.absolutePaths = null;
71
+ }
72
+
73
+ async copyFile(source: IAppFile, destFolderID: number, siteRoot: string) {
74
+ siteRoot = siteRoot + source.name + "/";
75
+
76
+ // check if file exists...
77
+
78
+ let destFile = await this.entityService.query(AppFile)
79
+ .where({ destFolderID, name: source.name }, (p) => (x) => x.parentID === p.destFolderID
80
+ && x.isDeleted === false
81
+ && x.name === p.name)
82
+ .firstOrDefault();
83
+ destFile ??= AppFile.create({
84
+ ... source,
85
+ fileContentID: void 0,
86
+ appFileID: void 0,
87
+ parentID: destFolderID
88
+ });
89
+ if (destFile.fileContentID !== source.fileContentID) {
90
+ destFile.fileContentID = source.fileContentID;
91
+ await this.entityService.save(destFile, (c) => c);
92
+ destFile.downloadUrl = source.downloadUrl;
93
+ destFile.url = source.url;
94
+ }
95
+
96
+ const tasks = [];
97
+
98
+ if (source.isFolder && source.children) {
99
+ for (const child of source.children) {
100
+ tasks.push(this.run(() => this.copyFile(child, destFile.appFileID, siteRoot)));
101
+ }
102
+ }
103
+
104
+ if (tasks.length) {
105
+ await Promise.all(tasks);
106
+ }
107
+
108
+ if (!destFile.fileContentID) {
109
+ return;
110
+ }
111
+
112
+ // replace html or css...
113
+ if (/\.html?$/i.test(destFile.name)) {
114
+ await this.updateHtmlReferences(source, destFile, siteRoot);
115
+ return;
116
+ }
117
+
118
+ if (/\.css$/i.test(destFile.name)) {
119
+ let css = await FetchBuilder.get(destFile.downloadUrl).responseAsText();
120
+ css = this.updateCssReferences(source, destFile, css);
121
+ if (css) {
122
+ await this.cloudFileService.saveFile({
123
+ appFileID: destFile.appFileID,
124
+ content: new File([css], destFile.name, { type: destFile.contentType })
125
+ });
126
+ }
127
+ }
128
+ }
129
+
130
+ updateCssReferences(source: IAppFile, destFile: IAppFile, css: string) {
131
+
132
+ const regex = /url\(((\"[^\"]+\")|([^\)]+))\)/gmi;
133
+
134
+ let updated = false;
135
+ let m;
136
+ const list = new Set<string>();
137
+ while ((m = regex.exec(css)) !== null) {
138
+ // This is necessary to avoid infinite loops with zero-width matches
139
+ if (m.index === regex.lastIndex) {
140
+ regex.lastIndex++;
141
+ }
142
+ if (m.length) {
143
+ const [matched, group] = m;
144
+ if (group) {
145
+ list.add(group);
146
+ }
147
+ }
148
+ }
149
+
150
+ for (const fg of list.values()) {
151
+ let link = fg;
152
+ const first = link[0];
153
+ const encoded = first === '"' || first === "'";
154
+ if (encoded) {
155
+ link = link.substring(1, link.length - 1);
156
+ }
157
+
158
+ if (!/(https?\:)?\/\//i.test(link)) {
159
+ continue;
160
+ }
161
+
162
+ const url = new URL(link, "https://socialmail.in");
163
+ if(!url.pathname.startsWith("/api/site/snapshot/")) {
164
+ continue;
165
+ }
166
+ const { 6: fcID } = url.pathname.split("/");
167
+
168
+ // get relative path...
169
+ const resource = this.fcMap.get(fcID);
170
+ link = this.getRelativePath(source, resource);
171
+ css = css.split(fg).join(link);
172
+ updated = true;
173
+ }
174
+
175
+ if (updated) {
176
+ return css;
177
+ }
178
+ return null;
179
+ }
180
+
181
+ async updateHtmlReferences(source: IAppFile, destFile: IAppFile, siteRoot: string) {
182
+ const parser = new DOMParser();
183
+ const text = await FetchBuilder.get(destFile.downloadUrl).responseAsText();
184
+ const dom = parser.parseFromString(text, "text/html");
185
+
186
+ let modified = false;
187
+
188
+ for (const iterator of Array.from(dom.documentElement.querySelectorAll("*"))) {
189
+
190
+ let attributeName = "src";
191
+
192
+ switch(iterator.tagName) {
193
+ case "LINK":
194
+ attributeName = "href";
195
+ break;
196
+ case "IMG":
197
+ break;
198
+ case "STYLE":
199
+ const css = this.updateCssReferences(source, destFile, iterator.textContent);
200
+ if (css) {
201
+ iterator.textContent = css;
202
+ }
203
+ continue;
204
+ default:
205
+ continue;
206
+ }
207
+
208
+ let link = iterator[attributeName];
209
+ const url = new URL(link);
210
+ if(!url.pathname.startsWith("/api/site/snapshot/")) {
211
+ continue;
212
+ }
213
+ const { 6: fcID } = url.pathname.split("/");
214
+
215
+ // get relative path...
216
+ const resource = this.fcMap.get(fcID);
217
+ link = this.getRelativePath(source, resource);
218
+ iterator.setAttribute(attributeName, link);
219
+ modified = true;
220
+ }
221
+
222
+ if (!modified) {
223
+ return;
224
+ }
225
+
226
+ // upload changes...
227
+ const content = dom.documentElement.outerHTML;
228
+ const fileName = destFile.name;
229
+ await this.cloudFileService.saveFile({
230
+ content: new File([content], fileName, { type: "text/html" }),
231
+ appFileID: destFile.appFileID,
232
+ });
233
+ }
234
+
235
+ getRelativePath(destFile: IAppFile, resource: IAppFile, prefix = ""): any {
236
+ const destPath = this.toAbsolutePath(destFile.parent);
237
+ const resPath = this.toAbsolutePath(resource);
238
+
239
+
240
+ if (resPath.startsWith(destPath)) {
241
+ prefix = prefix ? "../" : "./";
242
+ return prefix + resPath.substring(destPath.length + 1);
243
+ }
244
+
245
+ prefix = prefix ? prefix + "../" : "../";
246
+ return this.getRelativePath(destFile.parent, resource, prefix);
247
+ }
248
+
249
+ toAbsolutePath(resource: IAppFile) {
250
+ let path = this.absolutePaths.get(resource);
251
+ if(path) {
252
+ return path;
253
+ }
254
+
255
+ const parent = resource.parent;
256
+ if(parent) {
257
+ path = this.toAbsolutePath(parent) + "/" + resource.name;
258
+ this.absolutePaths.set(resource, path);
259
+ return path;
260
+ }
261
+
262
+ path = "/" + resource.name;
263
+ this.absolutePaths.set(resource, path);
264
+ return path;
265
+
266
+ }
267
+
32
268
  }
@@ -72,6 +72,7 @@ export default class WebSitePageEditor extends HtmlPageEditor {
72
72
  script.setAttribute("web-components", "social");
73
73
  script.setAttribute("async", "true");
74
74
  script.setAttribute("defer", "true");
75
+ this.htmlDocument.head.appendChild(this.htmlDocument.createTextNode("\n"));
75
76
  this.htmlDocument.head.appendChild(script);
76
77
  }
77
78
  script.setAttribute("src", "//cdn.jsdelivr.net/npm/@social-mail/web-components@1.0.48/dist/components.webpack.js");
@@ -90,6 +91,7 @@ export default class WebSitePageEditor extends HtmlPageEditor {
90
91
  }
91
92
  if (!link){
92
93
  link ??= document.createElement("link");
94
+ document.head.appendChild(this.htmlDocument.createTextNode("\n"));
93
95
  document.head.appendChild(link);
94
96
  link.rel = "stylesheet";
95
97
  link.setAttribute("styler-css", file.name);