Some checks failed
CI / lint-and-test (push) Failing after 45s
- Added Node.js setup and webapp testing steps to the CI workflow for improved integration. - Updated HTML to link multiple CSS files for better modularity and organization of styles. - Removed deprecated `style.css` and introduced new CSS files for base styles, calendar, day detail, hints, markers, states, and duty list to enhance maintainability and readability. - Implemented new styles for improved presentation of duty information and user interactions. - Added unit tests for new API functions and contact link rendering to ensure functionality and reliability.
89 lines
2.8 KiB
JavaScript
89 lines
2.8 KiB
JavaScript
/**
|
|
* Shared HTML builder for contact links (phone, Telegram) used by day detail,
|
|
* current duty, and duty list.
|
|
*/
|
|
|
|
import { t } from "./i18n.js";
|
|
import { escapeHtml } from "./utils.js";
|
|
|
|
/**
|
|
* Build HTML for contact links (phone, Telegram username).
|
|
* Validates phone/username, builds tel: and t.me hrefs, wraps in spans/links.
|
|
*
|
|
* @param {'ru'|'en'} lang - UI language for labels (when showLabels is true)
|
|
* @param {string|null|undefined} phone - Phone number
|
|
* @param {string|null|undefined} username - Telegram username with or without leading @
|
|
* @param {object} options - Rendering options
|
|
* @param {string} options.classPrefix - CSS class prefix (e.g. "day-detail-contact", "duty-contact")
|
|
* @param {boolean} [options.showLabels=true] - Whether to show "Phone:" / "Telegram:" labels
|
|
* @param {string} [options.separator=' '] - Separator between contact parts (e.g. " ", " · ")
|
|
* @returns {string} HTML string or "" if no valid contact
|
|
*/
|
|
export function buildContactLinksHtml(lang, phone, username, options) {
|
|
const { classPrefix, showLabels = true, separator = " " } = options || {};
|
|
const parts = [];
|
|
|
|
if (phone && String(phone).trim()) {
|
|
const p = String(phone).trim();
|
|
const safeHref =
|
|
"tel:" +
|
|
p.replace(/&/g, "&").replace(/"/g, """).replace(/</g, "<");
|
|
const linkHtml =
|
|
'<a href="' +
|
|
safeHref +
|
|
'" class="' +
|
|
escapeHtml(classPrefix + "-link " + classPrefix + "-phone") +
|
|
'">' +
|
|
escapeHtml(p) +
|
|
"</a>";
|
|
if (showLabels) {
|
|
const label = t(lang, "contact.phone");
|
|
parts.push(
|
|
'<span class="' +
|
|
escapeHtml(classPrefix) +
|
|
'">' +
|
|
escapeHtml(label) +
|
|
": " +
|
|
linkHtml +
|
|
"</span>"
|
|
);
|
|
} else {
|
|
parts.push(linkHtml);
|
|
}
|
|
}
|
|
|
|
if (username && String(username).trim()) {
|
|
const u = String(username).trim().replace(/^@+/, "");
|
|
if (u) {
|
|
const display = "@" + u;
|
|
const href = "https://t.me/" + encodeURIComponent(u);
|
|
const linkHtml =
|
|
'<a href="' +
|
|
escapeHtml(href) +
|
|
'" class="' +
|
|
escapeHtml(classPrefix + "-link " + classPrefix + "-username") +
|
|
'" target="_blank" rel="noopener noreferrer">' +
|
|
escapeHtml(display) +
|
|
"</a>";
|
|
if (showLabels) {
|
|
const label = t(lang, "contact.telegram");
|
|
parts.push(
|
|
'<span class="' +
|
|
escapeHtml(classPrefix) +
|
|
'">' +
|
|
escapeHtml(label) +
|
|
": " +
|
|
linkHtml +
|
|
"</span>"
|
|
);
|
|
} else {
|
|
parts.push(linkHtml);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (parts.length === 0) return "";
|
|
const rowClass = classPrefix + "-row";
|
|
return '<div class="' + escapeHtml(rowClass) + '">' + parts.join(separator) + "</div>";
|
|
}
|