@social-mail/social-mail-client 1.2.86 → 1.2.88
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 +189 -79
- package/dist/admin/AdminAppIndex.pack.js.map +1 -1
- package/dist/admin/AdminAppIndex.pack.min.js +8 -8
- package/dist/admin/AdminAppIndex.pack.min.js.map +1 -1
- package/dist/common/controls/html/InlineHtmlEditorWithToolbar.d.ts +3 -0
- package/dist/common/controls/html/InlineHtmlEditorWithToolbar.d.ts.map +1 -1
- package/dist/common/controls/html/InlineHtmlEditorWithToolbar.js +15 -1
- package/dist/common/controls/html/InlineHtmlEditorWithToolbar.js.map +1 -1
- package/dist/public/channel/ChannelView.pack.js +10 -2
- package/dist/public/channel/ChannelView.pack.js.map +1 -1
- package/dist/public/channel/ChannelView.pack.min.js +1 -1
- package/dist/public/channel/ChannelView.pack.min.js.map +1 -1
- package/dist/services/files/LocalFileService.js +1 -1
- package/dist/services/files/LocalFileService.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/web/AppIndex.pack.js +189 -79
- package/dist/web/AppIndex.pack.js.map +1 -1
- package/dist/web/AppIndex.pack.min.js +8 -8
- package/dist/web/AppIndex.pack.min.js.map +1 -1
- package/dist/web/page/mails/ComposeMailPage.d.ts.map +1 -1
- package/dist/web/page/mails/ComposeMailPage.js +5 -2
- package/dist/web/page/mails/ComposeMailPage.js.map +1 -1
- package/dist/web/page/mails/mini-compose/Atttach.d.ts +4 -0
- package/dist/web/page/mails/mini-compose/Atttach.d.ts.map +1 -0
- package/dist/web/page/mails/mini-compose/Atttach.js +64 -0
- package/dist/web/page/mails/mini-compose/Atttach.js.map +1 -0
- package/dist/web/page/mails/mini-compose/Insert.d.ts.map +1 -1
- package/dist/web/page/mails/mini-compose/Insert.js +13 -13
- package/dist/web/page/mails/mini-compose/Insert.js.map +1 -1
- package/dist/web/page/mails/mini-compose/MiniComposeBox.d.ts +9 -2
- package/dist/web/page/mails/mini-compose/MiniComposeBox.d.ts.map +1 -1
- package/dist/web/page/mails/mini-compose/MiniComposeBox.js +93 -35
- package/dist/web/page/mails/mini-compose/MiniComposeBox.js.map +1 -1
- package/dist/web/page/mails/service/ConversationService.d.ts.map +1 -1
- package/dist/web/page/mails/service/ConversationService.js +10 -2
- package/dist/web/page/mails/service/ConversationService.js.map +1 -1
- package/node_modules/@web-atoms/web-controls/dist/html-editor/InlineHtmlEditor.d.ts.map +1 -1
- package/node_modules/@web-atoms/web-controls/dist/html-editor/InlineHtmlEditor.js +3 -5
- package/node_modules/@web-atoms/web-controls/dist/html-editor/InlineHtmlEditor.js.map +1 -1
- package/node_modules/@web-atoms/web-controls/dist/tsconfig.tsbuildinfo +1 -1
- package/node_modules/@web-atoms/web-controls/package.json +1 -1
- package/node_modules/@web-atoms/web-controls/src/html-editor/InlineHtmlEditor.tsx +3 -9
- package/package.json +2 -2
- package/src/common/controls/html/InlineHtmlEditorWithToolbar.tsx +18 -2
- package/src/services/files/LocalFileService.tsx +1 -1
- package/src/web/page/mails/ComposeMailPage.tsx +3 -0
- package/src/web/page/mails/mini-compose/Atttach.tsx +68 -0
- package/src/web/page/mails/mini-compose/Insert.tsx +13 -15
- package/src/web/page/mails/mini-compose/MiniComposeBox.tsx +85 -20
- package/src/web/page/mails/service/ConversationService.tsx +10 -2
|
@@ -27,6 +27,7 @@ import InjectProperty from "@web-atoms/core/dist/core/InjectProperty";
|
|
|
27
27
|
import { StringHelper } from "@web-atoms/core/dist/core/StringHelper";
|
|
28
28
|
import styled from "@web-atoms/core/dist/style/styled";
|
|
29
29
|
import { descendentElementIterator, descendentIterator } from "@web-atoms/core/dist/web/core/AtomUI";
|
|
30
|
+
import { IAppFile } from "../../../model/model";
|
|
30
31
|
|
|
31
32
|
const link = document.createElement("link");
|
|
32
33
|
link.href = "https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css";
|
|
@@ -134,13 +135,28 @@ const css = styled.css `
|
|
|
134
135
|
|
|
135
136
|
export class MailHtmlEditor extends InlineHtmlEditor {
|
|
136
137
|
|
|
137
|
-
public files: IUploadedFile[];
|
|
138
|
+
public files: IUploadedFile[] = [];
|
|
139
|
+
|
|
140
|
+
public attachments: IAppFile[] = [];
|
|
138
141
|
|
|
139
142
|
public autofocus = false;
|
|
140
143
|
|
|
141
144
|
@InjectProperty
|
|
142
145
|
private localFileService: LocalFileService;
|
|
143
146
|
|
|
147
|
+
protected onContentSet(): void {
|
|
148
|
+
super.onContentSet();
|
|
149
|
+
const files = this.attachments;
|
|
150
|
+
const items = Array.from(this.editor.querySelectorAll(`*[data-content-id]`)) as HTMLElement[];
|
|
151
|
+
for (const iterator of items) {
|
|
152
|
+
const file = files.find((x) => x.contentID === iterator.getAttribute("data-content-id"));
|
|
153
|
+
if (!file) {
|
|
154
|
+
continue;
|
|
155
|
+
}
|
|
156
|
+
iterator.setAttribute("src", file.url);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
144
160
|
protected onPasteEvent(e: ClipboardEvent): void {
|
|
145
161
|
if (e.clipboardData.files.length) {
|
|
146
162
|
e.preventDefault();
|
|
@@ -161,7 +177,7 @@ export class MailHtmlEditor extends InlineHtmlEditor {
|
|
|
161
177
|
super.preCreate();
|
|
162
178
|
this.element.className = css;
|
|
163
179
|
this.sanitizeHtml = (node) => {
|
|
164
|
-
const images = Array.from(node.querySelectorAll(
|
|
180
|
+
const images = Array.from(node.querySelectorAll(`*[data-content-id]`));
|
|
165
181
|
for (const image of images) {
|
|
166
182
|
image.setAttribute("src", `cid:${image.getAttribute("data-content-id")}`);
|
|
167
183
|
}
|
|
@@ -171,7 +171,7 @@ export default class LocalFileService extends TaskManager {
|
|
|
171
171
|
|
|
172
172
|
const sha256 = await this.sha256(file);
|
|
173
173
|
|
|
174
|
-
if (extra
|
|
174
|
+
if (extra?.parentID) {
|
|
175
175
|
const existing = await this.entityService.query(AppFile, "children", extra.parentID, folder ? folder + "/" + file.name : file.name, sha256)
|
|
176
176
|
.firstOrDefault();
|
|
177
177
|
if (existing) {
|
|
@@ -68,6 +68,8 @@ export default class ComposeMailPage extends PopupWindowPage {
|
|
|
68
68
|
attachments: []
|
|
69
69
|
});
|
|
70
70
|
|
|
71
|
+
this.model.attachments ??= [];
|
|
72
|
+
|
|
71
73
|
if (this.parameters.social) {
|
|
72
74
|
// load social template....
|
|
73
75
|
const senderName = this.parameters.mailbox.emailAddress.name;
|
|
@@ -102,6 +104,7 @@ export default class ComposeMailPage extends PopupWindowPage {
|
|
|
102
104
|
data-html-editor="email-editor"
|
|
103
105
|
presenter={Bind.presenter((c) => this.editor = c )}
|
|
104
106
|
content={this.model.htmlBody}
|
|
107
|
+
attachments={this.model.attachments}
|
|
105
108
|
style-min-height="200px"
|
|
106
109
|
/>
|
|
107
110
|
<AtomRepeater
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import Bind from "@web-atoms/core/dist/core/Bind";
|
|
2
|
+
import XNode from "@web-atoms/core/dist/core/XNode";
|
|
3
|
+
import { IPopupOptions } from "@web-atoms/core/dist/web/services/PopupService";
|
|
4
|
+
import PageNavigator from "@web-atoms/web-controls/dist/PageNavigator";
|
|
5
|
+
import PopupButton, { MenuItem } from "@web-atoms/web-controls/dist/basic/PopupButton";
|
|
6
|
+
import UploadEvent from "@web-atoms/web-controls/dist/basic/UploadEvent";
|
|
7
|
+
import CodeSnippetPage from "../../../../code-editor/CodeSnippetPage";
|
|
8
|
+
import type { MailHtmlEditor } from "../../../../common/controls/html/InlineHtmlEditorWithToolbar";
|
|
9
|
+
|
|
10
|
+
export default function Attach({ alignment = "above" as IPopupOptions["alignment"]}) {
|
|
11
|
+
return <PopupButton
|
|
12
|
+
class="command"
|
|
13
|
+
data-layout="toolbar-button"
|
|
14
|
+
icon="fa-light fa-file-plus"
|
|
15
|
+
title="Attach"
|
|
16
|
+
alignment={alignment}>
|
|
17
|
+
<MenuItem
|
|
18
|
+
{ ... UploadEvent.AttachUploadAction({
|
|
19
|
+
accept: "image/*",
|
|
20
|
+
multiple: true,
|
|
21
|
+
extra: {
|
|
22
|
+
}
|
|
23
|
+
})}
|
|
24
|
+
icon="fas fa-image"
|
|
25
|
+
label="Attach Photos"
|
|
26
|
+
/>
|
|
27
|
+
<MenuItem
|
|
28
|
+
{ ... UploadEvent.AttachUploadAction({
|
|
29
|
+
accept: "image/*",
|
|
30
|
+
capture: "user",
|
|
31
|
+
extra: {
|
|
32
|
+
}
|
|
33
|
+
})}
|
|
34
|
+
icon="fa-duotone fa-camera-retro"
|
|
35
|
+
label="Take Photo"
|
|
36
|
+
/>
|
|
37
|
+
<MenuItem
|
|
38
|
+
{ ... UploadEvent.AttachUploadAction({
|
|
39
|
+
accept: "video/*",
|
|
40
|
+
multiple: false,
|
|
41
|
+
extra: {
|
|
42
|
+
}
|
|
43
|
+
})}
|
|
44
|
+
icon="fas fa-file-video"
|
|
45
|
+
label="Attach Video"
|
|
46
|
+
/>
|
|
47
|
+
<MenuItem
|
|
48
|
+
{ ... UploadEvent.AttachUploadAction({
|
|
49
|
+
accept: "video/*",
|
|
50
|
+
capture: "user",
|
|
51
|
+
extra: {
|
|
52
|
+
}
|
|
53
|
+
})}
|
|
54
|
+
icon="fa-duotone fa-video-plus"
|
|
55
|
+
label="Record Video"
|
|
56
|
+
/>
|
|
57
|
+
<MenuItem
|
|
58
|
+
{ ... UploadEvent.AttachUploadAction({
|
|
59
|
+
accept: "*/*",
|
|
60
|
+
extra: {
|
|
61
|
+
}
|
|
62
|
+
})}
|
|
63
|
+
icon="fa-duotone fa-file"
|
|
64
|
+
label="Attach Documents"
|
|
65
|
+
style-min-width="150px"
|
|
66
|
+
/>
|
|
67
|
+
</PopupButton>;
|
|
68
|
+
}
|
|
@@ -12,7 +12,7 @@ export default function Insert({ alignment = "above" as IPopupOptions["alignment
|
|
|
12
12
|
class="command"
|
|
13
13
|
data-layout="toolbar-button"
|
|
14
14
|
icon="fas fa-plus"
|
|
15
|
-
title="
|
|
15
|
+
title="Insert"
|
|
16
16
|
alignment={alignment}>
|
|
17
17
|
<MenuItem
|
|
18
18
|
icon="ri-list-unordered"
|
|
@@ -36,7 +36,9 @@ export default function Insert({ alignment = "above" as IPopupOptions["alignment
|
|
|
36
36
|
{ ... UploadEvent.AttachUploadAction({
|
|
37
37
|
accept: "image/*",
|
|
38
38
|
multiple: true,
|
|
39
|
-
extra: {
|
|
39
|
+
extra: {
|
|
40
|
+
insert: true
|
|
41
|
+
}
|
|
40
42
|
})}
|
|
41
43
|
data-click-event="send-photos"
|
|
42
44
|
icon="fas fa-image"
|
|
@@ -46,7 +48,9 @@ export default function Insert({ alignment = "above" as IPopupOptions["alignment
|
|
|
46
48
|
{ ... UploadEvent.AttachUploadAction({
|
|
47
49
|
accept: "image/*",
|
|
48
50
|
capture: "user",
|
|
49
|
-
extra: {
|
|
51
|
+
extra: {
|
|
52
|
+
insert: true
|
|
53
|
+
}
|
|
50
54
|
})}
|
|
51
55
|
data-click-event="take-photo"
|
|
52
56
|
icon="fa-duotone fa-camera-retro"
|
|
@@ -56,27 +60,21 @@ export default function Insert({ alignment = "above" as IPopupOptions["alignment
|
|
|
56
60
|
{ ... UploadEvent.AttachUploadAction({
|
|
57
61
|
accept: "video/*",
|
|
58
62
|
multiple: false,
|
|
59
|
-
extra: {
|
|
63
|
+
extra: {
|
|
64
|
+
insert: true
|
|
65
|
+
}
|
|
60
66
|
})}
|
|
61
67
|
data-click-event="send-video"
|
|
62
68
|
icon="fas fa-file-video"
|
|
63
69
|
label="Add Video"
|
|
64
70
|
/>
|
|
65
|
-
<MenuItem
|
|
66
|
-
{ ... UploadEvent.AttachUploadAction({
|
|
67
|
-
accept: "*/*",
|
|
68
|
-
multiple: false,
|
|
69
|
-
extra: {}
|
|
70
|
-
})}
|
|
71
|
-
data-click-event="send-document"
|
|
72
|
-
icon="fas fa-file"
|
|
73
|
-
label="Add Document"
|
|
74
|
-
/>
|
|
75
71
|
<MenuItem
|
|
76
72
|
{ ... UploadEvent.AttachUploadAction({
|
|
77
73
|
accept: "video/*",
|
|
78
74
|
capture: "user",
|
|
79
|
-
extra: {
|
|
75
|
+
extra: {
|
|
76
|
+
insert: true
|
|
77
|
+
}
|
|
80
78
|
})}
|
|
81
79
|
data-click-event="record-video"
|
|
82
80
|
icon="fa-duotone fa-video-plus"
|
|
@@ -28,6 +28,8 @@ import Separator from "@web-atoms/web-controls/dist/html-editor/commands/Separat
|
|
|
28
28
|
import Insert from "./Insert";
|
|
29
29
|
import TimeSpan from "@web-atoms/date-time/dist/TimeSpan";
|
|
30
30
|
import ToggleEmoji from "./ToggleEmoji";
|
|
31
|
+
import Attach from "./Atttach";
|
|
32
|
+
import PopupService from "@web-atoms/core/dist/web/services/PopupService";
|
|
31
33
|
|
|
32
34
|
const css = styled.css `
|
|
33
35
|
display: grid;
|
|
@@ -115,6 +117,8 @@ export default class MiniComposeBox extends AtomControl {
|
|
|
115
117
|
<Toolbar>
|
|
116
118
|
<Insert/>
|
|
117
119
|
<Separator/>
|
|
120
|
+
<Attach/>
|
|
121
|
+
<Separator/>
|
|
118
122
|
<Bold/>
|
|
119
123
|
<Italic/>
|
|
120
124
|
<Underline/>
|
|
@@ -123,8 +127,6 @@ export default class MiniComposeBox extends AtomControl {
|
|
|
123
127
|
<Separator/>
|
|
124
128
|
<AddLink/>
|
|
125
129
|
<Unlink/>
|
|
126
|
-
<Separator/>
|
|
127
|
-
<ToggleEmoji/>
|
|
128
130
|
</Toolbar>
|
|
129
131
|
<input
|
|
130
132
|
style-place-self="stretch"
|
|
@@ -142,6 +144,7 @@ export default class MiniComposeBox extends AtomControl {
|
|
|
142
144
|
presenter={Bind.presenter((c) => this.editor = c )}
|
|
143
145
|
content={this.typedMessage}
|
|
144
146
|
style-min-height="50px"
|
|
147
|
+
attachments={Bind.oneWay(() => this.draft.attachments)}
|
|
145
148
|
/>
|
|
146
149
|
<i
|
|
147
150
|
data-element="send"
|
|
@@ -173,8 +176,57 @@ export default class MiniComposeBox extends AtomControl {
|
|
|
173
176
|
}
|
|
174
177
|
|
|
175
178
|
@Action({ onEvent: "filesAvailable"})
|
|
176
|
-
async filesAvailable({ files, extra }) {
|
|
177
|
-
|
|
179
|
+
async filesAvailable({ files, extra }: { files: IUploadedFile[], extra: any }) {
|
|
180
|
+
|
|
181
|
+
if (extra.stream) {
|
|
182
|
+
await this.streamFiles({ files, extra });
|
|
183
|
+
return;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const size = files.reduce((pv, cv) => pv + cv.file.size , 0);
|
|
187
|
+
if (size > 20*1024*1024) {
|
|
188
|
+
if (!extra.stream) {
|
|
189
|
+
throw new Error(`Total size of attachments cannot be more than 20MB.`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (extra.insert) {
|
|
194
|
+
this.ensureDraft();
|
|
195
|
+
// insert into the email..
|
|
196
|
+
const firstChild = this.editor.editor.firstElementChild;
|
|
197
|
+
for (const iterator of files) {
|
|
198
|
+
if (/^image\//.test(iterator.contentType)) {
|
|
199
|
+
const af = this.createAppFile(iterator);
|
|
200
|
+
const img = firstChild.ownerDocument.createElement("img");
|
|
201
|
+
img.src = iterator.url;
|
|
202
|
+
img.setAttribute("data-content-id", af.contentID);
|
|
203
|
+
this.draft.attachments.add(af);
|
|
204
|
+
firstChild.appendChild(img);
|
|
205
|
+
const newLine = document.createElement("div");
|
|
206
|
+
newLine.appendChild(document.createElement("br"));
|
|
207
|
+
firstChild.appendChild(newLine);
|
|
208
|
+
continue;
|
|
209
|
+
}
|
|
210
|
+
if (/^(video|audio)\//.test(iterator.contentType)) {
|
|
211
|
+
const af = this.createAppFile(iterator);
|
|
212
|
+
const img = firstChild.ownerDocument.createElement("video");
|
|
213
|
+
img.src = iterator.url;
|
|
214
|
+
img.setAttribute("data-content-id", af.contentID);
|
|
215
|
+
this.draft.attachments.add(af);
|
|
216
|
+
firstChild.appendChild(img);
|
|
217
|
+
const newLine = document.createElement("div");
|
|
218
|
+
newLine.appendChild(document.createElement("br"));
|
|
219
|
+
firstChild.appendChild(newLine);
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return;
|
|
224
|
+
}
|
|
225
|
+
await this.addFiles(... files);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
async streamFiles({ files, extra }: { files: IUploadedFile[], extra: any }) {
|
|
229
|
+
// do nothing...
|
|
178
230
|
}
|
|
179
231
|
|
|
180
232
|
@Action({
|
|
@@ -187,10 +239,13 @@ export default class MiniComposeBox extends AtomControl {
|
|
|
187
239
|
}
|
|
188
240
|
|
|
189
241
|
@Action({ onEvent: CommonEvents.onDraftDeleted })
|
|
190
|
-
async
|
|
242
|
+
async recreateDraft() {
|
|
243
|
+
this.draft = null;
|
|
191
244
|
this.draft ??= Email.create({
|
|
245
|
+
subject: "",
|
|
192
246
|
attachments: []
|
|
193
247
|
});
|
|
248
|
+
this.draft.attachments ??= [];
|
|
194
249
|
}
|
|
195
250
|
|
|
196
251
|
@Action({ onEvent: "input", defer: 500, blockMultipleExecution: true })
|
|
@@ -246,28 +301,38 @@ export default class MiniComposeBox extends AtomControl {
|
|
|
246
301
|
@Action({})
|
|
247
302
|
async sendAudioMessage() {
|
|
248
303
|
const uploadedFile = await AudioRecorder.show<IUploadedFile>();
|
|
249
|
-
this.
|
|
250
|
-
attachments: []
|
|
251
|
-
});
|
|
304
|
+
this.ensureDraft();
|
|
252
305
|
this.draft.mdBody = this.typedMessage;
|
|
253
|
-
this.addFiles(uploadedFile);
|
|
306
|
+
await this.addFiles(uploadedFile);
|
|
254
307
|
await this.save();
|
|
255
308
|
}
|
|
256
309
|
|
|
257
|
-
private addFiles(... files: IUploadedFile[]) {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
for (const
|
|
261
|
-
attachments.add(
|
|
262
|
-
appFileID,
|
|
263
|
-
contentType: file.type,
|
|
264
|
-
name: file.name,
|
|
265
|
-
contentID: appFileID.toString(36),
|
|
266
|
-
url
|
|
267
|
-
}));
|
|
310
|
+
private async addFiles(... files: IUploadedFile[]) {
|
|
311
|
+
this.ensureDraft();
|
|
312
|
+
const attachments = this.draft.attachments;
|
|
313
|
+
for (const file of files) {
|
|
314
|
+
attachments.add(this.createAppFile(file));
|
|
268
315
|
}
|
|
269
316
|
}
|
|
270
317
|
|
|
318
|
+
private createAppFile(file: IUploadedFile): IAppFile {
|
|
319
|
+
return AppFile.create({
|
|
320
|
+
appFileID: file.appFileID,
|
|
321
|
+
contentType: file.file.type,
|
|
322
|
+
name: file.file.name,
|
|
323
|
+
contentID: file.appFileID.toString(36),
|
|
324
|
+
url: file.url
|
|
325
|
+
});
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
private ensureDraft() {
|
|
329
|
+
this.draft ??= Email.create({
|
|
330
|
+
subject: "",
|
|
331
|
+
attachments: []
|
|
332
|
+
});
|
|
333
|
+
this.draft.attachments ??= [];
|
|
334
|
+
}
|
|
335
|
+
|
|
271
336
|
private async save() {
|
|
272
337
|
this.draft = await this.conversationService.draft({ ... this.mailboxContact, email: this.draft }, true);
|
|
273
338
|
}
|
|
@@ -34,11 +34,19 @@ export const renderMail = AtomControl.registerProperty("data-html", "html", (c,
|
|
|
34
34
|
}
|
|
35
35
|
msg.innerHTML = html;
|
|
36
36
|
for (const iterator of descendentElementIterator(msg)) {
|
|
37
|
-
|
|
37
|
+
let cid = iterator.getAttribute("data-content-id");
|
|
38
|
+
if (cid) {
|
|
39
|
+
const a = mail.attachments.find((x) => x.contentID === cid);
|
|
40
|
+
if (a) {
|
|
41
|
+
iterator.setAttribute("src", a.url);
|
|
42
|
+
continue;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if(/^(IMG|VIDEO)$/.test(iterator.tagName)) {
|
|
38
46
|
const src = iterator.getAttribute("src");
|
|
39
47
|
if (src) {
|
|
40
48
|
if (src.startsWith("cid:")) {
|
|
41
|
-
|
|
49
|
+
cid = src.substring(4);
|
|
42
50
|
const a = mail.attachments.find((x) => x.contentID === cid);
|
|
43
51
|
if (a) {
|
|
44
52
|
iterator.setAttribute("src", `/api/files/${a.appFileID}/${a.fileContentID}/${a.name}`);
|