gitoriaLog in with ident

ident

All repositories: gitoria

ReadmeCodePull requestsReleasesTicketsSettings
Commitff78726cff78726cident: Hybriel master 190aa11d (fc838894 GC correctness, #127, #126 closure scopes); gates all greenmreff78726c/avatar.js

2.4 KB

  1. // avatar.js — the avatar upload of ident's identity form (ticket #15). A picked image file is
  2. // cut to a centred square, scaled to 128×128 and written into the form's hidden #favatar as a
  3. // data URL (WebP; JPEG when the browser cannot make WebP and PNG would be too big); an `input`
  4. // event hands it to the page, which sends it with the other fields. Idempotent: hl:webex may
  5. // run a page script again when it recreates a view (hybriel #32), so the listener sits on the
  6. // document once.
  7. (function () {
  8. if (window.__identAvatar) return;
  9. window.__identAvatar = true;
  10. const SIDE = 128, MAX_FILE = 20 * 1024 * 1024, MAX_URL = 60000;
  11. function note(text) {
  12. const n = document.querySelector('#avatarnote');
  13. if (n) n.textContent = text;
  14. }
  15. function encode(canvas) {
  16. let url = canvas.toDataURL('image/webp', 0.85);
  17. if (!url.startsWith('data:image/webp') && url.length > MAX_URL) url = canvas.toDataURL('image/jpeg', 0.85);
  18. return url;
  19. }
  20. document.addEventListener('change', function (ev) {
  21. const input = ev.target;
  22. if (!input || input.id !== 'favatarfile') return;
  23. const file = input.files && input.files[0];
  24. if (!file) return;
  25. note('');
  26. if (!/^image\/(png|jpeg|webp|gif)$/.test(file.type)) { note('That is not a picture (PNG, JPEG, WebP or GIF).'); input.value = ''; return; }
  27. if (file.size > MAX_FILE) { note('That picture is too big (at most 20 MB).'); input.value = ''; return; }
  28. const src = URL.createObjectURL(file);
  29. const img = new Image();
  30. img.onload = function () {
  31. URL.revokeObjectURL(src);
  32. const side = Math.min(img.naturalWidth, img.naturalHeight);
  33. if (!side) { note('That picture could not be read.'); return; }
  34. const canvas = document.createElement('canvas');
  35. canvas.width = SIDE; canvas.height = SIDE;
  36. const cx = canvas.getContext('2d');
  37. cx.drawImage(img, (img.naturalWidth - side) / 2, (img.naturalHeight - side) / 2, side, side, 0, 0, SIDE, SIDE);
  38. const url = encode(canvas);
  39. if (url.length > MAX_URL) { note('That picture is too complex — try another one.'); return; }
  40. const field = document.querySelector('#favatar');
  41. if (!field) return;
  42. field.value = url;
  43. field.dispatchEvent(new Event('input', { bubbles: true }));
  44. input.value = '';
  45. };
  46. img.onerror = function () { URL.revokeObjectURL(src); note('That picture could not be read.'); input.value = ''; };
  47. img.src = src;
  48. });
  49. })();

Branches

Latest commits

  • ff78726cident: Hybriel master 190aa11d (fc838894 GC correctness, #127, #126 closure scopes); gates all greenmre
  • a3a7d21aident: Hybriel master 8efba065 (#126 GC by bytes, #48 lambda params copy); session-writing lambdas take &sessionmre
  • 98226b41antcolony#40: mission references point to the moved missionsmre
  • ff805b9aantcolony#40: history (LOG.md), worker briefs (missions/) and reports moved here from antcolony, numbered per project; old numbers in antcolony docs/mission-map.mdmre
  • 51a7bcdfident: Hybriel master 73267707 (#122); /code uses the new page() signature; pending address passed as parameter; once-checksmre
  • 836f644fident#24: installable app (manifest, service worker, data-free offline /start), own iconmre
  • 8bebbbf2deploy.sh: back up live storage/.sessions/.env before every deploy (newest 5 kept)mre
  • cc063ea2deploy.sh: never send .git or .gitignore to Byrodinmre
  • 81b15b7bState of 2026-09-27, before the move to gitoriamre