Skip to content

Instantly share code, notes, and snippets.

@Pamblam
Created July 28, 2023 12:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Pamblam/49fdb7dcb9a8fb90fb234cdf418ecc8d to your computer and use it in GitHub Desktop.
Save Pamblam/49fdb7dcb9a8fb90fb234cdf418ecc8d to your computer and use it in GitHub Desktop.
VCard Implementtaion in Javascript
// See: https://www.rfc-editor.org/rfc/rfc6350
class VCard{
constructor(){
this.kind = null;
this.name = [];
this.nickname = [];
this.photo = [];
this.bday = null;
this.anniversary = null;
this.gender = null;
this.gender_ident = null;
this.address = [];
}
// see: .rfc6350 3.2 line delimiting and formatting
formatTextValue(str){
var chars = [...str];
var max_line_bytes = 75;
var lines = [];
var curr_line = [];
var curr_line_bytes = 0;
for (let i = 0; i < chars.length; i++) {
var char = chars[i];
if(char === ',') char = '\,';
if(char === "\n") char = '\\n';
var char_bytes = new Blob([char]).size;
if(curr_line_bytes + char_bytes > max_line_bytes){
lines.push(curr_line.join(''));
curr_line = [' ', char];
curr_line_bytes = 1 + char_bytes;
}else{
curr_line.push(char);
curr_line_bytes += char_bytes;
}
}
lines.push(curr_line.join(''));
return lines.join("\n");
}
formatDate(date){
var [y, m, d, h, min, sec, ms] = date.toISOString().split(/[^\d]+/);
return `${y}${m}${d}T${h}${min}${sec}Z`;
}
imgToDataURI(img){
var image = new Image();
image.crossOrigin = 'Anonymous';
image.onload = ()=>{
var canvas = document.createElement('canvas');
var context = canvas.getContext('2d');
canvas.height = image.naturalHeight;
canvas.width = image.naturalWidth;
context.drawImage(image, 0, 0);
done(canvas.toDataURL('image/jpeg'));
};
image.src = img.src;
}
setNickname(nickname){
this.nickname.push(nickname);
return this;
}
setName(name){
this.name.push(name);
return this;
}
setKind(kind){
kind = kind.trim().toLowerCase();
let allowed_values = [
VCard.KIND_IND,
VCard.KIND_GRP,
VCard.KIND_ORG,
VCard.KIND_LOC
];
if(!allowed_values.includes(kind)){
throw new Error("Invalid Kind value.");
}
this.kind = kind;
return this;
}
setPhoto(img){
if(!(img instanceof Image)){
throw new Error('Invalid Image.');
}
this.photo.push(img);
return this;
}
setBday(bday){
if(!(bday instanceof Date)){
throw new Error("Invalid Birthday date");
}
this.bday = bday;
return this;
}
setAnniversary(anniversary){
if(!(anniversary instanceof Date)){
throw new Error("Invalid Anniversary date");
}
this.anniversary = anniversary;
return this;
}
setGender(gender, ident=null){
gender = gender.trim().toLowerCase();
if(ident) ident = ident.trim().toLowerCase();
let allowed_values = [
VCard.GENDER_MAL,
VCard.GENDER_FEM,
VCard.GENDER_OTH,
VCard.GENDER_NON,
VCard.GENDER_UNK
];
if(!allowed_values.includes(gender)){
throw new Error("Invalid Gender value.");
}
this.gender = gender;
this.gender_ident = ident;
return this;
}
setAddress(){
}
async render(){
if(!this.name.length){
throw new Error("Missing Name property.");
}
var parts = [];
parts.push('BEGIN:VCARD');
parts.push('VERSION:4.0');
if(this.kind){
parts.push(`KIND:${this.kind}`);
}
for(let i=0; i<this.name.length; i++){
parts.push(this.formatTextValue(`FN:${this.name[i]}`));
}
if(this.nickname.length){
parts.push(`NICKNAME:${this.formatTextValue(this.nickname.join(','))}`);
}
for(let i=0; i<this.photo.length; i++){
let photo = await this.imgToDataURI(this.photo[i]);
parts.push(this.formatTextValue(`PHOTO:${photo}`));
}
if(this.bday){
parts.push(this.formatDate(`BDAY:${this.bday}`));
}
if(this.anniversary){
parts.push(this.formatDate(`ANNIVERSARY:${this.anniversary}`));
}
if(this.gender){
let gender = this.gender;
if(this.gender_ident) gender += `;${this.gender_ident}`;
parts.push(this.formatTextValue(`GENDER:${gender}`));
}
parts.push('END:VCARD');
}
}
VCard.KIND_IND = 'individual';
VCard.KIND_GRP = 'group';
VCard.KIND_ORG = 'org';
VCard.KIND_LOC = 'location';
VCard.GENDER_MAL = 'M';
VCard.GENDER_FEM = 'F';
VCard.GENDER_OTH = 'O';
VCard.GENDER_NON = 'N';
VCard.GENDER_UNK = 'U';
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment