diff --git a/README.md b/README.md index d2c93f794..ec0426be8 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,7 @@ It is a partial implementation of ActivityPub and of the Mastodon client API — - 📦 **Migration** — a page of its own behind your account: **Export** takes your profile, follows, followers, blocks, mutes, bookmarks, likes and every post you have written as a zip (your private key is deliberately not in it), **Import** reads one back — including an archive from `occ user:export` — and a third section brings your follows over from Mastodon, Pixelfed, GoToSocial or Akkoma via their `following_accounts.csv`. It says plainly which networks cannot be imported from, and leaves a whole-account `Move` to `occ social:account:alias` and `occ social:account:move`, since that federates and cannot be undone. - ✍️ **Composer** — write posts and replies, pick a visibility (public, unlisted, followers-only, direct), insert emoji, and attach images. `@mentions` and `#hashtags` typed by hand are extracted from the text and turned into real recipients and tags. - 📊 **Polls** — write one in the composer (up to four options, single or multiple choice, 30 minutes to a week), and view and vote on federated ones. Votes travel to the poll's author as ActivityPub vote notes, incoming votes are counted, and the new totals federate back as `Update{Question}` (`lib/Service/PollService.php`). -- 🖼️ **Media attachments** — images (JPEG, PNG, GIF, WebP, AVIF, and **HEIC/HEIF** from an iPhone, transcoded to JPEG on the way in where the server has Imagick with libheif), video (MP4, WebM, QuickTime) and audio (MP3, MP4/AAC, OGG/Opus, WAV, FLAC); `filterMimeTypes()` in `lib/Service/CacheDocumentService.php` is the exact list. Up to **ten** per post. Video and audio are stored as-is — **no transcoding** — but a video gets a **poster frame** where the server has ffmpeg, so a page of videos can be scrolled without downloading one, and `/media/{uuid}` answers **byte ranges**, so a video can actually be seeked. Video has a ceiling of its own (`max_video_size`, 2 GB) rather than the 10 MB `max_size` a picture is held to, because a video is streamed to storage a chunk at a time and never held in memory; the largest uploads go through `POST /api/v1/media/from-file`, where the Files app has already done the chunking. Clients upload through `POST /api/v2/media` (or v1), with alt text via `description`, editable with `PUT /api/v1/media/{id}` and attached to a status with `media_ids`. A **focal point** (`focus`, Mastodon's `x,y`) says where the subject is, so a square crop keeps it in frame; it federates as `focalPoint`. +- 🖼️ **Media attachments** — images (JPEG, PNG, GIF, WebP, AVIF, and **HEIC/HEIF** from an iPhone, transcoded to JPEG on the way in where the server has Imagick with libheif), video (MP4, WebM, QuickTime), audio (MP3, MP4/AAC, OGG/Opus, WAV, FLAC) — **and files**: PDF, plain text, Markdown, CSV, ZIP, EPUB and the ODF and Office document formats, shown as a named download card under the post and federated as an ActivityPub `Document` with their mime (Mastodon shows them as a link). Nothing a browser would run — no HTML, SVG or scripts — and the picture ceiling (`max_size`) applies; `filterMimeTypes()` in `lib/Service/CacheDocumentService.php` is the exact list. Up to **ten** per post. Video and audio are stored as-is — **no transcoding** — but a video gets a **poster frame** where the server has ffmpeg, so a page of videos can be scrolled without downloading one, and `/media/{uuid}` answers **byte ranges**, so a video can actually be seeked. Video has a ceiling of its own (`max_video_size`, 2 GB) rather than the 10 MB `max_size` a picture is held to, because a video is streamed to storage a chunk at a time and never held in memory; the largest uploads go through `POST /api/v1/media/from-file`, where the Files app has already done the chunking. Clients upload through `POST /api/v2/media` (or v1), with alt text via `description`, editable with `PUT /api/v1/media/{id}` and attached to a status with `media_ids`. A **focal point** (`focus`, Mastodon's `x,y`) says where the subject is, so a square crop keeps it in frame; it federates as `focalPoint`. - 🔒 **Metadata stripped on upload** — a photo off a phone carries an Exif block, and that block routinely carries the coordinates it was taken at. Every uploaded picture has its Exif, XMP, IPTC and comment blocks removed before it is stored or federated (`lib/Service/ImageMetadataService.php`). Done on the container rather than by re-encoding, so nothing loses a generation of quality, and the ICC colour profile is deliberately kept. A photo that says it is rotated is turned the right way up first, since the orientation tag goes with the rest. - 🎨 **Filters** — eight mild adjustments in the composer, previewed live and baked into the copy that is posted. - 🔳 **Profile grid** — a profile draws as a grid of squares or as a timeline, whichever you last chose. The crop follows each picture's focal point. @@ -72,7 +72,6 @@ It is a partial implementation of ActivityPub and of the Mastodon client API — These are absent from the code today, not merely rough edges: - **No status translation.** The `translate` action returns the post unchanged (`lib/Service/ActionService.php`). -- **No document or file attachments.** Images, video and audio only — anything else is refused by `filterMimeTypes()` (`lib/Service/CacheDocumentService.php`). - **No custom emoji of this instance's own.** Emoji from other servers render; `/api/v1/custom_emojis` returns an empty list (`lib/Controller/ApiController.php`, `customEmojis()`). - **No streaming API and no push subscriptions.** Third-party clients poll. (The web client does get live timelines when [notify_push](https://github.com/nextcloud/notify_push) is installed — that is a Nextcloud channel, not a Mastodon one.) diff --git a/appinfo/info.xml b/appinfo/info.xml index 3fad909b4..feeb6146c 100644 --- a/appinfo/info.xml +++ b/appinfo/info.xml @@ -32,7 +32,7 @@ What it does: - 📱 A layout for phones: the post takes the width of the screen, the face inside the card, the composer's toolbar wrapping You can pin your own posts to the top of your profile, bookmark any post, and see which hashtags the instance is using most. This is a partial implementation of ActivityPub and of the Mastodon client API. Blocking, muting and reporting (with a moderation panel in the administration settings) are supported, as are locked accounts with approvable follow requests. Polls are fully supported: create your own, and view and vote on federated ones. Profiles carry an avatar, a banner image and up to four profile metadata fields. Posts that link somewhere get a link preview card. Image (JPEG, PNG, GIF, WebP, AVIF, and HEIC from an iPhone where the server can read it), video (MP4, WebM, QuickTime) and audio attachments are supported, up to ten per post, each with alt text and a focal point. It does not offer lists.]]> - 0.19.51 + 0.19.53 agpl Benedikt Schächner Social diff --git a/composer.json b/composer.json index f1f29d4f7..63762b7f2 100644 --- a/composer.json +++ b/composer.json @@ -2,7 +2,7 @@ "name": "nextcloud/social", "description": "Social app", "license": "AGPL-3.0-or-later", - "version": "0.19.51", + "version": "0.19.53", "minimum-stability": "stable", "authors": [ { diff --git a/docs/API.md b/docs/API.md index 2f318c8f6..f7245b6f8 100644 --- a/docs/API.md +++ b/docs/API.md @@ -490,7 +490,7 @@ remote one, as on Mastodon: both describe a user of *this* instance. | Method | Route | Auth | Parameters | Description | |--------|-------|------|------------|-------------| -| POST | `/api/v1/media` | public, no-csrf (viewer required, `write` scope) | Multipart: `file` (required, read from `$_FILES['file']`), `description` (the alt text) | Stores an upload and returns the `MediaAttachment` (images get a resized preview and blurhash; video/audio are stored as-is with the media itself as `preview_url`). Refuses a mime type outside `CacheDocumentService::filterMimeTypes()`, and a file over its ceiling with a 422. **Two ceilings**: `max_size` (10 MB by default) for everything, and `max_video_size` (2048 MB) for video, because an image is read whole into memory to be stripped and resized while a video is copied to storage a chunk at a time and never held. The request-time check can only go on the type the *client* declared, so it is applied again after the content is sniffed — a file that claimed to be a video to get past the first check is refused by the second. The stored row is **not** public: `public` is what lets the unauthenticated `/media/{uuid}` route serve the file, and it is only set later, when a post attaches the media and that post is `public` or `unlisted`. `focus` is accepted and not stored. Rate-limited per user. | +| POST | `/api/v1/media` | public, no-csrf (viewer required, `write` scope) | Multipart: `file` (required, read from `$_FILES['file']`), `description` (the alt text) | Stores an upload and returns the `MediaAttachment` (images get a resized preview and blurhash; video/audio are stored as-is with the media itself as `preview_url`). Refuses a mime type outside `CacheDocumentService::filterMimeTypes()` — images, video, audio and the document kinds in `DOCUMENT_MIME_TYPES` (PDF, text, Markdown, CSV, ZIP, EPUB, ODF, Office), which come back as `type: "unknown"` with no `preview_url` and, when no `description` was sent, the upload's file name as the description — and a file over its ceiling with a 422. **Two ceilings**: `max_size` (10 MB by default) for everything, and `max_video_size` (2048 MB) for video, because an image is read whole into memory to be stripped and resized while a video is copied to storage a chunk at a time and never held. The request-time check can only go on the type the *client* declared, so it is applied again after the content is sniffed — a file that claimed to be a video to get past the first check is refused by the second. The stored row is **not** public: `public` is what lets the unauthenticated `/media/{uuid}` route serve the file, and it is only set later, when a post attaches the media and that post is `public` or `unlisted`. `focus` is accepted and not stored. Rate-limited per user. | | POST | `/api/v2/media` | public, no-csrf (viewer required, `write` scope) | Same as v1 | The same upload; modern clients POST v2 and only fall back to v1 on a 404. | | POST | `/api/v1/media/from-file` | public, no-csrf (viewer required, `write` scope) | Body (JSON or form-encoded): `path` (required, relative to the viewer's own files), `description` (the alt text) | **Nextcloud extension, not a Mastodon route.** Attaches a file the viewer already has in Nextcloud, so a picture that is already on the server does not have to be downloaded and uploaded back. The path is resolved inside the viewer's own user folder and nowhere else — a share they can read is fair game, a traversal is a 422 `no such file`, and so is a folder. The bytes are copied, not referenced: a post keeps the picture it was published with, so moving or deleting the original later cannot empty a post that has already federated. Everything after that is the upload path — the same size ceiling, the same mime filter, the same resizing — and the answer is the same `MediaAttachment`, equally not public until a post says so. Rate-limited per user. | | GET | `/api/v1/media/{nid}` | public, no-csrf | `nid` (path), `preview` (default `''`, ignored) | One of the viewer's own attachments, by the id the upload returned. 404 for an unknown id or someone else's attachment. | diff --git a/docs/Architecture.md b/docs/Architecture.md index 105556a16..9729d1edf 100644 --- a/docs/Architecture.md +++ b/docs/Architecture.md @@ -7,7 +7,7 @@ Nextcloud Social is a federated social networking app built on the W3C ActivityP **App ID:** `social` **Namespace:** `OCA\Social` **License:** AGPL-3.0-or-later -**App version:** 0.19.51 +**App version:** 0.19.53 **Supported Nextcloud versions:** 35 – 36 **Supported PHP versions:** 8.3 – 8.5 diff --git a/js/social-adminAnnouncements.js b/js/social-adminAnnouncements.js index 03d7d16b7..1e4242540 100644 --- a/js/social-adminAnnouncements.js +++ b/js/social-adminAnnouncements.js @@ -1,2 +1,2 @@ -(()=>{"use strict";var e={37844(e,d,o){var _=o(47606),n=o(55705);async function s(e){const{showError:d}=await Promise.all([o.e("vendors-node_modules_mdi_js_mdi_js-node_modules_nextcloud_vue_dist_chunks_NcDialogButton_vue_-bd7251"),o.e("vendors-node_modules_nextcloud_capabilities_dist_index_mjs-node_modules_nextcloud_l10n_dist_g-2544a4"),o.e("vendors-node_modules_nextcloud_dialogs_dist_index_mjs-node_modules_nextcloud_vue_dist_chunks_-6b9069")]).then(()=>o(84973));d(e)}async function a(e,d,o){const s=await fetch((0,n.Jv)("/apps/social/admin/announcements")+d,{method:e,headers:{"Content-Type":"application/json",requesttoken:(0,_.do)()},body:void 0===o?void 0:JSON.stringify(o)}),a=await s.json().catch(()=>({}));if(!s.ok)throw new Error(a.error||"request failed: "+s.status);return a}function l(e,d){return e?d?e.slice(0,10):e.slice(0,16).replace("T"," "):"—"}function c(e){const d=document.getElementById("social-announcements-list");if(null!==d){if(d.textContent="",0===e.length){const e=d.insertRow().insertCell();return e.colSpan=5,void(e.textContent=t("social","No announcements."))}e.forEach(e=>{const o=d.insertRow();o.dataset.announcementId=e.id,o.insertCell().textContent=e.text,o.insertCell().textContent=l(e.starts_at,e.all_day),o.insertCell().textContent=l(e.ends_at,e.all_day),o.insertCell().textContent=e.active?t("social","Shown now"):t("social","Not shown");const _=document.createElement("button");_.type="button",_.className="social-announcement-remove",_.textContent=t("social","Remove"),o.insertCell().appendChild(_)})}}async function f(){const e=document.getElementById("social-announcement-text"),d=document.getElementById("social-announcement-starts"),o=document.getElementById("social-announcement-ends"),_=document.getElementById("social-announcement-all-day");if(""!==e.value.trim())try{const n=await a("POST","",{text:e.value,starts_at:d.value,ends_at:o.value,all_day:_.checked});e.value="",d.value="",o.value="",_.checked=!1,c(n.announcements)}catch(e){await s(t("social","Could not post the announcement")+": "+e.message)}}async function u(e){const d=e.target.closest(".social-announcement-remove");if(null===d)return;const o=d.closest("tr");if(window.confirm(t("social","Remove this announcement? Everybody stops seeing it.")))try{c((await a("DELETE","/"+o.dataset.announcementId)).announcements)}catch{await s(t("social","Could not remove the announcement"))}}function i(){return null!==document.getElementById("social-announcements")&&(document.getElementById("social-announcement-add").addEventListener("click",f),document.getElementById("social-announcements-list").addEventListener("click",u),async function(){try{c((await a("GET","")).announcements)}catch{await s(t("social","Could not read the announcements"))}}(),!0)}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",i):i()}};const d={};function o(_){const n=d[_];if(void 0!==n)return n.exports;const s=d[_]={id:_,exports:{}};return e[_].call(s.exports,s,s.exports,o),s.exports}o.m=e,(()=>{const e=[];o.O=(d,_,n,s)=>{if(_){s=s||0;for(var a=e.length;a>0&&e[a-1][2]>s;a--)e[a]=e[a-1];return void(e[a]=[_,n,s])}let l=1/0;for(a=0;a=s)||!Object.keys(o.O).every(e=>o.O[e](_[t]))?(c=!1,s{const d=e&&e.__esModule?()=>e.default:()=>e;return o.d(d,{a:d}),d},o.d=(e,d)=>{if(Array.isArray(d))for(var _=0;_Promise.all(Object.keys(o.f).reduce((d,_)=>(o.f[_](e,d),d),[])),o.u=e=>"social-"+e+".js?v="+{"vendors-node_modules_mdi_js_mdi_js-node_modules_nextcloud_vue_dist_chunks_NcDialogButton_vue_-bd7251":"3e2b71cf51197c794c29","vendors-node_modules_nextcloud_capabilities_dist_index_mjs-node_modules_nextcloud_l10n_dist_g-2544a4":"a28894d8e9152722e7d9","vendors-node_modules_nextcloud_dialogs_dist_index_mjs-node_modules_nextcloud_vue_dist_chunks_-6b9069":"2ae851b0670e53454f64","vendors-node_modules_nextcloud_vue_dist_chunks_NcCheckboxRadioSwitch_mjs":"c4909cd77df1a40a4330","vendors-node_modules_nextcloud_files_dist_index_mjs":"53b15fa0c41f0d8a097e","vendors-node_modules_nextcloud_dialogs_dist_chunks_preview_mjs-node_modules_nextcloud_vue_dis-5d78a6":"945c5d0bcfe0eaf4fa9c","vendors-node_modules_nextcloud_dialogs_dist_chunks_ConflictPicker_mjs":"af68252184eed3d59710","vendors-node_modules_nextcloud_vue_dist_components_NcTextField_index_mjs":"3ea6155dab1c4c354348","vendors-node_modules_nextcloud_dialogs_dist_chunks_FilePicker_mjs":"4b0c621cb1fd75fbe5f0",node_modules_nextcloud_dialogs_dist_chunks_PublicAuthPrompt_mjs:"caeda7e73e2e577aa10a","vendors-node_modules_nextcloud_vue_dist_chunks_NcColorPicker_mjs":"fc2fcf460bd3bde759a2","node_modules_nextcloud_vue_dist_chunks_colors_mjs-node_modules_nextcloud_vue_dist_components_-f3952b":"a4dd6dcd265410f1c309","vendors-node_modules_nextcloud_vue_dist_components_NcDateTimePicker_index_mjs":"180e863b386b008b611b","node_modules_date-fns_locale_af_js":"568c99a50eb22ae04840","node_modules_date-fns_locale_ar-DZ_js":"6e89d6a2d4cfcfa30c61","node_modules_date-fns_locale_ar-EG_js":"be1ff514b0d6fc1198a0","node_modules_date-fns_locale_ar-MA_js":"f8c4b791ee7ce50afe69","node_modules_date-fns_locale_ar-SA_js":"98906aed5ac7d6f9c3e7","node_modules_date-fns_locale_ar-TN_js":"37139facab7983a31fe7","node_modules_date-fns_locale_ar_js":"1e6a3bd7f34370443280","node_modules_date-fns_locale_az_js":"b347187cd3a657be3303","vendors-node_modules_date-fns_locale_be-tarask_js":"6288131657b45948cd72","vendors-node_modules_date-fns_locale_be_js":"a036a6a873e65e6d996a","node_modules_date-fns_locale_bg_js":"3716dd6c67895e0a97d8","node_modules_date-fns_locale_bn_js":"ad9fd51273200f70045d","node_modules_date-fns_locale_bs_js":"5be34af0dfd14657caf7","node_modules_date-fns_locale_ca_js":"ecb9b5b9392c29a6b9c2","node_modules_date-fns_locale_ckb_js":"ab52b99a3de68d8bb3c8","node_modules_date-fns_locale_cs_js":"f3e801b3926b6291d052","node_modules_date-fns_locale_cy_js":"a843834a72287ae2eace","node_modules_date-fns_locale_da_js":"2c5b0383c0b5e043e0ad","node_modules_date-fns_locale_de-AT_js":"e72bc9a15ff2f0d4105e","node_modules_date-fns_locale_de_js":"75fd92a90b4980d5edbc","node_modules_date-fns_locale_el_js":"7c6edc1d0f74fc216589","node_modules_date-fns_locale_en-AU_js":"5ca04682bd5c803b05ea","node_modules_date-fns_locale_en-CA_js":"81a7afedca2c47e140fc","node_modules_date-fns_locale_en-GB_js":"98fddc07e3795d5874ed","node_modules_date-fns_locale_en-IE_js":"361c2f65d743136e3ec4","node_modules_date-fns_locale_en-IN_js":"82e2b1c92852a8d6e55a","node_modules_date-fns_locale_en-NZ_js":"59aad90c55be04d643bd","node_modules_date-fns_locale_en-ZA_js":"d30ac50ccb916d26ea79","node_modules_date-fns_locale_eo_js":"47a4dc5a2679155ca540","node_modules_date-fns_locale_es_js":"95976019b5a76437ad94","node_modules_date-fns_locale_et_js":"69f31ec6a4f1134c0da8","node_modules_date-fns_locale_eu_js":"943453591aba185b79f3","node_modules_date-fns_locale_fa-IR_js":"d5a6b40b3bd909abeaeb","node_modules_date-fns_locale_fi_js":"761ba05d1ef3c085f7fb","node_modules_date-fns_locale_fr-CA_js":"391a41fbf81e8532e012","node_modules_date-fns_locale_fr-CH_js":"06da66fe72d7fefe7a8a","node_modules_date-fns_locale_fr_js":"da0057b66ba6c20796e5","node_modules_date-fns_locale_fy_js":"f65f659e599327620007","node_modules_date-fns_locale_gd_js":"39ede8a94802f1a3cda8","node_modules_date-fns_locale_gl_js":"2f2ac87357e14fb26633","node_modules_date-fns_locale_gu_js":"179ac12c398d68c43610","node_modules_date-fns_locale_he_js":"a28a70115acac7dad4a9","node_modules_date-fns_locale_hi_js":"bd7e847b67a3cc859b76","node_modules_date-fns_locale_hr_js":"6dfaa62c0b98e880c941","node_modules_date-fns_locale_ht_js":"a95dd7bceabba303dda0","node_modules_date-fns_locale_hu_js":"ac8392ad5b1678ebfd98","node_modules_date-fns_locale_hy_js":"3a171c3d3a191690280b","node_modules_date-fns_locale_id_js":"66977128d3cef88a1e9b","node_modules_date-fns_locale_is_js":"44c1169ff3cba87f99b6","node_modules_date-fns_locale_it-CH_js":"e0795c631760ce2725c1","node_modules_date-fns_locale_it_js":"4e0a835b7a27689064e8","node_modules_date-fns_locale_ja-Hira_js":"92a285c1b2f3697da366","node_modules_date-fns_locale_ja_js":"a53163ec60f6a76248c6","node_modules_date-fns_locale_ka_js":"f4422b6464a934a7bf45","vendors-node_modules_date-fns_locale_kk_js":"8951e01f07eab56f7ee6","node_modules_date-fns_locale_km_js":"c9b96b942d36af319913","node_modules_date-fns_locale_kn_js":"99ec5cabd1585ad21a6a","node_modules_date-fns_locale_ko_js":"802f82cd669c91c0640f","node_modules_date-fns_locale_lb_js":"32aa5e189a8e07a0c21c","node_modules_date-fns_locale_lt_js":"e1e38226c66fac38b0b8","node_modules_date-fns_locale_lv_js":"9cf0f6e0b553d722381d","node_modules_date-fns_locale_mk_js":"925bd061c887a4760da4","node_modules_date-fns_locale_mn_js":"5b8012f4a110b6f0a3d2","node_modules_date-fns_locale_ms_js":"5049aa6f858d8647a525","node_modules_date-fns_locale_mt_js":"0f004de3b66ece204a61","node_modules_date-fns_locale_nb_js":"3cb82fc909bac3133c43","node_modules_date-fns_locale_nl-BE_js":"81f72650f040c3b48200","node_modules_date-fns_locale_nl_js":"ed3b052a5967d8d30726","node_modules_date-fns_locale_nn_js":"f1c96e02ed6bd0cce945","node_modules_date-fns_locale_oc_js":"efce8c0a2c7116e87565","node_modules_date-fns_locale_pl_js":"8eac758ad7ba41178d57","node_modules_date-fns_locale_pt-BR_js":"d8aa7ea1913c80e7e883","node_modules_date-fns_locale_pt_js":"e6d012791c238caf6da9","node_modules_date-fns_locale_ro_js":"38984a9e22e4375f4ad5","vendors-node_modules_date-fns_locale_ru_js":"66e37716f2be9f613c49","node_modules_date-fns_locale_se_js":"e9ce2b63e8962a8f53f3","node_modules_date-fns_locale_sk_js":"2eee76a3773ef54960db","node_modules_date-fns_locale_sl_js":"ab249dbe99080ab1dc49","node_modules_date-fns_locale_sq_js":"710e55d8844bf0b34b0f","node_modules_date-fns_locale_sr-Latn_js":"85dc36f5095f0a216480","node_modules_date-fns_locale_sr_js":"1de8a167bdfaf7b39e7d","node_modules_date-fns_locale_sv_js":"130bbf67a52d352e04d8","node_modules_date-fns_locale_ta_js":"b0fa7943fbff7d2afb62","node_modules_date-fns_locale_te_js":"047cade7b1eda27b7675","node_modules_date-fns_locale_th_js":"e6530c0aaf2f2d480ee3","node_modules_date-fns_locale_tr_js":"de92f93650bdf6dd30a6","node_modules_date-fns_locale_ug_js":"0a8f60c94518dca1f291","vendors-node_modules_date-fns_locale_uk_js":"8b92ef8649d20c2101d5","node_modules_date-fns_locale_uz-Cyrl_js":"e0dc86eededd804e89ee","node_modules_date-fns_locale_uz_js":"0c31e869dc60b8e46c99","node_modules_date-fns_locale_vi_js":"193ee6a45cf99fca1efb","node_modules_date-fns_locale_zh-CN_js":"ed2b186b169669aafacc","node_modules_date-fns_locale_zh-HK_js":"1bfa9f02dab15b463cd8","node_modules_date-fns_locale_zh-TW_js":"5b37dba10ab292c20b95"}[e],o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,d)=>Object.prototype.hasOwnProperty.call(e,d),(()=>{const e={},d="social:";o.l=(_,n,s,a)=>{if(e[_])return void e[_].push(n);let l,t;if(void 0!==s){const e=document.getElementsByTagName("script");for(var c=0;c{l.onerror=l.onload=null,clearTimeout(u);const n=e[_];if(delete e[_],l.parentNode?.removeChild(l),n?.forEach(e=>e(o)),d)return d(o)},u=setTimeout(f.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=f.bind(null,l.onerror),l.onload=f.bind(null,l.onload),t&&document.head.appendChild(l)}})(),o.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.j="adminAnnouncements",o.dn=e=>{var d=Object.getOwnPropertyDescriptor(e,"name");(!d||!d.writable&&d.configurable)&&Object.defineProperty(e,"name",{value:"default",configurable:!0})},o.p="/apps/social/js/",(()=>{const e={adminAnnouncements:0};o.f.j=(d,_)=>{let n=o.o(e,d)?e[d]:void 0;if(0!==n)if(n)_.push(n[2]);else{const s=new Promise((o,_)=>n=e[d]=[o,_]);_.push(n[2]=s);const a=new Error,l=_=>{if(o.o(e,d)&&(n=e[d],0!==n&&(e[d]=void 0),n)){const e=_&&("load"===_.type?"missing":_.type),o=_&&_.target&&_.target.src;a.message="Loading chunk "+d+" failed.\n("+e+": "+o+")",a.name="ChunkLoadError",a.type=e,a.request=o,a.event=_,n[1](a)}};o.l(o.p+o.u(d),l,"chunk-"+d,d)}},o.O.j=d=>0===e[d];const d=(d,_)=>{let[n,s,a]=_;var l,t,c=0;if(n.some(d=>0!==e[d])){for(l in s)o.o(s,l)&&(o.m[l]=s[l]);if(a)var f=a(o)}for(d&&d(_);co(37844));_=o.O(_)})(); -//# sourceMappingURL=social-adminAnnouncements.js.map?v=49c4e0c8b40687af2e00 \ No newline at end of file +(()=>{"use strict";var e={37844(e,d,o){var _=o(47606),n=o(55705);async function s(e){const{showError:d}=await Promise.all([o.e("vendors-node_modules_mdi_js_mdi_js-node_modules_nextcloud_vue_dist_chunks_NcDialogButton_vue_-bd7251"),o.e("vendors-node_modules_nextcloud_capabilities_dist_index_mjs-node_modules_nextcloud_l10n_dist_g-2544a4"),o.e("vendors-node_modules_nextcloud_dialogs_dist_index_mjs-node_modules_nextcloud_vue_dist_chunks_-6b9069")]).then(()=>o(84973));d(e)}async function a(e,d,o){const s=await fetch((0,n.Jv)("/apps/social/admin/announcements")+d,{method:e,headers:{"Content-Type":"application/json",requesttoken:(0,_.do)()},body:void 0===o?void 0:JSON.stringify(o)}),a=await s.json().catch(()=>({}));if(!s.ok)throw new Error(a.error||"request failed: "+s.status);return a}function l(e,d){return e?d?e.slice(0,10):e.slice(0,16).replace("T"," "):"—"}function c(e){const d=document.getElementById("social-announcements-list");if(null!==d){if(d.textContent="",0===e.length){const e=d.insertRow().insertCell();return e.colSpan=5,void(e.textContent=t("social","No announcements."))}e.forEach(e=>{const o=d.insertRow();o.dataset.announcementId=e.id,o.insertCell().textContent=e.text,o.insertCell().textContent=l(e.starts_at,e.all_day),o.insertCell().textContent=l(e.ends_at,e.all_day),o.insertCell().textContent=e.active?t("social","Shown now"):t("social","Not shown");const _=document.createElement("button");_.type="button",_.className="social-announcement-remove",_.textContent=t("social","Remove"),o.insertCell().appendChild(_)})}}async function f(){const e=document.getElementById("social-announcement-text"),d=document.getElementById("social-announcement-starts"),o=document.getElementById("social-announcement-ends"),_=document.getElementById("social-announcement-all-day");if(""!==e.value.trim())try{const n=await a("POST","",{text:e.value,starts_at:d.value,ends_at:o.value,all_day:_.checked});e.value="",d.value="",o.value="",_.checked=!1,c(n.announcements)}catch(e){await s(t("social","Could not post the announcement")+": "+e.message)}}async function u(e){const d=e.target.closest(".social-announcement-remove");if(null===d)return;const o=d.closest("tr");if(window.confirm(t("social","Remove this announcement? Everybody stops seeing it.")))try{c((await a("DELETE","/"+o.dataset.announcementId)).announcements)}catch{await s(t("social","Could not remove the announcement"))}}function i(){return null!==document.getElementById("social-announcements")&&(document.getElementById("social-announcement-add").addEventListener("click",f),document.getElementById("social-announcements-list").addEventListener("click",u),async function(){try{c((await a("GET","")).announcements)}catch{await s(t("social","Could not read the announcements"))}}(),!0)}"loading"===document.readyState?document.addEventListener("DOMContentLoaded",i):i()}};const d={};function o(_){const n=d[_];if(void 0!==n)return n.exports;const s=d[_]={id:_,exports:{}};return e[_].call(s.exports,s,s.exports,o),s.exports}o.m=e,(()=>{const e=[];o.O=(d,_,n,s)=>{if(_){s=s||0;for(var a=e.length;a>0&&e[a-1][2]>s;a--)e[a]=e[a-1];return void(e[a]=[_,n,s])}let l=1/0;for(a=0;a=s)||!Object.keys(o.O).every(e=>o.O[e](_[t]))?(c=!1,s{const d=e&&e.__esModule?()=>e.default:()=>e;return o.d(d,{a:d}),d},o.d=(e,d)=>{if(Array.isArray(d))for(var _=0;_Promise.all(Object.keys(o.f).reduce((d,_)=>(o.f[_](e,d),d),[])),o.u=e=>"social-"+e+".js?v="+{"vendors-node_modules_mdi_js_mdi_js-node_modules_nextcloud_vue_dist_chunks_NcDialogButton_vue_-bd7251":"3e2b71cf51197c794c29","vendors-node_modules_nextcloud_capabilities_dist_index_mjs-node_modules_nextcloud_l10n_dist_g-2544a4":"a28894d8e9152722e7d9","vendors-node_modules_nextcloud_dialogs_dist_index_mjs-node_modules_nextcloud_vue_dist_chunks_-6b9069":"2ae851b0670e53454f64","vendors-node_modules_nextcloud_vue_dist_chunks_NcCheckboxRadioSwitch_mjs":"c4909cd77df1a40a4330","vendors-node_modules_nextcloud_files_dist_index_mjs":"53b15fa0c41f0d8a097e","vendors-node_modules_nextcloud_dialogs_dist_chunks_preview_mjs-node_modules_nextcloud_vue_dis-5d78a6":"945c5d0bcfe0eaf4fa9c","vendors-node_modules_nextcloud_dialogs_dist_chunks_ConflictPicker_mjs":"af68252184eed3d59710","vendors-node_modules_nextcloud_vue_dist_components_NcTextField_index_mjs":"3ea6155dab1c4c354348","vendors-node_modules_nextcloud_dialogs_dist_chunks_FilePicker_mjs":"4b0c621cb1fd75fbe5f0",node_modules_nextcloud_dialogs_dist_chunks_PublicAuthPrompt_mjs:"caeda7e73e2e577aa10a","vendors-node_modules_nextcloud_vue_dist_chunks_NcColorPicker_mjs":"fc2fcf460bd3bde759a2","node_modules_nextcloud_vue_dist_chunks_colors_mjs-node_modules_nextcloud_vue_dist_components_-f3952b":"a4dd6dcd265410f1c309","vendors-node_modules_nextcloud_vue_dist_components_NcDateTimePicker_index_mjs":"9230b70e5e8a07f09e58","node_modules_date-fns_locale_af_js":"568c99a50eb22ae04840","node_modules_date-fns_locale_ar-DZ_js":"6e89d6a2d4cfcfa30c61","node_modules_date-fns_locale_ar-EG_js":"be1ff514b0d6fc1198a0","node_modules_date-fns_locale_ar-MA_js":"f8c4b791ee7ce50afe69","node_modules_date-fns_locale_ar-SA_js":"98906aed5ac7d6f9c3e7","node_modules_date-fns_locale_ar-TN_js":"37139facab7983a31fe7","node_modules_date-fns_locale_ar_js":"1e6a3bd7f34370443280","node_modules_date-fns_locale_az_js":"b347187cd3a657be3303","vendors-node_modules_date-fns_locale_be-tarask_js":"6288131657b45948cd72","vendors-node_modules_date-fns_locale_be_js":"a036a6a873e65e6d996a","node_modules_date-fns_locale_bg_js":"3716dd6c67895e0a97d8","node_modules_date-fns_locale_bn_js":"ad9fd51273200f70045d","node_modules_date-fns_locale_bs_js":"5be34af0dfd14657caf7","node_modules_date-fns_locale_ca_js":"ecb9b5b9392c29a6b9c2","node_modules_date-fns_locale_ckb_js":"ab52b99a3de68d8bb3c8","node_modules_date-fns_locale_cs_js":"f3e801b3926b6291d052","node_modules_date-fns_locale_cy_js":"a843834a72287ae2eace","node_modules_date-fns_locale_da_js":"2c5b0383c0b5e043e0ad","node_modules_date-fns_locale_de-AT_js":"e72bc9a15ff2f0d4105e","node_modules_date-fns_locale_de_js":"75fd92a90b4980d5edbc","node_modules_date-fns_locale_el_js":"7c6edc1d0f74fc216589","node_modules_date-fns_locale_en-AU_js":"5ca04682bd5c803b05ea","node_modules_date-fns_locale_en-CA_js":"81a7afedca2c47e140fc","node_modules_date-fns_locale_en-GB_js":"98fddc07e3795d5874ed","node_modules_date-fns_locale_en-IE_js":"361c2f65d743136e3ec4","node_modules_date-fns_locale_en-IN_js":"82e2b1c92852a8d6e55a","node_modules_date-fns_locale_en-NZ_js":"59aad90c55be04d643bd","node_modules_date-fns_locale_en-ZA_js":"d30ac50ccb916d26ea79","node_modules_date-fns_locale_eo_js":"47a4dc5a2679155ca540","node_modules_date-fns_locale_es_js":"95976019b5a76437ad94","node_modules_date-fns_locale_et_js":"69f31ec6a4f1134c0da8","node_modules_date-fns_locale_eu_js":"943453591aba185b79f3","node_modules_date-fns_locale_fa-IR_js":"d5a6b40b3bd909abeaeb","node_modules_date-fns_locale_fi_js":"761ba05d1ef3c085f7fb","node_modules_date-fns_locale_fr-CA_js":"391a41fbf81e8532e012","node_modules_date-fns_locale_fr-CH_js":"06da66fe72d7fefe7a8a","node_modules_date-fns_locale_fr_js":"da0057b66ba6c20796e5","node_modules_date-fns_locale_fy_js":"f65f659e599327620007","node_modules_date-fns_locale_gd_js":"39ede8a94802f1a3cda8","node_modules_date-fns_locale_gl_js":"2f2ac87357e14fb26633","node_modules_date-fns_locale_gu_js":"179ac12c398d68c43610","node_modules_date-fns_locale_he_js":"a28a70115acac7dad4a9","node_modules_date-fns_locale_hi_js":"bd7e847b67a3cc859b76","node_modules_date-fns_locale_hr_js":"6dfaa62c0b98e880c941","node_modules_date-fns_locale_ht_js":"a95dd7bceabba303dda0","node_modules_date-fns_locale_hu_js":"ac8392ad5b1678ebfd98","node_modules_date-fns_locale_hy_js":"3a171c3d3a191690280b","node_modules_date-fns_locale_id_js":"66977128d3cef88a1e9b","node_modules_date-fns_locale_is_js":"44c1169ff3cba87f99b6","node_modules_date-fns_locale_it-CH_js":"e0795c631760ce2725c1","node_modules_date-fns_locale_it_js":"4e0a835b7a27689064e8","node_modules_date-fns_locale_ja-Hira_js":"92a285c1b2f3697da366","node_modules_date-fns_locale_ja_js":"a53163ec60f6a76248c6","node_modules_date-fns_locale_ka_js":"f4422b6464a934a7bf45","vendors-node_modules_date-fns_locale_kk_js":"8951e01f07eab56f7ee6","node_modules_date-fns_locale_km_js":"c9b96b942d36af319913","node_modules_date-fns_locale_kn_js":"99ec5cabd1585ad21a6a","node_modules_date-fns_locale_ko_js":"802f82cd669c91c0640f","node_modules_date-fns_locale_lb_js":"32aa5e189a8e07a0c21c","node_modules_date-fns_locale_lt_js":"e1e38226c66fac38b0b8","node_modules_date-fns_locale_lv_js":"9cf0f6e0b553d722381d","node_modules_date-fns_locale_mk_js":"925bd061c887a4760da4","node_modules_date-fns_locale_mn_js":"5b8012f4a110b6f0a3d2","node_modules_date-fns_locale_ms_js":"5049aa6f858d8647a525","node_modules_date-fns_locale_mt_js":"0f004de3b66ece204a61","node_modules_date-fns_locale_nb_js":"3cb82fc909bac3133c43","node_modules_date-fns_locale_nl-BE_js":"81f72650f040c3b48200","node_modules_date-fns_locale_nl_js":"ed3b052a5967d8d30726","node_modules_date-fns_locale_nn_js":"f1c96e02ed6bd0cce945","node_modules_date-fns_locale_oc_js":"efce8c0a2c7116e87565","node_modules_date-fns_locale_pl_js":"8eac758ad7ba41178d57","node_modules_date-fns_locale_pt-BR_js":"d8aa7ea1913c80e7e883","node_modules_date-fns_locale_pt_js":"e6d012791c238caf6da9","node_modules_date-fns_locale_ro_js":"38984a9e22e4375f4ad5","vendors-node_modules_date-fns_locale_ru_js":"66e37716f2be9f613c49","node_modules_date-fns_locale_se_js":"e9ce2b63e8962a8f53f3","node_modules_date-fns_locale_sk_js":"2eee76a3773ef54960db","node_modules_date-fns_locale_sl_js":"ab249dbe99080ab1dc49","node_modules_date-fns_locale_sq_js":"710e55d8844bf0b34b0f","node_modules_date-fns_locale_sr-Latn_js":"85dc36f5095f0a216480","node_modules_date-fns_locale_sr_js":"1de8a167bdfaf7b39e7d","node_modules_date-fns_locale_sv_js":"130bbf67a52d352e04d8","node_modules_date-fns_locale_ta_js":"b0fa7943fbff7d2afb62","node_modules_date-fns_locale_te_js":"047cade7b1eda27b7675","node_modules_date-fns_locale_th_js":"e6530c0aaf2f2d480ee3","node_modules_date-fns_locale_tr_js":"de92f93650bdf6dd30a6","node_modules_date-fns_locale_ug_js":"0a8f60c94518dca1f291","vendors-node_modules_date-fns_locale_uk_js":"8b92ef8649d20c2101d5","node_modules_date-fns_locale_uz-Cyrl_js":"e0dc86eededd804e89ee","node_modules_date-fns_locale_uz_js":"0c31e869dc60b8e46c99","node_modules_date-fns_locale_vi_js":"193ee6a45cf99fca1efb","node_modules_date-fns_locale_zh-CN_js":"ed2b186b169669aafacc","node_modules_date-fns_locale_zh-HK_js":"1bfa9f02dab15b463cd8","node_modules_date-fns_locale_zh-TW_js":"5b37dba10ab292c20b95"}[e],o.g=function(){if("object"==typeof globalThis)return globalThis;try{return this||new Function("return this")()}catch(e){if("object"==typeof window)return window}}(),o.o=(e,d)=>Object.prototype.hasOwnProperty.call(e,d),(()=>{const e={},d="social:";o.l=(_,n,s,a)=>{if(e[_])return void e[_].push(n);let l,t;if(void 0!==s){const e=document.getElementsByTagName("script");for(var c=0;c{l.onerror=l.onload=null,clearTimeout(u);const n=e[_];if(delete e[_],l.parentNode?.removeChild(l),n?.forEach(e=>e(o)),d)return d(o)},u=setTimeout(f.bind(null,void 0,{type:"timeout",target:l}),12e4);l.onerror=f.bind(null,l.onerror),l.onload=f.bind(null,l.onload),t&&document.head.appendChild(l)}})(),o.r=e=>{Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},o.j="adminAnnouncements",o.dn=e=>{var d=Object.getOwnPropertyDescriptor(e,"name");(!d||!d.writable&&d.configurable)&&Object.defineProperty(e,"name",{value:"default",configurable:!0})},o.p="/apps/social/js/",(()=>{const e={adminAnnouncements:0};o.f.j=(d,_)=>{let n=o.o(e,d)?e[d]:void 0;if(0!==n)if(n)_.push(n[2]);else{const s=new Promise((o,_)=>n=e[d]=[o,_]);_.push(n[2]=s);const a=new Error,l=_=>{if(o.o(e,d)&&(n=e[d],0!==n&&(e[d]=void 0),n)){const e=_&&("load"===_.type?"missing":_.type),o=_&&_.target&&_.target.src;a.message="Loading chunk "+d+" failed.\n("+e+": "+o+")",a.name="ChunkLoadError",a.type=e,a.request=o,a.event=_,n[1](a)}};o.l(o.p+o.u(d),l,"chunk-"+d,d)}},o.O.j=d=>0===e[d];const d=(d,_)=>{let[n,s,a]=_;var l,t,c=0;if(n.some(d=>0!==e[d])){for(l in s)o.o(s,l)&&(o.m[l]=s[l]);if(a)var f=a(o)}for(d&&d(_);co(37844));_=o.O(_)})(); +//# sourceMappingURL=social-adminAnnouncements.js.map?v=3c81cd5732d2f6d47d9d \ No newline at end of file diff --git a/js/social-composer.js b/js/social-composer.js index 9a64c1cf9..289213984 100644 --- a/js/social-composer.js +++ b/js/social-composer.js @@ -1,2 +1,2 @@ -"use strict";(self.webpackChunksocial=self.webpackChunksocial||[]).push([["composer"],{70204(t,e,i){var n=i(24877),o=i(75783),r=i(50772),a=i(8435),s=i(17334),l=i.n(s),A=i(7880),c=i(23447),d=i(65924),p=i(78209),u=i(99318),C=i(20641),m=i(71085),h=i(66981),g=i(66067),b=i.n(g),v=i(16865),f=i(70642),x=i(59201),y=i(55705),w=i(28908),k=i(27274),_=i(81958),B=i(70330),I=i(10712),D=i(25897),T=i.n(D),F=i(44894),P=i(63360),E=i(38161),L=i(96231),z=i(49124),S=i(9699),O=i(92069),N=i(59512);const $=["image/","video/","audio/"],W=["image/*","video/*"];let j=null;const M=()=>j??=Promise.all([i.e("emoji-picker"),i.e("vendors-node_modules_nextcloud_vue_dist_chunks_NcColorPicker_mjs"),i.e("vendors-node_modules_nextcloud_vue_dist_components_NcEmojiPicker_index_mjs")]).then(()=>i(62823)),X={name:"Composer",components:{NcAvatar:A.A,NcEmojiPicker:(0,C.$V)({loader:M,onError:t=>P.A.error("Could not load the emoji picker",{error:t})}),NcButton:c.A,NcLoadingIcon:d.A,ActorAvatar:x.A,Paperclip:a.A,EmoticonOutline:n.A,Close:o.A,FolderImage:r.A,AlertOutline:p.A,PollIcon:u.A,PreviewGrid:w.A,VisibilitySelect:k.A,SubmitStatusButton:B.A,MessageContent:I.Ay},directives:{FocusOnCreate:v.A},props:{initialMention:{type:Object,default:null},defaultVisibility:{type:String,default:void 0},startExpanded:{type:Boolean,default:!1},inReplyTo:{type:Object,default:null},initialPaths:{type:Array,default:()=>[]}},emits:["posted"],setup(){const{hostname:t}=(0,N.H)(),{currentUser:e}=(0,O.i)();return{hostname:t,currentUser:e}},data(){return{emojiPickerLoaded:!1,emojiPickerLoading:!1,statusContent:"",statusText:"",openedByHand:this.startExpanded,visibility:this.defaultVisibility||this.inReplyTo?.visibility||G()||"followers",loading:!1,uploading:!1,uploadProgress:0,progressLabel:"",picking:!1,pickCount:0,filterTimers:{},draggingFiles:!1,refusedDrop:!1,attachments:{},showPoll:!1,showWarning:!1,spoilerText:"",pollOptions:["",""],pollMultiple:!1,pollExpiresIn:86400,search:"",replyTo:this.inReplyTo,quoteOf:null,tributeOptions:{spaceSelectsMatch:!0,collection:[{trigger:"@",lookup:t=>t.key+t.value,menuItemTemplate:t=>'
'+t.original.key+'
",selectTemplate:t=>`@${t.original.value} `,values:l()(async(t,e)=>{t.length<1&&e([]);const i=(await this.remoteSearchAccounts(t)).data.result.accounts.map(t=>({key:t.preferredUsername,value:t.account,url:t.url,avatar:t.local?(0,y.Jv)(`/avatar/${t.preferredUsername}/32`):(0,y.Jv)(`apps/social/api/v1/global/actor/avatar?id=${t.id}`)}));P.A.debug("Found accounts for a mention",{count:i.length}),e(i)},200)},{trigger:"#",menuItemTemplate:t=>t.original.value,selectTemplate(t){let e;return e=void 0===t?this.currentMentionTextSnapshot:t.original.value,'#'+e+""},values:l()(async(t,e)=>{t.length<1&&e([]);const i=await this.remoteSearchHashtags(t),n=[...i.data.result.exact&&!Array.isArray(i.data.result.exact)?[{key:i.data.result.exact,value:i.data.result.exact}]:[],...i.data.result.tags.map(({hashtag:t})=>({key:t,value:t}))];P.A.debug("Found hashtags for a mention",{count:n.length}),e(n)},200)}],noMatchTemplate(){if("#"===this.current.collection.trigger)return""===this.current.mentionText?void 0:'
  • #'+this.current.mentionText+"
  • "}}}},computed:{...(0,L.n2)(z.A),acceptedTypes:()=>$.map(t=>`${t}*`).join(","),hasAttachments(){return Object.keys(this.attachments).length>0},attachmentsFull(){return Object.keys(this.attachments).length>=10},prompt(){return this.hasAttachments?(0,m.Tl)("social","Write a caption…"):null!==this.replyTo?(0,m.Tl)("social","Write a reply…"):(0,m.Tl)("social","What would you like to share?")},anchoredReply(){return null!==this.inReplyTo&&this.replyTo?.id===this.inReplyTo.id},undescribed(){return Object.values(this.attachments).filter(t=>void 0!==t.data?.id&&""===(t.description||"").trim()).length},failedUploads(){return Object.values(this.attachments).filter(t=>!0===t.failed).length},hasPendingUploads(){return Object.values(this.attachments).some(t=>!0!==t.failed&&null===t.data)},mediaIds(){return Object.values(this.attachments).map(t=>t.data?.id).filter(t=>null!=t)},undescribedWarning(){return(0,m.zw)("social","%n attachment has no description","%n attachments have no description",this.undescribed)},charactersLeftLabel(){return this.statusIsTooLong?(0,m.zw)("social","%n character too many","%n characters too many",-this.charsLeft):(0,m.zw)("social","%n character left","%n characters left",this.charsLeft)},canPost(){return!this.hasPendingUploads&&(!this.statusIsTooLong&&(!this.statusIsEmpty&&!("direct"===this.visibility&&!this.hasMentions)))},statusIsEmpty(){return 0===this.statusText.trim().length&&0===this.mediaIds.length},expanded(){return this.openedByHand||this.loading||null!==this.replyTo&&!this.anchoredReply||null!==this.quoteOf||this.showPoll||this.showWarning||!this.statusIsEmpty||Object.keys(this.attachments).length>0},statusIsTooLong(){return this.statusText.length>500},charProgress(){return Math.min(this.statusText.length/500,1)},charsLeft(){return 500-this.statusText.length},hasMentions(){return/(?:^|\s)@[a-zA-Z0-9_.-]+/i.test(this.statusText)}},watch:{inReplyTo(t){this.replyTo=t},spoilerText:"rememberDraft",showWarning:"rememberDraft",visibility:"rememberDraft"},mounted(){this.tribute=new(T())(this.tributeOptions),this.tributeTarget=this.$refs.composerInput,this.tribute.attach(this.tributeTarget),this.onComposerReply=t=>{this.replyTo=t,this.prefillMessageWithMention(t.account),this.visibility=t.visibility,this.openedByHand=!0},F.A.on("composer-reply",this.onComposerReply),this.onComposerQuote=t=>{this.quoteOf=t},F.A.on("composer-quote",this.onComposerQuote),this.onComposerFocus=()=>this.focusInput(),F.A.on("shortcut:compose",this.onComposerFocus),this.restoreDraft(),null!==this.initialMention&&this.prefillMessageWithMention(this.initialMention);const t=this.initialPaths.filter(t=>"string"==typeof t&&""!==t&&"/"!==t);t.length>0&&(this.expand(),this.attachPaths(t)),this.onOutsideInteraction=t=>this.collapseIfIdle(t),document.addEventListener("pointerdown",this.onOutsideInteraction),document.addEventListener("focusin",this.onOutsideInteraction)},unmounted(){window.clearTimeout(this.refusalTimer),document.removeEventListener("pointerdown",this.onOutsideInteraction),document.removeEventListener("focusin",this.onOutsideInteraction),this.tribute&&this.tributeTarget&&this.tribute.detach(this.tributeTarget),F.A.off("composer-reply",this.onComposerReply),F.A.off("composer-quote",this.onComposerQuote),F.A.off("shortcut:compose",this.onComposerFocus)},methods:{expand(){this.openedByHand=!0},async loadEmojiPicker(){this.emojiPickerLoading||(this.emojiPickerLoading=!0,await M().catch(()=>{}),this.emojiPickerLoading=!1,this.emojiPickerLoaded=!0,await this.$nextTick(),await new Promise(t=>window.requestAnimationFrame(t)),this.$refs.emojiButton?.$el?.click())},collapseIfIdle(t){if(!this.openedByHand)return;const e=t.target;e instanceof Node&&!this.$el.contains(e)&&(e instanceof Element&&null!==e.closest(".v-popper__popper, .modal-mask")||(this.openedByHand=!1))},focusInput(){const t=this.$refs.composerInput;void 0!==t&&(t.focus(),"function"==typeof t.scrollIntoView&&t.scrollIntoView({block:"nearest"}))},prefillMessageWithMention(t){if(!this.statusIsEmpty||void 0===this.$refs.composerInput)return;let e=t.acct;e.includes("@")||(e+=`@${this.hostname}`);const i=document.createElement("span");i.className="mention",i.contentEditable="false";const n=document.createElement("a");n.href=t.url,n.target="_blank";const o=document.createElement("img");o.src=t.avatar,n.append(o,document.createTextNode(`@${e}`)),i.append(n),this.$refs.composerInput.replaceChildren(i,document.createTextNode(" ")),this.updateStatusContent()},updateStatusContent(){this.statusContent=this.$refs.composerInput.innerHTML,this.statusText=this.plainText(),this.rememberDraft()},plainText(){const t=this.$refs.composerInput;if(null==t)return"";const e=t.cloneNode(!0);return Array.from(e.getElementsByClassName("emoji")).forEach(t=>{t.replaceWith(document.createTextNode(t.getAttribute("alt")??""))}),b().decode(U(e).trim())},rememberDraft(){(0,E.J1)({text:this.statusText,spoilerText:this.showWarning?this.spoilerText:"",visibility:this.visibility})},restoreDraft(){const t=(0,E.C_)();return null!==t&&void 0!==this.$refs.composerInput&&(""!==t.text&&(this.$refs.composerInput.innerText=t.text),""!==t.spoilerText&&(this.showWarning=!0,this.spoilerText=t.spoilerText),(0,_.S)(t.visibility)&&void 0===this.defaultVisibility&&(this.visibility=t.visibility),this.updateStatusContent(),!0)},clickImportInput(){this.$refs.fileUploadInput.click()},async handleFileChange(t){const e=t.target,i=Array.from(e.files);e.value="",await this.attachFiles(i)},carriesFiles:t=>Array.from(t.dataTransfer?.types??[]).includes("Files"),acceptsFile:t=>$.some(e=>(t.type||"").startsWith(e)),handleDragEnter(t){this.carriesFiles(t)&&(t.preventDefault(),this.draggingFiles=!0)},handleDragOver(t){this.carriesFiles(t)&&(t.preventDefault(),t.dataTransfer&&(t.dataTransfer.dropEffect="copy"),this.draggingFiles=!0)},handleDragLeave(t){if(!this.draggingFiles)return;const e=t.relatedTarget;e instanceof Node&&this.$el.contains(e)||(this.draggingFiles=!1)},async handleDrop(t){this.carriesFiles(t)&&(t.preventDefault(),this.draggingFiles=!1,this.expand(),await this.attachDropped(Array.from(t.dataTransfer?.files??[])))},handlePaste(t){const e=Array.from(t.clipboardData?.files??[]).filter(t=>this.acceptsFile(t));0!==e.length&&(t.preventDefault(),this.attachFiles(e))},async attachDropped(t){const e=t.filter(t=>this.acceptsFile(t));e.length{this.refusedDrop=!1},400)},roomFor(t){const e=Math.max(10-Object.keys(this.attachments).length,0);return t.length>e&&this.announceCeiling(),t.slice(0,e)},announceCeiling(){(0,h.Qg)((0,m.zw)("social","A post can carry %n attachment","A post can carry %n attachments",10))},async pickFromFiles(){if(this.attachmentsFull)return void this.announceCeiling();let t;this.picking=!0;try{const{getFilePickerBuilder:e}=await Promise.all([i.e("vendors-node_modules_mdi_js_mdi_js-node_modules_nextcloud_vue_dist_chunks_NcDialogButton_vue_-bd7251"),i.e("vendors-node_modules_nextcloud_dialogs_dist_index_mjs")]).then(()=>i(84973));t=await e((0,m.Tl)("social","Pick pictures to attach")).setMultiSelect(!0).setMimeTypeFilter(W).allowDirectories(!1).build().pick()}catch(t){return void P.A.debug("The file picker was closed",{error:t})}finally{this.picking=!1}const e=(Array.isArray(t)?t:[t]).filter(t=>"string"==typeof t&&""!==t&&"/"!==t);0!==e.length&&(this.expand(),await this.attachPaths(e))},async attachPaths(t){const e=this.roomFor(t);this.picking=e.length>0,this.progressLabel=(0,m.Tl)("social","Attaching from Files…");for(const[t,i]of e.entries()){const n=`nextcloud:${++this.pickCount}:${i}`;this.attachments={...this.attachments,[n]:{file:null,path:i,data:null,failed:!1}},this.uploading=!0,this.uploadProgress=t/e.length;const o=await this.timelineStore.createMediaFromFile({path:i});this.uploadProgress=(t+1)/e.length,void 0!==this.attachments[n]&&(this.attachments={...this.attachments,[n]:{...this.attachments[n],data:void 0===o?.id?null:o,failed:void 0===o?.id}})}this.uploading=!1,this.uploadProgress=0,this.progressLabel="",this.picking=!1},applyFilter({key:t,filter:e}){const i=this.attachments[t];void 0!==i&&(this.attachments={...this.attachments,[t]:{...i,filter:e}},window.clearTimeout(this.filterTimers[t]),this.filterTimers[t]=window.setTimeout(()=>{this.reuploadFiltered(t)},600))},async reuploadFiltered(t){const e=this.attachments[t];if(void 0===e?.file)return;const i=await(0,S.Yo)(e.file,e.filter||"none");if(void 0===this.attachments[t])return;const n=await this.timelineStore.createMedia({file:i});if(void 0===this.attachments[t])return;if(void 0===n?.id)return void P.A.warn("Could not upload the filtered copy; keeping the original");const o=(e.description||"").trim();""!==o&&this.timelineStore.describeMedia({id:n.id,description:o}),this.attachments={...this.attachments,[t]:{...this.attachments[t],data:n,failed:!1}}},async attachFiles(t){const e=this.roomFor(t);this.progressLabel=(0,m.Tl)("social","Uploading…");for(const[t,i]of e.entries()){const n=URL.createObjectURL(i);this.attachments={...this.attachments,[n]:{file:i,data:null,failed:!1}},this.uploading=!0,this.uploadProgress=t/e.length;const o=await this.timelineStore.createMedia({file:i,onProgress:i=>{this.uploadProgress=(t+i)/e.length}});this.uploading=!1,this.uploadProgress=0,void 0!==this.attachments[n]&&(this.attachments={...this.attachments,[n]:{...this.attachments[n],data:void 0===o?.id?null:o,failed:void 0===o?.id}})}this.progressLabel=""},insert(t){if("object"==typeof t){const e=t[Object.keys(t)[0]];t=e[Object.keys(e)[0]]}const e=this.$refs.composerInput.lastChild,i=document.createElement("div");if(i.textContent=t+" ",null===e)this.$refs.composerInput.innerHTML=i.innerHTML;else switch(e.tagName){case"BR":e.before(i.firstChild);break;case"DIV":if("BR"===e.lastChild.tagName)e.lastChild.before(i.firstChild);else e.append(i.firstChild);break;default:e.after(i.firstChild)}this.updateStatusContent()},keyup(t){t.ctrlKey&&this.createPost()},updatePostFromTribute(){this.updateStatusContent()},n:m.zw,async createPost(){if(!this.canPost||this.loading)return;const t=this.plainText(),e=this.showWarning?this.spoilerText.trim():"",i={content_type:"",media_ids:this.mediaIds,sensitive:""!==e,spoiler_text:e,status:t,in_reply_to_id:this.replyTo?.id,quote_id:this.quoteOf?.id,visibility:this.visibility},n=this.pollOptions.map(t=>t.trim()).filter(t=>""!==t);let o;this.showPoll&&n.length>=2&&(i.poll={options:n,expires_in:this.pollExpiresIn,multiple:this.pollMultiple}),P.A.debug("Posting status",{visibility:i.visibility,attachments:i.media_ids.length});try{this.loading=!0,await this.saveDescriptions(),o=await this.timelineStore.post(i)}finally{this.loading=!1}void 0!==o?(this.replyTo=this.inReplyTo,this.quoteOf=null,null!==this.inReplyTo&&(this.openedByHand=this.startExpanded),this.$refs.composerInput.innerText="",Object.keys(this.attachments).forEach(t=>this.releasePreview(t)),this.attachments={},this.showPoll=!1,this.pollOptions=["",""],this.pollMultiple=!1,this.showWarning=!1,this.spoilerText="",(0,E.nr)(),this.updateStatusContent(),this.timelineStore.refreshTimeline(),this.$emit("posted"),F.A.emit("post-published",o)):this.rememberDraft()},toggleWarning(){this.showWarning=!this.showWarning,this.showWarning||(this.spoilerText="")},togglePoll(){this.showPoll=!this.showPoll,this.showPoll||(this.pollOptions=["",""],this.pollMultiple=!1)},closeReply(){this.replyTo=this.inReplyTo,null!==this.inReplyTo?this.openedByHand=this.startExpanded:this.timelineStore.setComposerDisplayStatus(!1)},removeQuote(){this.quoteOf=null},remoteSearchAccounts:t=>f.Ay.get((0,y.Jv)("apps/social/api/v1/global/accounts/search"),{params:{search:t}}),remoteSearchHashtags:t=>f.Ay.get((0,y.Jv)("apps/social/api/v1/global/tags/search"),{params:{search:t}}),deletePreview(t){const e={...this.attachments};delete e[t],this.attachments=e,this.releasePreview(t)},releasePreview(t){if(t.startsWith("blob:"))try{URL.revokeObjectURL(t)}catch(t){P.A.debug("Could not release a preview URL",{error:t})}},async saveDescriptions(){const t=Object.values(this.attachments).filter(t=>t.data?.id&&""!==(t.description||"").trim()&&(t.description||"").trim()!==t.saved);await Promise.all(t.map(t=>this.timelineStore.describeMedia({id:t.data.id,description:t.description.trim()})))},async commitDescription({key:t,description:e}){const i=this.attachments[t],n=(e||"").trim();void 0!==i?.data?.id&&""!==n&&n!==i.saved&&(this.attachments={...this.attachments,[t]:{...i,description:e,saved:n}},await this.timelineStore.describeMedia({id:i.data.id,description:n}))},describeAttachment({key:t,description:e}){void 0!==this.attachments[t]&&(this.attachments={...this.attachments,[t]:{...this.attachments[t],description:e}})}}};function G(){let t;try{t=window.localStorage.getItem("social.lastPostType")??""}catch{return""}return(0,_.S)(t)?t:""}function U(t){let e="";for(const i of Array.from(t.childNodes)){if(i.nodeType===Node.TEXT_NODE){e+=i.textContent||"";continue}if(i.nodeType!==Node.ELEMENT_NODE)continue;const t=i;"BR"!==t.tagName?(e+=U(t),["DIV","P","LI","BLOCKQUOTE","PRE"].includes(t.tagName)&&(e+="\n")):e+="\n"}return e}i.d(e,["A",0,X])},6766(t,e,i){var n=i(9699),o=i(71085);const r={name:"FilterPicker",props:{modelValue:{type:String,default:"none"},preview:{type:String,default:""}},emits:["update:modelValue"],computed:{filters:()=>(0,n.Tw)()},methods:{t:o.t}};i.d(e,["A",0,r])},58104(t,e,i){var n=i(70937),o=i(88864),r=i(71085);const a={name:"PreviewGrid",components:{PreviewGridItem:n.A,FileUpload:o.A},props:{uploadProgress:{type:Number,required:!0},progressLabel:{type:String,default:""},uploading:{type:Boolean,required:!0},miniatures:{type:Object,required:!0}},emits:["deleted","describe","commitDescription","filter"],computed:{count(){return Object.keys(this.miniatures).length},label(){return this.progressLabel||(0,r.Tl)("social","Uploading…")}},methods:{deletePreview(t){this.$emit("deleted",t)},t:r.Tl}};i.d(e,["A",0,a])},19013(t,e,i){var n=i(75783),o=i(89948),r=i(23447),a=i(9699),s=i(71085),l=i(17438);const A={name:"PreviewGridItem",components:{Close:n.A,FilterPicker:o.A,NcButton:r.A,MediaAttachment:l.A},props:{preview:{type:Object,required:!0},randomKey:{type:String,required:!0}},emits:["delete","describe","commitDescription"],computed:{described(){return""!==(this.preview.description||"").trim()},fieldId(){return"composer-alt-"+this.randomKey},isPicture(){const t=this.preview?.file?.type||this.preview?.data?.type||"";return t.startsWith("image/")?!["image/gif","image/webp"].includes(t):"image"===t},previewUrl(){return this.randomKey}},methods:{t:s.Tl,filterCss:a.M8}};i.d(e,["A",0,A])},61384(e,i,n){var o=n(37867);const r={name:"SubmitStatusButton",components:{NcButton:n(23447).A,Send:o.A},props:{visibility:{type:String,required:!0},disabled:{type:Boolean,default:!0}},emits:["click"],computed:{postTo(){switch(this.visibility){case"public":case"unlisted":return t("social","Post");case"followers":return t("social","Post to followers");case"direct":return t("social","Send message to mentioned users")}return""},currentVisibilityPostLabel(){return this.visibilityPostLabel(this.visibility)},visibilityPostLabel(){return e=>{switch(void 0===e&&(e=this.visibility),e){case"public":return t("social","Post publicly");case"followers":return t("social","Post to followers");case"direct":return t("social","Post to recipients");case"unlisted":return t("social","Post unlisted")}}}},methods:{handleClick(){this.$emit("click")}}};n.d(i,["A",0,r])},22188(t,e,i){var n=i(8018),o=i(99045),r=i(71085),a=i(81958),s=i(56589),l=i(63360);const A={name:"VisibilitySelect",components:{NcActions:n.A,NcActionButton:o.A,VisibilityIcon:s.A},props:{visibility:{type:String,required:!0}},emits:["update:visibility"],data:()=>({visibilitiesInfo:a.A}),computed:{selectedVisibilityDetails(){return a.A.find(({id:t})=>this.visibility===t)??a.A.find(({id:t})=>"followers"===t)}},methods:{switchType(t){this.$emit("update:visibility",t.id);try{localStorage.setItem("social.lastPostType",t.id)}catch(t){l.A.debug("Could not remember the visibility",{error:t})}},t:r.Tl}};i.d(e,["A",0,A])},2682(t,e,i){i.d(e,{X:()=>L});var n=i(20641),o=i(53751),r=i(90033);const a={key:0,class:"new-post__drop-hint","aria-hidden":"true"},s=["accept"],l={class:"new-post-author"},A={class:"post-author"},c={class:"post-author-name"},d={key:1,class:"reply-to"},p={class:"reply-info"},u={key:2,class:"quote-of"},C={class:"quote-info"},m=["aria-label","placeholder"],h=["contenteditable","aria-label","aria-describedby","placeholder"],g={key:1,class:"poll-editor"},b=["onUpdate:modelValue","placeholder"],v={class:"poll-editor__settings"},f=["aria-label"],x={value:1800},y={value:3600},w={value:21600},k={value:86400},_={value:259200},B={value:604800},I={class:"options"},D={class:"new-post-form__emoji-picker"},T={key:0,class:"composer-alt-warning",role:"status"},F=["title"],P={key:0,class:"char-ring__count","aria-hidden":"true"},E={class:"hidden-visually",role:"status"};function L(t,e,i,L,z,S){const O=(0,n.g2)("NcAvatar"),N=(0,n.g2)("ActorAvatar"),$=(0,n.g2)("Close"),W=(0,n.g2)("NcButton"),j=(0,n.g2)("MessageContent"),M=(0,n.g2)("PreviewGrid"),X=(0,n.g2)("Paperclip"),G=(0,n.g2)("FolderImage"),U=(0,n.g2)("AlertOutline"),q=(0,n.g2)("PollIcon"),V=(0,n.g2)("EmoticonOutline"),Y=(0,n.g2)("NcEmojiPicker"),R=(0,n.g2)("NcLoadingIcon"),Q=(0,n.g2)("VisibilitySelect"),H=(0,n.g2)("SubmitStatusButton");return(0,n.uX)(),(0,n.CE)("div",{class:(0,r.C4)(["new-post",{"new-post--collapsed":!S.expanded,"new-post--drop-target":z.draggingFiles,"new-post--refused":z.refusedDrop}]),"data-id":"",onFocusin:e[11]||(e[11]=(...t)=>S.expand&&S.expand(...t)),onDragenter:e[12]||(e[12]=(...t)=>S.handleDragEnter&&S.handleDragEnter(...t)),onDragover:e[13]||(e[13]=(...t)=>S.handleDragOver&&S.handleDragOver(...t)),onDragleave:e[14]||(e[14]=(...t)=>S.handleDragLeave&&S.handleDragLeave(...t)),onDrop:e[15]||(e[15]=(...t)=>S.handleDrop&&S.handleDrop(...t))},[z.draggingFiles?((0,n.uX)(),(0,n.CE)("div",a,[(0,n.Lk)("span",null,(0,r.v_)(t.t("social","Drop to attach")),1)])):(0,n.Q3)("",!0),(0,n.Lk)("input",{id:"file-upload",ref:"fileUploadInput",type:"file",accept:S.acceptedTypes,multiple:"true",tabindex:"-1","aria-hidden":"true",class:"hidden-visually",onChange:e[0]||(e[0]=t=>S.handleFileChange(t))},null,40,s),(0,n.Lk)("div",l,[(0,n.bF)(O,{user:L.currentUser.uid,displayName:L.currentUser.displayName,disableMenu:!0,disableTooltip:!0,size:32},null,8,["user","displayName"]),(0,n.Lk)("div",A,[(0,n.Lk)("span",c,(0,r.v_)(L.currentUser.displayName),1)])]),z.replyTo&&!S.anchoredReply?((0,n.uX)(),(0,n.CE)("div",d,[(0,n.Lk)("p",p,[(0,n.Lk)("span",null,(0,r.v_)(t.t("social","In reply to")),1),(0,n.bF)(N,{actor:z.replyTo.account,size:16,link:!1},null,8,["actor"]),(0,n.Lk)("strong",null,(0,r.v_)(z.replyTo.account.acct),1),(0,n.bF)(W,{variant:"tertiary",class:"close-button","aria-label":t.t("social","Close reply"),onClick:S.closeReply},{icon:(0,n.k6)(()=>[(0,n.bF)($,{size:20})]),_:1},8,["aria-label","onClick"])]),(0,n.bF)(j,{item:z.replyTo},null,8,["item"])])):(0,n.Q3)("",!0),z.quoteOf?((0,n.uX)(),(0,n.CE)("div",u,[(0,n.Lk)("p",C,[(0,n.Lk)("span",null,(0,r.v_)(t.t("social","Quoting")),1),(0,n.bF)(N,{actor:z.quoteOf.account,size:16,link:!1},null,8,["actor"]),(0,n.Lk)("strong",null,(0,r.v_)(z.quoteOf.account.acct),1),(0,n.bF)(W,{variant:"tertiary",class:"close-button","aria-label":t.t("social","Remove quote"),onClick:S.removeQuote},{icon:(0,n.k6)(()=>[(0,n.bF)($,{size:20})]),_:1},8,["aria-label","onClick"])]),(0,n.bF)(j,{item:z.quoteOf},null,8,["item"])])):(0,n.Q3)("",!0),(0,n.Lk)("form",{class:(0,r.C4)(["new-post-form",{"new-post-form--media-first":S.hasAttachments}]),onSubmit:e[10]||(e[10]=(0,o.D$)(()=>{},["prevent"]))},[z.showWarning?(0,n.bo)(((0,n.uX)(),(0,n.CE)("input",{key:0,"onUpdate:modelValue":e[1]||(e[1]=t=>z.spoilerText=t),type:"text",class:"content-warning",maxlength:"200","aria-label":t.t("social","Content warning"),placeholder:t.t("social","Content warning, e.g. what the post is about")},null,8,m)),[[o.Jo,z.spoilerText]]):(0,n.Q3)("",!0),(0,n.bF)(M,{uploading:z.uploading,uploadProgress:z.uploadProgress,progressLabel:z.progressLabel,miniatures:z.attachments,onDeleted:S.deletePreview,onDescribe:S.describeAttachment,onCommitDescription:S.commitDescription,onFilter:S.applyFilter},null,8,["uploading","uploadProgress","progressLabel","miniatures","onDeleted","onDescribe","onCommitDescription","onFilter"]),(0,n.Lk)("div",{ref:"composerInput",contenteditable:!z.loading,class:(0,r.C4)(["message",{"icon-loading":z.loading,"too-long":S.statusIsTooLong,"message--caption":S.hasAttachments}]),role:"textbox","aria-multiline":"true","aria-label":S.prompt,"aria-describedby":S.statusIsTooLong?"composer-length":void 0,placeholder:S.prompt,onKeyup:e[2]||(e[2]=(0,o.jR)((0,o.D$)((...t)=>S.keyup&&S.keyup(...t),["prevent"]),["enter"])),onInput:e[3]||(e[3]=(...t)=>S.updateStatusContent&&S.updateStatusContent(...t)),onPaste:e[4]||(e[4]=(...t)=>S.handlePaste&&S.handlePaste(...t)),onTributeReplaced:e[5]||(e[5]=(...t)=>S.updatePostFromTribute&&S.updatePostFromTribute(...t))},null,42,h),z.showPoll?((0,n.uX)(),(0,n.CE)("div",g,[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(z.pollOptions,(e,i)=>((0,n.uX)(),(0,n.CE)("div",{key:i,class:"poll-editor__option"},[(0,n.bo)((0,n.Lk)("input",{"onUpdate:modelValue":t=>z.pollOptions[i]=t,type:"text",placeholder:t.t("social","Poll option {number}",{number:i+1}),maxlength:"100"},null,8,b),[[o.Jo,z.pollOptions[i]]]),z.pollOptions.length>2?((0,n.uX)(),(0,n.Wv)(W,{key:0,variant:"tertiary","aria-label":t.t("social","Remove option"),onClick:(0,o.D$)(t=>z.pollOptions.splice(i,1),["prevent"])},{icon:(0,n.k6)(()=>[(0,n.bF)($,{size:18})]),_:1},8,["aria-label","onClick"])):(0,n.Q3)("",!0)]))),128)),(0,n.Lk)("div",v,[z.pollOptions.length<4?((0,n.uX)(),(0,n.Wv)(W,{key:0,variant:"tertiary",onClick:e[6]||(e[6]=(0,o.D$)(t=>z.pollOptions.push(""),["prevent"]))},{default:(0,n.k6)(()=>[(0,n.eW)((0,r.v_)(t.t("social","Add option")),1)]),_:1})):(0,n.Q3)("",!0),(0,n.Lk)("label",null,[(0,n.bo)((0,n.Lk)("input",{"onUpdate:modelValue":e[7]||(e[7]=t=>z.pollMultiple=t),type:"checkbox"},null,512),[[o.lH,z.pollMultiple]]),(0,n.eW)(" "+(0,r.v_)(t.t("social","Multiple choice")),1)]),(0,n.bo)((0,n.Lk)("select",{"onUpdate:modelValue":e[8]||(e[8]=t=>z.pollExpiresIn=t),"aria-label":t.t("social","Poll duration")},[(0,n.Lk)("option",x,(0,r.v_)(t.t("social","30 minutes")),1),(0,n.Lk)("option",y,(0,r.v_)(t.t("social","1 hour")),1),(0,n.Lk)("option",w,(0,r.v_)(t.t("social","6 hours")),1),(0,n.Lk)("option",k,(0,r.v_)(t.t("social","1 day")),1),(0,n.Lk)("option",_,(0,r.v_)(t.t("social","3 days")),1),(0,n.Lk)("option",B,(0,r.v_)(t.t("social","7 days")),1)],8,f),[[o.u1,z.pollExpiresIn,void 0,{number:!0}]])])])):(0,n.Q3)("",!0),(0,n.Lk)("div",I,[(0,n.bF)(W,{title:t.t("social","Add attachment"),variant:"tertiary","aria-label":t.t("social","Add attachment"),disabled:S.attachmentsFull,onClick:(0,o.D$)(S.clickImportInput,["prevent"])},{icon:(0,n.k6)(()=>[(0,n.bF)(X,{size:22,decorative:"",title:""})]),_:1},8,["title","aria-label","disabled","onClick"]),(0,n.bF)(W,{title:t.t("social","Add from Files"),variant:"tertiary","aria-label":t.t("social","Add from Files"),disabled:S.attachmentsFull||z.picking,onClick:(0,o.D$)(S.pickFromFiles,["prevent"])},{icon:(0,n.k6)(()=>[(0,n.bF)(G,{size:22,decorative:"",title:""})]),_:1},8,["title","aria-label","disabled","onClick"]),(0,n.bF)(W,{title:z.showWarning?t.t("social","Remove content warning"):t.t("social","Add content warning"),variant:"tertiary","aria-label":z.showWarning?t.t("social","Remove content warning"):t.t("social","Add content warning"),"aria-pressed":z.showWarning,onClick:(0,o.D$)(S.toggleWarning,["prevent"])},{icon:(0,n.k6)(()=>[(0,n.bF)(U,{size:22,decorative:"",title:""})]),_:1},8,["title","aria-label","aria-pressed","onClick"]),(0,n.bF)(W,{title:z.showPoll?t.t("social","Remove poll"):t.t("social","Add poll"),variant:"tertiary","aria-label":z.showPoll?t.t("social","Remove poll"):t.t("social","Add poll"),onClick:(0,o.D$)(S.togglePoll,["prevent"])},{icon:(0,n.k6)(()=>[(0,n.bF)(q,{size:22,decorative:"",title:""})]),_:1},8,["title","aria-label","onClick"]),(0,n.Lk)("div",D,[z.emojiPickerLoaded?((0,n.uX)(),(0,n.Wv)(Y,{key:0,search:z.search,closeOnSelect:!1,container:"#content-vue",onSelect:S.insert},{default:(0,n.k6)(()=>[(0,n.bF)(W,{ref:"emojiButton",title:t.t("social","Add emoji"),variant:"tertiary","aria-haspopup":!0,"aria-label":t.t("social","Add emoji")},{icon:(0,n.k6)(()=>[(0,n.bF)(V,{size:22,decorative:"",title:""})]),_:1},8,["title","aria-label"])]),_:1},8,["search","onSelect"])):((0,n.uX)(),(0,n.Wv)(W,{key:1,title:t.t("social","Add emoji"),variant:"tertiary","aria-haspopup":!0,"aria-label":t.t("social","Add emoji"),onClick:S.loadEmojiPicker},{icon:(0,n.k6)(()=>[z.emojiPickerLoading?((0,n.uX)(),(0,n.Wv)(R,{key:0,size:22})):((0,n.uX)(),(0,n.Wv)(V,{key:1,size:22,decorative:"",title:""}))]),_:1},8,["title","aria-label","onClick"]))]),S.undescribed>0?((0,n.uX)(),(0,n.CE)("span",T,(0,r.v_)(S.undescribedWarning),1)):(0,n.Q3)("",!0),(0,n.bF)(Q,{visibility:z.visibility,"onUpdate:visibility":e[9]||(e[9]=t=>z.visibility=t)},null,8,["visibility"]),e[16]||(e[16]=(0,n.Lk)("div",{class:"emptySpace"},null,-1)),z.statusText.length>0?((0,n.uX)(),(0,n.CE)("span",{key:1,id:"composer-length",class:(0,r.C4)(["char-ring",{"char-ring--warning":S.charsLeft<=50,"char-ring--over":S.statusIsTooLong}]),style:(0,r.Tr)({"--char-progress":S.charProgress}),title:S.charactersLeftLabel},[S.charsLeft<=50?((0,n.uX)(),(0,n.CE)("span",P,(0,r.v_)(S.charsLeft),1)):(0,n.Q3)("",!0),(0,n.Lk)("span",E,(0,r.v_)(S.charsLeft<=50?S.charactersLeftLabel:""),1)],14,F)):(0,n.Q3)("",!0),(0,n.bF)(H,{visibility:z.visibility,disabled:!S.canPost||z.loading,onClick:S.createPost},null,8,["visibility","disabled","onClick"])])],34)],34)}},63883(t,e,i){i.d(e,{X:()=>c});var n=i(20641),o=i(90033);const r=["aria-label"],a=["aria-checked","title","onClick"],s={class:"filter-picker__swatch"},l=["src"],A={class:"filter-picker__name"};function c(t,e,i,c,d,p){return(0,n.uX)(),(0,n.CE)("div",{class:"filter-picker",role:"radiogroup","aria-label":p.t("social","Filter")},[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(p.filters,e=>((0,n.uX)(),(0,n.CE)("button",{key:e.id,type:"button",role:"radio",class:(0,o.C4)(["filter-picker__option",{"filter-picker__option--active":e.id===i.modelValue}]),"aria-checked":String(e.id===i.modelValue),title:e.name,onClick:i=>t.$emit("update:modelValue",e.id)},[(0,n.Lk)("span",s,[i.preview?((0,n.uX)(),(0,n.CE)("img",{key:0,class:"filter-picker__image",src:i.preview,style:(0,o.Tr)({filter:e.css}),alt:"","aria-hidden":"true",decoding:"async"},null,12,l)):((0,n.uX)(),(0,n.CE)("span",{key:1,class:"filter-picker__placeholder",style:(0,o.Tr)({filter:e.css}),"aria-hidden":"true"},null,4))]),(0,n.Lk)("span",A,(0,o.v_)(e.name),1)],10,a))),128))],8,r)}},27289(t,e,i){i.d(e,{X:()=>c});var n=i(20641),o=i(90033);const r={class:"upload-form"},a={key:0,class:"upload-progress"},s={class:"upload-progress__icon"},l=["aria-label","aria-valuenow"],A={class:"upload-progress__backdrop"};function c(t,e,i,c,d,p){const u=(0,n.g2)("FileUpload"),C=(0,n.g2)("PreviewGridItem");return(0,n.uX)(),(0,n.CE)("div",r,[i.uploading?((0,n.uX)(),(0,n.CE)("div",a,[(0,n.Lk)("div",s,[(0,n.bF)(u,{size:32})]),(0,n.Lk)("div",{class:"upload-progress__message",role:"progressbar","aria-label":p.label,"aria-valuemin":"0","aria-valuemax":"100","aria-valuenow":Math.round(100*i.uploadProgress)},[(0,n.eW)((0,o.v_)(p.label)+" ",1),(0,n.Lk)("div",A,[(0,n.Lk)("div",{class:"upload-progress__tracker",style:(0,o.Tr)(`width: ${100*i.uploadProgress}%`)},null,4)])],8,l)])):(0,n.Q3)("",!0),(0,n.Lk)("div",{class:(0,o.C4)(["preview-grid",{"preview-grid--single":1===p.count}])},[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(i.miniatures,(i,o)=>((0,n.uX)(),(0,n.Wv)(C,{key:o,preview:i,randomKey:o,onDelete:p.deletePreview,onDescribe:e[0]||(e[0]=e=>t.$emit("describe",e)),onCommitDescription:e[1]||(e[1]=e=>t.$emit("commitDescription",e)),onFilter:e[2]||(e[2]=e=>t.$emit("filter",e))},null,8,["preview","randomKey","onDelete"]))),128))],2)])}},53607(t,e,i){i.d(e,{X:()=>p});var n=i(20641),o=i(90033);const r={class:"preview-item-wrapper"},a={class:"preview-item"},s={class:"preview-item__actions"},l={key:0,class:"preview-item__missing","aria-hidden":"true"},A={key:1,class:"preview-item__failed",role:"status"},c=["for"],d=["id","value","placeholder"];function p(t,e,i,p,u,C){const m=(0,n.g2)("MediaAttachment"),h=(0,n.g2)("Close"),g=(0,n.g2)("NcButton"),b=(0,n.g2)("FilterPicker");return(0,n.uX)(),(0,n.CE)("div",r,[(0,n.Lk)("div",a,[(0,n.Lk)("div",{class:"preview-item__filtered",style:(0,o.Tr)({filter:C.filterCss(i.preview.filter)})},[i.preview.failed?(0,n.Q3)("",!0):((0,n.uX)(),(0,n.Wv)(m,{key:0,attachment:i.preview.data},null,8,["attachment"]))],4),(0,n.Lk)("div",s,[(0,n.bF)(g,{variant:"tertiary-no-background",onClick:e[0]||(e[0]=e=>t.$emit("delete",i.randomKey))},{icon:(0,n.k6)(()=>[(0,n.bF)(h,{size:16,fillColor:"white"})]),default:(0,n.k6)(()=>[(0,n.Lk)("span",null,(0,o.v_)(C.t("social","Delete")),1)]),_:1})]),C.described||i.preview.failed?(0,n.Q3)("",!0):((0,n.uX)(),(0,n.CE)("span",l,(0,o.v_)(C.t("social","No description")),1)),i.preview.failed?((0,n.uX)(),(0,n.CE)("span",A,(0,o.v_)(C.t("social","Could not be attached")),1)):(0,n.Q3)("",!0)]),!i.preview.failed&&C.isPicture&&i.preview.data?((0,n.uX)(),(0,n.Wv)(b,{key:0,class:"preview-item__filters",modelValue:i.preview.filter||"none",preview:C.previewUrl,"onUpdate:modelValue":e[1]||(e[1]=e=>t.$emit("filter",{key:i.randomKey,filter:e}))},null,8,["modelValue","preview"])):(0,n.Q3)("",!0),i.preview.failed?(0,n.Q3)("",!0):((0,n.uX)(),(0,n.CE)("label",{key:1,class:"preview-item__label",for:C.fieldId},(0,o.v_)(C.t("social","Describe this for people who cannot see it")),9,c)),i.preview.failed?(0,n.Q3)("",!0):((0,n.uX)(),(0,n.CE)("textarea",{key:2,id:C.fieldId,class:"preview-item__description",rows:"2",maxlength:"1500",value:i.preview.description||"",placeholder:C.t("social","A cat asleep on a keyboard"),onInput:e[2]||(e[2]=e=>t.$emit("describe",{key:i.randomKey,description:e.target.value})),onChange:e[3]||(e[3]=e=>t.$emit("commitDescription",{key:i.randomKey,description:e.target.value}))},null,40,d))])}},34173(t,e,i){i.d(e,{X:()=>a});var n=i(20641),o=i(53751),r=i(90033);function a(t,e,i,a,s,l){const A=(0,n.g2)("Send"),c=(0,n.g2)("NcButton");return(0,n.uX)(),(0,n.Wv)(c,{value:l.currentVisibilityPostLabel,disabled:i.disabled,variant:"primary",onClick:(0,o.D$)(l.handleClick,["prevent"])},{icon:(0,n.k6)(()=>[(0,n.bF)(A,{title:"",size:22,decorative:""})]),default:(0,n.k6)(()=>[(0,n.eW)(" "+(0,r.v_)(l.postTo),1)]),_:1},8,["value","disabled","onClick"])}},10083(t,e,i){i.d(e,{X:()=>r});var n=i(20641),o=i(90033);function r(t,e,i,r,a,s){const l=(0,n.g2)("VisibilityIcon"),A=(0,n.g2)("NcActionButton"),c=(0,n.g2)("NcActions");return(0,n.uX)(),(0,n.Wv)(c,{variant:"tertiary",menuName:s.selectedVisibilityDetails.text,"aria-label":s.t("social","Choose a visibility")},{icon:(0,n.k6)(()=>[(0,n.bF)(l,{visibility:s.selectedVisibilityDetails.id,size:20},null,8,["visibility"])]),default:(0,n.k6)(()=>[((0,n.uX)(!0),(0,n.CE)(n.FK,null,(0,n.pI)(a.visibilitiesInfo,t=>((0,n.uX)(),(0,n.Wv)(A,{key:t.id,class:(0,o.C4)({"selected-visibility":t.id===s.selectedVisibilityDetails.id}),closeAfterClick:!0,onClick:e=>s.switchType(t)},{icon:(0,n.k6)(()=>[(0,n.bF)(l,{visibility:t.id,size:20},null,8,["visibility"])]),default:(0,n.k6)(()=>[(0,n.eW)(" "+(0,o.v_)(t.description),1)]),_:2},1032,["class","onClick"]))),128))]),_:1},8,["menuName","aria-label"])}},16865(t,e,i){var n=i(20641);const o={mounted(t){(0,n.dY)(()=>{t.focus()})}};i.d(e,["A",0,o])},38161(t,e,i){i.d(e,{C_:()=>r,J1:()=>o,nr:()=>a});const n="social.composer.draft";function o({text:t,spoilerText:e="",visibility:i=""}){if(""===(t??"").trim()&&""===e.trim())return a();try{return window.localStorage.setItem(n,JSON.stringify({text:t,spoilerText:e,visibility:i,savedAt:Date.now()})),!0}catch{return!1}}function r(){let t,e;try{t=window.localStorage.getItem(n)}catch{return null}if(!t)return null;try{e=JSON.parse(t)}catch{return a(),null}return null===e||"object"!=typeof e||"string"!=typeof e.text||"number"==typeof e.savedAt&&Date.now()-e.savedAt>6048e5?(a(),null):{text:e.text,spoilerText:"string"==typeof e.spoilerText?e.spoilerText:"",visibility:"string"==typeof e.visibility?e.visibility:"",savedAt:"number"==typeof e.savedAt?e.savedAt:0}}function a(){try{return window.localStorage.removeItem(n),!0}catch{return!1}}},9699(t,e,i){i.d(e,{M8:()=>s,Tw:()=>a,Yo:()=>l});var n=i(71085);const o=[{id:"none",css:""},{id:"mono",css:"grayscale(1)"},{id:"noir",css:"grayscale(1) contrast(1.3) brightness(0.9)"},{id:"warm",css:"sepia(0.35) saturate(1.3) contrast(1.05)"},{id:"cool",css:"hue-rotate(-12deg) saturate(1.15) brightness(1.05)"},{id:"vivid",css:"saturate(1.6) contrast(1.1)"},{id:"faded",css:"saturate(0.75) contrast(0.9) brightness(1.1)"},{id:"sepia",css:"sepia(0.8)"}];function r(t){switch(t){case"none":default:return(0,n.t)("social","Original");case"mono":return(0,n.t)("social","Mono");case"noir":return(0,n.t)("social","Noir");case"warm":return(0,n.t)("social","Warm");case"cool":return(0,n.t)("social","Cool");case"vivid":return(0,n.t)("social","Vivid");case"faded":return(0,n.t)("social","Faded");case"sepia":return(0,n.t)("social","Sepia")}}function a(){return o.map(t=>({...t,name:r(t.id)}))}function s(t){return o.find(e=>e.id===t)?.css??""}async function l(t,e){const i=s(e);if(""===i||!t||!t.type?.startsWith("image/"))return t;if("image/gif"===t.type||"image/webp"===t.type)return t;try{const e=await createImageBitmap(t),n=document.createElement("canvas");n.width=e.width,n.height=e.height;const o=n.getContext("2d");if(null===o||!("filter"in o))return t;o.filter=i,o.drawImage(e,0,0),"function"==typeof e.close&&e.close();const r="image/png"===t.type?"image/png":"image/jpeg",a=await new Promise(t=>{n.toBlob(t,r,.92)});return null===a?t:new File([a],function(t,e){const i=(t||"image").replace(/\.[^.]+$/,""),n="image/png"===e?"png":"jpg";return`${i}.${n}`}(t.name,r),{type:r,lastModified:t.lastModified})}catch{return t}}},25113(t,e,i){var n=i(71354),o=i.n(n),r=i(76314),a=i.n(r),s=i(4417),l=i.n(s),A=new URL(i(92280),i.b),c=a()(o()),d=l()(A);c.push([t.id,`.new-post[data-v-0491766e]{background:var(--color-main-background);border:2px solid var(--color-border);border-radius:var(--border-radius-large, 12px);padding:18px;margin:calc(var(--default-grid-baseline)*3) auto;max-width:var(--social-column);position:sticky;top:0;z-index:100;box-shadow:var(--social-elevation-resting);transition:padding 220ms cubic-bezier(0.25, 0.8, 0.35, 1),border-color 220ms cubic-bezier(0.25, 0.8, 0.35, 1),background-color 220ms cubic-bezier(0.25, 0.8, 0.35, 1),box-shadow 220ms cubic-bezier(0.25, 0.8, 0.35, 1)}.new-post[data-v-0491766e]:focus-within{box-shadow:var(--social-elevation-raised)}.new-post-form[data-v-0491766e]{margin-top:12px;margin-inline-start:0;transition:margin-top 220ms cubic-bezier(0.25, 0.8, 0.35, 1)}.new-post-form__emoji-picker[data-v-0491766e]{z-index:1}.new-post--collapsed[data-v-0491766e]{display:flex;align-items:center;gap:12px;padding:10px 12px}.new-post--collapsed .new-post-author[data-v-0491766e]{padding-bottom:0;margin-bottom:0;border-bottom:none}.new-post--collapsed .new-post-form[data-v-0491766e]{flex:1 1 auto;min-width:0;margin-top:0}.new-post--collapsed .message[data-v-0491766e]{min-height:0;padding:9px 16px;border-radius:999px}.new-post--collapsed .options[data-v-0491766e]{max-height:0;margin-top:0;opacity:0;visibility:hidden;pointer-events:none;transform:translateY(-4px)}.new-post--drop-target[data-v-0491766e]{border-color:var(--color-primary-element);background:var(--color-primary-element-light, var(--color-background-hover))}.new-post--drop-target .message[data-v-0491766e]{border-color:var(--color-primary-element)}.new-post__drop-hint[data-v-0491766e]{position:absolute;inset:0;z-index:2;display:flex;align-items:center;justify-content:center;border-radius:inherit;pointer-events:none}.new-post__drop-hint span[data-v-0491766e]{padding:6px 14px;border-radius:var(--border-radius-pill, 999px);background:var(--color-primary-element);color:var(--color-primary-element-text, var(--color-primary-text));font-size:13px;font-weight:600;box-shadow:var(--social-elevation-raised);animation:composer-drop-hint-0491766e 220ms cubic-bezier(0.25, 0.8, 0.35, 1)}@keyframes composer-drop-hint-0491766e{0%{opacity:0;transform:scale(0.94)}100%{opacity:1;transform:scale(1)}}@keyframes composer-refused-0491766e{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}.new-post--refused[data-v-0491766e]{animation:composer-refused-0491766e 400ms cubic-bezier(0.25, 0.8, 0.35, 1)}@media(prefers-reduced-motion: reduce){.new-post[data-v-0491766e],.new-post .new-post-form[data-v-0491766e],.new-post .message[data-v-0491766e],.new-post .options[data-v-0491766e]{transition:none}.new-post--refused[data-v-0491766e],.new-post__drop-hint span[data-v-0491766e]{animation:none}}.new-post-author[data-v-0491766e]{display:flex;align-items:center;gap:10px;padding-bottom:10px;border-bottom:1px solid var(--color-border);margin-bottom:10px}.new-post-author .post-author[data-v-0491766e]{display:flex;align-items:center}.new-post-author .post-author .post-author-name[data-v-0491766e]{font-weight:700;font-size:14px;line-height:1.3}.reply-to[data-v-0491766e]{background:var(--color-background-hover);border-radius:8px;padding:12px 12px 12px 36px;margin-bottom:12px;position:relative}.reply-to[data-v-0491766e]::before{content:"";position:absolute;inset-inline-start:12px;top:12px;width:16px;height:16px;background-image:url(${d});background-size:contain;background-repeat:no-repeat}.reply-to .avatardiv[data-v-0491766e]{margin:0 4px;vertical-align:middle}.reply-to .reply-info[data-v-0491766e]{display:flex;align-items:center;gap:4px;font-size:13px;color:var(--color-text-lighter);margin-bottom:4px}.reply-to .close-button[data-v-0491766e]{margin-inline-start:auto;min-width:28px;min-height:28px;height:28px;width:28px !important}.quote-of[data-v-0491766e]{background:var(--color-background-hover);border-inline-start:3px solid var(--color-border-dark);border-radius:8px;padding:12px;margin-bottom:12px;font-size:14px}.quote-of .avatardiv[data-v-0491766e]{margin:0 4px;vertical-align:middle}.quote-of .quote-info[data-v-0491766e]{display:flex;align-items:center;gap:4px;font-size:13px;color:var(--color-text-lighter);margin-bottom:4px}.quote-of .close-button[data-v-0491766e]{margin-inline-start:auto;min-width:28px;min-height:28px;height:28px;width:28px !important}.message[data-v-0491766e]{width:100%;min-height:80px;padding:12px 14px;border:1px solid var(--color-border);border-radius:8px;transition:min-height 220ms cubic-bezier(0.25, 0.8, 0.35, 1),padding 220ms cubic-bezier(0.25, 0.8, 0.35, 1),border-radius 220ms cubic-bezier(0.25, 0.8, 0.35, 1),border-color 220ms cubic-bezier(0.25, 0.8, 0.35, 1);background:var(--color-main-background);font-size:14px;line-height:1.6;color:var(--color-main-text)}.message[data-v-0491766e]:focus-visible{border-color:var(--color-primary-element);outline:2px solid var(--color-primary-element);outline-offset:1px}.message.too-long[data-v-0491766e]{color:var(--color-error);border-color:var(--color-error)}.message[data-v-0491766e] .mention{color:var(--color-primary-element);background-color:var(--color-background-dark);border-radius:4px;padding:1px 6px 1px 2px;display:inline-flex;align-items:center}.message[data-v-0491766e] .mention img{width:16px;height:16px;border-radius:50%;margin-inline-end:3px}.new-post-form--media-first[data-v-0491766e] .preview-grid{margin-bottom:10px}.new-post-form--media-first .message--caption[data-v-0491766e]{min-height:44px}[contenteditable=true][data-v-0491766e]:empty:before{content:attr(placeholder);display:block;color:var(--color-text-lighter)}.options[data-v-0491766e]{display:flex;align-items:center;gap:8px;margin-top:10px;max-height:60px;opacity:1;overflow:hidden;transform:translateY(0);transition:max-height 220ms cubic-bezier(0.25, 0.8, 0.35, 1),margin-top 220ms cubic-bezier(0.25, 0.8, 0.35, 1),opacity 220ms cubic-bezier(0.25, 0.8, 0.35, 1),transform 220ms cubic-bezier(0.25, 0.8, 0.35, 1),visibility 220ms step-start}.emptySpace[data-v-0491766e]{flex-grow:1}@media(max-width: 600px){.options[data-v-0491766e]{flex-wrap:wrap;row-gap:4px;max-height:120px}.options .emptySpace[data-v-0491766e]{display:none}.options[data-v-0491766e] .action-item__menutoggle .button-vue__text{display:none}.options[data-v-0491766e]>:last-child{margin-inline-start:auto}}.hashtag[data-v-0491766e]{color:var(--color-primary-element);text-decoration:none}`,"",{version:3,sources:["webpack://./src/components/Composer/Composer.vue"],names:[],mappings:"AAMA,2BACC,uCAAA,CACA,oCAAA,CACA,8CAAA,CACA,YAAA,CACA,gDAAA,CAIA,8BAAA,CACA,eAAA,CACA,KAAA,CACA,WAAA,CACA,0CAAA,CACA,uNACC,CAOD,wCACC,yCAAA,CAGD,gCACC,eAAA,CACA,qBAAA,CACA,4DAAA,CAEA,8CACC,SAAA,CAQH,sCACC,YAAA,CACA,kBAAA,CACA,QAAA,CACA,iBAAA,CAEA,uDACC,gBAAA,CACA,eAAA,CACA,kBAAA,CAGD,qDACC,aAAA,CACA,WAAA,CACA,YAAA,CAGD,+CACC,YAAA,CACA,gBAAA,CACA,mBAAA,CAGD,+CACC,YAAA,CACA,YAAA,CACA,SAAA,CACA,iBAAA,CACA,mBAAA,CACA,0BAAA,CAQF,wCACC,yCAAA,CACA,4EAAA,CAEA,iDACC,yCAAA,CAIF,sCACC,iBAAA,CACA,OAAA,CACA,SAAA,CACA,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,qBAAA,CAGA,mBAAA,CAEA,2CACC,gBAAA,CACA,8CAAA,CACA,uCAAA,CACA,kEAAA,CACA,cAAA,CACA,eAAA,CACA,yCAAA,CACA,4EAAA,CAIF,uCACC,GAAA,SAAA,CAAA,qBAAA,CACA,KAAA,SAAA,CAAA,kBAAA,CAAA,CAID,qCACC,QAAA,uBAAA,CACA,IAAA,0BAAA,CACA,IAAA,yBAAA,CAAA,CAGD,oCAEC,0EAAA,CAGD,uCACC,6IAIC,eAAA,CAGD,+EAEC,cAAA,CAAA,CAIF,kCACC,YAAA,CACA,kBAAA,CACA,QAAA,CACA,mBAAA,CACA,2CAAA,CACA,kBAAA,CAEA,+CACC,YAAA,CACA,kBAAA,CAEA,iEACC,eAAA,CACA,cAAA,CACA,eAAA,CAKH,2BACC,wCAAA,CACA,iBAAA,CACA,2BAAA,CACA,kBAAA,CACA,iBAAA,CAEA,mCACC,UAAA,CACA,iBAAA,CACA,uBAAA,CACA,QAAA,CACA,UAAA,CACA,WAAA,CACA,wDAAA,CACA,uBAAA,CACA,2BAAA,CAGD,sCACC,YAAA,CACA,qBAAA,CAGD,uCACC,YAAA,CACA,kBAAA,CACA,OAAA,CACA,cAAA,CACA,+BAAA,CACA,iBAAA,CAGD,yCACC,wBAAA,CACA,cAAA,CACA,eAAA,CACA,WAAA,CACA,qBAAA,CAKF,2BACC,wCAAA,CACA,sDAAA,CACA,iBAAA,CACA,YAAA,CACA,kBAAA,CACA,cAAA,CAEA,sCACC,YAAA,CACA,qBAAA,CAGD,uCACC,YAAA,CACA,kBAAA,CACA,OAAA,CACA,cAAA,CACA,+BAAA,CACA,iBAAA,CAGD,yCACC,wBAAA,CACA,cAAA,CACA,eAAA,CACA,WAAA,CACA,qBAAA,CAIF,0BACC,UAAA,CACA,eAAA,CACA,iBAAA,CACA,oCAAA,CACA,iBAAA,CACA,oNACC,CAID,uCAAA,CACA,cAAA,CACA,eAAA,CACA,4BAAA,CACA,wCACC,yCAAA,CACA,8CAAA,CACA,kBAAA,CAGD,mCACC,wBAAA,CACA,+BAAA,CAGD,mCACC,kCAAA,CACA,6CAAA,CACA,iBAAA,CACA,uBAAA,CACA,mBAAA,CACA,kBAAA,CAEA,uCACC,UAAA,CACA,WAAA,CACA,iBAAA,CACA,qBAAA,CAUF,2DACC,kBAAA,CAGD,+DACC,eAAA,CAIF,qDACC,yBAAA,CACA,aAAA,CACA,+BAAA,CAGD,0BACC,YAAA,CACA,kBAAA,CACA,OAAA,CACA,eAAA,CACA,eAAA,CACA,SAAA,CACA,eAAA,CACA,uBAAA,CACA,0OACC,CAOF,6BACC,WAAA,CASD,yBACC,0BACC,cAAA,CACA,WAAA,CACA,gBAAA,CAEA,sCACC,YAAA,CAGD,qEACC,YAAA,CAGD,sCACC,wBAAA,CAAA,CAKH,0BACC,kCAAA,CACA,oBAAA",sourcesContent:["\n// one duration and one curve for the whole opening, so the parts of it arrive\n// together rather than each on its own schedule\n$composer-ease: cubic-bezier(0.25, 0.8, 0.35, 1);\n$composer-duration: 220ms;\n\n.new-post {\n\tbackground: var(--color-main-background);\n\tborder: 2px solid var(--color-border);\n\tborder-radius: var(--border-radius-large, 12px);\n\tpadding: 18px;\n\tmargin: calc(var(--default-grid-baseline) * 3) auto;\n\t// the full column, where the list only fills it inside its own gutter: the\n\t// box you write in reaches a little past the posts it will join on both\n\t// sides, so it reads as the thing that makes them rather than one of them\n\tmax-width: var(--social-column);\n\tposition: sticky;\n\ttop: 0;\n\tz-index: 100;\n\tbox-shadow: var(--social-elevation-resting);\n\ttransition:\n\t\tpadding $composer-duration $composer-ease,\n\t\tborder-color $composer-duration $composer-ease,\n\t\tbackground-color $composer-duration $composer-ease,\n\t\tbox-shadow $composer-duration $composer-ease;\n\n\t// lifted, not outlined: the box the caret is in draws the ring, and two\n\t// nested rings around the same caret is one too many\n\t&:focus-within {\n\t\tbox-shadow: var(--social-elevation-raised);\n\t}\n\n\t&-form {\n\t\tmargin-top: 12px;\n\t\tmargin-inline-start: 0;\n\t\ttransition: margin-top $composer-duration $composer-ease;\n\n\t\t&__emoji-picker {\n\t\t\tz-index: 1;\n\t\t}\n\t}\n}\n\n// Closed: a portrait and a line to write on. Everything else is still in the\n// document — it is measured, not removed, so the opening can be animated — but\n// it is out of the tab order and out of the accessibility tree until it is.\n.new-post--collapsed {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 12px;\n\tpadding: 10px 12px;\n\n\t.new-post-author {\n\t\tpadding-bottom: 0;\n\t\tmargin-bottom: 0;\n\t\tborder-bottom: none;\n\t}\n\n\t.new-post-form {\n\t\tflex: 1 1 auto;\n\t\tmin-width: 0;\n\t\tmargin-top: 0;\n\t}\n\n\t.message {\n\t\tmin-height: 0;\n\t\tpadding: 9px 16px;\n\t\tborder-radius: 999px;\n\t}\n\n\t.options {\n\t\tmax-height: 0;\n\t\tmargin-top: 0;\n\t\topacity: 0;\n\t\tvisibility: hidden;\n\t\tpointer-events: none;\n\t\ttransform: translateY(-4px);\n\t}\n}\n\n// A file is being dragged over the card: the whole thing is the target, said\n// with a tint and the primary border it already uses for focus, plus one pill\n// naming what will happen. No dashes, no bounce — it is an invitation, not an\n// alarm, and it borrows the composer's own duration and curve.\n.new-post--drop-target {\n\tborder-color: var(--color-primary-element);\n\tbackground: var(--color-primary-element-light, var(--color-background-hover));\n\n\t.message {\n\t\tborder-color: var(--color-primary-element);\n\t}\n}\n\n.new-post__drop-hint {\n\tposition: absolute;\n\tinset: 0;\n\tz-index: 2;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tborder-radius: inherit;\n\t// it must never take the drop it is announcing, and it must not turn the\n\t// card into a storm of dragenter/dragleave by sitting under the pointer\n\tpointer-events: none;\n\n\tspan {\n\t\tpadding: 6px 14px;\n\t\tborder-radius: var(--border-radius-pill, 999px);\n\t\tbackground: var(--color-primary-element);\n\t\tcolor: var(--color-primary-element-text, var(--color-primary-text));\n\t\tfont-size: 13px;\n\t\tfont-weight: 600;\n\t\tbox-shadow: var(--social-elevation-raised);\n\t\tanimation: composer-drop-hint $composer-duration $composer-ease;\n\t}\n}\n\n@keyframes composer-drop-hint {\n\t0% { opacity: 0; transform: scale(.94); }\n\t100% { opacity: 1; transform: scale(1); }\n}\n\n/* what was dropped is not something the composer can take */\n@keyframes composer-refused {\n\t0%, 100% { transform: translateX(0); }\n\t25% { transform: translateX(-4px); }\n\t75% { transform: translateX(4px); }\n}\n\n.new-post--refused {\n\t// 400ms, the same span REFUSAL_DURATION keeps the class on for\n\tanimation: composer-refused 400ms $composer-ease;\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.new-post,\n\t.new-post .new-post-form,\n\t.new-post .message,\n\t.new-post .options {\n\t\ttransition: none;\n\t}\n\n\t.new-post--refused,\n\t.new-post__drop-hint span {\n\t\tanimation: none;\n\t}\n}\n\n.new-post-author {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding-bottom: 10px;\n\tborder-bottom: 1px solid var(--color-border);\n\tmargin-bottom: 10px;\n\n\t.post-author {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\n\t\t.post-author-name {\n\t\t\tfont-weight: 700;\n\t\t\tfont-size: 14px;\n\t\t\tline-height: 1.3;\n\t\t}\n\t}\n}\n\n.reply-to {\n\tbackground: var(--color-background-hover);\n\tborder-radius: 8px;\n\tpadding: 12px 12px 12px 36px;\n\tmargin-bottom: 12px;\n\tposition: relative;\n\n\t&::before {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\tinset-inline-start: 12px;\n\t\ttop: 12px;\n\t\twidth: 16px;\n\t\theight: 16px;\n\t\tbackground-image: url(../../../img/reply.svg);\n\t\tbackground-size: contain;\n\t\tbackground-repeat: no-repeat;\n\t}\n\n\t.avatardiv {\n\t\tmargin: 0 4px;\n\t\tvertical-align: middle;\n\t}\n\n\t.reply-info {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 4px;\n\t\tfont-size: 13px;\n\t\tcolor: var(--color-text-lighter);\n\t\tmargin-bottom: 4px;\n\t}\n\n\t.close-button {\n\t\tmargin-inline-start: auto;\n\t\tmin-width: 28px;\n\t\tmin-height: 28px;\n\t\theight: 28px;\n\t\twidth: 28px !important;\n\t}\n}\n\n/* set in and ruled off, the same way a quote reads in the timeline */\n.quote-of {\n\tbackground: var(--color-background-hover);\n\tborder-inline-start: 3px solid var(--color-border-dark);\n\tborder-radius: 8px;\n\tpadding: 12px;\n\tmargin-bottom: 12px;\n\tfont-size: 14px;\n\n\t.avatardiv {\n\t\tmargin: 0 4px;\n\t\tvertical-align: middle;\n\t}\n\n\t.quote-info {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 4px;\n\t\tfont-size: 13px;\n\t\tcolor: var(--color-text-lighter);\n\t\tmargin-bottom: 4px;\n\t}\n\n\t.close-button {\n\t\tmargin-inline-start: auto;\n\t\tmin-width: 28px;\n\t\tmin-height: 28px;\n\t\theight: 28px;\n\t\twidth: 28px !important;\n\t}\n}\n\n.message {\n\twidth: 100%;\n\tmin-height: 80px;\n\tpadding: 12px 14px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: 8px;\n\ttransition:\n\t\tmin-height $composer-duration $composer-ease,\n\t\tpadding $composer-duration $composer-ease,\n\t\tborder-radius $composer-duration $composer-ease,\n\t\tborder-color $composer-duration $composer-ease;\n\tbackground: var(--color-main-background);\n\tfont-size: 14px;\n\tline-height: 1.6;\n\tcolor: var(--color-main-text);\n\t&:focus-visible {\n\t\tborder-color: var(--color-primary-element);\n\t\toutline: 2px solid var(--color-primary-element);\n\t\toutline-offset: 1px;\n\t}\n\n\t&.too-long {\n\t\tcolor: var(--color-error);\n\t\tborder-color: var(--color-error);\n\t}\n\n\t:deep(.mention) {\n\t\tcolor: var(--color-primary-element);\n\t\tbackground-color: var(--color-background-dark);\n\t\tborder-radius: 4px;\n\t\tpadding: 1px 6px 1px 2px;\n\t\tdisplay: inline-flex;\n\t\talign-items: center;\n\n\t\timg {\n\t\t\twidth: 16px;\n\t\t\theight: 16px;\n\t\t\tborder-radius: 50%;\n\t\t\tmargin-inline-end: 3px;\n\t\t}\n\t}\n}\n\n// Photo-first: the picture is the post and the box under it is its caption,\n// so the box gives up the height it was holding for a post that has no picture.\n// Nothing is moved or hidden — the same controls in the same order, weighted\n// the other way round.\n.new-post-form--media-first {\n\t:deep(.preview-grid) {\n\t\tmargin-bottom: 10px;\n\t}\n\n\t.message--caption {\n\t\tmin-height: 44px;\n\t}\n}\n\n[contenteditable=true]:empty:before {\n\tcontent: attr(placeholder);\n\tdisplay: block;\n\tcolor: var(--color-text-lighter);\n}\n\n.options {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tmargin-top: 10px;\n\tmax-height: 60px;\n\topacity: 1;\n\toverflow: hidden;\n\ttransform: translateY(0);\n\ttransition:\n\t\tmax-height $composer-duration $composer-ease,\n\t\tmargin-top $composer-duration $composer-ease,\n\t\topacity $composer-duration $composer-ease,\n\t\ttransform $composer-duration $composer-ease,\n\t\tvisibility $composer-duration step-start;\n}\n\n.emptySpace {\n\tflex-grow: 1;\n}\n\n/*\n * A phone. Seven controls and a Post button do not fit one row of 358px, and\n * the row used to end with half the button off the screen. The row wraps: the\n * spacer goes, the visibility menu shows its icon only, and Post keeps the\n * end of whatever row it lands on.\n */\n@media (max-width: 600px) {\n\t.options {\n\t\tflex-wrap: wrap;\n\t\trow-gap: 4px;\n\t\tmax-height: 120px;\n\n\t\t.emptySpace {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\t:deep(.action-item__menutoggle .button-vue__text) {\n\t\t\tdisplay: none;\n\t\t}\n\n\t\t> :last-child {\n\t\t\tmargin-inline-start: auto;\n\t\t}\n\t}\n}\n\n.hashtag {\n\tcolor: var(--color-primary-element);\n\ttext-decoration: none;\n}\n"],sourceRoot:""}]);const p=c;i.d(e,["A",0,p])},65943(t,e,i){var n=i(71354),o=i.n(n),r=i(76314),a=i.n(r)()(o());a.push([t.id,'.tribute-container{position:absolute;top:0;inset-inline-start:0;height:auto;max-height:300px;max-width:500px;min-width:200px;overflow:auto;display:block;z-index:999999;border-radius:8px;border:1px solid var(--color-border)}.tribute-container ul{margin:0;margin-top:2px;padding:4px;list-style:none;background:var(--color-main-background);border-radius:8px;background-clip:padding-box;overflow:hidden}.tribute-container ul li{color:var(--color-text);padding:6px 10px;cursor:pointer;font-size:14px;display:flex;border-radius:6px;margin:2px 0}.tribute-container ul li span{display:block;font-weight:bold}.tribute-container ul li.highlight,.tribute-container ul li:hover{background:var(--color-primary);color:var(--color-primary-text)}.tribute-container ul li img{width:32px;height:32px;border-radius:50%;overflow:hidden;margin-inline:-3px 10px;margin-top:3px}.tribute-container ul li.no-match{cursor:default}.tribute-container .menu-highlighted{font-weight:bold}.tribute-container .account,.tribute-container li.highlight .account,.tribute-container li:hover .account{font-weight:normal;color:var(--color-text-light)}.tribute-container li.highlight .account,.tribute-container li:hover .account{color:var(--color-primary-text) !important}.poll-editor{margin:8px 0;padding:8px;border:1px solid var(--color-border);border-radius:var(--border-radius)}.poll-editor__option{display:flex;gap:4px;margin-bottom:4px}.poll-editor__option input[type=text]{flex-grow:1}.poll-editor__settings{display:flex;align-items:center;gap:12px;flex-wrap:wrap}.composer-alt-warning{align-self:center;padding:2px 8px;border-radius:var(--border-radius-pill);background:var(--color-warning);color:var(--color-warning-text, var(--color-main-text));font-size:12px;font-weight:600}.char-ring{position:relative;width:24px;height:24px;flex-shrink:0;align-self:center;border-radius:50%;background:conic-gradient(var(--color-primary-element) calc(var(--char-progress) * 360deg), var(--color-background-dark) 0);transition:background .2s ease}.char-ring::after{content:"";position:absolute;inset:3px;border-radius:50%;background:var(--color-main-background)}.char-ring--warning{background:conic-gradient(var(--color-warning) calc(var(--char-progress) * 360deg), var(--color-background-dark) 0)}.char-ring--over{background:var(--color-error)}.char-ring__count{position:absolute;inset:0;z-index:1;display:flex;align-items:center;justify-content:center;font-size:10px;font-weight:bold;color:var(--color-main-text)}@media(prefers-reduced-motion: reduce){.char-ring{transition:none}}.content-warning{width:100%;margin-bottom:6px;padding:8px 10px;border:1px solid var(--color-border);border-radius:var(--border-radius, 8px);background:var(--color-main-background);color:var(--color-main-text);font-size:14px}.content-warning:focus-visible{border-color:var(--color-primary-element);outline:2px solid var(--color-primary-element);outline-offset:1px}',"",{version:3,sources:["webpack://./src/components/Composer/Composer.vue"],names:[],mappings:"AACA,mBACC,iBAAA,CACA,KAAA,CACA,oBAAA,CACA,WAAA,CACA,gBAAA,CACA,eAAA,CACA,eAAA,CACA,aAAA,CACA,aAAA,CACA,cAAA,CACA,iBAAA,CACA,oCAAA,CAEA,sBACC,QAAA,CACA,cAAA,CACA,WAAA,CACA,eAAA,CACA,uCAAA,CACA,iBAAA,CACA,2BAAA,CACA,eAAA,CAEA,yBACC,uBAAA,CACA,gBAAA,CACA,cAAA,CACA,cAAA,CACA,YAAA,CACA,iBAAA,CACA,YAAA,CAEA,8BACC,aAAA,CACA,gBAAA,CAGD,kEAEC,+BAAA,CACA,+BAAA,CAGD,6BACC,UAAA,CACA,WAAA,CACA,iBAAA,CACA,eAAA,CACA,uBAAA,CACA,cAAA,CAGD,kCACC,cAAA,CAKH,qCACC,gBAAA,CAGD,0GAGC,kBAAA,CACA,6BAAA,CAGD,8EAEC,0CAAA,CAIF,aACC,YAAA,CACA,WAAA,CACA,oCAAA,CACA,kCAAA,CAEA,qBACC,YAAA,CACA,OAAA,CACA,iBAAA,CAEA,sCACC,WAAA,CAIF,uBACC,YAAA,CACA,kBAAA,CACA,QAAA,CACA,cAAA,CAIF,sBACC,iBAAA,CACA,eAAA,CACA,uCAAA,CACA,+BAAA,CACA,uDAAA,CACA,cAAA,CACA,eAAA,CAGD,WACC,iBAAA,CACA,UAAA,CACA,WAAA,CACA,aAAA,CACA,iBAAA,CACA,iBAAA,CACA,2HAAA,CAIA,8BAAA,CAEA,kBACC,UAAA,CACA,iBAAA,CACA,SAAA,CACA,iBAAA,CACA,uCAAA,CAGD,oBACC,mHAAA,CAMD,iBACC,6BAAA,CAGD,kBACC,iBAAA,CACA,OAAA,CACA,SAAA,CACA,YAAA,CACA,kBAAA,CACA,sBAAA,CACA,cAAA,CACA,gBAAA,CACA,4BAAA,CAIF,uCACC,WACC,eAAA,CAAA,CAIF,iBACC,UAAA,CACA,iBAAA,CACA,gBAAA,CACA,oCAAA,CACA,uCAAA,CACA,uCAAA,CACA,4BAAA,CACA,cAAA,CAEA,+BACC,yCAAA,CACA,8CAAA,CACA,kBAAA",sourcesContent:["\n.tribute-container {\n\tposition: absolute;\n\ttop: 0;\n\tinset-inline-start: 0;\n\theight: auto;\n\tmax-height: 300px;\n\tmax-width: 500px;\n\tmin-width: 200px;\n\toverflow: auto;\n\tdisplay: block;\n\tz-index: 999999;\n\tborder-radius: 8px;\n\tborder: 1px solid var(--color-border);\n\n\tul {\n\t\tmargin: 0;\n\t\tmargin-top: 2px;\n\t\tpadding: 4px;\n\t\tlist-style: none;\n\t\tbackground: var(--color-main-background);\n\t\tborder-radius: 8px;\n\t\tbackground-clip: padding-box;\n\t\toverflow: hidden;\n\n\t\tli {\n\t\t\tcolor: var(--color-text);\n\t\t\tpadding: 6px 10px;\n\t\t\tcursor: pointer;\n\t\t\tfont-size: 14px;\n\t\t\tdisplay: flex;\n\t\t\tborder-radius: 6px;\n\t\t\tmargin: 2px 0;\n\n\t\t\tspan {\n\t\t\t\tdisplay: block;\n\t\t\t\tfont-weight: bold;\n\t\t\t}\n\n\t\t\t&.highlight,\n\t\t\t&:hover {\n\t\t\t\tbackground: var(--color-primary);\n\t\t\t\tcolor: var(--color-primary-text);\n\t\t\t}\n\n\t\t\timg {\n\t\t\t\twidth: 32px;\n\t\t\t\theight: 32px;\n\t\t\t\tborder-radius: 50%;\n\t\t\t\toverflow: hidden;\n\t\t\t\tmargin-inline: -3px 10px;\n\t\t\t\tmargin-top: 3px;\n\t\t\t}\n\n\t\t\t&.no-match {\n\t\t\t\tcursor: default;\n\t\t\t}\n\t\t}\n\t}\n\n\t.menu-highlighted {\n\t\tfont-weight: bold;\n\t}\n\n\t.account,\n\tli.highlight .account,\n\tli:hover .account {\n\t\tfont-weight: normal;\n\t\tcolor: var(--color-text-light);\n\t}\n\n\tli.highlight .account,\n\tli:hover .account {\n\t\tcolor: var(--color-primary-text) !important;\n\t}\n}\n\n.poll-editor {\n\tmargin: 8px 0;\n\tpadding: 8px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius);\n\n\t&__option {\n\t\tdisplay: flex;\n\t\tgap: 4px;\n\t\tmargin-bottom: 4px;\n\n\t\tinput[type='text'] {\n\t\t\tflex-grow: 1;\n\t\t}\n\t}\n\n\t&__settings {\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tgap: 12px;\n\t\tflex-wrap: wrap;\n\t}\n}\n/* the allowance as a ring that fills, rather than a limit you discover */\n.composer-alt-warning {\n\talign-self: center;\n\tpadding: 2px 8px;\n\tborder-radius: var(--border-radius-pill);\n\tbackground: var(--color-warning);\n\tcolor: var(--color-warning-text, var(--color-main-text));\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.char-ring {\n\tposition: relative;\n\twidth: 24px;\n\theight: 24px;\n\tflex-shrink: 0;\n\talign-self: center;\n\tborder-radius: 50%;\n\tbackground: conic-gradient(\n\t\tvar(--color-primary-element) calc(var(--char-progress) * 360deg),\n\t\tvar(--color-background-dark) 0\n\t);\n\ttransition: background .2s ease;\n\n\t&::after {\n\t\tcontent: '';\n\t\tposition: absolute;\n\t\tinset: 3px;\n\t\tborder-radius: 50%;\n\t\tbackground: var(--color-main-background);\n\t}\n\n\t&--warning {\n\t\tbackground: conic-gradient(\n\t\t\tvar(--color-warning) calc(var(--char-progress) * 360deg),\n\t\t\tvar(--color-background-dark) 0\n\t\t);\n\t}\n\n\t&--over {\n\t\tbackground: var(--color-error);\n\t}\n\n\t&__count {\n\t\tposition: absolute;\n\t\tinset: 0;\n\t\tz-index: 1;\n\t\tdisplay: flex;\n\t\talign-items: center;\n\t\tjustify-content: center;\n\t\tfont-size: 10px;\n\t\tfont-weight: bold;\n\t\tcolor: var(--color-main-text);\n\t}\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.char-ring {\n\t\ttransition: none;\n\t}\n}\n\n.content-warning {\n\twidth: 100%;\n\tmargin-bottom: 6px;\n\tpadding: 8px 10px;\n\tborder: 1px solid var(--color-border);\n\tborder-radius: var(--border-radius, 8px);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 14px;\n\n\t&:focus-visible {\n\t\tborder-color: var(--color-primary-element);\n\t\toutline: 2px solid var(--color-primary-element);\n\t\toutline-offset: 1px;\n\t}\n}\n"],sourceRoot:""}]);const s=a;i.d(e,["A",0,s])},13360(t,e,i){var n=i(71354),o=i.n(n),r=i(76314),a=i.n(r)()(o());a.push([t.id,".filter-picker[data-v-64b107b5]{display:flex;gap:var(--default-grid-baseline);overflow-x:auto;padding-block:var(--default-grid-baseline);overscroll-behavior-x:contain}.filter-picker__option[data-v-64b107b5]{display:flex;flex-direction:column;align-items:center;gap:2px;padding:2px;border:none;background:none;cursor:pointer;flex:0 0 auto}.filter-picker__option[data-v-64b107b5]:focus-visible{outline:2px solid var(--color-primary-element);border-radius:var(--border-radius)}.filter-picker__swatch[data-v-64b107b5]{width:48px;height:48px;border-radius:var(--border-radius);overflow:hidden;border:2px solid rgba(0,0,0,0);background-color:var(--color-background-dark)}.filter-picker__option--active .filter-picker__swatch[data-v-64b107b5]{border-color:var(--color-primary-element)}.filter-picker__image[data-v-64b107b5],.filter-picker__placeholder[data-v-64b107b5]{width:100%;height:100%;object-fit:cover;display:block}.filter-picker__placeholder[data-v-64b107b5]{background:linear-gradient(135deg, var(--color-primary-element), var(--color-background-darker))}.filter-picker__name[data-v-64b107b5]{font-size:var(--font-size-small, 0.85em);color:var(--color-text-maxcontrast)}.filter-picker__option--active .filter-picker__name[data-v-64b107b5]{color:var(--color-main-text);font-weight:bold}","",{version:3,sources:["webpack://./src/components/Composer/FilterPicker.vue"],names:[],mappings:"AACA,gCACC,YAAA,CACA,gCAAA,CACA,eAAA,CACA,0CAAA,CAGA,6BAAA,CAEA,wCACC,YAAA,CACA,qBAAA,CACA,kBAAA,CACA,OAAA,CACA,WAAA,CACA,WAAA,CACA,eAAA,CACA,cAAA,CACA,aAAA,CAEA,sDACC,8CAAA,CACA,kCAAA,CAIF,wCACC,UAAA,CACA,WAAA,CACA,kCAAA,CACA,eAAA,CACA,8BAAA,CACA,6CAAA,CAEA,uEACC,yCAAA,CAIF,oFAEC,UAAA,CACA,WAAA,CACA,gBAAA,CACA,aAAA,CAGD,6CACC,gGAAA,CAGD,sCACC,wCAAA,CACA,mCAAA,CAEA,qEACC,4BAAA,CACA,gBAAA",sourcesContent:["\n.filter-picker {\n\tdisplay: flex;\n\tgap: var(--default-grid-baseline);\n\toverflow-x: auto;\n\tpadding-block: var(--default-grid-baseline);\n\t// a filter strip is a horizontal scroller by nature; keep it from stealing\n\t// the vertical scroll of the composer around it\n\toverscroll-behavior-x: contain;\n\n\t&__option {\n\t\tdisplay: flex;\n\t\tflex-direction: column;\n\t\talign-items: center;\n\t\tgap: 2px;\n\t\tpadding: 2px;\n\t\tborder: none;\n\t\tbackground: none;\n\t\tcursor: pointer;\n\t\tflex: 0 0 auto;\n\n\t\t&:focus-visible {\n\t\t\toutline: 2px solid var(--color-primary-element);\n\t\t\tborder-radius: var(--border-radius);\n\t\t}\n\t}\n\n\t&__swatch {\n\t\twidth: 48px;\n\t\theight: 48px;\n\t\tborder-radius: var(--border-radius);\n\t\toverflow: hidden;\n\t\tborder: 2px solid transparent;\n\t\tbackground-color: var(--color-background-dark);\n\n\t\t.filter-picker__option--active & {\n\t\t\tborder-color: var(--color-primary-element);\n\t\t}\n\t}\n\n\t&__image,\n\t&__placeholder {\n\t\twidth: 100%;\n\t\theight: 100%;\n\t\tobject-fit: cover;\n\t\tdisplay: block;\n\t}\n\n\t&__placeholder {\n\t\tbackground: linear-gradient(135deg, var(--color-primary-element), var(--color-background-darker));\n\t}\n\n\t&__name {\n\t\tfont-size: var(--font-size-small, 0.85em);\n\t\tcolor: var(--color-text-maxcontrast);\n\n\t\t.filter-picker__option--active & {\n\t\t\tcolor: var(--color-main-text);\n\t\t\tfont-weight: bold;\n\t\t}\n\t}\n}\n"],sourceRoot:""}]);const s=a;i.d(e,["A",0,s])},61982(t,e,i){var n=i(71354),o=i.n(n),r=i(76314),a=i.n(r)()(o());a.push([t.id,".upload-progress[data-v-131432de]{display:flex;align-items:center;gap:10px;margin-bottom:8px}.upload-progress__message[data-v-131432de]{flex-grow:1;font-size:13px;color:var(--color-text-lighter)}.upload-progress__backdrop[data-v-131432de]{margin-top:4px;height:4px;border-radius:2px;background:var(--color-background-dark);overflow:hidden}.upload-progress__tracker[data-v-131432de]{height:100%;background:var(--color-primary-element);transition:width .2s ease}@media(prefers-reduced-motion: reduce){.upload-progress__tracker[data-v-131432de]{transition:none}}.preview-grid[data-v-131432de]{display:flex;flex-wrap:wrap;flex-direction:row;margin-inline:-5px}.preview-grid--single[data-v-131432de] .preview-item{height:260px}","",{version:3,sources:["webpack://./src/components/Composer/PreviewGrid.vue"],names:[],mappings:"AACA,kCACC,YAAA,CACA,kBAAA,CACA,QAAA,CACA,iBAAA,CAEA,2CACC,WAAA,CACA,cAAA,CACA,+BAAA,CAGD,4CACC,cAAA,CACA,UAAA,CACA,iBAAA,CACA,uCAAA,CACA,eAAA,CAGD,2CACC,WAAA,CACA,uCAAA,CACA,yBAAA,CAIF,uCACC,2CACC,eAAA,CAAA,CAIF,+BACC,YAAA,CACA,cAAA,CACA,kBAAA,CACA,kBAAA,CAID,qDACC,YAAA",sourcesContent:["\n.upload-progress {\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tmargin-bottom: 8px;\n\n\t&__message {\n\t\tflex-grow: 1;\n\t\tfont-size: 13px;\n\t\tcolor: var(--color-text-lighter);\n\t}\n\n\t&__backdrop {\n\t\tmargin-top: 4px;\n\t\theight: 4px;\n\t\tborder-radius: 2px;\n\t\tbackground: var(--color-background-dark);\n\t\toverflow: hidden;\n\t}\n\n\t&__tracker {\n\t\theight: 100%;\n\t\tbackground: var(--color-primary-element);\n\t\ttransition: width .2s ease;\n\t}\n}\n\n@media (prefers-reduced-motion: reduce) {\n\t.upload-progress__tracker {\n\t\ttransition: none;\n\t}\n}\n\n.preview-grid {\n\tdisplay: flex;\n\tflex-wrap: wrap;\n\tflex-direction: row;\n\tmargin-inline: -5px;\n}\n\n// one picture is the post, not a thumbnail of it\n.preview-grid--single :deep(.preview-item) {\n\theight: 260px;\n}\n"],sourceRoot:""}]);const s=a;i.d(e,["A",0,s])},35346(t,e,i){var n=i(71354),o=i.n(n),r=i(76314),a=i.n(r)()(o());a.push([t.id,".preview-item-wrapper[data-v-44df805c]{flex:1 1 0;min-width:40%;margin:5px}.preview-item__missing[data-v-44df805c]{position:absolute;inset-inline-start:8px;inset-block-end:8px;padding:2px 8px;border-radius:var(--border-radius-pill);background:var(--color-warning);color:var(--color-warning-text, var(--color-main-text));font-size:12px;font-weight:600}.preview-item__failed[data-v-44df805c]{position:absolute;inset-inline-start:8px;inset-block-end:8px;padding:2px 8px;border-radius:var(--border-radius-pill);background:var(--color-error);color:var(--color-primary-element-text, white);font-size:12px;font-weight:600}.preview-item__label[data-v-44df805c]{display:block;margin:6px 2px 2px;font-size:12px;color:var(--color-text-maxcontrast)}.preview-item__description[data-v-44df805c]{width:100%;min-height:44px;resize:vertical;box-sizing:border-box;border-radius:var(--border-radius);border:1px solid var(--color-border-dark);background:var(--color-main-background);color:var(--color-main-text);font-size:13px;padding:6px 8px}.preview-item__description[data-v-44df805c]:focus-visible{border-color:var(--color-primary-element);outline:2px solid var(--color-primary-element);outline-offset:1px}.preview-item[data-v-44df805c]{border-radius:var(--border-radius-large);background:var(--color-background-darker);background-position:50%;background-size:cover;background-repeat:no-repeat;height:140px;width:100%;overflow:hidden;position:relative}.preview-item .button-vue--tertiary-no-background[data-v-44df805c]{color:#fff !important}.preview-item__actions[data-v-44df805c]{position:absolute;top:0;width:100%;background:linear-gradient(180deg, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.35) 80%, transparent);display:flex;align-items:flex-start;justify-content:space-between}.preview-item__actions .button-vue__text[data-v-44df805c]{color:#fff !important}.preview-item .description-warning[data-v-44df805c]{position:absolute;z-index:2;bottom:0;inset-inline:0;box-sizing:border-box;background:linear-gradient(0deg, rgba(0, 0, 0, 0.8), rgba(0, 0, 0, 0.35) 80%, transparent);color:#fff;padding:10px}.modal__content[data-v-44df805c]{padding:20px}textarea[data-v-44df805c]{width:100%;height:100px;margin-bottom:20px}","",{version:3,sources:["webpack://./src/components/Composer/PreviewGridItem.vue"],names:[],mappings:"AACA,uCACC,UAAA,CACA,aAAA,CACA,UAAA,CAGD,wCACC,iBAAA,CACA,sBAAA,CACA,mBAAA,CACA,eAAA,CACA,uCAAA,CACA,+BAAA,CACA,uDAAA,CACA,cAAA,CACA,eAAA,CAGD,uCACC,iBAAA,CACA,sBAAA,CACA,mBAAA,CACA,eAAA,CACA,uCAAA,CACA,6BAAA,CACA,8CAAA,CACA,cAAA,CACA,eAAA,CAGD,sCACC,aAAA,CACA,kBAAA,CACA,cAAA,CACA,mCAAA,CAGD,4CACC,UAAA,CACA,eAAA,CACA,eAAA,CACA,qBAAA,CACA,kCAAA,CACA,yCAAA,CACA,uCAAA,CACA,4BAAA,CACA,cAAA,CACA,eAAA,CAEA,0DACC,yCAAA,CACA,8CAAA,CACA,kBAAA,CAIF,+BACC,wCAAA,CACA,yCAAA,CACA,uBAAA,CACA,qBAAA,CACA,2BAAA,CACA,YAAA,CACA,UAAA,CACA,eAAA,CACA,iBAAA,CAEA,mEACC,qBAAA,CAGD,wCACC,iBAAA,CACA,KAAA,CACA,UAAA,CACA,4FAAA,CACA,YAAA,CACA,sBAAA,CACA,6BAAA,CAEA,0DACC,qBAAA,CAIF,oDACC,iBAAA,CACA,SAAA,CACA,QAAA,CACA,cAAA,CACA,qBAAA,CACA,0FAAA,CACA,UAAA,CACA,YAAA,CAIF,iCACC,YAAA,CAGD,0BACC,UAAA,CACA,YAAA,CACA,kBAAA",sourcesContent:["\n.preview-item-wrapper {\n\tflex: 1 1 0;\n\tmin-width: 40%;\n\tmargin: 5px;\n}\n\n.preview-item__missing {\n\tposition: absolute;\n\tinset-inline-start: 8px;\n\tinset-block-end: 8px;\n\tpadding: 2px 8px;\n\tborder-radius: var(--border-radius-pill);\n\tbackground: var(--color-warning);\n\tcolor: var(--color-warning-text, var(--color-main-text));\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.preview-item__failed {\n\tposition: absolute;\n\tinset-inline-start: 8px;\n\tinset-block-end: 8px;\n\tpadding: 2px 8px;\n\tborder-radius: var(--border-radius-pill);\n\tbackground: var(--color-error);\n\tcolor: var(--color-primary-element-text, white);\n\tfont-size: 12px;\n\tfont-weight: 600;\n}\n\n.preview-item__label {\n\tdisplay: block;\n\tmargin: 6px 2px 2px;\n\tfont-size: 12px;\n\tcolor: var(--color-text-maxcontrast);\n}\n\n.preview-item__description {\n\twidth: 100%;\n\tmin-height: 44px;\n\tresize: vertical;\n\tbox-sizing: border-box;\n\tborder-radius: var(--border-radius);\n\tborder: 1px solid var(--color-border-dark);\n\tbackground: var(--color-main-background);\n\tcolor: var(--color-main-text);\n\tfont-size: 13px;\n\tpadding: 6px 8px;\n\n\t&:focus-visible {\n\t\tborder-color: var(--color-primary-element);\n\t\toutline: 2px solid var(--color-primary-element);\n\t\toutline-offset: 1px;\n\t}\n}\n\n.preview-item {\n\tborder-radius: var(--border-radius-large);\n\tbackground: var(--color-background-darker);\n\tbackground-position: 50%;\n\tbackground-size: cover;\n\tbackground-repeat: no-repeat;\n\theight: 140px;\n\twidth: 100%;\n\toverflow: hidden;\n\tposition: relative;\n\n\t.button-vue--tertiary-no-background {\n\t\tcolor: white !important;\n\t}\n\n\t&__actions {\n\t\tposition: absolute;\n\t\ttop: 0;\n\t\twidth: 100%;\n\t\tbackground: linear-gradient(180deg,rgba(0,0,0,.8),rgba(0,0,0,.35) 80%,transparent);\n\t\tdisplay: flex;\n\t\talign-items: flex-start;\n\t\tjustify-content: space-between;\n\n\t\t.button-vue__text {\n\t\t\tcolor: white !important;\n\t\t}\n\t}\n\n\t.description-warning {\n\t\tposition: absolute;\n\t\tz-index: 2;\n\t\tbottom: 0;\n\t\tinset-inline: 0;\n\t\tbox-sizing: border-box;\n\t\tbackground: linear-gradient(0deg,rgba(0,0,0,.8),rgba(0,0,0,.35) 80%,transparent);\n\t\tcolor: white;\n\t\tpadding: 10px;\n\t}\n}\n\n.modal__content {\n\tpadding: 20px;\n}\n\ntextarea {\n\twidth: 100%;\n\theight: 100px;\n\tmargin-bottom: 20px;\n}\n"],sourceRoot:""}]);const s=a;i.d(e,["A",0,s])},47601(t,e,i){var n=i(71354),o=i.n(n),r=i(76314),a=i.n(r)()(o());a.push([t.id,"\n.selected-visibility[data-v-4cce609e] {\n\toutline: 1px solid var(--color-success);\n\tborder-radius: 6px;\n\tbackground: var(--color-background-hover);\n}\n","",{version:3,sources:["webpack://./src/components/Visibility/VisibilitySelect.vue"],names:[],mappings:";AAuFA;CACC,uCAAuC;CACvC,kBAAkB;CAClB,yCAAyC;AAC1C",sourcesContent:["\x3c!--\n - SPDX-FileCopyrightText: 2018 Nextcloud GmbH and Nextcloud contributors\n - SPDX-License-Identifier: AGPL-3.0-or-later\n--\x3e\n\n\n diff --git a/tests/Controller/ApiControllerTest.php b/tests/Controller/ApiControllerTest.php index 3ead3f587..931a5d8f1 100644 --- a/tests/Controller/ApiControllerTest.php +++ b/tests/Controller/ApiControllerTest.php @@ -3057,6 +3057,7 @@ private function userFolderHolding( $file = $this->createMock(File::class); $file->method('getSize')->willReturn(strlen($contents)); + $file->method('getName')->willReturn(basename($path)); $file->method('getPath')->willReturn('/alice/files/' . ltrim($path, '/')); $file->method('fopen')->willReturn($stream); diff --git a/tests/Model/ActivityPub/Object/DocumentTest.php b/tests/Model/ActivityPub/Object/DocumentTest.php index bf6944c94..698f389bb 100644 --- a/tests/Model/ActivityPub/Object/DocumentTest.php +++ b/tests/Model/ActivityPub/Object/DocumentTest.php @@ -162,6 +162,28 @@ public function testConvertToMediaAttachmentOfAVideoUsesTheMediaAsItsOwnPreview( $this->assertSame($media->getUrl(), $media->getPreviewUrl(), 'no resized copy: the media is the preview'); } + /** + * A PDF is not an "application": it is a file a client cannot render, which + * Mastodon calls `unknown` -- and it has no preview of itself, so none is + * offered rather than the file being handed back as a picture. + */ + public function testAFileConvertsToAnUnknownAttachmentWithoutAPreview(): void { + $document = new Document(); + $document->setNid(9) + ->setMediaType('application/pdf') + ->setLocalCopy('doc') + ->setResizedCopy('') + ->setDescription('minutes.pdf'); + + $media = $document->convertToMediaAttachment($this->urlGenerator); + + $this->assertSame('unknown', $media->getType()); + $this->assertSame('application/pdf', $media->getMediaType()); + $this->assertSame('https://cloud.example.org/social.Api.mediaOpen/doc.pdf', $media->getUrl()); + $this->assertSame('', $media->getPreviewUrl(), 'a file is not its own preview'); + $this->assertSame('minutes.pdf', $media->getDescription()); + } + public function testConvertToMediaAttachmentWithoutUrlGeneratorLeavesLocalUrlsEmpty(): void { $document = new Document(); $document->setMediaType('video/mp4') diff --git a/tests/Model/Client/MediaAttachmentTest.php b/tests/Model/Client/MediaAttachmentTest.php index 87141c5f6..d84dad989 100644 --- a/tests/Model/Client/MediaAttachmentTest.php +++ b/tests/Model/Client/MediaAttachmentTest.php @@ -122,6 +122,7 @@ public function testARowWithoutTheMimeGetsAGuessRatherThanNothing(): void { $this->assertSame('image/jpeg', MediaAttachment::guessMediaType('image', 'https://x.example/media/uuid')); $this->assertSame('video/mp4', MediaAttachment::guessMediaType('gifv', 'https://x.example/media/uuid')); $this->assertSame('audio/mpeg', MediaAttachment::guessMediaType('audio', '')); + $this->assertSame('application/pdf', MediaAttachment::guessMediaType('unknown', 'https://x.example/media/report.pdf')); $this->assertSame('', MediaAttachment::guessMediaType('unknown', '')); } diff --git a/tests/Service/CacheDocumentServiceTest.php b/tests/Service/CacheDocumentServiceTest.php index acadb7081..d7b613a59 100644 --- a/tests/Service/CacheDocumentServiceTest.php +++ b/tests/Service/CacheDocumentServiceTest.php @@ -208,6 +208,14 @@ public static function allowedMimeProvider(): array { 'opus' => ['audio/opus'], 'wav' => ['audio/wav'], 'flac' => ['audio/flac'], + // files: what people on a Nextcloud actually have to share + 'pdf' => ['application/pdf'], + 'plain text' => ['text/plain'], + 'markdown' => ['text/markdown'], + 'csv' => ['text/csv'], + 'zip' => ['application/zip'], + 'odt' => ['application/vnd.oasis.opendocument.text'], + 'docx' => ['application/vnd.openxmlformats-officedocument.wordprocessingml.document'], ]; } @@ -224,10 +232,19 @@ public static function rejectedMimeProvider(): array { 'html' => ['text/html'], 'php' => ['application/x-httpd-php'], 'mkv' => ['video/x-matroska'], + // a file a browser would run is not a file a post may carry + 'exe' => ['application/x-msdownload'], + 'javascript' => ['text/javascript'], 'empty' => [''], ]; } + public function testADocumentMimeIsKnownAsOne(): void { + $this->assertTrue(CacheDocumentService::isDocumentMime('application/pdf')); + $this->assertFalse(CacheDocumentService::isDocumentMime('image/png')); + $this->assertFalse(CacheDocumentService::isDocumentMime('text/html')); + } + #[DataProvider('rejectedMimeProvider')] public function testFilterMimeTypesRejectsEverythingElse(string $mime): void { $this->expectException(CacheContentMimeTypeException::class); @@ -523,9 +540,10 @@ public function testAVideoMayBeLargerThanAnImageMay(): void { $this->service->filterSize('video/mp4', 3000 * 1048576); } - public function testSaveFromTempToCacheRejectsNonImages(): void { + public function testSaveFromTempToCacheRejectsWhatABrowserWouldRun(): void { $tmp = tempnam(sys_get_temp_dir(), 'social-test-'); - file_put_contents($tmp, 'plain text'); + // plain text is a file a post may carry now; a web page is not + file_put_contents($tmp, "\nx"); try { $this->appData->expects($this->never())->method($this->anything()); diff --git a/tests/js/components/Composer.test.js b/tests/js/components/Composer.test.js index 2c9ae65b4..ef4f85ea5 100644 --- a/tests/js/components/Composer.test.js +++ b/tests/js/components/Composer.test.js @@ -709,7 +709,7 @@ describe('Composer', () => { await addFromFiles(wrapper) expect(builder.setMultiSelect).toHaveBeenCalledWith(true) - expect(builder.setMimeTypeFilter).toHaveBeenCalledWith(['image/*', 'video/*']) + expect(builder.setMimeTypeFilter).toHaveBeenCalledWith(expect.arrayContaining(['image/*', 'video/*', 'application/pdf', 'text/plain'])) expect(builder.allowDirectories).toHaveBeenCalledWith(false) expect(store.createMediaFromFile).toHaveBeenCalledWith({ path: beach }) }) @@ -993,7 +993,7 @@ describe('Composer', () => { it('refuses a file the file dialog would never have offered', async () => { const { wrapper, store } = mountComposer() - const notes = new File(['x'], 'notes.txt', { type: 'text/plain' }) + const notes = new File(['x'], 'setup.exe', { type: 'application/x-msdownload' }) await dispatch(wrapper, card(wrapper).element, dragEvent('drop', { dataTransfer: transfer([notes]) })) await flushPromises() @@ -1006,7 +1006,7 @@ describe('Composer', () => { it('takes the pictures out of a mixed drop and leaves the rest', async () => { const { wrapper, store } = mountComposer() const file = picture() - const notes = new File(['x'], 'notes.txt', { type: 'text/plain' }) + const notes = new File(['x'], 'setup.exe', { type: 'application/x-msdownload' }) await dispatch(wrapper, card(wrapper).element, dragEvent('drop', { dataTransfer: transfer([file, notes]) })) await flushPromises() @@ -1057,7 +1057,7 @@ describe('Composer', () => { it('leaves a pasted file of a kind it cannot take to the input', async () => { const { wrapper, store } = mountComposer() - const notes = new File(['x'], 'notes.txt', { type: 'text/plain' }) + const notes = new File(['x'], 'setup.exe', { type: 'application/x-msdownload' }) const event = await dispatch(wrapper, input(wrapper).element, pasteEvent([notes])) await flushPromises() diff --git a/tests/js/components/MediaAttachment.test.js b/tests/js/components/MediaAttachment.test.js index 778bd609c..0ce12f9c1 100644 --- a/tests/js/components/MediaAttachment.test.js +++ b/tests/js/components/MediaAttachment.test.js @@ -84,6 +84,31 @@ describe('MediaAttachment', () => { expect(video.attributes('preload')).toBe('metadata') }) + it('shows a file as a named download card rather than a broken picture', () => { + const wrapper = mount(MediaAttachment, { + props: { attachment: { id: '9', type: 'unknown', url: 'https://cloud.example.org/media/abc.pdf', preview_url: null, description: 'minutes.pdf' }, interactive: true }, + }) + + const card = wrapper.find('a.attachment__file') + expect(card.exists()).toBe(true) + expect(card.attributes('href')).toBe('https://cloud.example.org/media/abc.pdf') + expect(card.attributes('download')).toBeDefined() + expect(card.find('.attachment__file-name').text()).toBe('minutes.pdf') + expect(card.find('.attachment__file-kind').text()).toBe('PDF') + // nothing to load, so nothing spins and no placeholder says it failed + expect(wrapper.find('.attachment__failed').exists()).toBe(false) + expect(wrapper.findComponent({ name: 'NcLoadingIcon' }).exists()).toBe(false) + }) + + it('names an undescribed file after the last part of its address', () => { + const wrapper = mount(MediaAttachment, { + props: { attachment: { id: '9', type: 'unknown', url: 'https://cloud.example.org/media/Q3%20report.docx?x=1', preview_url: null, description: null } }, + }) + + expect(wrapper.find('.attachment__file-name').text()).toBe('Q3 report.docx') + expect(wrapper.find('.attachment__file-kind').text()).toBe('DOCX') + }) + it('renders the small preview image', () => { const wrapper = mount(MediaAttachment, { props: { attachment } }) expect(wrapper.find('img.attachment__preview').attributes('src')).toBe(attachment.preview_url) diff --git a/tests/js/components/PostAttachment.test.js b/tests/js/components/PostAttachment.test.js index 12041d0a0..5eb22fbd4 100644 --- a/tests/js/components/PostAttachment.test.js +++ b/tests/js/components/PostAttachment.test.js @@ -79,6 +79,26 @@ describe('PostAttachment', () => { getContext.mockRestore() }) + it('lists files under the pictures instead of tiling them', () => { + const picture = attachments(1)[0] + const file = { id: 'f1', type: 'unknown', url: 'https://cloud.example.org/media/notes.pdf', preview_url: null, description: 'notes.pdf' } + const wrapper = mountAttachments([picture, file]) + + // one tile, for the picture; the file is not in the tile count + expect(wrapper.findAll('button.attachment')).toHaveLength(1) + const files = wrapper.find('.post-attachments__files') + expect(files.exists()).toBe(true) + expect(files.findAllComponents(MediaAttachment).map((tile) => tile.props('attachment'))).toEqual([file]) + }) + + it('shows a post that carries only a file as a file, with no empty gallery', () => { + const file = { id: 'f1', type: 'unknown', url: 'https://cloud.example.org/media/notes.pdf', preview_url: null, description: 'notes.pdf' } + const wrapper = mountAttachments([file], { mediaFirst: true }) + + expect(wrapper.find('.gallery-mosaic').exists()).toBe(false) + expect(wrapper.find('.post-attachments__files').exists()).toBe(true) + }) + it('renders a tile per attachment for up to four attachments', () => { const items = attachments(4) const wrapper = mountAttachments(items)