Mercurial > xmpp-account-manager
annotate avatar.js @ 19:bde4f0bbfe69
Clear a spinner’s timeout on change if it had been set previously.
| author | Emmanuel Gil Peyrot <linkmauve@linkmauve.fr> |
|---|---|
| date | Sat, 22 Dec 2018 19:53:01 +0100 |
| parents | 3eed9fe0bd7c |
| children | cd35420457ac |
| rev | line source |
|---|---|
| 0 | 1 'use strict'; |
| 2 | |
| 3 function initAvatar(connection) { | |
| 4 const DEFAULT_AVATAR = 'data:image/svg+xml,<?xml version="1.0"?><svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 150 150"><rect width="150" height="150" fill="#888" stroke-width="1" stroke="#000"/><text x="75" y="100" text-anchor="middle" font-size="100">?</text></svg>'; | |
| 5 | |
| 6 const avatar_data = {}; | |
| 7 const avatar_img = document.getElementById('avatar'); | |
| 8 const avatar_size = document.getElementById('avatar-size'); | |
| 9 const avatar_file = document.getElementById('avatar-file'); | |
| 10 const avatar_upload = document.getElementById('avatar-upload'); | |
| 11 const avatar_change = document.getElementById('avatar-change'); | |
|
2
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
12 const avatar_access = document.getElementById('avatar-access'); |
|
11
aedf80eefc19
Also use a spinner on avatar get/set.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
13 const spinner_img = document.getElementById('avatar-spinner'); |
|
aedf80eefc19
Also use a spinner on avatar get/set.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
14 const access_model_spinner_img = document.getElementById('access-model-avatar-spinner'); |
| 0 | 15 |
| 16 avatar_img.src = DEFAULT_AVATAR; | |
| 17 const iq = $iq({type: 'get'}) | |
| 18 .c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) | |
| 19 .c('items', {node: 'urn:xmpp:avatar:metadata'}); | |
| 20 connection.sendIQ(iq, onAvatarMetadata, onAvatarRetrievalError.bind(null, 'PubSub metadata query failed.')); | |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
21 displaySpinner(spinner_img); |
| 0 | 22 |
| 23 function onAvatarMetadata(result_iq) | |
| 24 { | |
| 25 const item = parseXPath(result_iq, './pubsub:pubsub/pubsub:items/pubsub:item'); | |
| 26 if (item == null) | |
| 27 return onAvatarRetrievalError('no item found.'); | |
| 28 const id = item.getAttributeNS(null, 'id'); | |
| 29 const info = parseXPath(item, './avatar_metadata:metadata/avatar_metadata:info'); | |
| 30 if (info == null) | |
| 31 return onAvatarRetrievalError('no info found, your avatar metadata node is broken.'); | |
| 32 if (id != info.getAttributeNS(null, 'id')) | |
| 33 return onAvatarRetrievalError('invalid id in metadata.'); | |
| 34 | |
| 35 const parsed_info = { | |
| 36 id: id, | |
| 37 type: info.getAttributeNS(null, 'type'), | |
| 38 bytes: info.getAttributeNS(null, 'bytes'), | |
| 39 width: info.getAttributeNS(null, 'width'), | |
| 40 height: info.getAttributeNS(null, 'height'), | |
| 41 }; | |
| 42 const iq = $iq({type: 'get'}) | |
| 43 .c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) | |
| 44 .c('items', {node: 'urn:xmpp:avatar:data'}) | |
| 45 .c('item', {id: id}); | |
| 46 connection.sendIQ(iq, onAvatarData.bind(null, parsed_info), onAvatarRetrievalError.bind(null, 'PubSub data query failed.')); | |
| 47 } | |
| 48 | |
| 49 function onAvatarData(info, result_iq) | |
| 50 { | |
| 51 const item = parseXPath(result_iq, './pubsub:pubsub/pubsub:items/pubsub:item'); | |
| 52 if (item == null) | |
| 53 return onAvatarRetrievalError('no item found.'); | |
| 54 if (info.id != item.getAttributeNS(null, 'id')) | |
| 55 return onAvatarRetrievalError('invalid id in data.'); | |
| 56 | |
| 57 const data = parseXPath(item, './avatar_data:data').textContent; | |
| 58 const url = 'data:' + info.type + ';base64,' + data; | |
| 59 // TODO: validate the bytes too. | |
| 60 /* | |
| 61 // TODO: figure out why this didn’t work. | |
| 62 avatar_img.onload = function (evt) { | |
| 63 const img = evt.target; | |
| 64 if (img.naturalWidth != info.width || img.naturalHeight != info.height) | |
| 65 return onAvatarRetrievalError('invalid width or height in image data.'); | |
| 66 avatar_img.onload = null; | |
| 67 }; | |
| 68 */ | |
| 69 avatar_img.src = url; | |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
70 hideSpinner(spinner_img); |
| 0 | 71 } |
| 72 | |
| 73 function onAvatarRetrievalError(string) | |
| 74 { | |
| 75 console.log('Failed to retrieve avatar, an empty one is displayed instead: ' + string); | |
| 76 avatar_img.src = DEFAULT_AVATAR; | |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
77 hideSpinner(spinner_img); |
| 0 | 78 } |
| 79 | |
| 80 avatar_upload.addEventListener('click', function (evt) { | |
| 81 avatar_file.click(); | |
| 82 }); | |
| 83 | |
| 84 avatar_change.addEventListener('click', function (evt) { | |
| 85 const metadata_iq = $iq({type: 'set'}) | |
| 86 .c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) | |
| 87 .c('publish', {node: 'urn:xmpp:avatar:metadata'}) | |
| 88 .c('item', {id: avatar_data.id}) | |
| 89 .c('metadata', {xmlns: 'urn:xmpp:avatar:metadata'}) | |
| 90 .c('info', { | |
| 91 id: avatar_data.id, | |
| 92 type: avatar_data.type, | |
| 93 bytes: avatar_data.bytes, | |
| 94 width: avatar_img.naturalWidth, | |
| 95 height: avatar_img.naturalHeight, | |
| 96 }); | |
| 97 connection.sendIQ(metadata_iq, onAvatarMetadataUpload, onAvatarUploadError); | |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
98 displaySpinner(spinner_img); |
|
11
aedf80eefc19
Also use a spinner on avatar get/set.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
99 }); |
|
aedf80eefc19
Also use a spinner on avatar get/set.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
100 |
|
aedf80eefc19
Also use a spinner on avatar get/set.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
101 function onAvatarMetadataUpload(iq) |
|
aedf80eefc19
Also use a spinner on avatar get/set.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
3
diff
changeset
|
102 { |
| 0 | 103 const data_iq = $iq({type: 'set'}) |
| 104 .c('pubsub', {xmlns: 'http://jabber.org/protocol/pubsub'}) | |
| 105 .c('publish', {node: 'urn:xmpp:avatar:data'}) | |
| 106 .c('item', {id: avatar_data.id}) | |
| 107 .c('data', {xmlns: 'urn:xmpp:avatar:data'}) | |
| 108 .t(avatar_data.data); | |
| 109 connection.sendIQ(data_iq, onAvatarDataUpload, onAvatarUploadError); | |
| 110 } | |
| 111 | |
| 112 function onAvatarDataUpload(iq) | |
| 113 { | |
| 114 console.log('Avatar successfully uploaded!', iq); | |
|
13
8724e28ccbd7
Improve styling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
11
diff
changeset
|
115 avatar_change.hidden = true; |
| 0 | 116 avatar_size.innerHTML = ''; |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
117 spinnerOk(spinner_img); |
| 0 | 118 } |
| 119 | |
| 120 function onAvatarUploadError(iq) | |
| 121 { | |
| 122 console.log("onAvatarUploadError", iq); | |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
123 spinnerError(spinner_img); |
| 0 | 124 } |
| 125 | |
| 126 avatar_file.addEventListener('change', function (evt) { | |
| 127 const file = evt.target.files[0]; | |
| 128 avatar_data.type = file.type; | |
| 129 avatar_data.bytes = file.size; | |
| 130 | |
| 131 // Set the preview. | |
| 132 avatar_img.src = URL.createObjectURL(file); | |
| 133 const [size, unit] = friendlyDataSize(file.size); | |
| 134 avatar_size.innerHTML = Math.round(size) + ' ' + unit; | |
| 135 | |
| 136 // Obtain the base64 version of this file. | |
| 137 const base64_reader = new FileReader(); | |
| 138 base64_reader.onload = function (evt) { | |
| 139 const data = evt.target.result; | |
| 140 avatar_data.data = data.substr(data.indexOf(',') + 1); | |
| 141 } | |
| 142 base64_reader.readAsDataURL(file); | |
| 143 | |
| 144 // Compute the sha1 of this file. | |
| 145 const sha1_reader = new FileReader(); | |
| 146 sha1_reader.onload = async function (evt) { | |
| 147 const data = evt.target.result; | |
| 148 const digest = await window.crypto.subtle.digest('SHA-1', data); | |
| 149 const sha1 = (Array | |
| 150 .from(new Uint8Array(digest)) | |
| 151 .map(b => b.toString(16).padStart(2, "0")) | |
| 152 .join("")); | |
| 153 avatar_data.id = sha1; | |
|
13
8724e28ccbd7
Improve styling.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
11
diff
changeset
|
154 avatar_change.hidden = false; |
| 0 | 155 } |
| 156 sha1_reader.readAsArrayBuffer(file); | |
| 157 }); | |
| 158 | |
| 159 function friendlyDataSize(bytes) { | |
| 160 let unit = 'B' | |
| 161 if (bytes >= 1024) { | |
| 162 bytes /= 1024; | |
| 163 unit = 'KiB'; | |
| 164 } | |
| 165 if (bytes >= 1024) { | |
| 166 bytes /= 1024; | |
| 167 unit = 'MiB'; | |
| 168 } | |
| 169 if (bytes >= 1024) { | |
| 170 bytes /= 1024; | |
| 171 unit = 'GiB'; | |
| 172 } | |
| 173 if (bytes >= 1024) { | |
| 174 bytes /= 1024; | |
| 175 unit = 'TiB'; | |
| 176 } | |
| 177 return [bytes, unit]; | |
| 178 } | |
|
2
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
179 |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
180 avatar_access.addEventListener('change', function (evt) { |
|
3
5aa1bf7154b0
Add a simple PEP node viewer and editor.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
2
diff
changeset
|
181 const iq = configurePEPField('urn:xmpp:avatar:metadata', 'pubsub#access_model', evt.target.value); |
|
2
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
182 connection.sendIQ(iq, onAvatarConfigured, onAvatarConfigureError.bind(null, 'PubSub configuration failed.')); |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
183 displaySpinner(access_model_spinner_img); |
|
2
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
184 }); |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
185 |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
186 function onAvatarConfigured(result_iq) |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
187 { |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
188 console.log('Successfully set avatar access model.') |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
189 spinnerOk(access_model_spinner_img); |
|
2
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
190 } |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
191 |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
192 function onAvatarConfigureError(string) |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
193 { |
|
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
194 console.log('Failed to configure avatar node: ' + string); |
|
15
3eed9fe0bd7c
End spinners with either a green ✔ or a red ✘.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
13
diff
changeset
|
195 spinnerError(access_model_spinner_img); |
|
2
db033e5eabcb
Add pubsub#access_model configuration for avatars.
Emmanuel Gil Peyrot <linkmauve@linkmauve.fr>
parents:
1
diff
changeset
|
196 } |
| 0 | 197 } |
