@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.
- package/dist/admin/AdminAppIndex.pack.js +212 -28
- package/dist/admin/AdminAppIndex.pack.js.map +1 -1
- package/dist/admin/AdminAppIndex.pack.min.js +3 -3
- package/dist/admin/AdminAppIndex.pack.min.js.map +1 -1
- package/dist/common/SocialMailApp.d.ts +1 -0
- package/dist/common/SocialMailApp.d.ts.map +1 -1
- package/dist/common/SocialMailApp.js.map +1 -1
- package/dist/common/fileUrl.d.ts.map +1 -1
- package/dist/common/fileUrl.js +3 -2
- package/dist/common/fileUrl.js.map +1 -1
- package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.d.ts +3 -1
- package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.d.ts.map +1 -1
- package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.js +7 -23
- package/dist/common/pages/websites/templates/ChooseWebSiteTemplatePage.js.map +1 -1
- package/dist/common/pages/websites/templates/TemplateService.d.ts +14 -1
- package/dist/common/pages/websites/templates/TemplateService.d.ts.map +1 -1
- package/dist/common/pages/websites/templates/TemplateService.js +200 -3
- package/dist/common/pages/websites/templates/TemplateService.js.map +1 -1
- package/dist/site-editor/editor/WebSitePageEditor.d.ts.map +1 -1
- package/dist/site-editor/editor/WebSitePageEditor.js +2 -0
- package/dist/site-editor/editor/WebSitePageEditor.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/web/AppIndex.pack.js +212 -28
- package/dist/web/AppIndex.pack.js.map +1 -1
- package/dist/web/AppIndex.pack.min.js +3 -3
- package/dist/web/AppIndex.pack.min.js.map +1 -1
- package/package.json +1 -1
- package/src/common/SocialMailApp.ts +1 -0
- package/src/common/fileUrl.ts +3 -2
- package/src/common/pages/websites/templates/ChooseWebSiteTemplatePage.tsx +8 -33
- package/src/common/pages/websites/templates/TemplateService.ts +238 -2
- package/src/site-editor/editor/WebSitePageEditor.tsx +2 -0
package/package.json
CHANGED
package/src/common/fileUrl.ts
CHANGED
|
@@ -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}/${
|
|
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}/${
|
|
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
|
-
|
|
140
|
-
|
|
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);
|