adjustment
This commit is contained in:
parent
3e9ee59178
commit
29209a3a00
@ -1,7 +1,7 @@
|
||||
import { Grid, Dropdown, createElement, createCheckbox, Popup, showAlert } from "../../ui";
|
||||
import { isEmail, nullOrEmpty, r } from "../../utility";
|
||||
|
||||
class Contact {
|
||||
export class Contact {
|
||||
#option;
|
||||
#refs;
|
||||
|
||||
@ -191,7 +191,7 @@ class Contact {
|
||||
}
|
||||
}
|
||||
|
||||
class CustomerRecordContact {
|
||||
export class CustomerRecordContact {
|
||||
#option;
|
||||
#grid;
|
||||
|
||||
@ -253,5 +253,3 @@ class CustomerRecordContact {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export { Contact, CustomerRecordContact };
|
@ -1,6 +1,6 @@
|
||||
import { Grid, GridColumn, createElement, setTooltip, createIcon, createCheckbox, createRadiobox, showAlert, showConfirm, Popup, createPicture, createAudio, createVideo, createPdf, createSmilefile, createVcard, createVideofile, createFile } from "../../ui";
|
||||
import { Grid, GridColumn, createElement, setTooltip, createIcon, createCheckbox, createRadiobox, showAlert, showConfirm, Popup } from "../../ui";
|
||||
import { r, nullOrEmpty, formatUrl, isEmail, isPhone } from "../../utility";
|
||||
import { createBox } from "./lib";
|
||||
import { createBox, appendMedia, fileSupported, insertFile } from "./lib";
|
||||
import { Contact, CustomerRecordContact } from "./contact";
|
||||
import Follower from "./follower";
|
||||
|
||||
@ -35,6 +35,8 @@ class CustomerCommunication {
|
||||
#followers;
|
||||
#buttonFollower;
|
||||
#enter;
|
||||
#fileControl;
|
||||
#file;
|
||||
#message;
|
||||
#data = {};
|
||||
#gridContact;
|
||||
@ -118,6 +120,38 @@ class CustomerCommunication {
|
||||
}
|
||||
}
|
||||
|
||||
get file() { return this.#file || this.#fileControl?.files?.[0] }
|
||||
set file(f) {
|
||||
this.#fileControl?.remove();
|
||||
const label = this.#container.querySelector('.file-selector>.selector-name');
|
||||
if (f == null) {
|
||||
this.#fileControl = null;
|
||||
this.#file = null;
|
||||
if (label != null) {
|
||||
label.style.display = 'none';
|
||||
label.innerText = '';
|
||||
label.querySelector('.ui-tooltip-wrapper')?.remove();
|
||||
}
|
||||
} else {
|
||||
if (f instanceof HTMLInputElement) {
|
||||
this.#fileControl = f;
|
||||
this.#file = f.files[0];
|
||||
const link = this.#container.querySelector('.file-selector>.selector-link');
|
||||
if (link != null) {
|
||||
link.appendChild(f);
|
||||
}
|
||||
} else {
|
||||
this.#fileControl = null;
|
||||
this.#file = f;
|
||||
}
|
||||
if (label != null) {
|
||||
label.style.display = '';
|
||||
label.innerText = f.name;
|
||||
setTooltip(label, f.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
get customerName() { return this.#container.querySelector('.customer-name>.ui-input')?.value }
|
||||
set customerName(name) {
|
||||
const element = this.#container.querySelector('.customer-name>.ui-input');
|
||||
@ -400,10 +434,20 @@ class CustomerCommunication {
|
||||
// enter.disabled = true;
|
||||
// }
|
||||
enter.addEventListener('input', () => {
|
||||
const val = this.#enter.value;
|
||||
const val = this.text;
|
||||
const s = String(nullOrEmpty(val) ? 0 : val.length) + '/' + String(option.maxLength);
|
||||
this.#container.querySelector('.message-bar .prompt-count').innerText = s;
|
||||
});
|
||||
enter.addEventListener('paste', e => {
|
||||
if (option.customerNameVisible === true) {
|
||||
return;
|
||||
}
|
||||
const file = e.clipboardData.files[0];
|
||||
if (file != null) {
|
||||
e.preventDefault();
|
||||
this.file = insertFile(container, file);
|
||||
}
|
||||
});
|
||||
this.#enter = enter;
|
||||
container.appendChild(
|
||||
createElement('div', div => {
|
||||
@ -411,6 +455,28 @@ class CustomerCommunication {
|
||||
if (readonly === true) {
|
||||
div.style.display = 'none';
|
||||
}
|
||||
div.addEventListener('dragover', e => {
|
||||
if (option.readonly !== true) {
|
||||
const item = e.dataTransfer.items[0];
|
||||
if (item?.kind === 'file') {
|
||||
e.preventDefault();
|
||||
if (item.type.length > 0 && fileSupported.indexOf(item.type) < 0) {
|
||||
e.dataTransfer.dropEffect = 'none';
|
||||
} else {
|
||||
e.dataTransfer.dropEffect = 'link';
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
div.addEventListener('drop', e => {
|
||||
if (option.readonly !== true) {
|
||||
const file = e.dataTransfer.files[0];
|
||||
if (file != null) {
|
||||
e.preventDefault();
|
||||
this.file = insertFile(container, file);
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
enter,
|
||||
createElement('div', div => div.style.textAlign = 'right',
|
||||
@ -426,6 +492,41 @@ class CustomerCommunication {
|
||||
input.className = 'ui-input';
|
||||
})
|
||||
),
|
||||
createElement('div', selector => {
|
||||
selector.className = 'file-selector';
|
||||
if (option.customerNameVisible === true) {
|
||||
selector.style.display = 'none';
|
||||
}
|
||||
},
|
||||
createElement('div', div => {
|
||||
div.className = 'selector-link';
|
||||
div.addEventListener('click', () => {
|
||||
this.#fileControl?.remove();
|
||||
const file = createElement('input', input => {
|
||||
input.type = 'file';
|
||||
input.accept = fileSupported.join(',');
|
||||
input.addEventListener('change', () => {
|
||||
const file = insertFile(container, input.files?.[0]);
|
||||
if (file != null) {
|
||||
this.file = file;
|
||||
}
|
||||
});
|
||||
});
|
||||
div.appendChild(this.#fileControl = file);
|
||||
file.dispatchEvent(new MouseEvent('click'));
|
||||
});
|
||||
},
|
||||
createIcon('fa-regular', 'link')
|
||||
),
|
||||
createElement('span', span => {
|
||||
span.className = 'selector-name';
|
||||
span.style.display = 'none';
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.appendChild(createIcon('fa-regular', 'times'));
|
||||
layer.addEventListener('click', () => this.file = null);
|
||||
})
|
||||
),
|
||||
createElement('div', 'prompt-count'),
|
||||
createElement('button', button => {
|
||||
button.className = 'roundbtn button-send-message';
|
||||
@ -436,7 +537,7 @@ class CustomerCommunication {
|
||||
button.appendChild(createIcon('fa-solid', 'paper-plane'));
|
||||
setTooltip(button, r('sendMessage', 'Send Message'));
|
||||
button.addEventListener('click', () => {
|
||||
const val = this.#enter.value;
|
||||
const val = this.text;
|
||||
if (nullOrEmpty(val?.trim())) {
|
||||
const p = showAlert(r('error', 'Error'), r('messageRequired', 'Please input the message.'), 'warn');
|
||||
if (typeof option.onMasking === 'function') {
|
||||
@ -446,7 +547,7 @@ class CustomerCommunication {
|
||||
return;
|
||||
}
|
||||
if (typeof option.onAddMessage === 'function') {
|
||||
option.onAddMessage(this.#enter.value);
|
||||
option.onAddMessage(this.text, this.file);
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -1063,43 +1164,20 @@ class CustomerCommunication {
|
||||
}
|
||||
}));
|
||||
const content = createElement('div', 'item-content');
|
||||
const emoji = s => s.replace(/(=[A-Fa-f0-9]{2}){4}/, s => decodeURIComponent(s.replaceAll('=', '%')));
|
||||
const mmsParts = createElement('div', div => div.style.display = 'none');
|
||||
content.appendChild(createElement('span', span => {
|
||||
if (/https?:\/\//i.test(comm.Message)) {
|
||||
span.innerHTML = formatUrl(comm.Message);
|
||||
span.innerHTML = emoji(formatUrl(comm.Message));
|
||||
} else {
|
||||
span.innerText = comm.Message;
|
||||
span.innerText = emoji(comm.Message);
|
||||
}
|
||||
span.appendChild(mmsParts);
|
||||
}));
|
||||
if (comm.IsMMS && comm.MMSParts?.length > 0) {
|
||||
mmsParts.style.display = '';
|
||||
for (let kv of comm.MMSParts) {
|
||||
switch (kv.Key) {
|
||||
case 'application/pdf':
|
||||
content.appendChild(createPdf(kv.Value));
|
||||
break;
|
||||
case 'application/smil':
|
||||
content.appendChild(createSmilefile(kv.Value));
|
||||
break;
|
||||
case 'audio/amr':
|
||||
content.appendChild(createAudio(kv.Key));
|
||||
break;
|
||||
case 'image/gif':
|
||||
case 'image/jpeg':
|
||||
case 'image/png':
|
||||
content.appendChild(createPicture(kv.Value));
|
||||
break;
|
||||
case 'text/x-vcard':
|
||||
content.appendChild(createVcard(kv.Value));
|
||||
break;
|
||||
case 'video/3gpp':
|
||||
content.appendChild(createVideofile(kv.Value));
|
||||
break;
|
||||
case 'video/mp4':
|
||||
content.appendChild(createVideo(kv.Value));
|
||||
break;
|
||||
default:
|
||||
content.appendChild(createFile(kv.Value));
|
||||
break;
|
||||
}
|
||||
appendMedia(mmsParts, kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
if (comm.IsReply) {
|
||||
|
@ -1,11 +1,13 @@
|
||||
import { createElement, setTooltip, createIcon } from "../../ui";
|
||||
import { createElement, setTooltip, createIcon, showAlert } from "../../ui";
|
||||
import { r, nullOrEmpty, escapeHtml } from "../../utility";
|
||||
import { createBox } from "./lib";
|
||||
import { createBox, appendMedia, fileSupported, insertFile } from "./lib";
|
||||
|
||||
class InternalComment {
|
||||
#container;
|
||||
#option;
|
||||
#enter;
|
||||
#fileControl;
|
||||
#file;
|
||||
#message;
|
||||
|
||||
constructor(opt) {
|
||||
@ -22,6 +24,50 @@ class InternalComment {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} flag
|
||||
*/
|
||||
set loading(flag) {
|
||||
if (this.#container == null) {
|
||||
return;
|
||||
}
|
||||
this.#enter.disabled = flag;
|
||||
this.#container.querySelector('.button-send-message').disabled = flag;
|
||||
this.#container.querySelector('.button-post-note').disabled = flag;
|
||||
}
|
||||
|
||||
get file() { return this.#file || this.#fileControl?.files?.[0] }
|
||||
set file(f) {
|
||||
this.#fileControl?.remove();
|
||||
const label = this.#container.querySelector('.file-selector>.selector-name');
|
||||
if (f == null) {
|
||||
this.#fileControl = null;
|
||||
this.#file = null;
|
||||
if (label != null) {
|
||||
label.style.display = 'none';
|
||||
label.innerText = '';
|
||||
label.querySelector('.ui-tooltip-wrapper')?.remove();
|
||||
}
|
||||
} else {
|
||||
if (f instanceof HTMLInputElement) {
|
||||
this.#fileControl = f;
|
||||
this.#file = f.files[0];
|
||||
const link = this.#container.querySelector('.file-selector>.selector-link');
|
||||
if (link != null) {
|
||||
link.appendChild(f);
|
||||
}
|
||||
} else {
|
||||
this.#fileControl = null;
|
||||
this.#file = f;
|
||||
}
|
||||
if (label != null) {
|
||||
label.style.display = '';
|
||||
label.innerText = f.name;
|
||||
setTooltip(label, f.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {boolean} flag
|
||||
*/
|
||||
@ -50,18 +96,85 @@ class InternalComment {
|
||||
enter.placeholder = r('typeComment', 'Enter Comment Here');
|
||||
enter.maxLength = this.#option.maxLength ??= 3000;
|
||||
enter.addEventListener('input', () => {
|
||||
const val = this.#enter.value;
|
||||
const val = this.text;
|
||||
const s = String(nullOrEmpty(val) ? 0 : val.length) + '/' + String(this.#option.maxLength);
|
||||
this.#container.querySelector('.message-bar .prompt-count').innerText = s;
|
||||
});
|
||||
if (readonly === true) {
|
||||
enter.disabled = true;
|
||||
}
|
||||
// enter.addEventListener('paste', e => {
|
||||
// const file = e.clipboardData.files[0];
|
||||
// if (file != null) {
|
||||
// e.preventDefault();
|
||||
// this.file = insertFile(container, file);
|
||||
// }
|
||||
// });
|
||||
this.#enter = enter;
|
||||
container.appendChild(
|
||||
createElement('div', 'message-bar',
|
||||
createElement('div', div => {
|
||||
div.className = 'message-bar';
|
||||
// div.addEventListener('dragover', e => {
|
||||
// if (option.readonly !== true) {
|
||||
// const item = e.dataTransfer.items[0];
|
||||
// if (item?.kind === 'file') {
|
||||
// e.preventDefault();
|
||||
// if (item.type.length > 0 && fileSupported.indexOf(item.type) < 0) {
|
||||
// e.dataTransfer.dropEffect = 'none';
|
||||
// } else {
|
||||
// e.dataTransfer.dropEffect = 'link';
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// div.addEventListener('drop', e => {
|
||||
// if (option.readonly !== true) {
|
||||
// const file = e.dataTransfer.files[0];
|
||||
// if (file != null) {
|
||||
// e.preventDefault();
|
||||
// this.file = insertFile(container, file);
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
},
|
||||
enter,
|
||||
createElement('div', div => div.style.textAlign = 'right',
|
||||
createElement('div', selector => {
|
||||
selector.className = 'file-selector';
|
||||
if (this.#option.noMessage === true) {
|
||||
selector.style.display = 'none';
|
||||
}
|
||||
},
|
||||
createElement('div', div => {
|
||||
div.className = 'selector-link';
|
||||
div.style.display = 'none';
|
||||
// div.addEventListener('click', () => {
|
||||
// this.#fileControl?.remove();
|
||||
// const file = createElement('input', input => {
|
||||
// input.type = 'file';
|
||||
// input.accept = fileSupported.join(',');
|
||||
// input.addEventListener('change', () => {
|
||||
// const file = insertFile(container, input.files?.[0]);
|
||||
// if (file != null) {
|
||||
// this.file = file;
|
||||
// }
|
||||
// });
|
||||
// });
|
||||
// div.appendChild(this.#fileControl = file);
|
||||
// file.dispatchEvent(new MouseEvent('click'));
|
||||
// });
|
||||
},
|
||||
createIcon('fa-regular', 'link')
|
||||
),
|
||||
createElement('span', span => {
|
||||
span.className = 'selector-name';
|
||||
span.style.display = 'none';
|
||||
}),
|
||||
createElement('layer', layer => {
|
||||
layer.appendChild(createIcon('fa-regular', 'times'));
|
||||
layer.addEventListener('click', () => this.file = null);
|
||||
})
|
||||
),
|
||||
createElement('div', 'prompt-count'),
|
||||
createElement('button', button => {
|
||||
button.className = 'roundbtn button-send-message';
|
||||
@ -73,7 +186,7 @@ class InternalComment {
|
||||
setTooltip(button, r('sendMessage', 'Send Message'));
|
||||
button.addEventListener('click', () => {
|
||||
if (typeof this.#option.onAddMessage === 'function') {
|
||||
this.#option.onAddMessage(this.#enter.value);
|
||||
this.#option.onAddMessage(this.text);
|
||||
}
|
||||
})
|
||||
}),
|
||||
@ -88,7 +201,7 @@ class InternalComment {
|
||||
setTooltip(button, r('postNote', 'Post Note'));
|
||||
button.addEventListener('click', () => {
|
||||
if (typeof this.#option.onAddComment === 'function') {
|
||||
this.#option.onAddComment(this.#enter.value);
|
||||
this.#option.onAddComment(this.text, this.file);
|
||||
}
|
||||
})
|
||||
})
|
||||
@ -115,7 +228,15 @@ class InternalComment {
|
||||
div.innerText = comment.UserName;
|
||||
}));
|
||||
const content = createElement('div', 'item-content');
|
||||
content.appendChild(createElement('span', span => span.innerHTML = escapeHtml(comment.Comment)));
|
||||
const emoji = s => s.replace(/(=[A-Fa-f0-9]{2}){4}/, s => decodeURIComponent(s.replaceAll('=', '%')));
|
||||
const mmsParts = createElement('div', div => div.style.display = 'none');
|
||||
content.appendChild(createElement('span', span => span.innerHTML = emoji(escapeHtml(comment.Comment)), mmsParts));
|
||||
if (comment.IsMMS && comment.MMSParts?.length > 0) {
|
||||
mmsParts.style.display = '';
|
||||
for (let kv of comment.MMSParts) {
|
||||
appendMedia(mmsParts, kv.Key, kv.Value);
|
||||
}
|
||||
}
|
||||
if (comment.FollowUp?.length > 0) {
|
||||
div.classList.add('item-sent');
|
||||
const sendto = r('sendToColon', 'Send To :') + '\r\n' + comment.FollowUp.split(';').join('\r\n');
|
||||
|
2
lib/app/communications/lib.d.ts
vendored
2
lib/app/communications/lib.d.ts
vendored
@ -1 +1,3 @@
|
||||
export function createBox(title: HTMLElement, functions: HTMLElement[]): HTMLElement
|
||||
|
||||
export function appendMedia(container: HTMLElement, mimeType: string, url: string): HTMLElement
|
@ -1,6 +1,7 @@
|
||||
import { createElement } from "../../ui";
|
||||
import { createElement, setTooltip, showAlert, createPicture, createAudio, createVideo, createFile } from "../../ui";
|
||||
import { r } from "../../utility";
|
||||
|
||||
function createBox(title, functions) {
|
||||
export function createBox(title, functions) {
|
||||
const container = createElement('div', 'comm');
|
||||
const header = createElement('div', 'title-bar',
|
||||
title,
|
||||
@ -8,8 +9,115 @@ function createBox(title, functions) {
|
||||
);
|
||||
container.appendChild(header);
|
||||
return container;
|
||||
}
|
||||
};
|
||||
|
||||
export {
|
||||
createBox
|
||||
export function appendMedia(container, mimeType, url) {
|
||||
switch (mimeType) {
|
||||
case 'application/pdf':
|
||||
container.appendChild(createFile(url, 'file-pdf'));
|
||||
break;
|
||||
case 'application/smil':
|
||||
// TODO: ignore smil files
|
||||
// container.appendChild(createFile(url, 'smile'));
|
||||
break;
|
||||
case 'audio/amr':
|
||||
case 'audio/mp3':
|
||||
case 'audio/mpeg':
|
||||
case 'audio/x-mpeg':
|
||||
case 'audio/aac':
|
||||
case 'audio/ogg':
|
||||
case 'audio/opus':
|
||||
case 'audio/wav':
|
||||
case 'audio/webm':
|
||||
container.appendChild(createAudio(mimeType, url));
|
||||
break;
|
||||
case 'image/gif':
|
||||
case 'image/jpeg':
|
||||
case 'image/png':
|
||||
container.appendChild(createPicture(url));
|
||||
break;
|
||||
case 'text/x-vcard':
|
||||
container.appendChild(createFile(url, 'id-card'));
|
||||
break;
|
||||
case 'video/mp4':
|
||||
case 'video/mpeg':
|
||||
case 'video/x-mpeg':
|
||||
case 'video/mp2t':
|
||||
case 'video/webm':
|
||||
case 'video/quicktime':
|
||||
container.appendChild(createVideo(url));
|
||||
break;
|
||||
default:
|
||||
if (/^audio\//.test(mimeType)) {
|
||||
container.appendChild(createFile(url, 'music'));
|
||||
} else if (/^video\//.test(mimeType)) {
|
||||
container.appendChild(createFile(url, 'video'));
|
||||
} else {
|
||||
container.appendChild(createFile(url));
|
||||
}
|
||||
break;
|
||||
}
|
||||
return container;
|
||||
};
|
||||
|
||||
const MaxAttachmentSize = {
|
||||
limit: 2 * 1024 * 1024,
|
||||
text: '2MB'
|
||||
};
|
||||
|
||||
export const fileSupported = [
|
||||
'application/pdf',
|
||||
'audio/mpeg',
|
||||
'audio/x-mpeg',
|
||||
'audio/amr',
|
||||
'.amr',
|
||||
'image/bmp',
|
||||
'image/gif',
|
||||
'image/jpeg',
|
||||
'image/png',
|
||||
'image/tiff',
|
||||
'text/plain',
|
||||
'text/x-vcard',
|
||||
'video/3gpp',
|
||||
'video/mp4',
|
||||
'video/webm',
|
||||
'video/quicktime'
|
||||
];
|
||||
|
||||
export function insertFile(container, file) {
|
||||
const label = container.querySelector('.file-selector>.selector-name');
|
||||
if (label != null && file != null) {
|
||||
let type = file.type;
|
||||
if (type == null || type.length === 0) {
|
||||
type = file.name;
|
||||
type = type.substring(type.lastIndexOf('.'));
|
||||
}
|
||||
if (fileSupported.indexOf(type) < 0) {
|
||||
showAlert(r('error', 'Error'), r('notSupported', 'File type "{type}" is now not supported.').replace('{type}', type));
|
||||
return;
|
||||
}
|
||||
const isImage = /^image\//.test(type);
|
||||
if (!isImage && file.size > MaxAttachmentSize.limit) {
|
||||
showAlert(r('error', 'Error'), r('fileTooLarge', `File is too large. (> ${MaxAttachmentSize.text})`), 'warn');
|
||||
return;
|
||||
}
|
||||
const fn = file.name;
|
||||
label.style.display = '';
|
||||
label.innerText = fn;
|
||||
if (isImage) {
|
||||
const img = new Image();
|
||||
const reader = new FileReader();
|
||||
reader.onload = e => {
|
||||
img.src = e.target.result;
|
||||
setTooltip(label, img);
|
||||
};
|
||||
reader.onerror = () => setTooltip(label, fn);
|
||||
reader.readAsDataURL(file);
|
||||
// img.src = URL.createObjectURL(file);
|
||||
// setTooltip(label, img);
|
||||
} else {
|
||||
setTooltip(label, fn);
|
||||
}
|
||||
return file;
|
||||
}
|
||||
};
|
@ -290,6 +290,61 @@
|
||||
}
|
||||
}
|
||||
|
||||
>.file-selector {
|
||||
float: left;
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
height: 30px;
|
||||
|
||||
>.selector-link {
|
||||
cursor: pointer;
|
||||
display: flex;
|
||||
|
||||
>svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: var(--secondary-link-color);
|
||||
}
|
||||
|
||||
>input {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
>.selector-name {
|
||||
max-width: 130px;
|
||||
padding: 0 20px 0 4px;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
|
||||
+layer {
|
||||
display: none;
|
||||
margin-left: -20px;
|
||||
cursor: pointer;
|
||||
|
||||
>svg {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
fill: var(--red-color);
|
||||
}
|
||||
|
||||
&:hover {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover+layer {
|
||||
display: flex;
|
||||
}
|
||||
|
||||
>.ui-tooltip-wrapper img {
|
||||
max-width: 120px;
|
||||
max-height: 80px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
>.prompt-count {
|
||||
display: inline-block;
|
||||
color: var(--light-color);
|
||||
@ -340,6 +395,10 @@
|
||||
max-width: 240px;
|
||||
background-color: rgb(244, 244, 244);
|
||||
|
||||
audio[controls] {
|
||||
width: 220px;
|
||||
}
|
||||
|
||||
a>svg {
|
||||
width: 13px;
|
||||
height: 13px;
|
||||
|
@ -8,7 +8,7 @@ import { Dropdown } from "./ui/dropdown";
|
||||
import { Grid } from "./ui/grid/grid";
|
||||
import { GridColumn, GridInputColumn, GridDropdownColumn, GridCheckboxColumn, GridIconColumn, GridTextColumn } from './ui/grid/column';
|
||||
import { Popup, createPopup, showAlert, showConfirm } from "./ui/popup";
|
||||
import { createPicture, createAudio, createVideo, createPdf, createSmilefile, createVcard, createVideofile, createFile } from './ui/media';
|
||||
import { createPicture, createAudio, createVideo, createFile } from './ui/media';
|
||||
|
||||
export {
|
||||
createElement,
|
||||
@ -42,9 +42,5 @@ export {
|
||||
createPicture,
|
||||
createAudio,
|
||||
createVideo,
|
||||
createPdf,
|
||||
createSmilefile,
|
||||
createVcard,
|
||||
createVideofile,
|
||||
createFile
|
||||
}
|
||||
|
@ -29,7 +29,7 @@ function fillCheckbox(container, type = 'fa-regular', label, tabindex = -1, char
|
||||
}
|
||||
}
|
||||
|
||||
function createRadiobox(opts = {}) {
|
||||
export function createRadiobox(opts = {}) {
|
||||
const container = createElement('label', 'ui-check-wrapper ui-radio-wrapper',
|
||||
createElement('input', input => {
|
||||
input.setAttribute('type', 'radio');
|
||||
@ -56,7 +56,7 @@ function createRadiobox(opts = {}) {
|
||||
return container;
|
||||
}
|
||||
|
||||
function createCheckbox(opts = {}) {
|
||||
export function createCheckbox(opts = {}) {
|
||||
const container = createElement('label', 'ui-check-wrapper',
|
||||
createElement('input', input => {
|
||||
input.setAttribute('type', 'checkbox');
|
||||
@ -97,7 +97,7 @@ function createCheckbox(opts = {}) {
|
||||
return container;
|
||||
}
|
||||
|
||||
function resolveCheckbox(container = document.body, legacy) {
|
||||
export function resolveCheckbox(container = document.body, legacy) {
|
||||
if (legacy) {
|
||||
const checks = container.querySelectorAll('input[type="checkbox"]');
|
||||
for (let chk of checks) {
|
||||
@ -178,9 +178,3 @@ function resolveCheckbox(container = document.body, legacy) {
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
export {
|
||||
createCheckbox,
|
||||
resolveCheckbox,
|
||||
createRadiobox
|
||||
}
|
@ -8,9 +8,9 @@
|
||||
align-items: center;
|
||||
|
||||
>svg {
|
||||
width: 26px;
|
||||
height: 26px;
|
||||
fill: var(--link-color);
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
fill: var(--secondary-link-color);
|
||||
}
|
||||
|
||||
>a {
|
||||
|
@ -27,6 +27,7 @@
|
||||
--title-bg-color: rgb(68, 114, 196);
|
||||
--hover-bg-color: #eee;
|
||||
--link-color: #1890ff;
|
||||
--secondary-link-color: #1d9ac0;
|
||||
--primary-color: rgb(123, 28, 33);
|
||||
--loading-bg-color: hsla(0, 0%, 100%, .4);
|
||||
--loading-fore-color: rgba(0, 0, 0, .2);
|
||||
|
@ -9,14 +9,14 @@ function createUse(type, id) {
|
||||
return use;
|
||||
}
|
||||
|
||||
function changeIcon(svg, type, id) {
|
||||
export function changeIcon(svg, type, id) {
|
||||
if (svg instanceof SVGElement) {
|
||||
svg.replaceChildren(createUse(type, id));
|
||||
}
|
||||
return svg;
|
||||
}
|
||||
|
||||
function createIcon(type, id, style) {
|
||||
export function createIcon(type, id, style) {
|
||||
const svg = document.createElementNS(svgns, 'svg');
|
||||
svg.appendChild(createUse(type, id));
|
||||
if (style != null) {
|
||||
@ -27,7 +27,7 @@ function createIcon(type, id, style) {
|
||||
return svg;
|
||||
}
|
||||
|
||||
function resolveIcon(container) {
|
||||
export function resolveIcon(container) {
|
||||
const svgs = container.querySelectorAll('svg[data-id]');
|
||||
for (let icon of svgs) {
|
||||
const type = icon.dataset.type;
|
||||
@ -38,9 +38,3 @@ function resolveIcon(container) {
|
||||
}
|
||||
return container;
|
||||
}
|
||||
|
||||
export {
|
||||
createIcon,
|
||||
changeIcon,
|
||||
resolveIcon
|
||||
}
|
29
lib/ui/media.d.ts
vendored
29
lib/ui/media.d.ts
vendored
@ -19,31 +19,8 @@ export function createAudio(mime: string, url: string): HTMLAudioElement | HTMLD
|
||||
export function createVideo(url: string): HTMLVideoElement
|
||||
|
||||
/**
|
||||
* 创建一个 pdf 文件元素
|
||||
* @param url pdf 文件 url
|
||||
*/
|
||||
export function createPdf(url: string): HTMLDivElement
|
||||
|
||||
/**
|
||||
* 创建一个 smil 文件元素
|
||||
* @param url smil 文件 url
|
||||
*/
|
||||
export function createSmilefile(url: string): HTMLDivElement
|
||||
|
||||
/**
|
||||
* 创建一个 vcard 文件元素
|
||||
* @param url vcard 文件 url
|
||||
*/
|
||||
export function createVcard(url: string): HTMLDivElement
|
||||
|
||||
/**
|
||||
* 创建一个不支持的视频文件元素
|
||||
* @param url 视频 url
|
||||
*/
|
||||
export function createVideofile(url: string): HTMLDivElement
|
||||
|
||||
/**
|
||||
* 创建一个通用文件元素
|
||||
* 创建一个文件元素
|
||||
* @param url 文件 url
|
||||
* @param icon 图标,默认为 `file-alt`
|
||||
*/
|
||||
export function createFile(url: string): HTMLDivElement
|
||||
export function createFile(url: string, icon?: string): HTMLDivElement
|
@ -74,18 +74,18 @@ export function createAudio(mime, url) {
|
||||
let timer;
|
||||
return createElement('div', 'ui-media-audio',
|
||||
createElement('button', button => {
|
||||
button.className = 'play';
|
||||
button.addEventListener('click', () => {
|
||||
if (context != null) {
|
||||
clearInterval(timer);
|
||||
context.close();
|
||||
context = null;
|
||||
timestamp.textContent = '00:00 / 00:00';
|
||||
button.className = 'play';
|
||||
button.replaceChildren(createIcon('fa-solid', 'play'));
|
||||
return;
|
||||
}
|
||||
get(url, {
|
||||
accept: mime
|
||||
})
|
||||
get(url, { accept: mime })
|
||||
.then(r => r.blob())
|
||||
.then(r => readBlob(r))
|
||||
.then(r => playAmrArray(r))
|
||||
@ -93,10 +93,12 @@ export function createAudio(mime, url) {
|
||||
context = null;
|
||||
clearInterval(timer);
|
||||
timestamp.textContent = '00:00 / ' + getTimeLabel(ctx.duration);
|
||||
button.className = 'play';
|
||||
button.replaceChildren(createIcon('fa-solid', 'play'));
|
||||
}))
|
||||
.then(ctx => {
|
||||
context = ctx;
|
||||
button.className = 'stop';
|
||||
button.replaceChildren(createIcon('fa-solid', 'stop'));
|
||||
const total = getTimeLabel(ctx.duration);
|
||||
const refresh = () => timestamp.textContent = getTimeLabel(ctx.currentTime) + ' / ' + total;
|
||||
@ -128,8 +130,8 @@ export function createVideo(url) {
|
||||
});
|
||||
}
|
||||
|
||||
function createFileElement(url, icon) {
|
||||
return createElement('div', 'ui-media-file',
|
||||
export function createFile(url, icon = 'file-alt') {
|
||||
return createElement('div', `ui-media-file ${icon}`,
|
||||
createIcon('fa-solid', icon),
|
||||
createElement('a', a => {
|
||||
a.target = '_blank';
|
||||
@ -138,23 +140,3 @@ function createFileElement(url, icon) {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
export function createPdf(url) {
|
||||
return createFileElement(url, 'file-pdf');
|
||||
}
|
||||
|
||||
export function createSmilefile(url) {
|
||||
return createFileElement(url, 'smile');
|
||||
}
|
||||
|
||||
export function createVcard(url) {
|
||||
return createFileElement(url, 'id-card');
|
||||
}
|
||||
|
||||
export function createVideofile(url) {
|
||||
return createFileElement(url, 'photo-video');
|
||||
}
|
||||
|
||||
export function createFile(url) {
|
||||
return createFileElement(url, 'file-alt');
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
function setCookie(name, value, expireDays) {
|
||||
export function setCookie(name, value, expireDays) {
|
||||
if (name == null) {
|
||||
return;
|
||||
}
|
||||
@ -14,7 +14,7 @@ function setCookie(name, value, expireDays) {
|
||||
document.cookie = `${name}=${encodeURIComponent(value)}${extra}`;
|
||||
}
|
||||
|
||||
function getCookie(name) {
|
||||
export function getCookie(name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
@ -29,12 +29,6 @@ function getCookie(name) {
|
||||
return null;
|
||||
}
|
||||
|
||||
function deleteCookie(name) {
|
||||
export function deleteCookie(name) {
|
||||
setCookie(name, '', -1);
|
||||
}
|
||||
|
||||
export {
|
||||
getCookie,
|
||||
setCookie,
|
||||
deleteCookie
|
||||
}
|
@ -98,7 +98,7 @@ function applyLanguage(dom, result) {
|
||||
}
|
||||
}
|
||||
|
||||
async function init(dom = document.body, options = {}) {
|
||||
export async function init(dom = document.body, options = {}) {
|
||||
const lgid = getCurrentLgId();
|
||||
let lgres = localStorage.getItem(getStorageKey(lgid));
|
||||
let result;
|
||||
@ -139,14 +139,14 @@ async function init(dom = document.body, options = {}) {
|
||||
}
|
||||
}
|
||||
|
||||
function r(key, defaultValue) {
|
||||
export function r(key, defaultValue) {
|
||||
if (cache != null) {
|
||||
return getLanguage(cache, key, defaultValue);
|
||||
}
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
const lang = {
|
||||
export const lang = {
|
||||
get current() {
|
||||
return getCurrentLgId();
|
||||
},
|
||||
@ -157,9 +157,3 @@ const lang = {
|
||||
return r('savedSuccessfully', 'Saved successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
export {
|
||||
init,
|
||||
r,
|
||||
lang
|
||||
}
|
@ -8,7 +8,7 @@ function combineUrl(url) {
|
||||
return (consts.path || '') + url;
|
||||
}
|
||||
|
||||
function get(url, options = {}) {
|
||||
export function get(url, options = {}) {
|
||||
return fetch(combineUrl(url), {
|
||||
method: options.method || 'GET',
|
||||
headers: {
|
||||
@ -21,7 +21,7 @@ function get(url, options = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
function post(url, data, options = {}) {
|
||||
export function post(url, data, options = {}) {
|
||||
// let contentType;
|
||||
if (data instanceof FormData) {
|
||||
// contentType = 'multipart/form-data';
|
||||
@ -46,7 +46,7 @@ function post(url, data, options = {}) {
|
||||
});
|
||||
}
|
||||
|
||||
function upload(url, data, options = {}) {
|
||||
export function upload(url, data, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const request = new XMLHttpRequest();
|
||||
request.onreadystatechange = function () {
|
||||
@ -74,9 +74,3 @@ function upload(url, data, options = {}) {
|
||||
request.send(data);
|
||||
});
|
||||
}
|
||||
|
||||
export {
|
||||
get,
|
||||
post,
|
||||
upload
|
||||
}
|
@ -1,8 +1,8 @@
|
||||
function nullOrEmpty(s) {
|
||||
export function nullOrEmpty(s) {
|
||||
return s == null || typeof s !== 'string' || s.length === 0;
|
||||
}
|
||||
|
||||
function contains(s, key, ignoreCase) {
|
||||
export function contains(s, key, ignoreCase) {
|
||||
if (nullOrEmpty(s) || key == null) {
|
||||
return false;
|
||||
}
|
||||
@ -15,21 +15,21 @@ function contains(s, key, ignoreCase) {
|
||||
return s.indexOf(key) >= 0;
|
||||
}
|
||||
|
||||
function endsWith(s, suffix) {
|
||||
export function endsWith(s, suffix) {
|
||||
if (nullOrEmpty(s) || nullOrEmpty(suffix)) {
|
||||
return false;
|
||||
}
|
||||
return s.indexOf(suffix) === s.length - suffix.length;
|
||||
}
|
||||
|
||||
function padStart(s, num, char) {
|
||||
export function padStart(s, num, char) {
|
||||
if (nullOrEmpty(s) || isNaN(num) || num <= s.length) {
|
||||
return s;
|
||||
}
|
||||
return (char ?? ' ').repeat(num - s.length);
|
||||
}
|
||||
|
||||
function formatUrl(msg) {
|
||||
export function formatUrl(msg) {
|
||||
//const urlReg = /(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?/ig;
|
||||
//const urlArrray = str.match(urlReg);
|
||||
const p = /(http|ftp|https):\/\/.+?(\s|\r\n|\r|\n|\"|\'|\*|$)/g;
|
||||
@ -53,7 +53,7 @@ function formatUrl(msg) {
|
||||
return msg;
|
||||
}
|
||||
|
||||
function escapeHtml(text) {
|
||||
export function escapeHtml(text) {
|
||||
if (text == null) {
|
||||
return '';
|
||||
}
|
||||
@ -65,12 +65,3 @@ function escapeHtml(text) {
|
||||
.replaceAll('\n', '<br/>')
|
||||
.replaceAll(' ', ' ');
|
||||
}
|
||||
|
||||
export {
|
||||
nullOrEmpty,
|
||||
contains,
|
||||
endsWith,
|
||||
padStart,
|
||||
formatUrl,
|
||||
escapeHtml
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user