Skip to content

Instantly share code, notes, and snippets.

@dun4n
Last active November 4, 2024 15:26
Show Gist options
  • Select an option

  • Save dun4n/9353031 to your computer and use it in GitHub Desktop.

Select an option

Save dun4n/9353031 to your computer and use it in GitHub Desktop.

Revisions

  1. Amaury revised this gist Mar 5, 2014. 1 changed file with 7 additions and 9 deletions.
    16 changes: 7 additions & 9 deletions vcard.js
    Original file line number Diff line number Diff line change
    @@ -149,17 +149,15 @@

    Card.prototype[fn] = (function(key, format) {
    return (function() {
    var args = arguments
    var value = format && (function() {
    for(var j = 0, la = args.length; j < la; j++) {
    format = format.replace("{" + j + "}", args[j])
    }
    var args = Array.prototype.slice.call(arguments)
    var lastArg = args.length > 0 ? args[args.length - 1] : undefined

    return format.replace(/\{[0-9]\}/, "")
    })() || arguments[0]
    var model = vCard.Type.hasOwnProperty(lastArg) ? args.slice(0, args.length - 1) : args
    var value = format && format.replace(/\{([0-9]*)\}/g, function(match, parameter) {
    return model[parseInt(parameter)] || ''
    }) || model[0]

    var lastArg = Array.prototype.slice.call(args, -1)[0]
    this.add(key, value, vCard.Type.hasOwnProperty(lastArg) && lastArg || undefined)
    this.add(key, value, vCard.Type.hasOwnProperty(lastArg) && lastArg)
    })
    })(property.key, property.format)
    }
  2. Amaury revised this gist Mar 4, 2014. 1 changed file with 0 additions and 1 deletion.
    1 change: 0 additions & 1 deletion vcard.html
    Original file line number Diff line number Diff line change
    @@ -9,7 +9,6 @@
    var fooBar = vCard.create(vCard.Version.FOUR)
    fooBar.addFormattedname("Mr Foo Bar")
    fooBar.addEmail("foor@bar.com", vCard.Type.HOME)
    fooBar.addFormattedname("Mr Foo BAR")
    fooBar.addAddress("street", "code", "city", "country", vCard.Type.HOME)

    var link = vCard.export(fooBar, "Foo Bar", false) // use parameter true to force download
  3. Amaury revised this gist Mar 4, 2014. 2 changed files with 106 additions and 32 deletions.
    24 changes: 19 additions & 5 deletions vcard.html
    Original file line number Diff line number Diff line change
    @@ -1,29 +1,43 @@
    <!doctype html>
    <html>
    <head>
    <script type="text/javascript" src="vcard.js"></script>
    <script type="text/javascript" src="vcard2.js"></script>
    </head>
    <body>
    <script type="text/javascript">
    var johnDoe = vCard.create()
    johnDoe.add(vCard.Entry.NAME, vCard.name("John", "DOE"))
    johnDoe.add(vCard.Entry.FORMATTED_NAME, "John Doe")
    // With helper methods
    var fooBar = vCard.create(vCard.Version.FOUR)
    fooBar.addFormattedname("Mr Foo Bar")
    fooBar.addEmail("foor@bar.com", vCard.Type.HOME)
    fooBar.addFormattedname("Mr Foo BAR")
    fooBar.addAddress("street", "code", "city", "country", vCard.Type.HOME)

    var link = vCard.export(fooBar, "Foo Bar", false) // use parameter true to force download
    document.body.appendChild(link)
    </script>
    <br/>
    <script type="text/javascript">
    // Without helper methods
    var johnDoe = vCard.create(vCard.Version.FOUR)
    johnDoe.add(vCard.Entry.NAME, "DOE;John;;")
    johnDoe.add(vCard.Entry.FORMATTEDNAME, "John Doe")
    johnDoe.add(vCard.Entry.NICKNAME, "jd")
    johnDoe.add(vCard.Entry.TITLE, "Missing man")
    johnDoe.add(vCard.Entry.PHONE, "555-555-555", vCard.Type.CELL)
    johnDoe.add(vCard.Entry.EMAIL, "john.doe@work.com", vCard.Type.WORK)
    johnDoe.add(vCard.Entry.EMAIL, "john.doe@home.com", vCard.Type.HOME)
    johnDoe.add(vCard.Entry.ORGANIZATION, "JohnDoe Corp.")
    johnDoe.add(vCard.Entry.ADDRESS, ";;street;city;state;zip code;country", vCard.Type.HOME)
    johnDoe.add(vCard.Entry.ADDRESS, vCard.address("street", "zip code", "city", "country", "state"), vCard.Type.WORK)
    johnDoe.add(vCard.Entry.URL, "http://john.doe")

    var link = vCard.export(johnDoe, "John Doe", false) // use parameter true to force download
    document.body.appendChild(link)
    </script>
    <br/>
    <script type="text/javascript">
    // From JSON
    var johnSmith = {
    "version": "4.0",
    "n": "SMITH;John;;",
    "fn": "John Smith",
    "nickname":"js",
    114 changes: 87 additions & 27 deletions vcard.js
    Original file line number Diff line number Diff line change
    @@ -1,18 +1,53 @@
    (function(context) {
    var version = {
    "TWO": "2.1",
    "THREE": "3.0",
    "FOUR": "4.0"
    }

    var vCard = {
    Version: version,
    Entry: {
    "NAME": "N",
    "FORMATTED_NAME": "FN",
    "NICKNAME": "NICKNAME",
    "TITLE": "TITLE",
    "ORGANIZATION": "ORG",
    "EMAIL": "EMAIL",
    "PHONE": "TEL",
    "ADDRESS": "ADR",
    "URL": "URL",
    "BIRTHDAY": "BDAY",
    "NOTE": "NOTE",
    "ROLE": "ROLE"
    "ADDRESS": {"version": [version.TWO, version.THREE, version.FOUR], "key": "ADR", "format": ";;{0};{2};{4};{1};{3}", "@comment": "usage: addAdr(street, code, city, country, state)"},
    "AGENT": {"version": [version.TWO, version.THREE], "key": "AGENT"},
    "ANNIVERSARY": {"version": [version.FOUR], "key": "ANNIVERSARY"},
    "BIRTHDAY": {"version": [version.TWO, version.THREE, version.FOUR], "key": "BDAY"},
    "CALENDARADDURI": {"version": [version.FOUR], "key": "CALADRURI"},
    "CALENDARURI": {"version": [version.FOUR], "key": "CALURI"},
    "CATEGORIES": {"version": [version.TWO, version.THREE, version.FOUR], "key": "CATEGORIES"},
    "CLASS": {"version": [version.THREE], "key": "CLASS"},
    "CLIENTPIDMAP": {"version": [version.FOUR], "key": "CLIENTPIDMAP"},
    "EMAIL": {"version": [version.TWO, version.THREE, version.FOUR], "key": "EMAIL"},
    "FBURL": {"version": [version.FOUR], "key": "FBURL"},
    "FORMATTEDNAME": {"version": [version.TWO, version.THREE, version.FOUR], "key": "FN"},
    "GENDER": {"version": [version.FOUR], "key": "GENDER"},
    "GEO": {"version": [version.TWO, version.THREE, version.FOUR], "key": "GEO"}, // FIXME two differents formats
    "IMPP": {"version": [version.THREE, version.FOUR], "key": "IMPP"},
    // TODO: KEY
    "KIND": {"version": [version.FOUR], "key": "KIND"},
    "LABEL": {"version": [version.TWO, version.THREE], "key": "LABEL"},
    // TODO: LOGO
    "MAILER": {"version": [version.TWO, version.THREE], "key": "MAILER"},
    "MEMBER": {"version": [version.FOUR], "key": "MEMBER"},
    "NAME": {"version": [version.TWO, version.THREE, version.FOUR], "key": "N", "format": "{1};{0};;{2}", "@comment": "usage: addName(firstname, lastname, title)"},
    "NICKNAME": {"version": [version.THREE, version.FOUR], "key": "NICKNAME"},
    "NOTE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "NOTE"},
    "ORGANIZATION": {"version": [version.TWO, version.THREE, version.FOUR], "key": "ORG"},
    // TODO: PHOTO
    "PRODID": {"version": [version.THREE, version.FOUR], "key": "PRODID"},
    "PROFILE": {"version": [version.TWO, version.THREE], "key": "PROFILE"},
    "RELATED": {"version": [version.FOUR], "key": "RELATED"},
    "REVISION": {"version": [version.TWO, version.THREE, version.FOUR], "key": "REV"},
    "ROLE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "ROLE"},
    "SORTSTRING": {"version": [version.TWO, version.THREE, version.FOUR], "key": "SORT-STRING"},
    // TODO: SOUND
    "SOURCE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "SOURCE"},
    "PHONE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "TEL"},
    "TITLE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "TITLE"},
    "TIMEZONE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "TZ"}, // FIXME: two differents formats
    "UID": {"version": [version.TWO, version.THREE, version.FOUR], "key": "UID"},
    "URL": {"version": [version.TWO, version.THREE, version.FOUR], "key": "URL"},
    "XML": {"version": [version.FOUR], "key": "XML"}
    },
    Type: {
    "HOME": "HOME",
    @@ -21,11 +56,15 @@
    "MAIN": "MAIN",
    "OTHER":"OTHER"
    },
    create: function(firstname, lastname, title) {
    return new Card()
    create: function(version) {
    for(var key in this.Version) {
    if(this.Version[key] === version)
    return new Card(version)
    }
    throw new Error("Unknown vCard version")
    },
    dump: function(card) {
    var str = "BEGIN:VCARD\nVERSION:4.0\n"
    var str = "BEGIN:VCARD\n"

    for(var key in card) {
    var entry = card[key]
    @@ -58,21 +97,13 @@
    var blob = new Blob([this.dump(card)], {"type": "text/vcard"})
    a.href = URL.createObjectURL(blob)
    } else {
    a.href = "data:text/vcard;base64," + vCard.btoa(card.dump())
    a.href = "data:text/vcard;base64," + this.btoa(this.dump(card))
    }

    force && a.click()

    return a
    },
    address: function(street, code, city, country, state) {
    var options = ["", "", street, city, state, code, country]
    return options.join(";")
    },
    name: function(firstname, lastname, title) {
    var options = [lastname, firstname, "", title]
    return options.join(";")
    },
    btoa: function(str) {
    str = unescape(encodeURIComponent(str))

    @@ -105,13 +136,42 @@
    }
    }

    var Card = function() {
    var Card = function(version) {
    this.version = version

    for(var key in vCard.Entry) {
    var property = vCard.Entry[key]

    if(!property.version || property.version.indexOf(version) < 0)
    continue

    var fn = "add" + key[0].toUpperCase() + key.slice(1).toLowerCase()

    Card.prototype[fn] = (function(key, format) {
    return (function() {
    var args = arguments
    var value = format && (function() {
    for(var j = 0, la = args.length; j < la; j++) {
    format = format.replace("{" + j + "}", args[j])
    }

    return format.replace(/\{[0-9]\}/, "")
    })() || arguments[0]

    var lastArg = Array.prototype.slice.call(args, -1)[0]
    this.add(key, value, vCard.Type.hasOwnProperty(lastArg) && lastArg || undefined)
    })
    })(property.key, property.format)
    }

    this.add = function(entry, value, type) {
    !this[entry] && (this[entry] = [])
    var key = (typeof entry === "object" && entry.key) ? entry.key : entry

    !this[key] && (this[key] = [])
    var e = {"value": value}
    type && (e.type = type)

    this[entry].push(e)
    this[key].push(e)
    }
    }

  4. Amaury created this gist Mar 4, 2014.
    44 changes: 44 additions & 0 deletions vcard.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,44 @@
    <!doctype html>
    <html>
    <head>
    <script type="text/javascript" src="vcard.js"></script>
    </head>
    <body>
    <script type="text/javascript">
    var johnDoe = vCard.create()
    johnDoe.add(vCard.Entry.NAME, vCard.name("John", "DOE"))
    johnDoe.add(vCard.Entry.FORMATTED_NAME, "John Doe")
    johnDoe.add(vCard.Entry.NICKNAME, "jd")
    johnDoe.add(vCard.Entry.TITLE, "Missing man")
    johnDoe.add(vCard.Entry.PHONE, "555-555-555", vCard.Type.CELL)
    johnDoe.add(vCard.Entry.EMAIL, "john.doe@work.com", vCard.Type.WORK)
    johnDoe.add(vCard.Entry.EMAIL, "john.doe@home.com", vCard.Type.HOME)
    johnDoe.add(vCard.Entry.ORGANIZATION, "JohnDoe Corp.")
    johnDoe.add(vCard.Entry.ADDRESS, ";;street;city;state;zip code;country", vCard.Type.HOME)
    johnDoe.add(vCard.Entry.ADDRESS, vCard.address("street", "zip code", "city", "country", "state"), vCard.Type.WORK)
    johnDoe.add(vCard.Entry.URL, "http://john.doe")

    var link = vCard.export(johnDoe, "John Doe", false) // use parameter true to force download
    document.body.appendChild(link)
    </script>
    <br/>
    <script type="text/javascript">
    var johnSmith = {
    "n": "SMITH;John;;",
    "fn": "John Smith",
    "nickname":"js",
    "title": "Missing man too",
    "tel": [
    {"value": "555-555-555", "type": "cell"}
    ],
    "email": [
    { "value": "john.smith@work.com", "type": "work" },
    { "value": "john.smith@home.com", "type": "home" }
    ]
    }

    var link = vCard.export(johnSmith, "John Smith", false) // use parameter true to force download
    document.body.appendChild(link)
    </script>
    </body>
    </html>
    119 changes: 119 additions & 0 deletions vcard.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,119 @@
    (function(context) {
    var vCard = {
    Entry: {
    "NAME": "N",
    "FORMATTED_NAME": "FN",
    "NICKNAME": "NICKNAME",
    "TITLE": "TITLE",
    "ORGANIZATION": "ORG",
    "EMAIL": "EMAIL",
    "PHONE": "TEL",
    "ADDRESS": "ADR",
    "URL": "URL",
    "BIRTHDAY": "BDAY",
    "NOTE": "NOTE",
    "ROLE": "ROLE"
    },
    Type: {
    "HOME": "HOME",
    "WORK": "WORK",
    "CELL": "CELL",
    "MAIN": "MAIN",
    "OTHER":"OTHER"
    },
    create: function(firstname, lastname, title) {
    return new Card()
    },
    dump: function(card) {
    var str = "BEGIN:VCARD\nVERSION:4.0\n"

    for(var key in card) {
    var entry = card[key]

    if(typeof entry === "function")
    continue

    if(Object.prototype.toString.call(entry) === "[object Array]") {
    for(var i = 0, l = entry.length; i < l; i++) {
    var e = entry[i]
    str += key.toUpperCase() + (e.type ? ";TYPE=" + e.type.toUpperCase() + ":" : ":") + e.value + "\n"
    }
    } else if(typeof entry === "object") {
    str += key.toUpperCase() + (entry.type ? ";TYPE=" + entry.type.toUpperCase() + ":" : ":") + entry.value + "\n"
    } else {
    str += key.toUpperCase() + ":" + entry + "\n"
    }
    }

    str += "END:VCARD"

    return str
    },
    export: function(card, name, force) {
    var a = document.createElement('a')
    a.download = name + ".vcf"
    a.textContent = name

    if(Blob) {
    var blob = new Blob([this.dump(card)], {"type": "text/vcard"})
    a.href = URL.createObjectURL(blob)
    } else {
    a.href = "data:text/vcard;base64," + vCard.btoa(card.dump())
    }

    force && a.click()

    return a
    },
    address: function(street, code, city, country, state) {
    var options = ["", "", street, city, state, code, country]
    return options.join(";")
    },
    name: function(firstname, lastname, title) {
    var options = [lastname, firstname, "", title]
    return options.join(";")
    },
    btoa: function(str) {
    str = unescape(encodeURIComponent(str))

    if(!btoa) {
    var b64c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    var i, res = "", length = str.length;
    for (i = 0; i < length - 2; i += 3) {
    res += b64c[str.charCodeAt(i) >>> 2];
    res += b64c[((str.charCodeAt(i) & 3) << 4) | (str.charCodeAt(i + 1) >>> 4)];
    res += b64c[((str.charCodeAt(i + 1) & 15) << 2) | (str.charCodeAt(i + 2) >>> 6)];
    res += b64c[str.charCodeAt(i + 2) & 63];
    }

    if (length % 3 === 2) {
    res += b64c[str.charCodeAt(i) >>> 2];
    res += b64c[((str.charCodeAt(i) & 3) << 4) | (str.charCodeAt(i + 1) >>> 4)];
    res += b64c[((str.charCodeAt(i + 1) & 15) << 2)];
    res += "=";
    } else if (length % 3 === 1) {
    res += b64c[str.charCodeAt(i) >>> 2];
    res += b64c[((str.charCodeAt(i) & 3) << 4)];
    res += "==";
    }

    return res;
    } else {
    return btoa(str)
    }
    }
    }

    var Card = function() {
    this.add = function(entry, value, type) {
    !this[entry] && (this[entry] = [])
    var e = {"value": value}
    type && (e.type = type)

    this[entry].push(e)
    }
    }

    context.vCard = vCard
    })(this)