1(function(context) { 2 var version = { 3 "TWO": "2.1", 4 "THREE": "3.0", 5 "FOUR": "4.0" 6 } 7 8 var vCard = { 9 Version: version, 10 Entry: { 11 "ADDRESS": {"version": [version.TWO, version.THREE, version.FOUR], "key": "ADR", "format": ";;{0};{2};{4};{1};{3}", "@comment": "usage: addAdr(street, code, city, country, state)"}, 12 "AGENT": {"version": [version.TWO, version.THREE], "key": "AGENT"}, 13 "ANNIVERSARY": {"version": [version.FOUR], "key": "ANNIVERSARY"}, 14 "BIRTHDAY": {"version": [version.TWO, version.THREE, version.FOUR], "key": "BDAY"}, 15 "CALENDARADDURI": {"version": [version.FOUR], "key": "CALADRURI"}, 16 "CALENDARURI": {"version": [version.FOUR], "key": "CALURI"}, 17 "CATEGORIES": {"version": [version.TWO, version.THREE, version.FOUR], "key": "CATEGORIES"}, 18 "CLASS": {"version": [version.THREE], "key": "CLASS"}, 19 "CLIENTPIDMAP": {"version": [version.FOUR], "key": "CLIENTPIDMAP"}, 20 "EMAIL": {"version": [version.TWO, version.THREE, version.FOUR], "key": "EMAIL"}, 21 "FBURL": {"version": [version.FOUR], "key": "FBURL"}, 22 "FORMATTEDNAME": {"version": [version.TWO, version.THREE, version.FOUR], "key": "FN"}, 23 "GENDER": {"version": [version.FOUR], "key": "GENDER"}, 24 "GEO": {"version": [version.TWO, version.THREE, version.FOUR], "key": "GEO"}, // FIXME two differents formats 25 "IMPP": {"version": [version.THREE, version.FOUR], "key": "IMPP"}, 26 // TODO: KEY 27 "KIND": {"version": [version.FOUR], "key": "KIND"}, 28 "LABEL": {"version": [version.TWO, version.THREE], "key": "LABEL"}, 29 // TODO: LOGO 30 "MAILER": {"version": [version.TWO, version.THREE], "key": "MAILER"}, 31 "MEMBER": {"version": [version.FOUR], "key": "MEMBER"}, 32 "NAME": {"version": [version.TWO, version.THREE, version.FOUR], "key": "N", "format": "{1};{0};;{2}", "@comment": "usage: addName(firstname, lastname, title)"}, 33 "NICKNAME": {"version": [version.THREE, version.FOUR], "key": "NICKNAME"}, 34 "NOTE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "NOTE"}, 35 "ORGANIZATION": {"version": [version.TWO, version.THREE, version.FOUR], "key": "ORG"}, 36 // TODO: PHOTO 37 "PRODID": {"version": [version.THREE, version.FOUR], "key": "PRODID"}, 38 "PROFILE": {"version": [version.TWO, version.THREE], "key": "PROFILE"}, 39 "RELATED": {"version": [version.FOUR], "key": "RELATED"}, 40 "REVISION": {"version": [version.TWO, version.THREE, version.FOUR], "key": "REV"}, 41 "ROLE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "ROLE"}, 42 "SORTSTRING": {"version": [version.TWO, version.THREE, version.FOUR], "key": "SORT-STRING"}, 43 // TODO: SOUND 44 "SOURCE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "SOURCE"}, 45 "PHONE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "TEL"}, 46 "TITLE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "TITLE"}, 47 "TIMEZONE": {"version": [version.TWO, version.THREE, version.FOUR], "key": "TZ"}, // FIXME: two differents formats 48 "UID": {"version": [version.TWO, version.THREE, version.FOUR], "key": "UID"}, 49 "URL": {"version": [version.TWO, version.THREE, version.FOUR], "key": "URL"}, 50 "XML": {"version": [version.FOUR], "key": "XML"} 51 }, 52 Type: { 53 "HOME": "HOME", 54 "WORK": "WORK", 55 "CELL": "CELL", 56 "MAIN": "MAIN", 57 "OTHER":"OTHER" 58 }, 59 create: function(version) { 60 for(var key in this.Version) { 61 if(this.Version[key] === version) 62 return new Card(version) 63 } 64 throw new Error("vCard version") 65 }, 66 dump: function(card) { 67 var str = "BEGIN:VCARD\n" 68 69 for(var key in card) { 70 var entry = card[key] 71 72 if(typeof entry === "function") 73 continue 74 75 if(Object.prototype.toString.call(entry) === "[object Array]") { 76 for(var i = 0, l = entry.length; i < l; i++) { 77 var e = entry[i] 78 str += key.toUpperCase() + (e.type ? ";TYPE=" + e.type.toUpperCase() + ":" : ":") + e.value + "\n" 79 } 80 } else if(typeof entry === "object") { 81 str += key.toUpperCase() + (entry.type ? ";TYPE=" + entry.type.toUpperCase() + ":" : ":") + entry.value + "\n" 82 } else { 83 str += key.toUpperCase() + ":" + entry + "\n" 84 } 85 } 86 87 str += "END:VCARD"
88 89 return str 90 }, 91 export: function(card, name, force) { 92 var a = document.createElement('a') 93 a.download = name + ".vcf" 94 a.textContent = name 95 96 if(Blob) { 97 var blob = new Blob([this.dump(card)], {"type": "text/vcard"}) 98 a.href = URL.createObjectURL(blob) 99 } else { 100 a.href = "data:text/vcard;base64," + this.btoa(this.dump(card)) 101 } 102 103 force && a.click() 104 105 return a 106 }, 107 btoa: function(str) { 108 str = unescape(encodeURIComponent(str)) 109 110 if(!btoa) { 111 var b64c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 112 113 var i, res = "", length = str.length; 114 for (i = 0; i < length - 2; i += 3) { 115 res += b64c[str.charCodeAt(i) >>> 2]; 116 res += b64c[((str.charCodeAt(i) & 3) << 4) | (str.charCodeAt(i + 1) >>> 4)]; 117 res += b64c[((str.charCodeAt(i + 1) & 15) << 2) | (str.charCodeAt(i + 2) >>> 6)]; 118 res += b64c[str.charCodeAt(i + 2) & 63]; 119 } 120 121 if (length % 3 === 2) { 122 res += b64c[str.charCodeAt(i) >>> 2]; 123 res += b64c[((str.charCodeAt(i) & 3) << 4) | (str.charCodeAt(i + 1) >>> 4)]; 124 res += b64c[((str.charCodeAt(i + 1) & 15) << 2)]; 125 res += "="; 126 } else if (length % 3 === 1) { 127 res += b64c[str.charCodeAt(i) >>> 2]; 128 res += b64c[((str.charCodeAt(i) & 3) << 4)]; 129 res += "=="; 130 } 131 132 return res; 133 } else { 134 return btoa(str) 135 } 136 } 137 } 138 139 var Card = function(version) { 140 this.version = version 141 142 for(var key in vCard.Entry) { 143 var property = vCard.Entry[key] 144 145 if(!property.version || property.version.indexOf(version) < 0) 146 continue 147 148 var fn = "add" + key[0].toUpperCase() + key.slice(1).toLowerCase() 149 150 Card.prototype[fn] = (function(key, format) { 151 return (function() { 152 var args = Array.prototype.slice.call(arguments) 153 var lastArg = args.length > 0 ? args[args.length - 1] : undefined 154 155 var model = vCard.Type.hasOwnProperty(lastArg) ? args.slice(0, args.length - 1) : args 156 var value = format && format.replace(/\{([0-9]*)\}/g, function(match, parameter) { 157 return model[parseInt(parameter)] || '' 158 }) || model[0] 159 160 this.add(key, value, vCard.Type.hasOwnProperty(lastArg) && lastArg) 161 }) 162 })(property.key, property.format) 163 } 164 165 this.add = function(entry, value, type) { 166 var key = (typeof entry === "object" && entry.key) ? entry.key : entry 167 168 !this[key] && (this[key] = []) 169 var e = {"value": value} 170 type && (e.type = type) 171 172 this[key].push(e) 173 } 174 } 175
176 context.vCard = vCard 177})(this)
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.