Merge cb6e2be2a3
into 218070eb13
This commit is contained in:
commit
7ea86f1a45
|
@ -158,13 +158,19 @@ export class ClientServerService {
|
||||||
'purpose': 'any',
|
'purpose': 'any',
|
||||||
}],
|
}],
|
||||||
'share_target': {
|
'share_target': {
|
||||||
'action': '/share/',
|
'action': '/sw/share',
|
||||||
'method': 'GET',
|
'method': 'POST',
|
||||||
'enctype': 'application/x-www-form-urlencoded',
|
'enctype': 'multipart/form-data',
|
||||||
'params': {
|
'params': {
|
||||||
'title': 'title',
|
'title': 'title',
|
||||||
'text': 'text',
|
'text': 'text',
|
||||||
'url': 'url',
|
'url': 'url',
|
||||||
|
'files': [
|
||||||
|
{
|
||||||
|
'name': 'files',
|
||||||
|
'accept': '*/*',
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
'shortcuts': [{
|
'shortcuts': [{
|
||||||
|
|
|
@ -26,13 +26,19 @@
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"share_target": {
|
"share_target": {
|
||||||
"action": "/share/",
|
"action": "/sw/share",
|
||||||
"method": "GET",
|
"method": "POST",
|
||||||
"enctype": "application/x-www-form-urlencoded",
|
"enctype": "multipart/form-data",
|
||||||
"params": {
|
"params": {
|
||||||
"title": "title",
|
"title": "title",
|
||||||
"text": "text",
|
"text": "text",
|
||||||
"url": "url"
|
"url": "url",
|
||||||
|
"files": [
|
||||||
|
{
|
||||||
|
"name": "files",
|
||||||
|
"accept": "*/*"
|
||||||
|
}
|
||||||
|
]
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"shortcuts": [
|
"shortcuts": [
|
||||||
|
|
|
@ -227,6 +227,10 @@ uploader.events.on('itemUploaded', ctx => {
|
||||||
uploader.removeItem(ctx.item);
|
uploader.removeItem(ctx.item);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
if (props.initialLocalFiles) {
|
||||||
|
uploader.addFiles(props.initialLocalFiles);
|
||||||
|
}
|
||||||
|
|
||||||
const draftKey = computed((): string => {
|
const draftKey = computed((): string => {
|
||||||
let key = targetChannel.value ? `channel:${targetChannel.value.id}` : '';
|
let key = targetChannel.value ? `channel:${targetChannel.value.id}` : '';
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
:initialText="initialText"
|
:initialText="initialText"
|
||||||
:initialVisibility="visibility"
|
:initialVisibility="visibility"
|
||||||
:initialFiles="files"
|
:initialFiles="files"
|
||||||
|
:initialLocalFiles="tempFiles"
|
||||||
:initialLocalOnly="localOnly"
|
:initialLocalOnly="localOnly"
|
||||||
:reply="reply"
|
:reply="reply"
|
||||||
:renote="renote"
|
:renote="renote"
|
||||||
|
@ -33,6 +34,7 @@ SPDX-License-Identifier: AGPL-3.0-only
|
||||||
|
|
||||||
import { ref, computed } from 'vue';
|
import { ref, computed } from 'vue';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
|
import { get, del } from 'idb-keyval';
|
||||||
import MkButton from '@/components/MkButton.vue';
|
import MkButton from '@/components/MkButton.vue';
|
||||||
import MkPostForm from '@/components/MkPostForm.vue';
|
import MkPostForm from '@/components/MkPostForm.vue';
|
||||||
import * as os from '@/os.js';
|
import * as os from '@/os.js';
|
||||||
|
@ -41,7 +43,19 @@ import { definePage } from '@/page.js';
|
||||||
import { postMessageToParentWindow } from '@/utility/post-message.js';
|
import { postMessageToParentWindow } from '@/utility/post-message.js';
|
||||||
import { i18n } from '@/i18n.js';
|
import { i18n } from '@/i18n.js';
|
||||||
|
|
||||||
|
//#region parameters
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
const urlParams = new URLSearchParams(window.location.search);
|
||||||
|
// merge hash parameters
|
||||||
|
try {
|
||||||
|
const hashParams = new URLSearchParams(window.location.hash.slice(1));
|
||||||
|
for (const [key, value] of hashParams.entries()) {
|
||||||
|
urlParams.set(key, value);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to parse hash parameters:', e);
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
const localOnlyQuery = urlParams.get('localOnly');
|
const localOnlyQuery = urlParams.get('localOnly');
|
||||||
const visibilityQuery = urlParams.get('visibility') as typeof Misskey.noteVisibilities[number];
|
const visibilityQuery = urlParams.get('visibility') as typeof Misskey.noteVisibilities[number];
|
||||||
|
|
||||||
|
@ -56,6 +70,7 @@ const visibility = ref(Misskey.noteVisibilities.includes(visibilityQuery) ? visi
|
||||||
const localOnly = ref(localOnlyQuery === '0' ? false : localOnlyQuery === '1' ? true : undefined);
|
const localOnly = ref(localOnlyQuery === '0' ? false : localOnlyQuery === '1' ? true : undefined);
|
||||||
const files = ref([] as Misskey.entities.DriveFile[]);
|
const files = ref([] as Misskey.entities.DriveFile[]);
|
||||||
const visibleUsers = ref([] as Misskey.entities.UserDetailed[]);
|
const visibleUsers = ref([] as Misskey.entities.UserDetailed[]);
|
||||||
|
const tempFiles = ref([] as File[]);
|
||||||
|
|
||||||
async function init() {
|
async function init() {
|
||||||
let noteText = '';
|
let noteText = '';
|
||||||
|
@ -181,6 +196,29 @@ async function init() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//#region Local files
|
||||||
|
// If the browser supports IndexedDB, try to get the temporary files from temp.
|
||||||
|
if (typeof window !== 'undefined' ? !!(window.indexedDB && typeof window.indexedDB.open === 'function') : true) {
|
||||||
|
const filesFromIdb = await get<File[]>('share-files-temp');
|
||||||
|
if (Array.isArray(filesFromIdb) && filesFromIdb.length > 0 && filesFromIdb.every(file => file instanceof Blob)) {
|
||||||
|
tempFiles.value = filesFromIdb;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (urlParams.has('file') && urlParams.get('file').startsWith('data:')) {
|
||||||
|
try {
|
||||||
|
const file = await window.fetch(urlParams.get('file')).then(res => res.blob());
|
||||||
|
if (file instanceof Blob) {
|
||||||
|
tempFiles.value.push(file as File);
|
||||||
|
} else {
|
||||||
|
console.error('Fetched file is not a Blob:', file);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Failed to fetch file:', e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//#endregion
|
||||||
|
|
||||||
state.value = 'writing';
|
state.value = 'writing';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,10 +239,31 @@ function goToMisskey(): void {
|
||||||
|
|
||||||
function onPosted(): void {
|
function onPosted(): void {
|
||||||
state.value = 'posted';
|
state.value = 'posted';
|
||||||
|
// SWが保存したファイルは投稿が完了するまでIndexedDBに保持
|
||||||
|
del('share-files-temp');
|
||||||
postMessageToParentWindow('misskey:shareForm:shareCompleted');
|
postMessageToParentWindow('misskey:shareForm:shareCompleted');
|
||||||
}
|
}
|
||||||
|
|
||||||
const headerActions = computed(() => []);
|
const headerActions = computed(() => [
|
||||||
|
{
|
||||||
|
icon: 'ti ti-dots',
|
||||||
|
text: i18n.ts.menu,
|
||||||
|
handler: (ev: MouseEvent) => {
|
||||||
|
os.popupMenu([
|
||||||
|
{
|
||||||
|
icon: 'ti ti-home',
|
||||||
|
text: i18n.ts.goToMisskey,
|
||||||
|
action: () => goToMisskey(),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
icon: 'ti ti-x',
|
||||||
|
text: i18n.ts.close,
|
||||||
|
action: () => close(),
|
||||||
|
},
|
||||||
|
], ev.currentTarget ?? ev.target);
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
|
||||||
const headerTabs = computed(() => []);
|
const headerTabs = computed(() => []);
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,7 @@ export interface PostFormProps {
|
||||||
initialCw?: string;
|
initialCw?: string;
|
||||||
initialVisibility?: (typeof Misskey.noteVisibilities)[number];
|
initialVisibility?: (typeof Misskey.noteVisibilities)[number];
|
||||||
initialFiles?: Misskey.entities.DriveFile[];
|
initialFiles?: Misskey.entities.DriveFile[];
|
||||||
|
initialLocalFiles?: File[];
|
||||||
initialLocalOnly?: boolean;
|
initialLocalOnly?: boolean;
|
||||||
initialVisibleUsers?: Misskey.entities.UserDetailed[];
|
initialVisibleUsers?: Misskey.entities.UserDetailed[];
|
||||||
initialNote?: Misskey.entities.Note;
|
initialNote?: Misskey.entities.Note;
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
* SPDX-License-Identifier: AGPL-3.0-only
|
* SPDX-License-Identifier: AGPL-3.0-only
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import { get } from 'idb-keyval';
|
import { get, set } from 'idb-keyval';
|
||||||
import * as Misskey from 'misskey-js';
|
import * as Misskey from 'misskey-js';
|
||||||
import type { PushNotificationDataMap } from '@/types.js';
|
import type { PushNotificationDataMap } from '@/types.js';
|
||||||
import type { I18n } from '@@/js/i18n.js';
|
import type { I18n } from '@@/js/i18n.js';
|
||||||
|
@ -40,6 +40,34 @@ async function offlineContentHTML() {
|
||||||
}
|
}
|
||||||
|
|
||||||
globalThis.addEventListener('fetch', ev => {
|
globalThis.addEventListener('fetch', ev => {
|
||||||
|
//#region /sw/share
|
||||||
|
const url = new URL(ev.request.url);
|
||||||
|
if (url.pathname === '/sw/share') {
|
||||||
|
ev.respondWith((async () => {
|
||||||
|
const responseUrl = new URL(ev.request.url);
|
||||||
|
responseUrl.pathname = '/share';
|
||||||
|
const formData = await ev.request.formData();
|
||||||
|
|
||||||
|
// とりあえず初期化 (IndexedDBの削除は時間がかかる可能性があるため空の配列をセット)
|
||||||
|
await set('share-url-temp', []);
|
||||||
|
if (formData.has('files')) {
|
||||||
|
const files = formData.getAll('files');
|
||||||
|
if (files.length > 0 && files.every(file => file instanceof Blob)) {
|
||||||
|
set('share-files-temp', files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
formData.delete('files');
|
||||||
|
for (const [key, value] of formData.entries()) {
|
||||||
|
responseUrl.searchParams.set(key, value.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Response.redirect(responseUrl, 303);
|
||||||
|
})());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//#region others
|
||||||
let isHTMLRequest = false;
|
let isHTMLRequest = false;
|
||||||
if (ev.request.headers.get('sec-fetch-dest') === 'document') {
|
if (ev.request.headers.get('sec-fetch-dest') === 'document') {
|
||||||
isHTMLRequest = true;
|
isHTMLRequest = true;
|
||||||
|
@ -62,6 +90,7 @@ globalThis.addEventListener('fetch', ev => {
|
||||||
});
|
});
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
//#endregion
|
||||||
});
|
});
|
||||||
|
|
||||||
globalThis.addEventListener('push', ev => {
|
globalThis.addEventListener('push', ev => {
|
||||||
|
|
Loading…
Reference in New Issue