adding TheCard preview

This commit is contained in:
or-else
2026-01-17 12:55:45 +03:00
parent 930f4f0656
commit dea781b423
36 changed files with 7720 additions and 201 deletions
+105 -15
View File
@@ -4139,14 +4139,15 @@ TheCard.exportVCard = function (card) {
}
if (Array.isArray(card.comm)) {
card.comm.forEach(comm => {
const types = comm.des.join(',').toUpperCase();
if (comm.proto === 'tel') {
vcard += `TEL;TYPE=${comm.des.toUpperCase()}:${comm.value}\r\n`;
vcard += `TEL;TYPE=${types}:${comm.value}\r\n`;
} else if (comm.proto === 'email') {
vcard += `EMAIL;TYPE=${comm.des.toUpperCase()}:${comm.value}\r\n`;
vcard += `EMAIL;TYPE=${types}:${comm.value}\r\n`;
} else if (comm.proto === 'tinode') {
vcard += `IMPP;TYPE=${comm.des.toUpperCase()};tinode:${comm.value}\r\n`;
vcard += `IMPP;TYPE=${types};tinode:${comm.value}\r\n`;
} else if (comm.proto === 'http') {
vcard += `URL;TYPE=${comm.des.toUpperCase()}:${comm.value}\r\n`;
vcard += `URL;TYPE=${types}:${comm.value}\r\n`;
}
});
}
@@ -4157,8 +4158,25 @@ TheCard.importVCard = function (vcardStr) {
if (!vcardStr || typeof vcardStr !== 'string') {
return null;
}
const lines = vcardStr.split(/\r\n|\n/);
const rawLines = vcardStr.split(/\r\n|\n/);
const lines = [];
let currentLine = '';
for (let i = 0; i < rawLines.length; i++) {
const line = rawLines[i];
if (line.startsWith(' ') || line.startsWith('\t')) {
currentLine += line.substring(1);
} else {
if (currentLine) {
lines.push(currentLine);
}
currentLine = line;
}
}
if (currentLine) {
lines.push(currentLine);
}
let card = {};
const commMap = new Map();
lines.forEach(line => {
const [keyPart, ...valueParts] = line.split(':');
if (!keyPart || valueParts.length === 0) {
@@ -4219,21 +4237,83 @@ TheCard.importVCard = function (vcardStr) {
};
}
} else if (key === 'TEL') {
const des = keyPart.split(';').find(param => param.trim().toUpperCase().startsWith('TYPE='))?.split('=')[1].trim().toLowerCase() || 'voice';
card = TheCard.addPhone(card, value, des);
const typeParams = keyPart.split(';').filter(param => param.trim().toUpperCase().startsWith('TYPE='));
const types = typeParams.flatMap(param => {
const equalIndex = param.indexOf('=');
const valuesPart = param.substring(equalIndex + 1);
return valuesPart.split(',').map(t => {
const cleaned = t.trim().toLowerCase();
return cleaned.startsWith('type=') ? cleaned.substring(5) : cleaned;
});
}).filter(t => t !== 'internet');
const mapKey = `tel|${value}`;
if (!commMap.has(mapKey)) {
commMap.set(mapKey, new Set());
}
types.forEach(t => commMap.get(mapKey).add(t));
} else if (key === 'EMAIL') {
const des = keyPart.split(';').find(param => param.trim().toUpperCase().startsWith('TYPE='))?.split('=')[1].trim().toLowerCase() || 'home';
card = TheCard.addEmail(card, value, des);
const typeParams = keyPart.split(';').filter(param => param.trim().toUpperCase().startsWith('TYPE='));
const types = typeParams.flatMap(param => {
const equalIndex = param.indexOf('=');
const valuesPart = param.substring(equalIndex + 1);
return valuesPart.split(',').map(t => {
const cleaned = t.trim().toLowerCase();
return cleaned.startsWith('type=') ? cleaned.substring(5) : cleaned;
});
}).filter(t => t !== 'internet');
const mapKey = `email|${value}`;
if (!commMap.has(mapKey)) {
commMap.set(mapKey, new Set());
}
types.forEach(t => commMap.get(mapKey).add(t));
} else if (key === 'IMPP') {
const des = keyPart.split(';').find(param => param.trim().toUpperCase().startsWith('TYPE='))?.split('=')[1].trim().toLowerCase() || 'home';
const typeParams = keyPart.split(';').filter(param => param.trim().toUpperCase().startsWith('TYPE='));
const types = typeParams.flatMap(param => {
const equalIndex = param.indexOf('=');
const valuesPart = param.substring(equalIndex + 1);
return valuesPart.split(',').map(t => {
const cleaned = t.trim().toLowerCase();
return cleaned.startsWith('type=') ? cleaned.substring(5) : cleaned;
});
}).filter(t => t !== 'internet');
const tinodeID = value.replace(/^tinode:/, '');
card = TheCard.addTinodeID(card, tinodeID, des);
const mapKey = `tinode|${tinodeID}`;
if (!commMap.has(mapKey)) {
commMap.set(mapKey, new Set());
}
types.forEach(t => commMap.get(mapKey).add(t));
} else if (key === 'URL') {
const typeParams = keyPart.split(';').filter(param => param.trim().toUpperCase().startsWith('TYPE='));
const types = typeParams.flatMap(param => {
const equalIndex = param.indexOf('=');
const valuesPart = param.substring(equalIndex + 1);
return valuesPart.split(',').map(t => {
const cleaned = t.trim().toLowerCase();
return cleaned.startsWith('type=') ? cleaned.substring(5) : cleaned;
});
}).filter(t => t !== 'internet');
const mapKey = `http|${value}`;
if (!commMap.has(mapKey)) {
commMap.set(mapKey, new Set());
}
types.forEach(t => commMap.get(mapKey).add(t));
}
});
if (commMap.size > 0) {
card.comm = [];
commMap.forEach((types, key) => {
const [proto, value] = key.split('|', 2);
card.comm.push({
proto: proto,
des: Array.from(types),
value: value
});
});
}
return card;
};
TheCard.isFileSupported = function (type, name) {
return type == 'text/vcard' || (name || '').endsWith('.vcf') || (name || '').endsWith('.vcard');
return type == 'text/vcard' || (name || '').endsWith('.vcf') || (name || '').endsWith('.vcr') || (name || '').endsWith('.vcard');
};
function theCard(fn, imageUrl, imageMimeType, note) {
let card = null;
@@ -4275,11 +4355,14 @@ function addOrSetComm(card, proto, value, type, setOnly) {
card = card || {};
card.comm = card.comm || [];
if (setOnly) {
card.comm = card.comm.filter(c => !(c.proto == proto && c.des == type));
card.comm = card.comm.filter(c => {
if (c.proto != proto) return true;
return !c.des.includes(type);
});
}
card.comm.push({
proto: proto,
des: type,
des: [type],
value: value
});
}
@@ -4287,7 +4370,14 @@ function addOrSetComm(card, proto, value, type, setOnly) {
}
function clearComm(card, proto, value, type) {
if (card && Array.isArray(card.comm)) {
card.comm = card.comm.filter(c => !(c.proto == proto && (!type || c.des == type) && (!value || c.value == value)));
card.comm = card.comm.filter(c => {
if (c.proto != proto) return true;
if (value && c.value != value) return true;
if (type) {
return !c.des.includes(type);
}
return false;
});
}
return card;
}