From cf33e483f7e6f40e8cbbbc0118a7df70bdaf651f Mon Sep 17 00:00:00 2001 From: syuilo Date: Thu, 29 Mar 2018 20:32:18 +0900 Subject: 整理した MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/client/app/desktop/api/choose-drive-file.ts | 30 + src/client/app/desktop/api/choose-drive-folder.ts | 17 + src/client/app/desktop/api/contextmenu.ts | 16 + src/client/app/desktop/api/dialog.ts | 19 + src/client/app/desktop/api/input.ts | 20 + src/client/app/desktop/api/notify.ts | 10 + src/client/app/desktop/api/post.ts | 21 + src/client/app/desktop/api/update-avatar.ts | 98 +++ src/client/app/desktop/api/update-banner.ts | 98 +++ src/client/app/desktop/assets/grid.svg | 150 ++++ .../app/desktop/assets/header-logo-white.svg | 25 + src/client/app/desktop/assets/header-logo.svg | 25 + src/client/app/desktop/assets/index.jpg | Bin 0 -> 410409 bytes src/client/app/desktop/assets/remove.png | Bin 0 -> 3115 bytes src/client/app/desktop/script.ts | 167 +++++ src/client/app/desktop/style.styl | 50 ++ src/client/app/desktop/ui.styl | 125 ++++ .../desktop/views/components/activity.calendar.vue | 66 ++ .../desktop/views/components/activity.chart.vue | 103 +++ .../app/desktop/views/components/activity.vue | 116 ++++ .../app/desktop/views/components/analog-clock.vue | 108 +++ .../app/desktop/views/components/calendar.vue | 252 +++++++ .../components/choose-file-from-drive-window.vue | 180 +++++ .../components/choose-folder-from-drive-window.vue | 114 +++ .../desktop/views/components/context-menu.menu.vue | 121 ++++ .../app/desktop/views/components/context-menu.vue | 74 ++ .../app/desktop/views/components/crop-window.vue | 178 +++++ src/client/app/desktop/views/components/dialog.vue | 170 +++++ .../app/desktop/views/components/drive-window.vue | 56 ++ .../app/desktop/views/components/drive.file.vue | 317 +++++++++ .../app/desktop/views/components/drive.folder.vue | 267 +++++++ .../desktop/views/components/drive.nav-folder.vue | 113 +++ src/client/app/desktop/views/components/drive.vue | 773 +++++++++++++++++++++ .../app/desktop/views/components/ellipsis-icon.vue | 37 + .../app/desktop/views/components/follow-button.vue | 164 +++++ .../desktop/views/components/followers-window.vue | 26 + .../app/desktop/views/components/followers.vue | 26 + .../desktop/views/components/following-window.vue | 26 + .../app/desktop/views/components/following.vue | 26 + .../app/desktop/views/components/friends-maker.vue | 171 +++++ .../app/desktop/views/components/game-window.vue | 37 + src/client/app/desktop/views/components/home.vue | 357 ++++++++++ src/client/app/desktop/views/components/index.ts | 61 ++ .../app/desktop/views/components/input-dialog.vue | 180 +++++ .../views/components/media-image-dialog.vue | 69 ++ .../app/desktop/views/components/media-image.vue | 63 ++ .../views/components/media-video-dialog.vue | 70 ++ .../app/desktop/views/components/media-video.vue | 67 ++ .../app/desktop/views/components/mentions.vue | 125 ++++ .../views/components/messaging-room-window.vue | 32 + .../desktop/views/components/messaging-window.vue | 32 + .../app/desktop/views/components/notifications.vue | 317 +++++++++ .../desktop/views/components/post-detail.sub.vue | 126 ++++ .../app/desktop/views/components/post-detail.vue | 433 ++++++++++++ .../desktop/views/components/post-form-window.vue | 76 ++ .../app/desktop/views/components/post-form.vue | 536 ++++++++++++++ .../app/desktop/views/components/post-preview.vue | 103 +++ .../desktop/views/components/posts.post.sub.vue | 112 +++ .../app/desktop/views/components/posts.post.vue | 582 ++++++++++++++++ src/client/app/desktop/views/components/posts.vue | 89 +++ .../desktop/views/components/progress-dialog.vue | 95 +++ .../views/components/repost-form-window.vue | 42 ++ .../app/desktop/views/components/repost-form.vue | 131 ++++ .../desktop/views/components/settings-window.vue | 24 + .../app/desktop/views/components/settings.2fa.vue | 80 +++ .../app/desktop/views/components/settings.api.vue | 40 ++ .../app/desktop/views/components/settings.apps.vue | 39 ++ .../desktop/views/components/settings.drive.vue | 35 + .../app/desktop/views/components/settings.mute.vue | 35 + .../desktop/views/components/settings.password.vue | 47 ++ .../desktop/views/components/settings.profile.vue | 87 +++ .../desktop/views/components/settings.signins.vue | 98 +++ .../app/desktop/views/components/settings.vue | 419 +++++++++++ .../desktop/views/components/sub-post-content.vue | 56 ++ .../app/desktop/views/components/taskmanager.vue | 219 ++++++ .../app/desktop/views/components/timeline.vue | 156 +++++ .../desktop/views/components/ui-notification.vue | 61 ++ .../desktop/views/components/ui.header.account.vue | 225 ++++++ .../desktop/views/components/ui.header.clock.vue | 109 +++ .../app/desktop/views/components/ui.header.nav.vue | 175 +++++ .../views/components/ui.header.notifications.vue | 158 +++++ .../desktop/views/components/ui.header.post.vue | 54 ++ .../desktop/views/components/ui.header.search.vue | 70 ++ .../app/desktop/views/components/ui.header.vue | 172 +++++ src/client/app/desktop/views/components/ui.vue | 37 + .../app/desktop/views/components/user-preview.vue | 173 +++++ .../desktop/views/components/users-list.item.vue | 107 +++ .../app/desktop/views/components/users-list.vue | 143 ++++ .../desktop/views/components/widget-container.vue | 85 +++ src/client/app/desktop/views/components/window.vue | 635 +++++++++++++++++ src/client/app/desktop/views/directives/index.ts | 6 + .../app/desktop/views/directives/user-preview.ts | 72 ++ src/client/app/desktop/views/pages/drive.vue | 52 ++ .../app/desktop/views/pages/home-customize.vue | 12 + src/client/app/desktop/views/pages/home.vue | 62 ++ src/client/app/desktop/views/pages/index.vue | 16 + .../app/desktop/views/pages/messaging-room.vue | 54 ++ src/client/app/desktop/views/pages/othello.vue | 50 ++ src/client/app/desktop/views/pages/post.vue | 67 ++ src/client/app/desktop/views/pages/search.vue | 138 ++++ src/client/app/desktop/views/pages/selectdrive.vue | 177 +++++ .../views/pages/user/user.followers-you-know.vue | 84 +++ .../app/desktop/views/pages/user/user.friends.vue | 124 ++++ .../app/desktop/views/pages/user/user.header.vue | 196 ++++++ .../app/desktop/views/pages/user/user.home.vue | 103 +++ .../app/desktop/views/pages/user/user.photos.vue | 88 +++ .../app/desktop/views/pages/user/user.profile.vue | 138 ++++ .../app/desktop/views/pages/user/user.timeline.vue | 139 ++++ src/client/app/desktop/views/pages/user/user.vue | 53 ++ src/client/app/desktop/views/pages/welcome.vue | 319 +++++++++ src/client/app/desktop/views/widgets/activity.vue | 31 + .../desktop/views/widgets/channel.channel.form.vue | 67 ++ .../desktop/views/widgets/channel.channel.post.vue | 71 ++ .../app/desktop/views/widgets/channel.channel.vue | 106 +++ src/client/app/desktop/views/widgets/channel.vue | 107 +++ src/client/app/desktop/views/widgets/index.ts | 23 + src/client/app/desktop/views/widgets/messaging.vue | 59 ++ .../app/desktop/views/widgets/notifications.vue | 70 ++ src/client/app/desktop/views/widgets/polls.vue | 129 ++++ src/client/app/desktop/views/widgets/post-form.vue | 111 +++ src/client/app/desktop/views/widgets/profile.vue | 125 ++++ .../app/desktop/views/widgets/timemachine.vue | 28 + src/client/app/desktop/views/widgets/trends.vue | 135 ++++ src/client/app/desktop/views/widgets/users.vue | 172 +++++ 124 files changed, 14813 insertions(+) create mode 100644 src/client/app/desktop/api/choose-drive-file.ts create mode 100644 src/client/app/desktop/api/choose-drive-folder.ts create mode 100644 src/client/app/desktop/api/contextmenu.ts create mode 100644 src/client/app/desktop/api/dialog.ts create mode 100644 src/client/app/desktop/api/input.ts create mode 100644 src/client/app/desktop/api/notify.ts create mode 100644 src/client/app/desktop/api/post.ts create mode 100644 src/client/app/desktop/api/update-avatar.ts create mode 100644 src/client/app/desktop/api/update-banner.ts create mode 100644 src/client/app/desktop/assets/grid.svg create mode 100644 src/client/app/desktop/assets/header-logo-white.svg create mode 100644 src/client/app/desktop/assets/header-logo.svg create mode 100644 src/client/app/desktop/assets/index.jpg create mode 100644 src/client/app/desktop/assets/remove.png create mode 100644 src/client/app/desktop/script.ts create mode 100644 src/client/app/desktop/style.styl create mode 100644 src/client/app/desktop/ui.styl create mode 100644 src/client/app/desktop/views/components/activity.calendar.vue create mode 100644 src/client/app/desktop/views/components/activity.chart.vue create mode 100644 src/client/app/desktop/views/components/activity.vue create mode 100644 src/client/app/desktop/views/components/analog-clock.vue create mode 100644 src/client/app/desktop/views/components/calendar.vue create mode 100644 src/client/app/desktop/views/components/choose-file-from-drive-window.vue create mode 100644 src/client/app/desktop/views/components/choose-folder-from-drive-window.vue create mode 100644 src/client/app/desktop/views/components/context-menu.menu.vue create mode 100644 src/client/app/desktop/views/components/context-menu.vue create mode 100644 src/client/app/desktop/views/components/crop-window.vue create mode 100644 src/client/app/desktop/views/components/dialog.vue create mode 100644 src/client/app/desktop/views/components/drive-window.vue create mode 100644 src/client/app/desktop/views/components/drive.file.vue create mode 100644 src/client/app/desktop/views/components/drive.folder.vue create mode 100644 src/client/app/desktop/views/components/drive.nav-folder.vue create mode 100644 src/client/app/desktop/views/components/drive.vue create mode 100644 src/client/app/desktop/views/components/ellipsis-icon.vue create mode 100644 src/client/app/desktop/views/components/follow-button.vue create mode 100644 src/client/app/desktop/views/components/followers-window.vue create mode 100644 src/client/app/desktop/views/components/followers.vue create mode 100644 src/client/app/desktop/views/components/following-window.vue create mode 100644 src/client/app/desktop/views/components/following.vue create mode 100644 src/client/app/desktop/views/components/friends-maker.vue create mode 100644 src/client/app/desktop/views/components/game-window.vue create mode 100644 src/client/app/desktop/views/components/home.vue create mode 100644 src/client/app/desktop/views/components/index.ts create mode 100644 src/client/app/desktop/views/components/input-dialog.vue create mode 100644 src/client/app/desktop/views/components/media-image-dialog.vue create mode 100644 src/client/app/desktop/views/components/media-image.vue create mode 100644 src/client/app/desktop/views/components/media-video-dialog.vue create mode 100644 src/client/app/desktop/views/components/media-video.vue create mode 100644 src/client/app/desktop/views/components/mentions.vue create mode 100644 src/client/app/desktop/views/components/messaging-room-window.vue create mode 100644 src/client/app/desktop/views/components/messaging-window.vue create mode 100644 src/client/app/desktop/views/components/notifications.vue create mode 100644 src/client/app/desktop/views/components/post-detail.sub.vue create mode 100644 src/client/app/desktop/views/components/post-detail.vue create mode 100644 src/client/app/desktop/views/components/post-form-window.vue create mode 100644 src/client/app/desktop/views/components/post-form.vue create mode 100644 src/client/app/desktop/views/components/post-preview.vue create mode 100644 src/client/app/desktop/views/components/posts.post.sub.vue create mode 100644 src/client/app/desktop/views/components/posts.post.vue create mode 100644 src/client/app/desktop/views/components/posts.vue create mode 100644 src/client/app/desktop/views/components/progress-dialog.vue create mode 100644 src/client/app/desktop/views/components/repost-form-window.vue create mode 100644 src/client/app/desktop/views/components/repost-form.vue create mode 100644 src/client/app/desktop/views/components/settings-window.vue create mode 100644 src/client/app/desktop/views/components/settings.2fa.vue create mode 100644 src/client/app/desktop/views/components/settings.api.vue create mode 100644 src/client/app/desktop/views/components/settings.apps.vue create mode 100644 src/client/app/desktop/views/components/settings.drive.vue create mode 100644 src/client/app/desktop/views/components/settings.mute.vue create mode 100644 src/client/app/desktop/views/components/settings.password.vue create mode 100644 src/client/app/desktop/views/components/settings.profile.vue create mode 100644 src/client/app/desktop/views/components/settings.signins.vue create mode 100644 src/client/app/desktop/views/components/settings.vue create mode 100644 src/client/app/desktop/views/components/sub-post-content.vue create mode 100644 src/client/app/desktop/views/components/taskmanager.vue create mode 100644 src/client/app/desktop/views/components/timeline.vue create mode 100644 src/client/app/desktop/views/components/ui-notification.vue create mode 100644 src/client/app/desktop/views/components/ui.header.account.vue create mode 100644 src/client/app/desktop/views/components/ui.header.clock.vue create mode 100644 src/client/app/desktop/views/components/ui.header.nav.vue create mode 100644 src/client/app/desktop/views/components/ui.header.notifications.vue create mode 100644 src/client/app/desktop/views/components/ui.header.post.vue create mode 100644 src/client/app/desktop/views/components/ui.header.search.vue create mode 100644 src/client/app/desktop/views/components/ui.header.vue create mode 100644 src/client/app/desktop/views/components/ui.vue create mode 100644 src/client/app/desktop/views/components/user-preview.vue create mode 100644 src/client/app/desktop/views/components/users-list.item.vue create mode 100644 src/client/app/desktop/views/components/users-list.vue create mode 100644 src/client/app/desktop/views/components/widget-container.vue create mode 100644 src/client/app/desktop/views/components/window.vue create mode 100644 src/client/app/desktop/views/directives/index.ts create mode 100644 src/client/app/desktop/views/directives/user-preview.ts create mode 100644 src/client/app/desktop/views/pages/drive.vue create mode 100644 src/client/app/desktop/views/pages/home-customize.vue create mode 100644 src/client/app/desktop/views/pages/home.vue create mode 100644 src/client/app/desktop/views/pages/index.vue create mode 100644 src/client/app/desktop/views/pages/messaging-room.vue create mode 100644 src/client/app/desktop/views/pages/othello.vue create mode 100644 src/client/app/desktop/views/pages/post.vue create mode 100644 src/client/app/desktop/views/pages/search.vue create mode 100644 src/client/app/desktop/views/pages/selectdrive.vue create mode 100644 src/client/app/desktop/views/pages/user/user.followers-you-know.vue create mode 100644 src/client/app/desktop/views/pages/user/user.friends.vue create mode 100644 src/client/app/desktop/views/pages/user/user.header.vue create mode 100644 src/client/app/desktop/views/pages/user/user.home.vue create mode 100644 src/client/app/desktop/views/pages/user/user.photos.vue create mode 100644 src/client/app/desktop/views/pages/user/user.profile.vue create mode 100644 src/client/app/desktop/views/pages/user/user.timeline.vue create mode 100644 src/client/app/desktop/views/pages/user/user.vue create mode 100644 src/client/app/desktop/views/pages/welcome.vue create mode 100644 src/client/app/desktop/views/widgets/activity.vue create mode 100644 src/client/app/desktop/views/widgets/channel.channel.form.vue create mode 100644 src/client/app/desktop/views/widgets/channel.channel.post.vue create mode 100644 src/client/app/desktop/views/widgets/channel.channel.vue create mode 100644 src/client/app/desktop/views/widgets/channel.vue create mode 100644 src/client/app/desktop/views/widgets/index.ts create mode 100644 src/client/app/desktop/views/widgets/messaging.vue create mode 100644 src/client/app/desktop/views/widgets/notifications.vue create mode 100644 src/client/app/desktop/views/widgets/polls.vue create mode 100644 src/client/app/desktop/views/widgets/post-form.vue create mode 100644 src/client/app/desktop/views/widgets/profile.vue create mode 100644 src/client/app/desktop/views/widgets/timemachine.vue create mode 100644 src/client/app/desktop/views/widgets/trends.vue create mode 100644 src/client/app/desktop/views/widgets/users.vue (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/api/choose-drive-file.ts b/src/client/app/desktop/api/choose-drive-file.ts new file mode 100644 index 0000000000..fbda600e6e --- /dev/null +++ b/src/client/app/desktop/api/choose-drive-file.ts @@ -0,0 +1,30 @@ +import { url } from '../../config'; +import MkChooseFileFromDriveWindow from '../views/components/choose-file-from-drive-window.vue'; + +export default function(opts) { + return new Promise((res, rej) => { + const o = opts || {}; + + if (document.body.clientWidth > 800) { + const w = new MkChooseFileFromDriveWindow({ + propsData: { + title: o.title, + multiple: o.multiple, + initFolder: o.currentFolder + } + }).$mount(); + w.$once('selected', file => { + res(file); + }); + document.body.appendChild(w.$el); + } else { + window['cb'] = file => { + res(file); + }; + + window.open(url + '/selectdrive', + 'choose_drive_window', + 'height=500, width=800'); + } + }); +} diff --git a/src/client/app/desktop/api/choose-drive-folder.ts b/src/client/app/desktop/api/choose-drive-folder.ts new file mode 100644 index 0000000000..9b33a20d9a --- /dev/null +++ b/src/client/app/desktop/api/choose-drive-folder.ts @@ -0,0 +1,17 @@ +import MkChooseFolderFromDriveWindow from '../views/components/choose-folder-from-drive-window.vue'; + +export default function(opts) { + return new Promise((res, rej) => { + const o = opts || {}; + const w = new MkChooseFolderFromDriveWindow({ + propsData: { + title: o.title, + initFolder: o.currentFolder + } + }).$mount(); + w.$once('selected', folder => { + res(folder); + }); + document.body.appendChild(w.$el); + }); +} diff --git a/src/client/app/desktop/api/contextmenu.ts b/src/client/app/desktop/api/contextmenu.ts new file mode 100644 index 0000000000..b70d7122d3 --- /dev/null +++ b/src/client/app/desktop/api/contextmenu.ts @@ -0,0 +1,16 @@ +import Ctx from '../views/components/context-menu.vue'; + +export default function(e, menu, opts?) { + const o = opts || {}; + const vm = new Ctx({ + propsData: { + menu, + x: e.pageX - window.pageXOffset, + y: e.pageY - window.pageYOffset, + } + }).$mount(); + vm.$once('closed', () => { + if (o.closed) o.closed(); + }); + document.body.appendChild(vm.$el); +} diff --git a/src/client/app/desktop/api/dialog.ts b/src/client/app/desktop/api/dialog.ts new file mode 100644 index 0000000000..07935485b0 --- /dev/null +++ b/src/client/app/desktop/api/dialog.ts @@ -0,0 +1,19 @@ +import Dialog from '../views/components/dialog.vue'; + +export default function(opts) { + return new Promise((res, rej) => { + const o = opts || {}; + const d = new Dialog({ + propsData: { + title: o.title, + text: o.text, + modal: o.modal, + buttons: o.actions + } + }).$mount(); + d.$once('clicked', id => { + res(id); + }); + document.body.appendChild(d.$el); + }); +} diff --git a/src/client/app/desktop/api/input.ts b/src/client/app/desktop/api/input.ts new file mode 100644 index 0000000000..ce26a8112f --- /dev/null +++ b/src/client/app/desktop/api/input.ts @@ -0,0 +1,20 @@ +import InputDialog from '../views/components/input-dialog.vue'; + +export default function(opts) { + return new Promise((res, rej) => { + const o = opts || {}; + const d = new InputDialog({ + propsData: { + title: o.title, + placeholder: o.placeholder, + default: o.default, + type: o.type || 'text', + allowEmpty: o.allowEmpty + } + }).$mount(); + d.$once('done', text => { + res(text); + }); + document.body.appendChild(d.$el); + }); +} diff --git a/src/client/app/desktop/api/notify.ts b/src/client/app/desktop/api/notify.ts new file mode 100644 index 0000000000..1f89f40ce6 --- /dev/null +++ b/src/client/app/desktop/api/notify.ts @@ -0,0 +1,10 @@ +import Notification from '../views/components/ui-notification.vue'; + +export default function(message) { + const vm = new Notification({ + propsData: { + message + } + }).$mount(); + document.body.appendChild(vm.$el); +} diff --git a/src/client/app/desktop/api/post.ts b/src/client/app/desktop/api/post.ts new file mode 100644 index 0000000000..cf49615df3 --- /dev/null +++ b/src/client/app/desktop/api/post.ts @@ -0,0 +1,21 @@ +import PostFormWindow from '../views/components/post-form-window.vue'; +import RepostFormWindow from '../views/components/repost-form-window.vue'; + +export default function(opts) { + const o = opts || {}; + if (o.repost) { + const vm = new RepostFormWindow({ + propsData: { + repost: o.repost + } + }).$mount(); + document.body.appendChild(vm.$el); + } else { + const vm = new PostFormWindow({ + propsData: { + reply: o.reply + } + }).$mount(); + document.body.appendChild(vm.$el); + } +} diff --git a/src/client/app/desktop/api/update-avatar.ts b/src/client/app/desktop/api/update-avatar.ts new file mode 100644 index 0000000000..36a2ffe914 --- /dev/null +++ b/src/client/app/desktop/api/update-avatar.ts @@ -0,0 +1,98 @@ +import OS from '../../common/mios'; +import { apiUrl } from '../../config'; +import CropWindow from '../views/components/crop-window.vue'; +import ProgressDialog from '../views/components/progress-dialog.vue'; + +export default (os: OS) => (cb, file = null) => { + const fileSelected = file => { + + const w = new CropWindow({ + propsData: { + image: file, + title: 'アバターとして表示する部分を選択', + aspectRatio: 1 / 1 + } + }).$mount(); + + w.$once('cropped', blob => { + const data = new FormData(); + data.append('i', os.i.account.token); + data.append('file', blob, file.name + '.cropped.png'); + + os.api('drive/folders/find', { + name: 'アイコン' + }).then(iconFolder => { + if (iconFolder.length === 0) { + os.api('drive/folders/create', { + name: 'アイコン' + }).then(iconFolder => { + upload(data, iconFolder); + }); + } else { + upload(data, iconFolder[0]); + } + }); + }); + + w.$once('skipped', () => { + set(file); + }); + + document.body.appendChild(w.$el); + }; + + const upload = (data, folder) => { + const dialog = new ProgressDialog({ + propsData: { + title: '新しいアバターをアップロードしています' + } + }).$mount(); + document.body.appendChild(dialog.$el); + + if (folder) data.append('folderId', folder.id); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const file = JSON.parse((e.target as any).response); + (dialog as any).close(); + set(file); + }; + + xhr.upload.onprogress = e => { + if (e.lengthComputable) (dialog as any).update(e.loaded, e.total); + }; + + xhr.send(data); + }; + + const set = file => { + os.api('i/update', { + avatarId: file.id + }).then(i => { + os.i.avatarId = i.avatarId; + os.i.avatarUrl = i.avatarUrl; + + os.apis.dialog({ + title: '%fa:info-circle%アバターを更新しました', + text: '新しいアバターが反映されるまで時間がかかる場合があります。', + actions: [{ + text: 'わかった' + }] + }); + + if (cb) cb(i); + }); + }; + + if (file) { + fileSelected(file); + } else { + os.apis.chooseDriveFile({ + multiple: false, + title: '%fa:image%アバターにする画像を選択' + }).then(file => { + fileSelected(file); + }); + } +}; diff --git a/src/client/app/desktop/api/update-banner.ts b/src/client/app/desktop/api/update-banner.ts new file mode 100644 index 0000000000..e66dbf016b --- /dev/null +++ b/src/client/app/desktop/api/update-banner.ts @@ -0,0 +1,98 @@ +import OS from '../../common/mios'; +import { apiUrl } from '../../config'; +import CropWindow from '../views/components/crop-window.vue'; +import ProgressDialog from '../views/components/progress-dialog.vue'; + +export default (os: OS) => (cb, file = null) => { + const fileSelected = file => { + + const w = new CropWindow({ + propsData: { + image: file, + title: 'バナーとして表示する部分を選択', + aspectRatio: 16 / 9 + } + }).$mount(); + + w.$once('cropped', blob => { + const data = new FormData(); + data.append('i', os.i.account.token); + data.append('file', blob, file.name + '.cropped.png'); + + os.api('drive/folders/find', { + name: 'バナー' + }).then(bannerFolder => { + if (bannerFolder.length === 0) { + os.api('drive/folders/create', { + name: 'バナー' + }).then(iconFolder => { + upload(data, iconFolder); + }); + } else { + upload(data, bannerFolder[0]); + } + }); + }); + + w.$once('skipped', () => { + set(file); + }); + + document.body.appendChild(w.$el); + }; + + const upload = (data, folder) => { + const dialog = new ProgressDialog({ + propsData: { + title: '新しいバナーをアップロードしています' + } + }).$mount(); + document.body.appendChild(dialog.$el); + + if (folder) data.append('folderId', folder.id); + + const xhr = new XMLHttpRequest(); + xhr.open('POST', apiUrl + '/drive/files/create', true); + xhr.onload = e => { + const file = JSON.parse((e.target as any).response); + (dialog as any).close(); + set(file); + }; + + xhr.upload.onprogress = e => { + if (e.lengthComputable) (dialog as any).update(e.loaded, e.total); + }; + + xhr.send(data); + }; + + const set = file => { + os.api('i/update', { + bannerId: file.id + }).then(i => { + os.i.bannerId = i.bannerId; + os.i.bannerUrl = i.bannerUrl; + + os.apis.dialog({ + title: '%fa:info-circle%バナーを更新しました', + text: '新しいバナーが反映されるまで時間がかかる場合があります。', + actions: [{ + text: 'わかった' + }] + }); + + if (cb) cb(i); + }); + }; + + if (file) { + fileSelected(file); + } else { + os.apis.chooseDriveFile({ + multiple: false, + title: '%fa:image%バナーにする画像を選択' + }).then(file => { + fileSelected(file); + }); + } +}; diff --git a/src/client/app/desktop/assets/grid.svg b/src/client/app/desktop/assets/grid.svg new file mode 100644 index 0000000000..d1d72cd8ce --- /dev/null +++ b/src/client/app/desktop/assets/grid.svg @@ -0,0 +1,150 @@ + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/client/app/desktop/assets/header-logo-white.svg b/src/client/app/desktop/assets/header-logo-white.svg new file mode 100644 index 0000000000..8082edb30d --- /dev/null +++ b/src/client/app/desktop/assets/header-logo-white.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/client/app/desktop/assets/header-logo.svg b/src/client/app/desktop/assets/header-logo.svg new file mode 100644 index 0000000000..3a2207954a --- /dev/null +++ b/src/client/app/desktop/assets/header-logo.svg @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/client/app/desktop/assets/index.jpg b/src/client/app/desktop/assets/index.jpg new file mode 100644 index 0000000000..10c412efe2 Binary files /dev/null and b/src/client/app/desktop/assets/index.jpg differ diff --git a/src/client/app/desktop/assets/remove.png b/src/client/app/desktop/assets/remove.png new file mode 100644 index 0000000000..8b1f4c06c9 Binary files /dev/null and b/src/client/app/desktop/assets/remove.png differ diff --git a/src/client/app/desktop/script.ts b/src/client/app/desktop/script.ts new file mode 100644 index 0000000000..b95e168544 --- /dev/null +++ b/src/client/app/desktop/script.ts @@ -0,0 +1,167 @@ +/** + * Desktop Client + */ + +import VueRouter from 'vue-router'; + +// Style +import './style.styl'; +import '../../element.scss'; + +import init from '../init'; +import fuckAdBlock from '../common/scripts/fuck-ad-block'; +import { HomeStreamManager } from '../common/scripts/streaming/home'; +import composeNotification from '../common/scripts/compose-notification'; + +import chooseDriveFolder from './api/choose-drive-folder'; +import chooseDriveFile from './api/choose-drive-file'; +import dialog from './api/dialog'; +import input from './api/input'; +import post from './api/post'; +import notify from './api/notify'; +import updateAvatar from './api/update-avatar'; +import updateBanner from './api/update-banner'; + +import MkIndex from './views/pages/index.vue'; +import MkUser from './views/pages/user/user.vue'; +import MkSelectDrive from './views/pages/selectdrive.vue'; +import MkDrive from './views/pages/drive.vue'; +import MkHomeCustomize from './views/pages/home-customize.vue'; +import MkMessagingRoom from './views/pages/messaging-room.vue'; +import MkPost from './views/pages/post.vue'; +import MkSearch from './views/pages/search.vue'; +import MkOthello from './views/pages/othello.vue'; + +/** + * init + */ +init(async (launch) => { + // Register directives + require('./views/directives'); + + // Register components + require('./views/components'); + require('./views/widgets'); + + // Init router + const router = new VueRouter({ + mode: 'history', + routes: [ + { path: '/', name: 'index', component: MkIndex }, + { path: '/i/customize-home', component: MkHomeCustomize }, + { path: '/i/messaging/:user', component: MkMessagingRoom }, + { path: '/i/drive', component: MkDrive }, + { path: '/i/drive/folder/:folder', component: MkDrive }, + { path: '/selectdrive', component: MkSelectDrive }, + { path: '/search', component: MkSearch }, + { path: '/othello', component: MkOthello }, + { path: '/othello/:game', component: MkOthello }, + { path: '/@:user', component: MkUser }, + { path: '/@:user/:post', component: MkPost } + ] + }); + + // Launch the app + const [, os] = launch(router, os => ({ + chooseDriveFolder, + chooseDriveFile, + dialog, + input, + post, + notify, + updateAvatar: updateAvatar(os), + updateBanner: updateBanner(os) + })); + + /** + * Fuck AD Block + */ + fuckAdBlock(os); + + /** + * Init Notification + */ + if ('Notification' in window) { + // 許可を得ていなかったらリクエスト + if ((Notification as any).permission == 'default') { + await Notification.requestPermission(); + } + + if ((Notification as any).permission == 'granted') { + registerNotifications(os.stream); + } + } +}, true); + +function registerNotifications(stream: HomeStreamManager) { + if (stream == null) return; + + if (stream.hasConnection) { + attach(stream.borrow()); + } + + stream.on('connected', connection => { + attach(connection); + }); + + function attach(connection) { + connection.on('drive_file_created', file => { + const _n = composeNotification('drive_file_created', file); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon + }); + setTimeout(n.close.bind(n), 5000); + }); + + connection.on('mention', post => { + const _n = composeNotification('mention', post); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon + }); + setTimeout(n.close.bind(n), 6000); + }); + + connection.on('reply', post => { + const _n = composeNotification('reply', post); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon + }); + setTimeout(n.close.bind(n), 6000); + }); + + connection.on('quote', post => { + const _n = composeNotification('quote', post); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon + }); + setTimeout(n.close.bind(n), 6000); + }); + + connection.on('unread_messaging_message', message => { + const _n = composeNotification('unread_messaging_message', message); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon + }); + n.onclick = () => { + n.close(); + /*(riot as any).mount(document.body.appendChild(document.createElement('mk-messaging-room-window')), { + user: message.user + });*/ + }; + setTimeout(n.close.bind(n), 7000); + }); + + connection.on('othello_invited', matching => { + const _n = composeNotification('othello_invited', matching); + const n = new Notification(_n.title, { + body: _n.body, + icon: _n.icon + }); + }); + } +} diff --git a/src/client/app/desktop/style.styl b/src/client/app/desktop/style.styl new file mode 100644 index 0000000000..49f71fbde7 --- /dev/null +++ b/src/client/app/desktop/style.styl @@ -0,0 +1,50 @@ +@import "../app" +@import "../reset" + +@import "./ui" + +*::input-placeholder + color #D8CBC5 + +* + &:focus + outline none + + &::scrollbar + width 5px + background transparent + + &:horizontal + height 5px + + &::scrollbar-button + width 0 + height 0 + background rgba(0, 0, 0, 0.2) + + &::scrollbar-piece + background transparent + + &:start + background transparent + + &::scrollbar-thumb + background rgba(0, 0, 0, 0.2) + + &:hover + background rgba(0, 0, 0, 0.4) + + &:active + background $theme-color + + &::scrollbar-corner + background rgba(0, 0, 0, 0.2) + +html + height 100% + background #f7f7f7 + +body + display flex + flex-direction column + min-height 100% diff --git a/src/client/app/desktop/ui.styl b/src/client/app/desktop/ui.styl new file mode 100644 index 0000000000..5a8d1718e2 --- /dev/null +++ b/src/client/app/desktop/ui.styl @@ -0,0 +1,125 @@ +@import "../../const" + +button + font-family sans-serif + + * + pointer-events none + +button.ui +.button.ui + display inline-block + cursor pointer + padding 0 14px + margin 0 + min-width 100px + line-height 38px + font-size 14px + color #888 + text-decoration none + background linear-gradient(to bottom, #ffffff 0%, #f5f5f5 100%) + border solid 1px #e2e2e2 + border-radius 4px + outline none + + &.block + display block + + &:focus + &:after + content "" + pointer-events none + position absolute + top -5px + right -5px + bottom -5px + left -5px + border 2px solid rgba($theme-color, 0.3) + border-radius 8px + + &:disabled + opacity 0.7 + cursor default + + &:hover + background linear-gradient(to bottom, #f9f9f9 0%, #ececec 100%) + border-color #dcdcdc + + &:active + background #ececec + border-color #dcdcdc + + &.primary + color $theme-color-foreground + background linear-gradient(to bottom, lighten($theme-color, 25%) 0%, lighten($theme-color, 10%) 100%) + border solid 1px lighten($theme-color, 15%) + + &:not(:disabled) + font-weight bold + + &:hover:not(:disabled) + background linear-gradient(to bottom, lighten($theme-color, 8%) 0%, darken($theme-color, 8%) 100%) + border-color $theme-color + + &:active:not(:disabled) + background $theme-color + border-color $theme-color + +input:not([type]).ui +input[type='text'].ui +input[type='password'].ui +input[type='email'].ui +input[type='date'].ui +input[type='number'].ui +textarea.ui + display block + padding 10px + width 100% + height 40px + font-family sans-serif + font-size 16px + color #55595c + border solid 1px #dadada + border-radius 4px + + &:hover + border-color #b0b0b0 + + &:focus + border-color $theme-color + +textarea.ui + min-width 100% + max-width 100% + min-height 64px + +.ui.info + display block + margin 1em 0 + padding 0 1em + font-size 90% + color rgba(#000, 0.87) + background #f8f8f9 + border solid 1px rgba(34, 36, 38, 0.22) + border-radius 4px + + > p + opacity 0.8 + + > [data-fa]:first-child + margin-right 0.25em + + &.warn + color #573a08 + background #FFFAF3 + border-color #C9BA9B + +.ui.from.group + display block + margin 16px 0 + + > p:first-child + margin 0 0 6px 0 + font-size 90% + font-weight bold + color rgba(#373a3c, 0.9) diff --git a/src/client/app/desktop/views/components/activity.calendar.vue b/src/client/app/desktop/views/components/activity.calendar.vue new file mode 100644 index 0000000000..72233e9aca --- /dev/null +++ b/src/client/app/desktop/views/components/activity.calendar.vue @@ -0,0 +1,66 @@ + + + + + diff --git a/src/client/app/desktop/views/components/activity.chart.vue b/src/client/app/desktop/views/components/activity.chart.vue new file mode 100644 index 0000000000..5057786ed4 --- /dev/null +++ b/src/client/app/desktop/views/components/activity.chart.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/client/app/desktop/views/components/activity.vue b/src/client/app/desktop/views/components/activity.vue new file mode 100644 index 0000000000..480b956ecc --- /dev/null +++ b/src/client/app/desktop/views/components/activity.vue @@ -0,0 +1,116 @@ + + + + + diff --git a/src/client/app/desktop/views/components/analog-clock.vue b/src/client/app/desktop/views/components/analog-clock.vue new file mode 100644 index 0000000000..81eec81598 --- /dev/null +++ b/src/client/app/desktop/views/components/analog-clock.vue @@ -0,0 +1,108 @@ + + + + + diff --git a/src/client/app/desktop/views/components/calendar.vue b/src/client/app/desktop/views/components/calendar.vue new file mode 100644 index 0000000000..71aab2e8a5 --- /dev/null +++ b/src/client/app/desktop/views/components/calendar.vue @@ -0,0 +1,252 @@ + + + + + diff --git a/src/client/app/desktop/views/components/choose-file-from-drive-window.vue b/src/client/app/desktop/views/components/choose-file-from-drive-window.vue new file mode 100644 index 0000000000..9a1e9c958a --- /dev/null +++ b/src/client/app/desktop/views/components/choose-file-from-drive-window.vue @@ -0,0 +1,180 @@ + + + + + + diff --git a/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue b/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue new file mode 100644 index 0000000000..f99533176d --- /dev/null +++ b/src/client/app/desktop/views/components/choose-folder-from-drive-window.vue @@ -0,0 +1,114 @@ + + + + + diff --git a/src/client/app/desktop/views/components/context-menu.menu.vue b/src/client/app/desktop/views/components/context-menu.menu.vue new file mode 100644 index 0000000000..6359dbf1b4 --- /dev/null +++ b/src/client/app/desktop/views/components/context-menu.menu.vue @@ -0,0 +1,121 @@ + + + + + + + + diff --git a/src/client/app/desktop/views/components/context-menu.vue b/src/client/app/desktop/views/components/context-menu.vue new file mode 100644 index 0000000000..8bd9945840 --- /dev/null +++ b/src/client/app/desktop/views/components/context-menu.vue @@ -0,0 +1,74 @@ + + + + + diff --git a/src/client/app/desktop/views/components/crop-window.vue b/src/client/app/desktop/views/components/crop-window.vue new file mode 100644 index 0000000000..eb6a55d959 --- /dev/null +++ b/src/client/app/desktop/views/components/crop-window.vue @@ -0,0 +1,178 @@ + + + + + + + diff --git a/src/client/app/desktop/views/components/dialog.vue b/src/client/app/desktop/views/components/dialog.vue new file mode 100644 index 0000000000..fa17e4a9d2 --- /dev/null +++ b/src/client/app/desktop/views/components/dialog.vue @@ -0,0 +1,170 @@ + + + + + + + diff --git a/src/client/app/desktop/views/components/drive-window.vue b/src/client/app/desktop/views/components/drive-window.vue new file mode 100644 index 0000000000..3a072f4794 --- /dev/null +++ b/src/client/app/desktop/views/components/drive-window.vue @@ -0,0 +1,56 @@ + + + + + + diff --git a/src/client/app/desktop/views/components/drive.file.vue b/src/client/app/desktop/views/components/drive.file.vue new file mode 100644 index 0000000000..85f8361c9f --- /dev/null +++ b/src/client/app/desktop/views/components/drive.file.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/src/client/app/desktop/views/components/drive.folder.vue b/src/client/app/desktop/views/components/drive.folder.vue new file mode 100644 index 0000000000..a926bf47b2 --- /dev/null +++ b/src/client/app/desktop/views/components/drive.folder.vue @@ -0,0 +1,267 @@ + + + + + diff --git a/src/client/app/desktop/views/components/drive.nav-folder.vue b/src/client/app/desktop/views/components/drive.nav-folder.vue new file mode 100644 index 0000000000..d885a72f7f --- /dev/null +++ b/src/client/app/desktop/views/components/drive.nav-folder.vue @@ -0,0 +1,113 @@ + + + + + diff --git a/src/client/app/desktop/views/components/drive.vue b/src/client/app/desktop/views/components/drive.vue new file mode 100644 index 0000000000..c766dfec12 --- /dev/null +++ b/src/client/app/desktop/views/components/drive.vue @@ -0,0 +1,773 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ellipsis-icon.vue b/src/client/app/desktop/views/components/ellipsis-icon.vue new file mode 100644 index 0000000000..c54a7db29d --- /dev/null +++ b/src/client/app/desktop/views/components/ellipsis-icon.vue @@ -0,0 +1,37 @@ + + + diff --git a/src/client/app/desktop/views/components/follow-button.vue b/src/client/app/desktop/views/components/follow-button.vue new file mode 100644 index 0000000000..9eb22b0fb8 --- /dev/null +++ b/src/client/app/desktop/views/components/follow-button.vue @@ -0,0 +1,164 @@ + + + + + diff --git a/src/client/app/desktop/views/components/followers-window.vue b/src/client/app/desktop/views/components/followers-window.vue new file mode 100644 index 0000000000..623971fa33 --- /dev/null +++ b/src/client/app/desktop/views/components/followers-window.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/client/app/desktop/views/components/followers.vue b/src/client/app/desktop/views/components/followers.vue new file mode 100644 index 0000000000..a1b98995d8 --- /dev/null +++ b/src/client/app/desktop/views/components/followers.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/client/app/desktop/views/components/following-window.vue b/src/client/app/desktop/views/components/following-window.vue new file mode 100644 index 0000000000..612847b386 --- /dev/null +++ b/src/client/app/desktop/views/components/following-window.vue @@ -0,0 +1,26 @@ + + + + + diff --git a/src/client/app/desktop/views/components/following.vue b/src/client/app/desktop/views/components/following.vue new file mode 100644 index 0000000000..b7aedda84f --- /dev/null +++ b/src/client/app/desktop/views/components/following.vue @@ -0,0 +1,26 @@ + + + diff --git a/src/client/app/desktop/views/components/friends-maker.vue b/src/client/app/desktop/views/components/friends-maker.vue new file mode 100644 index 0000000000..fd9914b152 --- /dev/null +++ b/src/client/app/desktop/views/components/friends-maker.vue @@ -0,0 +1,171 @@ + + + + + diff --git a/src/client/app/desktop/views/components/game-window.vue b/src/client/app/desktop/views/components/game-window.vue new file mode 100644 index 0000000000..3c8bf40e12 --- /dev/null +++ b/src/client/app/desktop/views/components/game-window.vue @@ -0,0 +1,37 @@ + + + + + diff --git a/src/client/app/desktop/views/components/home.vue b/src/client/app/desktop/views/components/home.vue new file mode 100644 index 0000000000..7145ddce03 --- /dev/null +++ b/src/client/app/desktop/views/components/home.vue @@ -0,0 +1,357 @@ + + + + + diff --git a/src/client/app/desktop/views/components/index.ts b/src/client/app/desktop/views/components/index.ts new file mode 100644 index 0000000000..3798bf6d2d --- /dev/null +++ b/src/client/app/desktop/views/components/index.ts @@ -0,0 +1,61 @@ +import Vue from 'vue'; + +import ui from './ui.vue'; +import uiNotification from './ui-notification.vue'; +import home from './home.vue'; +import timeline from './timeline.vue'; +import posts from './posts.vue'; +import subPostContent from './sub-post-content.vue'; +import window from './window.vue'; +import postFormWindow from './post-form-window.vue'; +import repostFormWindow from './repost-form-window.vue'; +import analogClock from './analog-clock.vue'; +import ellipsisIcon from './ellipsis-icon.vue'; +import mediaImage from './media-image.vue'; +import mediaImageDialog from './media-image-dialog.vue'; +import mediaVideo from './media-video.vue'; +import notifications from './notifications.vue'; +import postForm from './post-form.vue'; +import repostForm from './repost-form.vue'; +import followButton from './follow-button.vue'; +import postPreview from './post-preview.vue'; +import drive from './drive.vue'; +import postDetail from './post-detail.vue'; +import settings from './settings.vue'; +import calendar from './calendar.vue'; +import activity from './activity.vue'; +import friendsMaker from './friends-maker.vue'; +import followers from './followers.vue'; +import following from './following.vue'; +import usersList from './users-list.vue'; +import widgetContainer from './widget-container.vue'; + +Vue.component('mk-ui', ui); +Vue.component('mk-ui-notification', uiNotification); +Vue.component('mk-home', home); +Vue.component('mk-timeline', timeline); +Vue.component('mk-posts', posts); +Vue.component('mk-sub-post-content', subPostContent); +Vue.component('mk-window', window); +Vue.component('mk-post-form-window', postFormWindow); +Vue.component('mk-repost-form-window', repostFormWindow); +Vue.component('mk-analog-clock', analogClock); +Vue.component('mk-ellipsis-icon', ellipsisIcon); +Vue.component('mk-media-image', mediaImage); +Vue.component('mk-media-image-dialog', mediaImageDialog); +Vue.component('mk-media-video', mediaVideo); +Vue.component('mk-notifications', notifications); +Vue.component('mk-post-form', postForm); +Vue.component('mk-repost-form', repostForm); +Vue.component('mk-follow-button', followButton); +Vue.component('mk-post-preview', postPreview); +Vue.component('mk-drive', drive); +Vue.component('mk-post-detail', postDetail); +Vue.component('mk-settings', settings); +Vue.component('mk-calendar', calendar); +Vue.component('mk-activity', activity); +Vue.component('mk-friends-maker', friendsMaker); +Vue.component('mk-followers', followers); +Vue.component('mk-following', following); +Vue.component('mk-users-list', usersList); +Vue.component('mk-widget-container', widgetContainer); diff --git a/src/client/app/desktop/views/components/input-dialog.vue b/src/client/app/desktop/views/components/input-dialog.vue new file mode 100644 index 0000000000..e939fc1903 --- /dev/null +++ b/src/client/app/desktop/views/components/input-dialog.vue @@ -0,0 +1,180 @@ + + + + + + diff --git a/src/client/app/desktop/views/components/media-image-dialog.vue b/src/client/app/desktop/views/components/media-image-dialog.vue new file mode 100644 index 0000000000..dec140d1c9 --- /dev/null +++ b/src/client/app/desktop/views/components/media-image-dialog.vue @@ -0,0 +1,69 @@ + + + + + diff --git a/src/client/app/desktop/views/components/media-image.vue b/src/client/app/desktop/views/components/media-image.vue new file mode 100644 index 0000000000..51309a0578 --- /dev/null +++ b/src/client/app/desktop/views/components/media-image.vue @@ -0,0 +1,63 @@ + + + + + diff --git a/src/client/app/desktop/views/components/media-video-dialog.vue b/src/client/app/desktop/views/components/media-video-dialog.vue new file mode 100644 index 0000000000..cbf862cd1c --- /dev/null +++ b/src/client/app/desktop/views/components/media-video-dialog.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/client/app/desktop/views/components/media-video.vue b/src/client/app/desktop/views/components/media-video.vue new file mode 100644 index 0000000000..4fd955a821 --- /dev/null +++ b/src/client/app/desktop/views/components/media-video.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/src/client/app/desktop/views/components/mentions.vue b/src/client/app/desktop/views/components/mentions.vue new file mode 100644 index 0000000000..90a92495b7 --- /dev/null +++ b/src/client/app/desktop/views/components/mentions.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/client/app/desktop/views/components/messaging-room-window.vue b/src/client/app/desktop/views/components/messaging-room-window.vue new file mode 100644 index 0000000000..3735267811 --- /dev/null +++ b/src/client/app/desktop/views/components/messaging-room-window.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/client/app/desktop/views/components/messaging-window.vue b/src/client/app/desktop/views/components/messaging-window.vue new file mode 100644 index 0000000000..ac27465987 --- /dev/null +++ b/src/client/app/desktop/views/components/messaging-window.vue @@ -0,0 +1,32 @@ + + + + + diff --git a/src/client/app/desktop/views/components/notifications.vue b/src/client/app/desktop/views/components/notifications.vue new file mode 100644 index 0000000000..5e6db08c12 --- /dev/null +++ b/src/client/app/desktop/views/components/notifications.vue @@ -0,0 +1,317 @@ + + + + + diff --git a/src/client/app/desktop/views/components/post-detail.sub.vue b/src/client/app/desktop/views/components/post-detail.sub.vue new file mode 100644 index 0000000000..35377e7c24 --- /dev/null +++ b/src/client/app/desktop/views/components/post-detail.sub.vue @@ -0,0 +1,126 @@ + + + + + + + diff --git a/src/client/app/desktop/views/components/post-detail.vue b/src/client/app/desktop/views/components/post-detail.vue new file mode 100644 index 0000000000..5c7a7dfdbe --- /dev/null +++ b/src/client/app/desktop/views/components/post-detail.vue @@ -0,0 +1,433 @@ + + + + + + + diff --git a/src/client/app/desktop/views/components/post-form-window.vue b/src/client/app/desktop/views/components/post-form-window.vue new file mode 100644 index 0000000000..d0b115e852 --- /dev/null +++ b/src/client/app/desktop/views/components/post-form-window.vue @@ -0,0 +1,76 @@ + + + + + diff --git a/src/client/app/desktop/views/components/post-form.vue b/src/client/app/desktop/views/components/post-form.vue new file mode 100644 index 0000000000..1c83a38b64 --- /dev/null +++ b/src/client/app/desktop/views/components/post-form.vue @@ -0,0 +1,536 @@ + + + + + diff --git a/src/client/app/desktop/views/components/post-preview.vue b/src/client/app/desktop/views/components/post-preview.vue new file mode 100644 index 0000000000..0ac3223be2 --- /dev/null +++ b/src/client/app/desktop/views/components/post-preview.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/client/app/desktop/views/components/posts.post.sub.vue b/src/client/app/desktop/views/components/posts.post.sub.vue new file mode 100644 index 0000000000..65d3017d3d --- /dev/null +++ b/src/client/app/desktop/views/components/posts.post.sub.vue @@ -0,0 +1,112 @@ + + + + + diff --git a/src/client/app/desktop/views/components/posts.post.vue b/src/client/app/desktop/views/components/posts.post.vue new file mode 100644 index 0000000000..37c6e63043 --- /dev/null +++ b/src/client/app/desktop/views/components/posts.post.vue @@ -0,0 +1,582 @@ + + + + + + + diff --git a/src/client/app/desktop/views/components/posts.vue b/src/client/app/desktop/views/components/posts.vue new file mode 100644 index 0000000000..5031667c7c --- /dev/null +++ b/src/client/app/desktop/views/components/posts.vue @@ -0,0 +1,89 @@ + + + + + diff --git a/src/client/app/desktop/views/components/progress-dialog.vue b/src/client/app/desktop/views/components/progress-dialog.vue new file mode 100644 index 0000000000..a4292e1aec --- /dev/null +++ b/src/client/app/desktop/views/components/progress-dialog.vue @@ -0,0 +1,95 @@ + + + + + diff --git a/src/client/app/desktop/views/components/repost-form-window.vue b/src/client/app/desktop/views/components/repost-form-window.vue new file mode 100644 index 0000000000..7db5adbff3 --- /dev/null +++ b/src/client/app/desktop/views/components/repost-form-window.vue @@ -0,0 +1,42 @@ + + + + + diff --git a/src/client/app/desktop/views/components/repost-form.vue b/src/client/app/desktop/views/components/repost-form.vue new file mode 100644 index 0000000000..3a5e3a7c56 --- /dev/null +++ b/src/client/app/desktop/views/components/repost-form.vue @@ -0,0 +1,131 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings-window.vue b/src/client/app/desktop/views/components/settings-window.vue new file mode 100644 index 0000000000..d5be177dcc --- /dev/null +++ b/src/client/app/desktop/views/components/settings-window.vue @@ -0,0 +1,24 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings.2fa.vue b/src/client/app/desktop/views/components/settings.2fa.vue new file mode 100644 index 0000000000..b8dd1dfd9b --- /dev/null +++ b/src/client/app/desktop/views/components/settings.2fa.vue @@ -0,0 +1,80 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings.api.vue b/src/client/app/desktop/views/components/settings.api.vue new file mode 100644 index 0000000000..0d5921ab7f --- /dev/null +++ b/src/client/app/desktop/views/components/settings.api.vue @@ -0,0 +1,40 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings.apps.vue b/src/client/app/desktop/views/components/settings.apps.vue new file mode 100644 index 0000000000..0503b03abd --- /dev/null +++ b/src/client/app/desktop/views/components/settings.apps.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings.drive.vue b/src/client/app/desktop/views/components/settings.drive.vue new file mode 100644 index 0000000000..8bb0c760a7 --- /dev/null +++ b/src/client/app/desktop/views/components/settings.drive.vue @@ -0,0 +1,35 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings.mute.vue b/src/client/app/desktop/views/components/settings.mute.vue new file mode 100644 index 0000000000..a8dfe10604 --- /dev/null +++ b/src/client/app/desktop/views/components/settings.mute.vue @@ -0,0 +1,35 @@ + + + diff --git a/src/client/app/desktop/views/components/settings.password.vue b/src/client/app/desktop/views/components/settings.password.vue new file mode 100644 index 0000000000..f883b54065 --- /dev/null +++ b/src/client/app/desktop/views/components/settings.password.vue @@ -0,0 +1,47 @@ + + + diff --git a/src/client/app/desktop/views/components/settings.profile.vue b/src/client/app/desktop/views/components/settings.profile.vue new file mode 100644 index 0000000000..ba86286f87 --- /dev/null +++ b/src/client/app/desktop/views/components/settings.profile.vue @@ -0,0 +1,87 @@ + + + + + + diff --git a/src/client/app/desktop/views/components/settings.signins.vue b/src/client/app/desktop/views/components/settings.signins.vue new file mode 100644 index 0000000000..a414c95c27 --- /dev/null +++ b/src/client/app/desktop/views/components/settings.signins.vue @@ -0,0 +1,98 @@ + + + + + diff --git a/src/client/app/desktop/views/components/settings.vue b/src/client/app/desktop/views/components/settings.vue new file mode 100644 index 0000000000..fd82c171c1 --- /dev/null +++ b/src/client/app/desktop/views/components/settings.vue @@ -0,0 +1,419 @@ + + + + + diff --git a/src/client/app/desktop/views/components/sub-post-content.vue b/src/client/app/desktop/views/components/sub-post-content.vue new file mode 100644 index 0000000000..f13822331b --- /dev/null +++ b/src/client/app/desktop/views/components/sub-post-content.vue @@ -0,0 +1,56 @@ + + + + + diff --git a/src/client/app/desktop/views/components/taskmanager.vue b/src/client/app/desktop/views/components/taskmanager.vue new file mode 100644 index 0000000000..a00fabb047 --- /dev/null +++ b/src/client/app/desktop/views/components/taskmanager.vue @@ -0,0 +1,219 @@ + + + + + + + diff --git a/src/client/app/desktop/views/components/timeline.vue b/src/client/app/desktop/views/components/timeline.vue new file mode 100644 index 0000000000..65b4bd1c7a --- /dev/null +++ b/src/client/app/desktop/views/components/timeline.vue @@ -0,0 +1,156 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui-notification.vue b/src/client/app/desktop/views/components/ui-notification.vue new file mode 100644 index 0000000000..9983f02c5e --- /dev/null +++ b/src/client/app/desktop/views/components/ui-notification.vue @@ -0,0 +1,61 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.account.vue b/src/client/app/desktop/views/components/ui.header.account.vue new file mode 100644 index 0000000000..ec4635f338 --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.account.vue @@ -0,0 +1,225 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.clock.vue b/src/client/app/desktop/views/components/ui.header.clock.vue new file mode 100644 index 0000000000..cd23a67506 --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.clock.vue @@ -0,0 +1,109 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.nav.vue b/src/client/app/desktop/views/components/ui.header.nav.vue new file mode 100644 index 0000000000..7582e8afce --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.nav.vue @@ -0,0 +1,175 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.notifications.vue b/src/client/app/desktop/views/components/ui.header.notifications.vue new file mode 100644 index 0000000000..e829418d18 --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.notifications.vue @@ -0,0 +1,158 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.post.vue b/src/client/app/desktop/views/components/ui.header.post.vue new file mode 100644 index 0000000000..c2f0e07dd3 --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.post.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.search.vue b/src/client/app/desktop/views/components/ui.header.search.vue new file mode 100644 index 0000000000..86215556ad --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.search.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.header.vue b/src/client/app/desktop/views/components/ui.header.vue new file mode 100644 index 0000000000..7e337d2ae5 --- /dev/null +++ b/src/client/app/desktop/views/components/ui.header.vue @@ -0,0 +1,172 @@ + + + + + diff --git a/src/client/app/desktop/views/components/ui.vue b/src/client/app/desktop/views/components/ui.vue new file mode 100644 index 0000000000..87f932ff14 --- /dev/null +++ b/src/client/app/desktop/views/components/ui.vue @@ -0,0 +1,37 @@ + + + + diff --git a/src/client/app/desktop/views/components/user-preview.vue b/src/client/app/desktop/views/components/user-preview.vue new file mode 100644 index 0000000000..8c86b2efe8 --- /dev/null +++ b/src/client/app/desktop/views/components/user-preview.vue @@ -0,0 +1,173 @@ + + + + + diff --git a/src/client/app/desktop/views/components/users-list.item.vue b/src/client/app/desktop/views/components/users-list.item.vue new file mode 100644 index 0000000000..d2bfc117da --- /dev/null +++ b/src/client/app/desktop/views/components/users-list.item.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/client/app/desktop/views/components/users-list.vue b/src/client/app/desktop/views/components/users-list.vue new file mode 100644 index 0000000000..a08e76f573 --- /dev/null +++ b/src/client/app/desktop/views/components/users-list.vue @@ -0,0 +1,143 @@ + + + + + diff --git a/src/client/app/desktop/views/components/widget-container.vue b/src/client/app/desktop/views/components/widget-container.vue new file mode 100644 index 0000000000..68c5bcb8dc --- /dev/null +++ b/src/client/app/desktop/views/components/widget-container.vue @@ -0,0 +1,85 @@ + + + + + diff --git a/src/client/app/desktop/views/components/window.vue b/src/client/app/desktop/views/components/window.vue new file mode 100644 index 0000000000..48dc46febd --- /dev/null +++ b/src/client/app/desktop/views/components/window.vue @@ -0,0 +1,635 @@ + + + + + diff --git a/src/client/app/desktop/views/directives/index.ts b/src/client/app/desktop/views/directives/index.ts new file mode 100644 index 0000000000..324e07596d --- /dev/null +++ b/src/client/app/desktop/views/directives/index.ts @@ -0,0 +1,6 @@ +import Vue from 'vue'; + +import userPreview from './user-preview'; + +Vue.directive('userPreview', userPreview); +Vue.directive('user-preview', userPreview); diff --git a/src/client/app/desktop/views/directives/user-preview.ts b/src/client/app/desktop/views/directives/user-preview.ts new file mode 100644 index 0000000000..8a4035881a --- /dev/null +++ b/src/client/app/desktop/views/directives/user-preview.ts @@ -0,0 +1,72 @@ +/** + * マウスオーバーするとユーザーがプレビューされる要素を設定します + */ + +import MkUserPreview from '../components/user-preview.vue'; + +export default { + bind(el, binding, vn) { + const self = el._userPreviewDirective_ = {} as any; + + self.user = binding.value; + self.tag = null; + self.showTimer = null; + self.hideTimer = null; + + self.close = () => { + if (self.tag) { + self.tag.close(); + self.tag = null; + } + }; + + const show = () => { + if (self.tag) return; + + self.tag = new MkUserPreview({ + parent: vn.context, + propsData: { + user: self.user + } + }).$mount(); + + const preview = self.tag.$el; + const rect = el.getBoundingClientRect(); + const x = rect.left + el.offsetWidth + window.pageXOffset; + const y = rect.top + window.pageYOffset; + + preview.style.top = y + 'px'; + preview.style.left = x + 'px'; + + preview.addEventListener('mouseover', () => { + clearTimeout(self.hideTimer); + }); + + preview.addEventListener('mouseleave', () => { + clearTimeout(self.showTimer); + self.hideTimer = setTimeout(self.close, 500); + }); + + document.body.appendChild(preview); + }; + + el.addEventListener('mouseover', () => { + clearTimeout(self.showTimer); + clearTimeout(self.hideTimer); + self.showTimer = setTimeout(show, 500); + }); + + el.addEventListener('mouseleave', () => { + clearTimeout(self.showTimer); + clearTimeout(self.hideTimer); + self.hideTimer = setTimeout(self.close, 500); + }); + }, + + unbind(el, binding, vn) { + const self = el._userPreviewDirective_; + clearTimeout(self.showTimer); + clearTimeout(self.hideTimer); + self.close(); + } +}; diff --git a/src/client/app/desktop/views/pages/drive.vue b/src/client/app/desktop/views/pages/drive.vue new file mode 100644 index 0000000000..353f59b703 --- /dev/null +++ b/src/client/app/desktop/views/pages/drive.vue @@ -0,0 +1,52 @@ + + + + + + diff --git a/src/client/app/desktop/views/pages/home-customize.vue b/src/client/app/desktop/views/pages/home-customize.vue new file mode 100644 index 0000000000..8aa06be57f --- /dev/null +++ b/src/client/app/desktop/views/pages/home-customize.vue @@ -0,0 +1,12 @@ + + + diff --git a/src/client/app/desktop/views/pages/home.vue b/src/client/app/desktop/views/pages/home.vue new file mode 100644 index 0000000000..69e134f79f --- /dev/null +++ b/src/client/app/desktop/views/pages/home.vue @@ -0,0 +1,62 @@ + + + diff --git a/src/client/app/desktop/views/pages/index.vue b/src/client/app/desktop/views/pages/index.vue new file mode 100644 index 0000000000..0ea47d913b --- /dev/null +++ b/src/client/app/desktop/views/pages/index.vue @@ -0,0 +1,16 @@ + + + diff --git a/src/client/app/desktop/views/pages/messaging-room.vue b/src/client/app/desktop/views/pages/messaging-room.vue new file mode 100644 index 0000000000..0cab1e0d10 --- /dev/null +++ b/src/client/app/desktop/views/pages/messaging-room.vue @@ -0,0 +1,54 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/othello.vue b/src/client/app/desktop/views/pages/othello.vue new file mode 100644 index 0000000000..0d8e987dd9 --- /dev/null +++ b/src/client/app/desktop/views/pages/othello.vue @@ -0,0 +1,50 @@ + + + diff --git a/src/client/app/desktop/views/pages/post.vue b/src/client/app/desktop/views/pages/post.vue new file mode 100644 index 0000000000..dbd707e049 --- /dev/null +++ b/src/client/app/desktop/views/pages/post.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/search.vue b/src/client/app/desktop/views/pages/search.vue new file mode 100644 index 0000000000..afd37c8cee --- /dev/null +++ b/src/client/app/desktop/views/pages/search.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/selectdrive.vue b/src/client/app/desktop/views/pages/selectdrive.vue new file mode 100644 index 0000000000..4f0b86014b --- /dev/null +++ b/src/client/app/desktop/views/pages/selectdrive.vue @@ -0,0 +1,177 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.followers-you-know.vue b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue new file mode 100644 index 0000000000..d0dab6c3df --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.followers-you-know.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.friends.vue b/src/client/app/desktop/views/pages/user/user.friends.vue new file mode 100644 index 0000000000..3ec30fb438 --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.friends.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.header.vue b/src/client/app/desktop/views/pages/user/user.header.vue new file mode 100644 index 0000000000..54f431fd2e --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.header.vue @@ -0,0 +1,196 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.home.vue b/src/client/app/desktop/views/pages/user/user.home.vue new file mode 100644 index 0000000000..071c9bb61c --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.home.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.photos.vue b/src/client/app/desktop/views/pages/user/user.photos.vue new file mode 100644 index 0000000000..1ff79b4aee --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.photos.vue @@ -0,0 +1,88 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.profile.vue b/src/client/app/desktop/views/pages/user/user.profile.vue new file mode 100644 index 0000000000..f5562d0915 --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.profile.vue @@ -0,0 +1,138 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.timeline.vue b/src/client/app/desktop/views/pages/user/user.timeline.vue new file mode 100644 index 0000000000..134ad423ce --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.timeline.vue @@ -0,0 +1,139 @@ + + + + + diff --git a/src/client/app/desktop/views/pages/user/user.vue b/src/client/app/desktop/views/pages/user/user.vue new file mode 100644 index 0000000000..67cef93269 --- /dev/null +++ b/src/client/app/desktop/views/pages/user/user.vue @@ -0,0 +1,53 @@ + + + + diff --git a/src/client/app/desktop/views/pages/welcome.vue b/src/client/app/desktop/views/pages/welcome.vue new file mode 100644 index 0000000000..34c28854b1 --- /dev/null +++ b/src/client/app/desktop/views/pages/welcome.vue @@ -0,0 +1,319 @@ + + + + + + + + + + + diff --git a/src/client/app/desktop/views/widgets/activity.vue b/src/client/app/desktop/views/widgets/activity.vue new file mode 100644 index 0000000000..0bdf4622af --- /dev/null +++ b/src/client/app/desktop/views/widgets/activity.vue @@ -0,0 +1,31 @@ + + + diff --git a/src/client/app/desktop/views/widgets/channel.channel.form.vue b/src/client/app/desktop/views/widgets/channel.channel.form.vue new file mode 100644 index 0000000000..aaf327f1ef --- /dev/null +++ b/src/client/app/desktop/views/widgets/channel.channel.form.vue @@ -0,0 +1,67 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/channel.channel.post.vue b/src/client/app/desktop/views/widgets/channel.channel.post.vue new file mode 100644 index 0000000000..433f9a00aa --- /dev/null +++ b/src/client/app/desktop/views/widgets/channel.channel.post.vue @@ -0,0 +1,71 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/channel.channel.vue b/src/client/app/desktop/views/widgets/channel.channel.vue new file mode 100644 index 0000000000..e9fb9e3fd7 --- /dev/null +++ b/src/client/app/desktop/views/widgets/channel.channel.vue @@ -0,0 +1,106 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/channel.vue b/src/client/app/desktop/views/widgets/channel.vue new file mode 100644 index 0000000000..c9b62dfeab --- /dev/null +++ b/src/client/app/desktop/views/widgets/channel.vue @@ -0,0 +1,107 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/index.ts b/src/client/app/desktop/views/widgets/index.ts new file mode 100644 index 0000000000..77d771d6b3 --- /dev/null +++ b/src/client/app/desktop/views/widgets/index.ts @@ -0,0 +1,23 @@ +import Vue from 'vue'; + +import wNotifications from './notifications.vue'; +import wTimemachine from './timemachine.vue'; +import wActivity from './activity.vue'; +import wTrends from './trends.vue'; +import wUsers from './users.vue'; +import wPolls from './polls.vue'; +import wPostForm from './post-form.vue'; +import wMessaging from './messaging.vue'; +import wChannel from './channel.vue'; +import wProfile from './profile.vue'; + +Vue.component('mkw-notifications', wNotifications); +Vue.component('mkw-timemachine', wTimemachine); +Vue.component('mkw-activity', wActivity); +Vue.component('mkw-trends', wTrends); +Vue.component('mkw-users', wUsers); +Vue.component('mkw-polls', wPolls); +Vue.component('mkw-post-form', wPostForm); +Vue.component('mkw-messaging', wMessaging); +Vue.component('mkw-channel', wChannel); +Vue.component('mkw-profile', wProfile); diff --git a/src/client/app/desktop/views/widgets/messaging.vue b/src/client/app/desktop/views/widgets/messaging.vue new file mode 100644 index 0000000000..2c9f473bd1 --- /dev/null +++ b/src/client/app/desktop/views/widgets/messaging.vue @@ -0,0 +1,59 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/notifications.vue b/src/client/app/desktop/views/widgets/notifications.vue new file mode 100644 index 0000000000..1a2b3d3f89 --- /dev/null +++ b/src/client/app/desktop/views/widgets/notifications.vue @@ -0,0 +1,70 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/polls.vue b/src/client/app/desktop/views/widgets/polls.vue new file mode 100644 index 0000000000..e5db34fc7a --- /dev/null +++ b/src/client/app/desktop/views/widgets/polls.vue @@ -0,0 +1,129 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/post-form.vue b/src/client/app/desktop/views/widgets/post-form.vue new file mode 100644 index 0000000000..cf7fd1f2b2 --- /dev/null +++ b/src/client/app/desktop/views/widgets/post-form.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/profile.vue b/src/client/app/desktop/views/widgets/profile.vue new file mode 100644 index 0000000000..83cd67b50c --- /dev/null +++ b/src/client/app/desktop/views/widgets/profile.vue @@ -0,0 +1,125 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/timemachine.vue b/src/client/app/desktop/views/widgets/timemachine.vue new file mode 100644 index 0000000000..6db3b14c62 --- /dev/null +++ b/src/client/app/desktop/views/widgets/timemachine.vue @@ -0,0 +1,28 @@ + + + diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue new file mode 100644 index 0000000000..77779787ee --- /dev/null +++ b/src/client/app/desktop/views/widgets/trends.vue @@ -0,0 +1,135 @@ + + + + + diff --git a/src/client/app/desktop/views/widgets/users.vue b/src/client/app/desktop/views/widgets/users.vue new file mode 100644 index 0000000000..7b89441126 --- /dev/null +++ b/src/client/app/desktop/views/widgets/users.vue @@ -0,0 +1,172 @@ + + + + + -- cgit v1.3.1-freya From 1af9efe54ea2fb5b9f8a2ead1b089ca1670f53f6 Mon Sep 17 00:00:00 2001 From: syuilo Date: Fri, 30 Mar 2018 18:48:51 +0900 Subject: 返信先プレビューなどではURLプレビューを表示しないように MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../app/desktop/views/components/sub-post-content.vue | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/views/components/sub-post-content.vue b/src/client/app/desktop/views/components/sub-post-content.vue index f13822331b..a79e5e0a4e 100644 --- a/src/client/app/desktop/views/components/sub-post-content.vue +++ b/src/client/app/desktop/views/components/sub-post-content.vue @@ -4,7 +4,6 @@ %fa:reply% RP: ... -
({{ post.media.length }}つのメディア) @@ -21,18 +20,7 @@ import Vue from 'vue'; export default Vue.extend({ - props: ['post'], - computed: { - urls(): string[] { - if (this.post.ast) { - return this.post.ast - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => t.url); - } else { - return null; - } - } - } + props: ['post'] }); -- cgit v1.3.1-freya From 8c4143290735b39bc68bf98439b2735af1910518 Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 31 Mar 2018 19:45:56 +0900 Subject: Set empty array instead of null to mediaIds property of posts --- src/client/app/desktop/views/components/post-detail.sub.vue | 2 +- src/client/app/desktop/views/components/post-detail.vue | 2 +- src/client/app/desktop/views/components/posts.post.vue | 2 +- src/client/app/desktop/views/components/sub-post-content.vue | 2 +- src/client/app/mobile/views/components/post-detail.vue | 2 +- src/client/app/mobile/views/components/post.vue | 2 +- src/client/app/mobile/views/components/sub-post-content.vue | 2 +- src/client/docs/api/entities/post.yaml | 4 ++-- src/server/api/endpoints/posts/create.ts | 2 +- tools/migration/nighthike/6.js | 1 + 10 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 tools/migration/nighthike/6.js (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/views/components/post-detail.sub.vue b/src/client/app/desktop/views/components/post-detail.sub.vue index 35377e7c24..285b5dedee 100644 --- a/src/client/app/desktop/views/components/post-detail.sub.vue +++ b/src/client/app/desktop/views/components/post-detail.sub.vue @@ -17,7 +17,7 @@
-
+
diff --git a/src/client/app/desktop/views/components/post-detail.vue b/src/client/app/desktop/views/components/post-detail.vue index 5c7a7dfdbe..1811e22bad 100644 --- a/src/client/app/desktop/views/components/post-detail.vue +++ b/src/client/app/desktop/views/components/post-detail.vue @@ -39,7 +39,7 @@
-
+
diff --git a/src/client/app/desktop/views/components/posts.post.vue b/src/client/app/desktop/views/components/posts.post.vue index 37c6e63043..aa1f1db41c 100644 --- a/src/client/app/desktop/views/components/posts.post.vue +++ b/src/client/app/desktop/views/components/posts.post.vue @@ -41,7 +41,7 @@ RP:
-
+
diff --git a/src/client/app/desktop/views/components/sub-post-content.vue b/src/client/app/desktop/views/components/sub-post-content.vue index a79e5e0a4e..1f5ce38984 100644 --- a/src/client/app/desktop/views/components/sub-post-content.vue +++ b/src/client/app/desktop/views/components/sub-post-content.vue @@ -5,7 +5,7 @@ RP: ...
-
+
({{ post.media.length }}つのメディア)
diff --git a/src/client/app/mobile/views/components/post-detail.vue b/src/client/app/mobile/views/components/post-detail.vue index f0af1a61aa..6411011b89 100644 --- a/src/client/app/mobile/views/components/post-detail.vue +++ b/src/client/app/mobile/views/components/post-detail.vue @@ -42,7 +42,7 @@
{{ tag }}
-
+
diff --git a/src/client/app/mobile/views/components/post.vue b/src/client/app/mobile/views/components/post.vue index a01eb7669e..52fb095372 100644 --- a/src/client/app/mobile/views/components/post.vue +++ b/src/client/app/mobile/views/components/post.vue @@ -40,7 +40,7 @@ RP:
-
+
diff --git a/src/client/app/mobile/views/components/sub-post-content.vue b/src/client/app/mobile/views/components/sub-post-content.vue index b95883de77..5ff88089aa 100644 --- a/src/client/app/mobile/views/components/sub-post-content.vue +++ b/src/client/app/mobile/views/components/sub-post-content.vue @@ -5,7 +5,7 @@ RP: ...
-
+
({{ post.media.length }}個のメディア)
diff --git a/src/client/docs/api/entities/post.yaml b/src/client/docs/api/entities/post.yaml index 74d7973e38..da79866ba1 100644 --- a/src/client/docs/api/entities/post.yaml +++ b/src/client/docs/api/entities/post.yaml @@ -33,8 +33,8 @@ props: type: "id(DriveFile)[]" optional: true desc: - ja: "添付されているメディアのID" - en: "The IDs of the attached media" + ja: "添付されているメディアのID (なければレスポンスでは空配列)" + en: "The IDs of the attached media (empty array for response if no media is attached)" - name: "media" type: "entity(DriveFile)[]" optional: true diff --git a/src/server/api/endpoints/posts/create.ts b/src/server/api/endpoints/posts/create.ts index 170b667191..aa7e93c28f 100644 --- a/src/server/api/endpoints/posts/create.ts +++ b/src/server/api/endpoints/posts/create.ts @@ -254,7 +254,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { createdAt: new Date(), channelId: channel ? channel._id : undefined, index: channel ? channel.index + 1 : undefined, - mediaIds: files ? files.map(file => file._id) : undefined, + mediaIds: files ? files.map(file => file._id) : [], replyId: reply ? reply._id : undefined, repostId: repost ? repost._id : undefined, poll: poll, diff --git a/tools/migration/nighthike/6.js b/tools/migration/nighthike/6.js new file mode 100644 index 0000000000..ff78df4e09 --- /dev/null +++ b/tools/migration/nighthike/6.js @@ -0,0 +1 @@ +db.posts.update({ mediaIds: null }, { $set: { mediaIds: [] } }, false, true); -- cgit v1.3.1-freya From 7da60a0147116130a94274e4a20ae54dd7d59dea Mon Sep 17 00:00:00 2001 From: Akihiko Odaki Date: Sat, 31 Mar 2018 19:53:30 +0900 Subject: Store texts as HTML --- src/client/app/common/views/components/index.ts | 2 +- .../views/components/messaging-room.message.vue | 33 +- .../app/common/views/components/post-html.ts | 141 --------- .../app/common/views/components/post-html.vue | 103 +++++++ src/client/app/common/views/components/url.vue | 66 ---- .../common/views/components/welcome-timeline.vue | 2 +- .../desktop/views/components/post-detail.sub.vue | 2 +- .../app/desktop/views/components/post-detail.vue | 27 +- .../app/desktop/views/components/posts.post.vue | 31 +- .../desktop/views/components/sub-post-content.vue | 2 +- .../app/mobile/views/components/post-detail.vue | 27 +- src/client/app/mobile/views/components/post.vue | 31 +- .../mobile/views/components/sub-post-content.vue | 2 +- src/client/docs/api/entities/post.yaml | 10 +- src/common/text/core/syntax-highlighter.ts | 334 --------------------- src/common/text/elements/bold.ts | 14 - src/common/text/elements/code.ts | 17 -- src/common/text/elements/emoji.ts | 14 - src/common/text/elements/hashtag.ts | 19 -- src/common/text/elements/inline-code.ts | 17 -- src/common/text/elements/link.ts | 19 -- src/common/text/elements/mention.ts | 17 -- src/common/text/elements/quote.ts | 14 - src/common/text/elements/url.ts | 14 - src/common/text/html.ts | 83 +++++ src/common/text/index.ts | 72 ----- src/common/text/parse/core/syntax-highlighter.ts | 334 +++++++++++++++++++++ src/common/text/parse/elements/bold.ts | 14 + src/common/text/parse/elements/code.ts | 17 ++ src/common/text/parse/elements/emoji.ts | 14 + src/common/text/parse/elements/hashtag.ts | 19 ++ src/common/text/parse/elements/inline-code.ts | 17 ++ src/common/text/parse/elements/link.ts | 19 ++ src/common/text/parse/elements/mention.ts | 17 ++ src/common/text/parse/elements/quote.ts | 14 + src/common/text/parse/elements/url.ts | 14 + src/common/text/parse/index.ts | 72 +++++ src/models/messaging-message.ts | 7 +- src/models/post.ts | 7 +- .../api/endpoints/messaging/messages/create.ts | 3 + src/server/api/endpoints/posts/create.ts | 4 +- tools/migration/nighthike/7.js | 16 + 42 files changed, 868 insertions(+), 833 deletions(-) delete mode 100644 src/client/app/common/views/components/post-html.ts create mode 100644 src/client/app/common/views/components/post-html.vue delete mode 100644 src/client/app/common/views/components/url.vue delete mode 100644 src/common/text/core/syntax-highlighter.ts delete mode 100644 src/common/text/elements/bold.ts delete mode 100644 src/common/text/elements/code.ts delete mode 100644 src/common/text/elements/emoji.ts delete mode 100644 src/common/text/elements/hashtag.ts delete mode 100644 src/common/text/elements/inline-code.ts delete mode 100644 src/common/text/elements/link.ts delete mode 100644 src/common/text/elements/mention.ts delete mode 100644 src/common/text/elements/quote.ts delete mode 100644 src/common/text/elements/url.ts create mode 100644 src/common/text/html.ts delete mode 100644 src/common/text/index.ts create mode 100644 src/common/text/parse/core/syntax-highlighter.ts create mode 100644 src/common/text/parse/elements/bold.ts create mode 100644 src/common/text/parse/elements/code.ts create mode 100644 src/common/text/parse/elements/emoji.ts create mode 100644 src/common/text/parse/elements/hashtag.ts create mode 100644 src/common/text/parse/elements/inline-code.ts create mode 100644 src/common/text/parse/elements/link.ts create mode 100644 src/common/text/parse/elements/mention.ts create mode 100644 src/common/text/parse/elements/quote.ts create mode 100644 src/common/text/parse/elements/url.ts create mode 100644 src/common/text/parse/index.ts create mode 100644 tools/migration/nighthike/7.js (limited to 'src/client/app/desktop') diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index b58ba37ecb..8c10bdee28 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -4,7 +4,7 @@ import signin from './signin.vue'; import signup from './signup.vue'; import forkit from './forkit.vue'; import nav from './nav.vue'; -import postHtml from './post-html'; +import postHtml from './post-html.vue'; import poll from './poll.vue'; import pollEditor from './poll-editor.vue'; import reactionIcon from './reaction-icon.vue'; diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue index 94f87fd709..25ceab85a1 100644 --- a/src/client/app/common/views/components/messaging-room.message.vue +++ b/src/client/app/common/views/components/messaging-room.message.vue @@ -4,13 +4,13 @@
-
+

%i18n:common.tags.mk-messaging-message.is-read%

- +
@@ -38,21 +38,32 @@ import getAcct from '../../../../../common/user/get-acct'; export default Vue.extend({ props: ['message'], + data() { + return { + urls: [] + }; + }, computed: { acct() { return getAcct(this.message.user); }, isMe(): boolean { return this.message.userId == (this as any).os.i.id; - }, - urls(): string[] { - if (this.message.ast) { - return this.message.ast - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => t.url); - } else { - return null; - } + } + }, + watch: { + message: { + handler(newMessage, oldMessage) { + if (!oldMessage || newMessage.textHtml !== oldMessage.textHtml) { + this.$nextTick(() => { + const elements = this.$refs.text.$el.getElementsByTagName('a'); + + this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) + .map(({ href }) => href); + }); + } + }, + immediate: true } } }); diff --git a/src/client/app/common/views/components/post-html.ts b/src/client/app/common/views/components/post-html.ts deleted file mode 100644 index 39d783aac5..0000000000 --- a/src/client/app/common/views/components/post-html.ts +++ /dev/null @@ -1,141 +0,0 @@ -import Vue from 'vue'; -import * as emojilib from 'emojilib'; -import getAcct from '../../../../../common/user/get-acct'; -import { url } from '../../../config'; -import MkUrl from './url.vue'; - -const flatten = list => list.reduce( - (a, b) => a.concat(Array.isArray(b) ? flatten(b) : b), [] -); - -export default Vue.component('mk-post-html', { - props: { - ast: { - type: Array, - required: true - }, - shouldBreak: { - type: Boolean, - default: true - }, - i: { - type: Object, - default: null - } - }, - render(createElement) { - const els = flatten((this as any).ast.map(token => { - switch (token.type) { - case 'text': - const text = token.content.replace(/(\r\n|\n|\r)/g, '\n'); - - if ((this as any).shouldBreak) { - const x = text.split('\n') - .map(t => t == '' ? [createElement('br')] : [createElement('span', t), createElement('br')]); - x[x.length - 1].pop(); - return x; - } else { - return createElement('span', text.replace(/\n/g, ' ')); - } - - case 'bold': - return createElement('strong', token.bold); - - case 'url': - return createElement(MkUrl, { - props: { - url: token.content, - target: '_blank' - } - }); - - case 'link': - return createElement('a', { - attrs: { - class: 'link', - href: token.url, - target: '_blank', - title: token.url - } - }, token.title); - - case 'mention': - return (createElement as any)('a', { - attrs: { - href: `${url}/@${getAcct(token)}`, - target: '_blank', - dataIsMe: (this as any).i && getAcct((this as any).i) == getAcct(token) - }, - directives: [{ - name: 'user-preview', - value: token.content - }] - }, token.content); - - case 'hashtag': - return createElement('a', { - attrs: { - href: `${url}/search?q=${token.content}`, - target: '_blank' - } - }, token.content); - - case 'code': - return createElement('pre', [ - createElement('code', { - domProps: { - innerHTML: token.html - } - }) - ]); - - case 'inline-code': - return createElement('code', { - domProps: { - innerHTML: token.html - } - }); - - case 'quote': - const text2 = token.quote.replace(/(\r\n|\n|\r)/g, '\n'); - - if ((this as any).shouldBreak) { - const x = text2.split('\n') - .map(t => [createElement('span', t), createElement('br')]); - x[x.length - 1].pop(); - return createElement('div', { - attrs: { - class: 'quote' - } - }, x); - } else { - return createElement('span', { - attrs: { - class: 'quote' - } - }, text2.replace(/\n/g, ' ')); - } - - case 'emoji': - const emoji = emojilib.lib[token.emoji]; - return createElement('span', emoji ? emoji.char : token.content); - - default: - console.log('unknown ast type:', token.type); - } - })); - - const _els = []; - els.forEach((el, i) => { - if (el.tag == 'br') { - if (els[i - 1].tag != 'div') { - _els.push(el); - } - } else { - _els.push(el); - } - }); - - return createElement('span', _els); - } -}); diff --git a/src/client/app/common/views/components/post-html.vue b/src/client/app/common/views/components/post-html.vue new file mode 100644 index 0000000000..1c949052b9 --- /dev/null +++ b/src/client/app/common/views/components/post-html.vue @@ -0,0 +1,103 @@ + + + + + diff --git a/src/client/app/common/views/components/url.vue b/src/client/app/common/views/components/url.vue deleted file mode 100644 index 14d4fc82f3..0000000000 --- a/src/client/app/common/views/components/url.vue +++ /dev/null @@ -1,66 +0,0 @@ - - - - - diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue index 8f6199732a..f379029f9f 100644 --- a/src/client/app/common/views/components/welcome-timeline.vue +++ b/src/client/app/common/views/components/welcome-timeline.vue @@ -15,7 +15,7 @@
- +
diff --git a/src/client/app/desktop/views/components/post-detail.sub.vue b/src/client/app/desktop/views/components/post-detail.sub.vue index 285b5dedee..b6148d9b28 100644 --- a/src/client/app/desktop/views/components/post-detail.sub.vue +++ b/src/client/app/desktop/views/components/post-detail.sub.vue @@ -16,7 +16,7 @@
- +
diff --git a/src/client/app/desktop/views/components/post-detail.vue b/src/client/app/desktop/views/components/post-detail.vue index 1811e22bad..e75ebe34b4 100644 --- a/src/client/app/desktop/views/components/post-detail.vue +++ b/src/client/app/desktop/views/components/post-detail.vue @@ -38,7 +38,7 @@
- +
@@ -109,6 +109,7 @@ export default Vue.extend({ context: [], contextFetching: false, replies: [], + urls: [] }; }, computed: { @@ -130,15 +131,6 @@ export default Vue.extend({ }, title(): string { return dateStringify(this.p.createdAt); - }, - urls(): string[] { - if (this.p.ast) { - return this.p.ast - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => t.url); - } else { - return null; - } } }, mounted() { @@ -170,6 +162,21 @@ export default Vue.extend({ } } }, + watch: { + post: { + handler(newPost, oldPost) { + if (!oldPost || newPost.text !== oldPost.text) { + this.$nextTick(() => { + const elements = this.$refs.text.$el.getElementsByTagName('a'); + + this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) + .map(({ href }) => href); + }); + } + }, + immediate: true + } + }, methods: { fetchContext() { this.contextFetching = true; diff --git a/src/client/app/desktop/views/components/posts.post.vue b/src/client/app/desktop/views/components/posts.post.vue index aa1f1db41c..f3566c81bf 100644 --- a/src/client/app/desktop/views/components/posts.post.vue +++ b/src/client/app/desktop/views/components/posts.post.vue @@ -38,7 +38,7 @@

@@ -112,7 +112,8 @@ export default Vue.extend({ return { isDetailOpened: false, connection: null, - connectionId: null + connectionId: null, + urls: [] }; }, computed: { @@ -140,15 +141,6 @@ export default Vue.extend({ }, url(): string { return `/@${this.acct}/${this.p.id}`; - }, - urls(): string[] { - if (this.p.ast) { - return this.p.ast - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => t.url); - } else { - return null; - } } }, created() { @@ -190,6 +182,21 @@ export default Vue.extend({ (this as any).os.stream.dispose(this.connectionId); } }, + watch: { + post: { + handler(newPost, oldPost) { + if (!oldPost || newPost.textHtml !== oldPost.textHtml) { + this.$nextTick(() => { + const elements = this.$refs.text.$el.getElementsByTagName('a'); + + this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) + .map(({ href }) => href); + }); + } + }, + immediate: true + } + }, methods: { capture(withHandler = false) { if ((this as any).os.isSignedIn) { @@ -450,7 +457,7 @@ export default Vue.extend({ font-size 1.1em color #717171 - >>> .quote + >>> blockquote margin 8px padding 6px 12px color #aaa diff --git a/src/client/app/desktop/views/components/sub-post-content.vue b/src/client/app/desktop/views/components/sub-post-content.vue index 1f5ce38984..58c81e7552 100644 --- a/src/client/app/desktop/views/components/sub-post-content.vue +++ b/src/client/app/desktop/views/components/sub-post-content.vue @@ -2,7 +2,7 @@
diff --git a/src/client/app/mobile/views/components/post-detail.vue b/src/client/app/mobile/views/components/post-detail.vue index 6411011b89..77a73426f2 100644 --- a/src/client/app/mobile/views/components/post-detail.vue +++ b/src/client/app/mobile/views/components/post-detail.vue @@ -38,7 +38,7 @@
- +
{{ tag }}
@@ -103,6 +103,7 @@ export default Vue.extend({ context: [], contextFetching: false, replies: [], + urls: [] }; }, computed: { @@ -127,15 +128,6 @@ export default Vue.extend({ .map(key => this.p.reactionCounts[key]) .reduce((a, b) => a + b) : 0; - }, - urls(): string[] { - if (this.p.ast) { - return this.p.ast - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => t.url); - } else { - return null; - } } }, mounted() { @@ -167,6 +159,21 @@ export default Vue.extend({ } } }, + watch: { + post: { + handler(newPost, oldPost) { + if (!oldPost || newPost.text !== oldPost.text) { + this.$nextTick(() => { + const elements = this.$refs.text.$el.getElementsByTagName('a'); + + this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) + .map(({ href }) => href); + }); + } + }, + immediate: true + } + }, methods: { fetchContext() { this.contextFetching = true; diff --git a/src/client/app/mobile/views/components/post.vue b/src/client/app/mobile/views/components/post.vue index 52fb095372..96ec9632f1 100644 --- a/src/client/app/mobile/views/components/post.vue +++ b/src/client/app/mobile/views/components/post.vue @@ -37,7 +37,7 @@ %fa:reply% - + RP:
@@ -90,7 +90,8 @@ export default Vue.extend({ data() { return { connection: null, - connectionId: null + connectionId: null, + urls: [] }; }, computed: { @@ -118,15 +119,6 @@ export default Vue.extend({ }, url(): string { return `/@${this.pAcct}/${this.p.id}`; - }, - urls(): string[] { - if (this.p.ast) { - return this.p.ast - .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) - .map(t => t.url); - } else { - return null; - } } }, created() { @@ -168,6 +160,21 @@ export default Vue.extend({ (this as any).os.stream.dispose(this.connectionId); } }, + watch: { + post: { + handler(newPost, oldPost) { + if (!oldPost || newPost.text !== oldPost.text) { + this.$nextTick(() => { + const elements = this.$refs.text.$el.getElementsByTagName('a'); + + this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) + .map(({ href }) => href); + }); + } + }, + immediate: true + } + }, methods: { capture(withHandler = false) { if ((this as any).os.isSignedIn) { @@ -389,7 +396,7 @@ export default Vue.extend({ font-size 1.1em color #717171 - >>> .quote + >>> blockquote margin 8px padding 6px 12px color #aaa diff --git a/src/client/app/mobile/views/components/sub-post-content.vue b/src/client/app/mobile/views/components/sub-post-content.vue index 5ff88089aa..955bb406b4 100644 --- a/src/client/app/mobile/views/components/sub-post-content.vue +++ b/src/client/app/mobile/views/components/sub-post-content.vue @@ -2,7 +2,7 @@
diff --git a/src/client/docs/api/entities/post.yaml b/src/client/docs/api/entities/post.yaml index da79866ba1..7077700129 100644 --- a/src/client/docs/api/entities/post.yaml +++ b/src/client/docs/api/entities/post.yaml @@ -27,8 +27,14 @@ props: type: "string" optional: true desc: - ja: "投稿の本文" - en: "The text of this post" + ja: "投稿の本文 (ローカルの場合Markdown風のフォーマット)" + en: "The text of this post (in Markdown like format if local)" + - name: "textHtml" + type: "string" + optional: true + desc: + ja: "投稿の本文 (HTML) (投稿時は無視)" + en: "The text of this post (in HTML. Ignored when posting.)" - name: "mediaIds" type: "id(DriveFile)[]" optional: true diff --git a/src/common/text/core/syntax-highlighter.ts b/src/common/text/core/syntax-highlighter.ts deleted file mode 100644 index c0396b1fc6..0000000000 --- a/src/common/text/core/syntax-highlighter.ts +++ /dev/null @@ -1,334 +0,0 @@ -function escape(text) { - return text - .replace(/>/g, '>') - .replace(/ k[0].toUpperCase() + k.substr(1))) - .concat(_keywords.map(k => k.toUpperCase())) - .sort((a, b) => b.length - a.length); - -const symbols = [ - '=', - '+', - '-', - '*', - '/', - '%', - '~', - '^', - '&', - '|', - '>', - '<', - '!', - '?' -]; - -const elements = [ - // comment - code => { - if (code.substr(0, 2) != '//') return null; - const match = code.match(/^\/\/(.+?)(\n|$)/); - if (!match) return null; - const comment = match[0]; - return { - html: `${escape(comment)}`, - next: comment.length - }; - }, - - // block comment - code => { - const match = code.match(/^\/\*([\s\S]+?)\*\//); - if (!match) return null; - return { - html: `${escape(match[0])}`, - next: match[0].length - }; - }, - - // string - code => { - if (!/^['"`]/.test(code)) return null; - const begin = code[0]; - let str = begin; - let thisIsNotAString = false; - for (let i = 1; i < code.length; i++) { - const char = code[i]; - if (char == '\\') { - str += char; - str += code[i + 1] || ''; - i++; - continue; - } else if (char == begin) { - str += char; - break; - } else if (char == '\n' || i == (code.length - 1)) { - thisIsNotAString = true; - break; - } else { - str += char; - } - } - if (thisIsNotAString) { - return null; - } else { - return { - html: `${escape(str)}`, - next: str.length - }; - } - }, - - // regexp - code => { - if (code[0] != '/') return null; - let regexp = ''; - let thisIsNotARegexp = false; - for (let i = 1; i < code.length; i++) { - const char = code[i]; - if (char == '\\') { - regexp += char; - regexp += code[i + 1] || ''; - i++; - continue; - } else if (char == '/') { - break; - } else if (char == '\n' || i == (code.length - 1)) { - thisIsNotARegexp = true; - break; - } else { - regexp += char; - } - } - - if (thisIsNotARegexp) return null; - if (regexp == '') return null; - if (regexp[0] == ' ' && regexp[regexp.length - 1] == ' ') return null; - - return { - html: `/${escape(regexp)}/`, - next: regexp.length + 2 - }; - }, - - // label - code => { - if (code[0] != '@') return null; - const match = code.match(/^@([a-zA-Z_-]+?)\n/); - if (!match) return null; - const label = match[0]; - return { - html: `${label}`, - next: label.length - }; - }, - - // number - (code, i, source) => { - const prev = source[i - 1]; - if (prev && /[a-zA-Z]/.test(prev)) return null; - if (!/^[\-\+]?[0-9\.]+/.test(code)) return null; - const match = code.match(/^[\-\+]?[0-9\.]+/)[0]; - if (match) { - return { - html: `${match}`, - next: match.length - }; - } else { - return null; - } - }, - - // nan - (code, i, source) => { - const prev = source[i - 1]; - if (prev && /[a-zA-Z]/.test(prev)) return null; - if (code.substr(0, 3) == 'NaN') { - return { - html: `NaN`, - next: 3 - }; - } else { - return null; - } - }, - - // method - code => { - const match = code.match(/^([a-zA-Z_-]+?)\(/); - if (!match) return null; - - if (match[1] == '-') return null; - - return { - html: `${match[1]}`, - next: match[1].length - }; - }, - - // property - (code, i, source) => { - const prev = source[i - 1]; - if (prev != '.') return null; - - const match = code.match(/^[a-zA-Z0-9_-]+/); - if (!match) return null; - - return { - html: `${match[0]}`, - next: match[0].length - }; - }, - - // keyword - (code, i, source) => { - const prev = source[i - 1]; - if (prev && /[a-zA-Z]/.test(prev)) return null; - - const match = keywords.filter(k => code.substr(0, k.length) == k)[0]; - if (match) { - if (/^[a-zA-Z]/.test(code.substr(match.length))) return null; - return { - html: `${match}`, - next: match.length - }; - } else { - return null; - } - }, - - // symbol - code => { - const match = symbols.filter(s => code[0] == s)[0]; - if (match) { - return { - html: `${match}`, - next: 1 - }; - } else { - return null; - } - } -]; - -// specify lang is todo -export default (source: string, lang?: string) => { - let code = source; - let html = ''; - - let i = 0; - - function push(token) { - html += token.html; - code = code.substr(token.next); - i += token.next; - } - - while (code != '') { - const parsed = elements.some(el => { - const e = el(code, i, source); - if (e) { - push(e); - return true; - } else { - return false; - } - }); - - if (!parsed) { - push({ - html: escape(code[0]), - next: 1 - }); - } - } - - return html; -}; diff --git a/src/common/text/elements/bold.ts b/src/common/text/elements/bold.ts deleted file mode 100644 index ce25764457..0000000000 --- a/src/common/text/elements/bold.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Bold - */ - -module.exports = text => { - const match = text.match(/^\*\*(.+?)\*\*/); - if (!match) return null; - const bold = match[0]; - return { - type: 'bold', - content: bold, - bold: bold.substr(2, bold.length - 4) - }; -}; diff --git a/src/common/text/elements/code.ts b/src/common/text/elements/code.ts deleted file mode 100644 index 4821e95fe2..0000000000 --- a/src/common/text/elements/code.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Code (block) - */ - -import genHtml from '../core/syntax-highlighter'; - -module.exports = text => { - const match = text.match(/^```([\s\S]+?)```/); - if (!match) return null; - const code = match[0]; - return { - type: 'code', - content: code, - code: code.substr(3, code.length - 6).trim(), - html: genHtml(code.substr(3, code.length - 6).trim()) - }; -}; diff --git a/src/common/text/elements/emoji.ts b/src/common/text/elements/emoji.ts deleted file mode 100644 index e24231a223..0000000000 --- a/src/common/text/elements/emoji.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Emoji - */ - -module.exports = text => { - const match = text.match(/^:[a-zA-Z0-9+-_]+:/); - if (!match) return null; - const emoji = match[0]; - return { - type: 'emoji', - content: emoji, - emoji: emoji.substr(1, emoji.length - 2) - }; -}; diff --git a/src/common/text/elements/hashtag.ts b/src/common/text/elements/hashtag.ts deleted file mode 100644 index ee57b140b8..0000000000 --- a/src/common/text/elements/hashtag.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Hashtag - */ - -module.exports = (text, i) => { - if (!(/^\s#[^\s]+/.test(text) || (i == 0 && /^#[^\s]+/.test(text)))) return null; - const isHead = text[0] == '#'; - const hashtag = text.match(/^\s?#[^\s]+/)[0]; - const res: any[] = !isHead ? [{ - type: 'text', - content: text[0] - }] : []; - res.push({ - type: 'hashtag', - content: isHead ? hashtag : hashtag.substr(1), - hashtag: isHead ? hashtag.substr(1) : hashtag.substr(2) - }); - return res; -}; diff --git a/src/common/text/elements/inline-code.ts b/src/common/text/elements/inline-code.ts deleted file mode 100644 index 9f9ef51a2b..0000000000 --- a/src/common/text/elements/inline-code.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Code (inline) - */ - -import genHtml from '../core/syntax-highlighter'; - -module.exports = text => { - const match = text.match(/^`(.+?)`/); - if (!match) return null; - const code = match[0]; - return { - type: 'inline-code', - content: code, - code: code.substr(1, code.length - 2).trim(), - html: genHtml(code.substr(1, code.length - 2).trim()) - }; -}; diff --git a/src/common/text/elements/link.ts b/src/common/text/elements/link.ts deleted file mode 100644 index 35563ddc3d..0000000000 --- a/src/common/text/elements/link.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * Link - */ - -module.exports = text => { - const match = text.match(/^\??\[([^\[\]]+?)\]\((https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+?)\)/); - if (!match) return null; - const silent = text[0] == '?'; - const link = match[0]; - const title = match[1]; - const url = match[2]; - return { - type: 'link', - content: link, - title: title, - url: url, - silent: silent - }; -}; diff --git a/src/common/text/elements/mention.ts b/src/common/text/elements/mention.ts deleted file mode 100644 index d05a76649d..0000000000 --- a/src/common/text/elements/mention.ts +++ /dev/null @@ -1,17 +0,0 @@ -/** - * Mention - */ -import parseAcct from '../../../common/user/parse-acct'; - -module.exports = text => { - const match = text.match(/^(?:@[a-zA-Z0-9\-]+){1,2}/); - if (!match) return null; - const mention = match[0]; - const { username, host } = parseAcct(mention.substr(1)); - return { - type: 'mention', - content: mention, - username, - host - }; -}; diff --git a/src/common/text/elements/quote.ts b/src/common/text/elements/quote.ts deleted file mode 100644 index cc8cfffdc4..0000000000 --- a/src/common/text/elements/quote.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * Quoted text - */ - -module.exports = text => { - const match = text.match(/^"([\s\S]+?)\n"/); - if (!match) return null; - const quote = match[0]; - return { - type: 'quote', - content: quote, - quote: quote.substr(1, quote.length - 2).trim(), - }; -}; diff --git a/src/common/text/elements/url.ts b/src/common/text/elements/url.ts deleted file mode 100644 index 1003aff9c3..0000000000 --- a/src/common/text/elements/url.ts +++ /dev/null @@ -1,14 +0,0 @@ -/** - * URL - */ - -module.exports = text => { - const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+/); - if (!match) return null; - const url = match[0]; - return { - type: 'url', - content: url, - url: url - }; -}; diff --git a/src/common/text/html.ts b/src/common/text/html.ts new file mode 100644 index 0000000000..797f3b3f33 --- /dev/null +++ b/src/common/text/html.ts @@ -0,0 +1,83 @@ +import { lib as emojilib } from 'emojilib'; +import { JSDOM } from 'jsdom'; + +const handlers = { + bold({ document }, { bold }) { + const b = document.createElement('b'); + b.textContent = bold; + document.body.appendChild(b); + }, + + code({ document }, { code }) { + const pre = document.createElement('pre'); + const inner = document.createElement('code'); + inner.innerHTML = code; + pre.appendChild(inner); + document.body.appendChild(pre); + }, + + emoji({ document }, { content, emoji }) { + const found = emojilib[emoji]; + const node = document.createTextNode(found ? found.char : content); + document.body.appendChild(node); + }, + + hashtag({ document }, { hashtag }) { + const a = document.createElement('a'); + a.href = '/search?q=#' + hashtag; + a.textContent = hashtag; + }, + + 'inline-code'({ document }, { code }) { + const element = document.createElement('code'); + element.textContent = code; + document.body.appendChild(element); + }, + + link({ document }, { url, title }) { + const a = document.createElement('a'); + a.href = url; + a.textContent = title; + document.body.appendChild(a); + }, + + mention({ document }, { content }) { + const a = document.createElement('a'); + a.href = '/' + content; + a.textContent = content; + document.body.appendChild(a); + }, + + quote({ document }, { quote }) { + const blockquote = document.createElement('blockquote'); + blockquote.textContent = quote; + document.body.appendChild(blockquote); + }, + + text({ document }, { content }) { + for (const text of content.split('\n')) { + const node = document.createTextNode(text); + document.body.appendChild(node); + + const br = document.createElement('br'); + document.body.appendChild(br); + } + }, + + url({ document }, { url }) { + const a = document.createElement('a'); + a.href = url; + a.textContent = url; + document.body.appendChild(a); + } +}; + +export default tokens => { + const { window } = new JSDOM(''); + + for (const token of tokens) { + handlers[token.type](window, token); + } + + return `

${window.document.body.innerHTML}

`; +}; diff --git a/src/common/text/index.ts b/src/common/text/index.ts deleted file mode 100644 index 1e2398dc38..0000000000 --- a/src/common/text/index.ts +++ /dev/null @@ -1,72 +0,0 @@ -/** - * Misskey Text Analyzer - */ - -const elements = [ - require('./elements/bold'), - require('./elements/url'), - require('./elements/link'), - require('./elements/mention'), - require('./elements/hashtag'), - require('./elements/code'), - require('./elements/inline-code'), - require('./elements/quote'), - require('./elements/emoji') -]; - -export default (source: string) => { - - if (source == '') { - return null; - } - - const tokens = []; - - function push(token) { - if (token != null) { - tokens.push(token); - source = source.substr(token.content.length); - } - } - - let i = 0; - - // パース - while (source != '') { - const parsed = elements.some(el => { - let _tokens = el(source, i); - if (_tokens) { - if (!Array.isArray(_tokens)) { - _tokens = [_tokens]; - } - _tokens.forEach(push); - return true; - } else { - return false; - } - }); - - if (!parsed) { - push({ - type: 'text', - content: source[0] - }); - } - - i++; - } - - // テキストを纏める - tokens[0] = [tokens[0]]; - return tokens.reduce((a, b) => { - if (a[a.length - 1].type == 'text' && b.type == 'text') { - const tail = a.pop(); - return a.concat({ - type: 'text', - content: tail.content + b.content - }); - } else { - return a.concat(b); - } - }); -}; diff --git a/src/common/text/parse/core/syntax-highlighter.ts b/src/common/text/parse/core/syntax-highlighter.ts new file mode 100644 index 0000000000..c0396b1fc6 --- /dev/null +++ b/src/common/text/parse/core/syntax-highlighter.ts @@ -0,0 +1,334 @@ +function escape(text) { + return text + .replace(/>/g, '>') + .replace(/ k[0].toUpperCase() + k.substr(1))) + .concat(_keywords.map(k => k.toUpperCase())) + .sort((a, b) => b.length - a.length); + +const symbols = [ + '=', + '+', + '-', + '*', + '/', + '%', + '~', + '^', + '&', + '|', + '>', + '<', + '!', + '?' +]; + +const elements = [ + // comment + code => { + if (code.substr(0, 2) != '//') return null; + const match = code.match(/^\/\/(.+?)(\n|$)/); + if (!match) return null; + const comment = match[0]; + return { + html: `${escape(comment)}`, + next: comment.length + }; + }, + + // block comment + code => { + const match = code.match(/^\/\*([\s\S]+?)\*\//); + if (!match) return null; + return { + html: `${escape(match[0])}`, + next: match[0].length + }; + }, + + // string + code => { + if (!/^['"`]/.test(code)) return null; + const begin = code[0]; + let str = begin; + let thisIsNotAString = false; + for (let i = 1; i < code.length; i++) { + const char = code[i]; + if (char == '\\') { + str += char; + str += code[i + 1] || ''; + i++; + continue; + } else if (char == begin) { + str += char; + break; + } else if (char == '\n' || i == (code.length - 1)) { + thisIsNotAString = true; + break; + } else { + str += char; + } + } + if (thisIsNotAString) { + return null; + } else { + return { + html: `${escape(str)}`, + next: str.length + }; + } + }, + + // regexp + code => { + if (code[0] != '/') return null; + let regexp = ''; + let thisIsNotARegexp = false; + for (let i = 1; i < code.length; i++) { + const char = code[i]; + if (char == '\\') { + regexp += char; + regexp += code[i + 1] || ''; + i++; + continue; + } else if (char == '/') { + break; + } else if (char == '\n' || i == (code.length - 1)) { + thisIsNotARegexp = true; + break; + } else { + regexp += char; + } + } + + if (thisIsNotARegexp) return null; + if (regexp == '') return null; + if (regexp[0] == ' ' && regexp[regexp.length - 1] == ' ') return null; + + return { + html: `/${escape(regexp)}/`, + next: regexp.length + 2 + }; + }, + + // label + code => { + if (code[0] != '@') return null; + const match = code.match(/^@([a-zA-Z_-]+?)\n/); + if (!match) return null; + const label = match[0]; + return { + html: `${label}`, + next: label.length + }; + }, + + // number + (code, i, source) => { + const prev = source[i - 1]; + if (prev && /[a-zA-Z]/.test(prev)) return null; + if (!/^[\-\+]?[0-9\.]+/.test(code)) return null; + const match = code.match(/^[\-\+]?[0-9\.]+/)[0]; + if (match) { + return { + html: `${match}`, + next: match.length + }; + } else { + return null; + } + }, + + // nan + (code, i, source) => { + const prev = source[i - 1]; + if (prev && /[a-zA-Z]/.test(prev)) return null; + if (code.substr(0, 3) == 'NaN') { + return { + html: `NaN`, + next: 3 + }; + } else { + return null; + } + }, + + // method + code => { + const match = code.match(/^([a-zA-Z_-]+?)\(/); + if (!match) return null; + + if (match[1] == '-') return null; + + return { + html: `${match[1]}`, + next: match[1].length + }; + }, + + // property + (code, i, source) => { + const prev = source[i - 1]; + if (prev != '.') return null; + + const match = code.match(/^[a-zA-Z0-9_-]+/); + if (!match) return null; + + return { + html: `${match[0]}`, + next: match[0].length + }; + }, + + // keyword + (code, i, source) => { + const prev = source[i - 1]; + if (prev && /[a-zA-Z]/.test(prev)) return null; + + const match = keywords.filter(k => code.substr(0, k.length) == k)[0]; + if (match) { + if (/^[a-zA-Z]/.test(code.substr(match.length))) return null; + return { + html: `${match}`, + next: match.length + }; + } else { + return null; + } + }, + + // symbol + code => { + const match = symbols.filter(s => code[0] == s)[0]; + if (match) { + return { + html: `${match}`, + next: 1 + }; + } else { + return null; + } + } +]; + +// specify lang is todo +export default (source: string, lang?: string) => { + let code = source; + let html = ''; + + let i = 0; + + function push(token) { + html += token.html; + code = code.substr(token.next); + i += token.next; + } + + while (code != '') { + const parsed = elements.some(el => { + const e = el(code, i, source); + if (e) { + push(e); + return true; + } else { + return false; + } + }); + + if (!parsed) { + push({ + html: escape(code[0]), + next: 1 + }); + } + } + + return html; +}; diff --git a/src/common/text/parse/elements/bold.ts b/src/common/text/parse/elements/bold.ts new file mode 100644 index 0000000000..ce25764457 --- /dev/null +++ b/src/common/text/parse/elements/bold.ts @@ -0,0 +1,14 @@ +/** + * Bold + */ + +module.exports = text => { + const match = text.match(/^\*\*(.+?)\*\*/); + if (!match) return null; + const bold = match[0]; + return { + type: 'bold', + content: bold, + bold: bold.substr(2, bold.length - 4) + }; +}; diff --git a/src/common/text/parse/elements/code.ts b/src/common/text/parse/elements/code.ts new file mode 100644 index 0000000000..4821e95fe2 --- /dev/null +++ b/src/common/text/parse/elements/code.ts @@ -0,0 +1,17 @@ +/** + * Code (block) + */ + +import genHtml from '../core/syntax-highlighter'; + +module.exports = text => { + const match = text.match(/^```([\s\S]+?)```/); + if (!match) return null; + const code = match[0]; + return { + type: 'code', + content: code, + code: code.substr(3, code.length - 6).trim(), + html: genHtml(code.substr(3, code.length - 6).trim()) + }; +}; diff --git a/src/common/text/parse/elements/emoji.ts b/src/common/text/parse/elements/emoji.ts new file mode 100644 index 0000000000..e24231a223 --- /dev/null +++ b/src/common/text/parse/elements/emoji.ts @@ -0,0 +1,14 @@ +/** + * Emoji + */ + +module.exports = text => { + const match = text.match(/^:[a-zA-Z0-9+-_]+:/); + if (!match) return null; + const emoji = match[0]; + return { + type: 'emoji', + content: emoji, + emoji: emoji.substr(1, emoji.length - 2) + }; +}; diff --git a/src/common/text/parse/elements/hashtag.ts b/src/common/text/parse/elements/hashtag.ts new file mode 100644 index 0000000000..ee57b140b8 --- /dev/null +++ b/src/common/text/parse/elements/hashtag.ts @@ -0,0 +1,19 @@ +/** + * Hashtag + */ + +module.exports = (text, i) => { + if (!(/^\s#[^\s]+/.test(text) || (i == 0 && /^#[^\s]+/.test(text)))) return null; + const isHead = text[0] == '#'; + const hashtag = text.match(/^\s?#[^\s]+/)[0]; + const res: any[] = !isHead ? [{ + type: 'text', + content: text[0] + }] : []; + res.push({ + type: 'hashtag', + content: isHead ? hashtag : hashtag.substr(1), + hashtag: isHead ? hashtag.substr(1) : hashtag.substr(2) + }); + return res; +}; diff --git a/src/common/text/parse/elements/inline-code.ts b/src/common/text/parse/elements/inline-code.ts new file mode 100644 index 0000000000..9f9ef51a2b --- /dev/null +++ b/src/common/text/parse/elements/inline-code.ts @@ -0,0 +1,17 @@ +/** + * Code (inline) + */ + +import genHtml from '../core/syntax-highlighter'; + +module.exports = text => { + const match = text.match(/^`(.+?)`/); + if (!match) return null; + const code = match[0]; + return { + type: 'inline-code', + content: code, + code: code.substr(1, code.length - 2).trim(), + html: genHtml(code.substr(1, code.length - 2).trim()) + }; +}; diff --git a/src/common/text/parse/elements/link.ts b/src/common/text/parse/elements/link.ts new file mode 100644 index 0000000000..35563ddc3d --- /dev/null +++ b/src/common/text/parse/elements/link.ts @@ -0,0 +1,19 @@ +/** + * Link + */ + +module.exports = text => { + const match = text.match(/^\??\[([^\[\]]+?)\]\((https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+?)\)/); + if (!match) return null; + const silent = text[0] == '?'; + const link = match[0]; + const title = match[1]; + const url = match[2]; + return { + type: 'link', + content: link, + title: title, + url: url, + silent: silent + }; +}; diff --git a/src/common/text/parse/elements/mention.ts b/src/common/text/parse/elements/mention.ts new file mode 100644 index 0000000000..2025dfdaad --- /dev/null +++ b/src/common/text/parse/elements/mention.ts @@ -0,0 +1,17 @@ +/** + * Mention + */ +import parseAcct from '../../../../common/user/parse-acct'; + +module.exports = text => { + const match = text.match(/^(?:@[a-zA-Z0-9\-]+){1,2}/); + if (!match) return null; + const mention = match[0]; + const { username, host } = parseAcct(mention.substr(1)); + return { + type: 'mention', + content: mention, + username, + host + }; +}; diff --git a/src/common/text/parse/elements/quote.ts b/src/common/text/parse/elements/quote.ts new file mode 100644 index 0000000000..cc8cfffdc4 --- /dev/null +++ b/src/common/text/parse/elements/quote.ts @@ -0,0 +1,14 @@ +/** + * Quoted text + */ + +module.exports = text => { + const match = text.match(/^"([\s\S]+?)\n"/); + if (!match) return null; + const quote = match[0]; + return { + type: 'quote', + content: quote, + quote: quote.substr(1, quote.length - 2).trim(), + }; +}; diff --git a/src/common/text/parse/elements/url.ts b/src/common/text/parse/elements/url.ts new file mode 100644 index 0000000000..1003aff9c3 --- /dev/null +++ b/src/common/text/parse/elements/url.ts @@ -0,0 +1,14 @@ +/** + * URL + */ + +module.exports = text => { + const match = text.match(/^https?:\/\/[\w\/:%#@\$&\?!\(\)\[\]~\.=\+\-]+/); + if (!match) return null; + const url = match[0]; + return { + type: 'url', + content: url, + url: url + }; +}; diff --git a/src/common/text/parse/index.ts b/src/common/text/parse/index.ts new file mode 100644 index 0000000000..1e2398dc38 --- /dev/null +++ b/src/common/text/parse/index.ts @@ -0,0 +1,72 @@ +/** + * Misskey Text Analyzer + */ + +const elements = [ + require('./elements/bold'), + require('./elements/url'), + require('./elements/link'), + require('./elements/mention'), + require('./elements/hashtag'), + require('./elements/code'), + require('./elements/inline-code'), + require('./elements/quote'), + require('./elements/emoji') +]; + +export default (source: string) => { + + if (source == '') { + return null; + } + + const tokens = []; + + function push(token) { + if (token != null) { + tokens.push(token); + source = source.substr(token.content.length); + } + } + + let i = 0; + + // パース + while (source != '') { + const parsed = elements.some(el => { + let _tokens = el(source, i); + if (_tokens) { + if (!Array.isArray(_tokens)) { + _tokens = [_tokens]; + } + _tokens.forEach(push); + return true; + } else { + return false; + } + }); + + if (!parsed) { + push({ + type: 'text', + content: source[0] + }); + } + + i++; + } + + // テキストを纏める + tokens[0] = [tokens[0]]; + return tokens.reduce((a, b) => { + if (a[a.length - 1].type == 'text' && b.type == 'text') { + const tail = a.pop(); + return a.concat({ + type: 'text', + content: tail.content + b.content + }); + } else { + return a.concat(b); + } + }); +}; diff --git a/src/models/messaging-message.ts b/src/models/messaging-message.ts index 8bee657c34..974ee54ab8 100644 --- a/src/models/messaging-message.ts +++ b/src/models/messaging-message.ts @@ -3,7 +3,6 @@ import deepcopy = require('deepcopy'); import { pack as packUser } from './user'; import { pack as packFile } from './drive-file'; import db from '../db/mongodb'; -import parse from '../common/text'; const MessagingMessage = db.get('messagingMessages'); export default MessagingMessage; @@ -12,6 +11,7 @@ export interface IMessagingMessage { _id: mongo.ObjectID; createdAt: Date; text: string; + textHtml: string; userId: mongo.ObjectID; recipientId: mongo.ObjectID; isRead: boolean; @@ -60,11 +60,6 @@ export const pack = ( _message.id = _message._id; delete _message._id; - // Parse text - if (_message.text) { - _message.ast = parse(_message.text); - } - // Populate user _message.user = await packUser(_message.userId, me); diff --git a/src/models/post.ts b/src/models/post.ts index 9bc0c1d3b9..6c853e4f81 100644 --- a/src/models/post.ts +++ b/src/models/post.ts @@ -8,7 +8,6 @@ import { pack as packChannel } from './channel'; import Vote from './poll-vote'; import Reaction from './post-reaction'; import { pack as packFile } from './drive-file'; -import parse from '../common/text'; const Post = db.get('posts'); @@ -31,6 +30,7 @@ export type IPost = { repostId: mongo.ObjectID; poll: any; // todo text: string; + textHtml: string; cw: string; userId: mongo.ObjectID; appId: mongo.ObjectID; @@ -103,11 +103,6 @@ export const pack = async ( delete _post.mentions; if (_post.geo) delete _post.geo.type; - // Parse text - if (_post.text) { - _post.ast = parse(_post.text); - } - // Populate user _post.user = packUser(_post.userId, meId); diff --git a/src/server/api/endpoints/messaging/messages/create.ts b/src/server/api/endpoints/messaging/messages/create.ts index d8ffa9fdec..3d3b204da5 100644 --- a/src/server/api/endpoints/messaging/messages/create.ts +++ b/src/server/api/endpoints/messaging/messages/create.ts @@ -11,6 +11,8 @@ import DriveFile from '../../../../../models/drive-file'; import { pack } from '../../../../../models/messaging-message'; import publishUserStream from '../../../event'; import { publishMessagingStream, publishMessagingIndexStream, pushSw } from '../../../event'; +import html from '../../../../../common/text/html'; +import parse from '../../../../../common/text/parse'; import config from '../../../../../conf'; /** @@ -74,6 +76,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { fileId: file ? file._id : undefined, recipientId: recipient._id, text: text ? text : undefined, + textHtml: text ? html(parse(text)) : undefined, userId: user._id, isRead: false }); diff --git a/src/server/api/endpoints/posts/create.ts b/src/server/api/endpoints/posts/create.ts index aa7e93c28f..5342f77728 100644 --- a/src/server/api/endpoints/posts/create.ts +++ b/src/server/api/endpoints/posts/create.ts @@ -3,7 +3,8 @@ */ import $ from 'cafy'; import deepEqual = require('deep-equal'); -import parse from '../../../../common/text'; +import html from '../../../../common/text/html'; +import parse from '../../../../common/text/parse'; import { default as Post, IPost, isValidText, isValidCw } from '../../../../models/post'; import { default as User, ILocalAccount, IUser } from '../../../../models/user'; import { default as Channel, IChannel } from '../../../../models/channel'; @@ -259,6 +260,7 @@ module.exports = (params, user: IUser, app) => new Promise(async (res, rej) => { repostId: repost ? repost._id : undefined, poll: poll, text: text, + textHtml: tokens === null ? null : html(tokens), cw: cw, tags: tags, userId: user._id, diff --git a/tools/migration/nighthike/7.js b/tools/migration/nighthike/7.js new file mode 100644 index 0000000000..c5055da8ba --- /dev/null +++ b/tools/migration/nighthike/7.js @@ -0,0 +1,16 @@ +// for Node.js interpretation + +const Message = require('../../../built/models/messaging-message').default; +const Post = require('../../../built/models/post').default; +const html = require('../../../built/common/text/html').default; +const parse = require('../../../built/common/text/parse').default; + +Promise.all([Message, Post].map(async model => { + const documents = await model.find(); + + return Promise.all(documents.map(({ _id, text }) => model.update(_id, { + $set: { + textHtml: html(parse(text)) + } + }))); +})).catch(console.error).then(process.exit); -- cgit v1.3.1-freya From 3178bb20c72380c4379e7b72afa7e468d24e3e97 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sat, 31 Mar 2018 21:41:08 +0900 Subject: Use Vue rendering function and some refactors --- src/client/app/common/views/components/index.ts | 2 +- .../views/components/messaging-room.message.vue | 41 +++--- .../app/common/views/components/post-html.ts | 157 +++++++++++++++++++++ .../app/common/views/components/post-html.vue | 103 -------------- src/client/app/common/views/components/url.vue | 57 ++++++++ .../common/views/components/welcome-timeline.vue | 2 +- .../desktop/views/components/post-detail.sub.vue | 2 +- .../app/desktop/views/components/post-detail.vue | 42 +++--- .../app/desktop/views/components/posts.post.vue | 43 +++--- .../desktop/views/components/sub-post-content.vue | 2 +- .../app/mobile/views/components/post-detail.vue | 37 ++--- src/client/app/mobile/views/components/post.vue | 45 +++--- .../mobile/views/components/sub-post-content.vue | 2 +- src/common/text/parse/index.ts | 2 +- 14 files changed, 324 insertions(+), 213 deletions(-) create mode 100644 src/client/app/common/views/components/post-html.ts delete mode 100644 src/client/app/common/views/components/post-html.vue create mode 100644 src/client/app/common/views/components/url.vue (limited to 'src/client/app/desktop') diff --git a/src/client/app/common/views/components/index.ts b/src/client/app/common/views/components/index.ts index 8c10bdee28..b58ba37ecb 100644 --- a/src/client/app/common/views/components/index.ts +++ b/src/client/app/common/views/components/index.ts @@ -4,7 +4,7 @@ import signin from './signin.vue'; import signup from './signup.vue'; import forkit from './forkit.vue'; import nav from './nav.vue'; -import postHtml from './post-html.vue'; +import postHtml from './post-html'; import poll from './poll.vue'; import pollEditor from './poll-editor.vue'; import reactionIcon from './reaction-icon.vue'; diff --git a/src/client/app/common/views/components/messaging-room.message.vue b/src/client/app/common/views/components/messaging-room.message.vue index 25ceab85a1..91af26bffe 100644 --- a/src/client/app/common/views/components/messaging-room.message.vue +++ b/src/client/app/common/views/components/messaging-room.message.vue @@ -4,13 +4,13 @@
-
+

%i18n:common.tags.mk-messaging-message.is-read%

- +
@@ -35,35 +35,30 @@ - - diff --git a/src/client/app/common/views/components/url.vue b/src/client/app/common/views/components/url.vue new file mode 100644 index 0000000000..e6ffe4466d --- /dev/null +++ b/src/client/app/common/views/components/url.vue @@ -0,0 +1,57 @@ + + + + + diff --git a/src/client/app/common/views/components/welcome-timeline.vue b/src/client/app/common/views/components/welcome-timeline.vue index f379029f9f..09b090bdc1 100644 --- a/src/client/app/common/views/components/welcome-timeline.vue +++ b/src/client/app/common/views/components/welcome-timeline.vue @@ -15,7 +15,7 @@
- +
diff --git a/src/client/app/desktop/views/components/post-detail.sub.vue b/src/client/app/desktop/views/components/post-detail.sub.vue index b6148d9b28..1d5649cf92 100644 --- a/src/client/app/desktop/views/components/post-detail.sub.vue +++ b/src/client/app/desktop/views/components/post-detail.sub.vue @@ -16,7 +16,7 @@
- +
diff --git a/src/client/app/desktop/views/components/post-detail.vue b/src/client/app/desktop/views/components/post-detail.vue index e75ebe34b4..70bfdbba35 100644 --- a/src/client/app/desktop/views/components/post-detail.vue +++ b/src/client/app/desktop/views/components/post-detail.vue @@ -38,7 +38,7 @@
- +
@@ -79,6 +79,7 @@ import Vue from 'vue'; import dateStringify from '../../../common/scripts/date-stringify'; import getAcct from '../../../../../common/user/get-acct'; +import parse from '../../../../../common/text/parse'; import MkPostFormWindow from './post-form-window.vue'; import MkRepostFormWindow from './repost-form-window.vue'; @@ -90,6 +91,7 @@ export default Vue.extend({ components: { XSub }, + props: { post: { type: Object, @@ -99,19 +101,15 @@ export default Vue.extend({ default: false } }, - computed: { - acct() { - return getAcct(this.post.user); - } - }, + data() { return { context: [], contextFetching: false, - replies: [], - urls: [] + replies: [] }; }, + computed: { isRepost(): boolean { return (this.post.repost && @@ -131,8 +129,22 @@ export default Vue.extend({ }, title(): string { return dateStringify(this.p.createdAt); + }, + acct(): string { + return getAcct(this.p.user); + }, + urls(): string[] { + if (this.p.text) { + const ast = parse(this.p.text); + return ast + .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) + .map(t => t.url); + } else { + return null; + } } }, + mounted() { // Get replies if (!this.compact) { @@ -162,21 +174,7 @@ export default Vue.extend({ } } }, - watch: { - post: { - handler(newPost, oldPost) { - if (!oldPost || newPost.text !== oldPost.text) { - this.$nextTick(() => { - const elements = this.$refs.text.$el.getElementsByTagName('a'); - this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) - .map(({ href }) => href); - }); - } - }, - immediate: true - } - }, methods: { fetchContext() { this.contextFetching = true; diff --git a/src/client/app/desktop/views/components/posts.post.vue b/src/client/app/desktop/views/components/posts.post.vue index f3566c81bf..c31e28d67f 100644 --- a/src/client/app/desktop/views/components/posts.post.vue +++ b/src/client/app/desktop/views/components/posts.post.vue @@ -38,7 +38,7 @@

@@ -86,6 +86,8 @@ import Vue from 'vue'; import dateStringify from '../../../common/scripts/date-stringify'; import getAcct from '../../../../../common/user/get-acct'; +import parse from '../../../../../common/text/parse'; + import MkPostFormWindow from './post-form-window.vue'; import MkRepostFormWindow from './repost-form-window.vue'; import MkPostMenu from '../../../common/views/components/post-menu.vue'; @@ -107,17 +109,19 @@ export default Vue.extend({ components: { XSub }, + props: ['post'], + data() { return { isDetailOpened: false, connection: null, - connectionId: null, - urls: [] + connectionId: null }; }, + computed: { - acct() { + acct(): string { return getAcct(this.p.user); }, isRepost(): boolean { @@ -141,14 +145,26 @@ export default Vue.extend({ }, url(): string { return `/@${this.acct}/${this.p.id}`; + }, + urls(): string[] { + if (this.p.text) { + const ast = parse(this.p.text); + return ast + .filter(t => (t.type == 'url' || t.type == 'link') && !t.silent) + .map(t => t.url); + } else { + return null; + } } }, + created() { if ((this as any).os.isSignedIn) { this.connection = (this as any).os.stream.getConnection(); this.connectionId = (this as any).os.stream.use(); } }, + mounted() { this.capture(true); @@ -174,6 +190,7 @@ export default Vue.extend({ } } }, + beforeDestroy() { this.decapture(true); @@ -182,21 +199,7 @@ export default Vue.extend({ (this as any).os.stream.dispose(this.connectionId); } }, - watch: { - post: { - handler(newPost, oldPost) { - if (!oldPost || newPost.textHtml !== oldPost.textHtml) { - this.$nextTick(() => { - const elements = this.$refs.text.$el.getElementsByTagName('a'); - - this.urls = [].filter.call(elements, ({ origin }) => origin !== location.origin) - .map(({ href }) => href); - }); - } - }, - immediate: true - } - }, + methods: { capture(withHandler = false) { if ((this as any).os.isSignedIn) { @@ -457,7 +460,7 @@ export default Vue.extend({ font-size 1.1em color #717171 - >>> blockquote + >>> .quote margin 8px padding 6px 12px color #aaa diff --git a/src/client/app/desktop/views/components/sub-post-content.vue b/src/client/app/desktop/views/components/sub-post-content.vue index 58c81e7552..17899af280 100644 --- a/src/client/app/desktop/views/components/sub-post-content.vue +++ b/src/client/app/desktop/views/components/sub-post-content.vue @@ -2,7 +2,7 @@
diff --git a/src/client/app/mobile/views/components/post-detail.vue b/src/client/app/mobile/views/components/post-detail.vue index 77a73426f2..0a4e36fc60 100644 --- a/src/client/app/mobile/views/components/post-detail.vue +++ b/src/client/app/mobile/views/components/post-detail.vue @@ -81,6 +81,8 @@ -- cgit v1.3.1-freya From cd2542e0fd8578f6e41114ffebbda1f16f7d04ce Mon Sep 17 00:00:00 2001 From: syuilo Date: Mon, 2 Apr 2018 04:15:27 +0900 Subject: Refactor --- src/client/app/ch/tags/channel.tag | 2 +- .../app/common/scripts/compose-notification.ts | 4 +- .../app/common/views/components/autocomplete.vue | 2 +- .../views/components/messaging-room.message.vue | 2 +- .../app/common/views/components/messaging.vue | 2 +- .../app/common/views/components/othello.game.vue | 2 +- .../app/common/views/components/othello.room.vue | 2 +- .../app/common/views/components/post-html.ts | 2 +- .../common/views/components/welcome-timeline.vue | 2 +- .../app/desktop/views/components/friends-maker.vue | 2 +- .../views/components/messaging-room-window.vue | 2 +- .../app/desktop/views/components/notifications.vue | 4 +- .../desktop/views/components/post-detail.sub.vue | 2 +- .../app/desktop/views/components/post-detail.vue | 2 +- .../app/desktop/views/components/post-preview.vue | 2 +- .../desktop/views/components/posts.post.sub.vue | 2 +- .../app/desktop/views/components/posts.post.vue | 2 +- .../app/desktop/views/components/settings.mute.vue | 2 +- .../app/desktop/views/components/user-preview.vue | 4 +- .../desktop/views/components/users-list.item.vue | 2 +- src/client/app/desktop/views/pages/home.vue | 2 +- .../app/desktop/views/pages/messaging-room.vue | 2 +- .../views/pages/user/user.followers-you-know.vue | 2 +- .../app/desktop/views/pages/user/user.friends.vue | 2 +- .../app/desktop/views/pages/user/user.header.vue | 2 +- src/client/app/desktop/views/pages/user/user.vue | 2 +- src/client/app/desktop/views/pages/welcome.vue | 2 +- .../desktop/views/widgets/channel.channel.post.vue | 2 +- src/client/app/desktop/views/widgets/polls.vue | 2 +- src/client/app/desktop/views/widgets/trends.vue | 2 +- src/client/app/desktop/views/widgets/users.vue | 2 +- src/client/app/mobile/api/post.ts | 2 +- .../views/components/notification-preview.vue | 2 +- .../app/mobile/views/components/notification.vue | 4 +- .../app/mobile/views/components/post-card.vue | 4 +- .../mobile/views/components/post-detail.sub.vue | 2 +- .../app/mobile/views/components/post-detail.vue | 2 +- .../app/mobile/views/components/post-preview.vue | 2 +- .../app/mobile/views/components/post.sub.vue | 2 +- src/client/app/mobile/views/components/post.vue | 2 +- .../app/mobile/views/components/user-card.vue | 2 +- .../app/mobile/views/components/user-preview.vue | 2 +- src/client/app/mobile/views/pages/followers.vue | 2 +- src/client/app/mobile/views/pages/following.vue | 2 +- src/client/app/mobile/views/pages/home.vue | 2 +- .../app/mobile/views/pages/messaging-room.vue | 2 +- src/client/app/mobile/views/pages/messaging.vue | 2 +- src/client/app/mobile/views/pages/user.vue | 4 +- .../views/pages/user/home.followers-you-know.vue | 2 +- .../app/mobile/views/pages/user/home.photos.vue | 2 +- src/common/drive/add-file.ts | 2 +- src/common/drive/upload-from-url.ts | 46 ++ src/common/drive/upload_from_url.ts | 46 -- src/common/get-notification-summary.ts | 27 - src/common/get-post-summary.ts | 45 - src/common/get-reaction-emoji.ts | 14 - src/common/othello/ai/back.ts | 376 --------- src/common/othello/ai/front.ts | 233 ------ src/common/othello/ai/index.ts | 1 - src/common/othello/core.ts | 340 -------- src/common/othello/maps.ts | 911 --------------------- src/common/remote/activitypub/act/create.ts | 9 - src/common/remote/activitypub/act/index.ts | 22 - src/common/remote/activitypub/create.ts | 87 -- src/common/remote/activitypub/renderer/context.ts | 5 - src/common/remote/activitypub/renderer/document.ts | 7 - src/common/remote/activitypub/renderer/follow.ts | 8 - src/common/remote/activitypub/renderer/hashtag.ts | 7 - src/common/remote/activitypub/renderer/image.ts | 6 - src/common/remote/activitypub/renderer/key.ts | 10 - src/common/remote/activitypub/renderer/note.ts | 44 - .../activitypub/renderer/ordered-collection.ts | 6 - src/common/remote/activitypub/renderer/person.ts | 20 - src/common/remote/activitypub/resolve-person.ts | 109 --- src/common/remote/activitypub/resolver.ts | 97 --- src/common/remote/activitypub/type.ts | 3 - src/common/remote/resolve-user.ts | 26 - src/common/remote/webfinger.ts | 25 - src/common/text/parse/elements/mention.ts | 2 +- src/common/user/get-acct.ts | 3 - src/common/user/get-summary.ts | 18 - src/common/user/parse-acct.ts | 4 - src/misc/get-notification-summary.ts | 27 + src/misc/get-post-summary.ts | 45 + src/misc/get-reaction-emoji.ts | 14 + src/misc/othello/ai/back.ts | 376 +++++++++ src/misc/othello/ai/front.ts | 233 ++++++ src/misc/othello/ai/index.ts | 1 + src/misc/othello/core.ts | 340 ++++++++ src/misc/othello/maps.ts | 911 +++++++++++++++++++++ src/misc/user/get-acct.ts | 3 + src/misc/user/get-summary.ts | 18 + src/misc/user/parse-acct.ts | 4 + src/processor/http/follow.ts | 4 +- src/processor/http/perform-activitypub.ts | 2 +- src/remote/activitypub/act/create.ts | 9 + src/remote/activitypub/act/index.ts | 22 + src/remote/activitypub/create.ts | 87 ++ src/remote/activitypub/renderer/context.ts | 5 + src/remote/activitypub/renderer/document.ts | 7 + src/remote/activitypub/renderer/follow.ts | 8 + src/remote/activitypub/renderer/hashtag.ts | 7 + src/remote/activitypub/renderer/image.ts | 6 + src/remote/activitypub/renderer/key.ts | 10 + src/remote/activitypub/renderer/note.ts | 44 + .../activitypub/renderer/ordered-collection.ts | 6 + src/remote/activitypub/renderer/person.ts | 20 + src/remote/activitypub/resolve-person.ts | 109 +++ src/remote/activitypub/resolver.ts | 97 +++ src/remote/activitypub/type.ts | 3 + src/remote/resolve-user.ts | 26 + src/remote/webfinger.ts | 25 + src/server/activitypub/inbox.ts | 2 +- src/server/activitypub/outbox.ts | 6 +- src/server/activitypub/post.ts | 6 +- src/server/activitypub/publickey.ts | 4 +- src/server/activitypub/user.ts | 4 +- src/server/activitypub/with-user.ts | 2 +- src/server/api/bot/core.ts | 8 +- src/server/api/bot/interfaces/line.ts | 6 +- .../api/endpoints/drive/files/upload_from_url.ts | 2 +- src/server/api/endpoints/othello/games/show.ts | 2 +- src/server/api/endpoints/othello/match.ts | 2 +- src/server/api/endpoints/posts/create.ts | 4 +- src/server/api/endpoints/users/show.ts | 2 +- src/server/api/limitter.ts | 2 +- src/server/api/stream/othello-game.ts | 4 +- src/server/webfinger.ts | 2 +- 128 files changed, 2599 insertions(+), 2599 deletions(-) create mode 100644 src/common/drive/upload-from-url.ts delete mode 100644 src/common/drive/upload_from_url.ts delete mode 100644 src/common/get-notification-summary.ts delete mode 100644 src/common/get-post-summary.ts delete mode 100644 src/common/get-reaction-emoji.ts delete mode 100644 src/common/othello/ai/back.ts delete mode 100644 src/common/othello/ai/front.ts delete mode 100644 src/common/othello/ai/index.ts delete mode 100644 src/common/othello/core.ts delete mode 100644 src/common/othello/maps.ts delete mode 100644 src/common/remote/activitypub/act/create.ts delete mode 100644 src/common/remote/activitypub/act/index.ts delete mode 100644 src/common/remote/activitypub/create.ts delete mode 100644 src/common/remote/activitypub/renderer/context.ts delete mode 100644 src/common/remote/activitypub/renderer/document.ts delete mode 100644 src/common/remote/activitypub/renderer/follow.ts delete mode 100644 src/common/remote/activitypub/renderer/hashtag.ts delete mode 100644 src/common/remote/activitypub/renderer/image.ts delete mode 100644 src/common/remote/activitypub/renderer/key.ts delete mode 100644 src/common/remote/activitypub/renderer/note.ts delete mode 100644 src/common/remote/activitypub/renderer/ordered-collection.ts delete mode 100644 src/common/remote/activitypub/renderer/person.ts delete mode 100644 src/common/remote/activitypub/resolve-person.ts delete mode 100644 src/common/remote/activitypub/resolver.ts delete mode 100644 src/common/remote/activitypub/type.ts delete mode 100644 src/common/remote/resolve-user.ts delete mode 100644 src/common/remote/webfinger.ts delete mode 100644 src/common/user/get-acct.ts delete mode 100644 src/common/user/get-summary.ts delete mode 100644 src/common/user/parse-acct.ts create mode 100644 src/misc/get-notification-summary.ts create mode 100644 src/misc/get-post-summary.ts create mode 100644 src/misc/get-reaction-emoji.ts create mode 100644 src/misc/othello/ai/back.ts create mode 100644 src/misc/othello/ai/front.ts create mode 100644 src/misc/othello/ai/index.ts create mode 100644 src/misc/othello/core.ts create mode 100644 src/misc/othello/maps.ts create mode 100644 src/misc/user/get-acct.ts create mode 100644 src/misc/user/get-summary.ts create mode 100644 src/misc/user/parse-acct.ts create mode 100644 src/remote/activitypub/act/create.ts create mode 100644 src/remote/activitypub/act/index.ts create mode 100644 src/remote/activitypub/create.ts create mode 100644 src/remote/activitypub/renderer/context.ts create mode 100644 src/remote/activitypub/renderer/document.ts create mode 100644 src/remote/activitypub/renderer/follow.ts create mode 100644 src/remote/activitypub/renderer/hashtag.ts create mode 100644 src/remote/activitypub/renderer/image.ts create mode 100644 src/remote/activitypub/renderer/key.ts create mode 100644 src/remote/activitypub/renderer/note.ts create mode 100644 src/remote/activitypub/renderer/ordered-collection.ts create mode 100644 src/remote/activitypub/renderer/person.ts create mode 100644 src/remote/activitypub/resolve-person.ts create mode 100644 src/remote/activitypub/resolver.ts create mode 100644 src/remote/activitypub/type.ts create mode 100644 src/remote/resolve-user.ts create mode 100644 src/remote/webfinger.ts (limited to 'src/client/app/desktop') diff --git a/src/client/app/ch/tags/channel.tag b/src/client/app/ch/tags/channel.tag index 2abfb106a5..70e494aedd 100644 --- a/src/client/app/ch/tags/channel.tag +++ b/src/client/app/ch/tags/channel.tag @@ -229,7 +229,7 @@ diff --git a/src/client/app/common/scripts/compose-notification.ts b/src/client/app/common/scripts/compose-notification.ts index ebc15952f6..e99d502960 100644 --- a/src/client/app/common/scripts/compose-notification.ts +++ b/src/client/app/common/scripts/compose-notification.ts @@ -1,5 +1,6 @@ import getPostSummary from '../../../../renderers/get-post-summary'; import getReactionEmoji from '../../../../renderers/get-reaction-emoji'; +import getUserName from '../../../../renderers/get-user-name'; type Notification = { title: string; @@ -21,35 +22,35 @@ export default function(type, data): Notification { case 'mention': return { - title: `${data.user.name}さんから:`, + title: `${getUserName(data.user)}さんから:`, body: getPostSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'reply': return { - title: `${data.user.name}さんから返信:`, + title: `${getUserName(data.user)}さんから返信:`, body: getPostSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'quote': return { - title: `${data.user.name}さんが引用:`, + title: `${getUserName(data.user)}さんが引用:`, body: getPostSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'reaction': return { - title: `${data.user.name}: ${getReactionEmoji(data.reaction)}:`, + title: `${getUserName(data.user)}: ${getReactionEmoji(data.reaction)}:`, body: getPostSummary(data.post), icon: data.user.avatarUrl + '?thumbnail&size=64' }; case 'unread_messaging_message': return { - title: `${data.user.name}さんからメッセージ:`, + title: `${getUserName(data.user)}さんからメッセージ:`, body: data.text, // TODO: getMessagingMessageSummary(data), icon: data.user.avatarUrl + '?thumbnail&size=64' }; @@ -57,7 +58,7 @@ export default function(type, data): Notification { case 'othello_invited': return { title: '対局への招待があります', - body: `${data.parent.name}さんから`, + body: `${getUserName(data.parent)}さんから`, icon: data.parent.avatarUrl + '?thumbnail&size=64' }; diff --git a/src/client/app/common/views/components/autocomplete.vue b/src/client/app/common/views/components/autocomplete.vue index 38eaf86508..8837fde6be 100644 --- a/src/client/app/common/views/components/autocomplete.vue +++ b/src/client/app/common/views/components/autocomplete.vue @@ -3,7 +3,7 @@
  1. - {{ user.name }} + {{ getUserName(user) }} @{{ getAcct(user) }}
@@ -22,6 +22,7 @@ import Vue from 'vue'; import * as emojilib from 'emojilib'; import contains from '../../../common/scripts/contains'; import getAcct from '../../../../../acct/render'; +import getUserName from '../../../../../renderers/get-user-name'; const lib = Object.entries(emojilib.lib).filter((x: any) => { return x[1].category != 'flags'; @@ -107,6 +108,7 @@ export default Vue.extend({ }, methods: { getAcct, + getUserName, exec() { this.select = -1; if (this.$refs.suggests) { diff --git a/src/client/app/common/views/components/messaging.vue b/src/client/app/common/views/components/messaging.vue index 4ab3e46e89..9b1449daa5 100644 --- a/src/client/app/common/views/components/messaging.vue +++ b/src/client/app/common/views/components/messaging.vue @@ -14,7 +14,7 @@ tabindex="-1" > - {{ user.name }} + {{ getUserName(user) }} @{{ getAcct(user) }} @@ -33,7 +33,7 @@
- {{ isMe(message) ? message.recipient.name : message.user.name }} + {{ getUserName(isMe(message) ? message.recipient : message.user) }} @{{ getAcct(isMe(message) ? message.recipient : message.user) }}
@@ -52,6 +52,7 @@ diff --git a/src/client/app/desktop/views/components/following-window.vue b/src/client/app/desktop/views/components/following-window.vue index 612847b386..cbd8ec5f94 100644 --- a/src/client/app/desktop/views/components/following-window.vue +++ b/src/client/app/desktop/views/components/following-window.vue @@ -1,7 +1,7 @@ @@ -36,7 +36,7 @@ export default define({ post() { this.posting = true; - (this as any).api('posts/create', { + (this as any).api('notes/create', { text: this.text }).then(data => { this.clear(); diff --git a/src/client/app/desktop/views/widgets/trends.vue b/src/client/app/desktop/views/widgets/trends.vue index 27c1860b32..c2c7636bb3 100644 --- a/src/client/app/desktop/views/widgets/trends.vue +++ b/src/client/app/desktop/views/widgets/trends.vue @@ -5,8 +5,8 @@

%fa:spinner .pulse .fw%%i18n:common.loading%

-
-

{{ post.text }}

+
+

{{ note.text }}

@{{ acct }}

%i18n:desktop.tags.mk-trends-home-widget.nothing%

@@ -25,12 +25,12 @@ export default define({ }).extend({ computed: { acct() { - return getAcct(this.post.user); + return getAcct(this.note.user); }, }, data() { return { - post: null, + note: null, fetching: true, offset: 0 }; @@ -44,23 +44,23 @@ export default define({ }, fetch() { this.fetching = true; - this.post = null; + this.note = null; - (this as any).api('posts/trend', { + (this as any).api('notes/trend', { limit: 1, offset: this.offset, - repost: false, + renote: false, reply: false, media: false, poll: false - }).then(posts => { - const post = posts ? posts[0] : null; - if (post == null) { + }).then(notes => { + const note = notes ? notes[0] : null; + if (note == null) { this.offset = 0; } else { this.offset++; } - this.post = post; + this.note = note; this.fetching = false; }); } @@ -103,7 +103,7 @@ export default define({ &:active color #999 - > .post + > .note padding 16px font-size 12px font-style oblique diff --git a/src/client/app/dev/views/new-app.vue b/src/client/app/dev/views/new-app.vue index e407ca00d7..c9d5971395 100644 --- a/src/client/app/dev/views/new-app.vue +++ b/src/client/app/dev/views/new-app.vue @@ -27,7 +27,7 @@ アカウントの情報を見る。 アカウントの情報を操作する。 - 投稿する。 + 投稿する。 リアクションしたりリアクションをキャンセルする。 フォローしたりフォロー解除する。 ドライブを見る。 diff --git a/src/client/app/mobile/api/post.ts b/src/client/app/mobile/api/post.ts index 98309ba8de..72919c6505 100644 --- a/src/client/app/mobile/api/post.ts +++ b/src/client/app/mobile/api/post.ts @@ -1,24 +1,24 @@ import PostForm from '../views/components/post-form.vue'; -//import RepostForm from '../views/components/repost-form.vue'; -import getPostSummary from '../../../../renderers/get-post-summary'; +//import RenoteForm from '../views/components/renote-form.vue'; +import getNoteSummary from '../../../../renderers/get-note-summary'; export default (os) => (opts) => { const o = opts || {}; - if (o.repost) { - /*const vm = new RepostForm({ + if (o.renote) { + /*const vm = new RenoteForm({ propsData: { - repost: o.repost + renote: o.renote } }).$mount(); vm.$once('cancel', recover); - vm.$once('post', recover); + vm.$once('note', recover); document.body.appendChild(vm.$el);*/ - const text = window.prompt(`「${getPostSummary(o.repost)}」をRepost`); + const text = window.prompt(`「${getNoteSummary(o.renote)}」をRenote`); if (text == null) return; - os.api('posts/create', { - repostId: o.repost.id, + os.api('notes/create', { + renoteId: o.renote.id, text: text == '' ? undefined : text }); } else { @@ -36,7 +36,7 @@ export default (os) => (opts) => { } }).$mount(); vm.$once('cancel', recover); - vm.$once('post', recover); + vm.$once('note', recover); document.body.appendChild(vm.$el); (vm as any).focus(); } diff --git a/src/client/app/mobile/script.ts b/src/client/app/mobile/script.ts index 4776fccddb..6265d0d45f 100644 --- a/src/client/app/mobile/script.ts +++ b/src/client/app/mobile/script.ts @@ -25,7 +25,7 @@ import MkDrive from './views/pages/drive.vue'; import MkNotifications from './views/pages/notifications.vue'; import MkMessaging from './views/pages/messaging.vue'; import MkMessagingRoom from './views/pages/messaging-room.vue'; -import MkPost from './views/pages/post.vue'; +import MkNote from './views/pages/note.vue'; import MkSearch from './views/pages/search.vue'; import MkFollowers from './views/pages/followers.vue'; import MkFollowing from './views/pages/following.vue'; @@ -68,7 +68,7 @@ init((launch) => { { path: '/@:user', component: MkUser }, { path: '/@:user/followers', component: MkFollowers }, { path: '/@:user/following', component: MkFollowing }, - { path: '/@:user/:post', component: MkPost } + { path: '/@:user/:note', component: MkNote } ] }); diff --git a/src/client/app/mobile/views/components/activity.vue b/src/client/app/mobile/views/components/activity.vue index 2e44017e77..dcd319cb69 100644 --- a/src/client/app/mobile/views/components/activity.vue +++ b/src/client/app/mobile/views/components/activity.vue @@ -2,14 +2,14 @@
- - @@ -32,12 +32,12 @@ export default Vue.extend({ userId: this.user.id, limit: 30 }).then(data => { - data.forEach(d => d.total = d.posts + d.replies + d.reposts); + data.forEach(d => d.total = d.notes + d.replies + d.renotes); this.peak = Math.max.apply(null, data.map(d => d.total)); data.forEach(d => { - d.postsH = d.posts / this.peak; + d.notesH = d.notes / this.peak; d.repliesH = d.replies / this.peak; - d.repostsH = d.reposts / this.peak; + d.renotesH = d.renotes / this.peak; }); data.reverse(); this.data = data; diff --git a/src/client/app/mobile/views/components/index.ts b/src/client/app/mobile/views/components/index.ts index fb8f65f47d..9346700304 100644 --- a/src/client/app/mobile/views/components/index.ts +++ b/src/client/app/mobile/views/components/index.ts @@ -2,16 +2,16 @@ import Vue from 'vue'; import ui from './ui.vue'; import timeline from './timeline.vue'; -import post from './post.vue'; -import posts from './posts.vue'; +import note from './note.vue'; +import notes from './notes.vue'; import mediaImage from './media-image.vue'; import mediaVideo from './media-video.vue'; import drive from './drive.vue'; -import postPreview from './post-preview.vue'; -import subPostContent from './sub-post-content.vue'; -import postCard from './post-card.vue'; +import notePreview from './note-preview.vue'; +import subNoteContent from './sub-note-content.vue'; +import noteCard from './note-card.vue'; import userCard from './user-card.vue'; -import postDetail from './post-detail.vue'; +import noteDetail from './note-detail.vue'; import followButton from './follow-button.vue'; import friendsMaker from './friends-maker.vue'; import notification from './notification.vue'; @@ -25,16 +25,16 @@ import widgetContainer from './widget-container.vue'; Vue.component('mk-ui', ui); Vue.component('mk-timeline', timeline); -Vue.component('mk-post', post); -Vue.component('mk-posts', posts); +Vue.component('mk-note', note); +Vue.component('mk-notes', notes); Vue.component('mk-media-image', mediaImage); Vue.component('mk-media-video', mediaVideo); Vue.component('mk-drive', drive); -Vue.component('mk-post-preview', postPreview); -Vue.component('mk-sub-post-content', subPostContent); -Vue.component('mk-post-card', postCard); +Vue.component('mk-note-preview', notePreview); +Vue.component('mk-sub-note-content', subNoteContent); +Vue.component('mk-note-card', noteCard); Vue.component('mk-user-card', userCard); -Vue.component('mk-post-detail', postDetail); +Vue.component('mk-note-detail', noteDetail); Vue.component('mk-follow-button', followButton); Vue.component('mk-friends-maker', friendsMaker); Vue.component('mk-notification', notification); diff --git a/src/client/app/mobile/views/components/note-card.vue b/src/client/app/mobile/views/components/note-card.vue new file mode 100644 index 0000000000..9ad0d3e294 --- /dev/null +++ b/src/client/app/mobile/views/components/note-card.vue @@ -0,0 +1,93 @@ + + + + + diff --git a/src/client/app/mobile/views/components/note-detail.sub.vue b/src/client/app/mobile/views/components/note-detail.sub.vue new file mode 100644 index 0000000000..38aea4ba20 --- /dev/null +++ b/src/client/app/mobile/views/components/note-detail.sub.vue @@ -0,0 +1,113 @@ + + + + + + diff --git a/src/client/app/mobile/views/components/note-detail.vue b/src/client/app/mobile/views/components/note-detail.vue new file mode 100644 index 0000000000..e1682e58ed --- /dev/null +++ b/src/client/app/mobile/views/components/note-detail.vue @@ -0,0 +1,462 @@ + + + + + + + diff --git a/src/client/app/mobile/views/components/note-preview.vue b/src/client/app/mobile/views/components/note-preview.vue new file mode 100644 index 0000000000..8c8d8645bb --- /dev/null +++ b/src/client/app/mobile/views/components/note-preview.vue @@ -0,0 +1,110 @@ + + + + + diff --git a/src/client/app/mobile/views/components/note.sub.vue b/src/client/app/mobile/views/components/note.sub.vue new file mode 100644 index 0000000000..a37d0dea08 --- /dev/null +++ b/src/client/app/mobile/views/components/note.sub.vue @@ -0,0 +1,119 @@ + + + + + + diff --git a/src/client/app/mobile/views/components/note.vue b/src/client/app/mobile/views/components/note.vue new file mode 100644 index 0000000000..4b33c6f071 --- /dev/null +++ b/src/client/app/mobile/views/components/note.vue @@ -0,0 +1,540 @@ + + + + + + + diff --git a/src/client/app/mobile/views/components/notes.vue b/src/client/app/mobile/views/components/notes.vue new file mode 100644 index 0000000000..573026d53e --- /dev/null +++ b/src/client/app/mobile/views/components/notes.vue @@ -0,0 +1,111 @@ + + + + + diff --git a/src/client/app/mobile/views/components/notification-preview.vue b/src/client/app/mobile/views/components/notification-preview.vue index 0492c5d86c..79ca3321e4 100644 --- a/src/client/app/mobile/views/components/notification-preview.vue +++ b/src/client/app/mobile/views/components/notification-preview.vue @@ -4,23 +4,23 @@ avatar

{{ name }}

-

%fa:quote-left%{{ getPostSummary(notification.post) }}%fa:quote-right%

+

%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%

- @@ -51,7 +51,7 @@ avatar

%fa:chart-pie%{{ name }}

-

%fa:quote-left%{{ getPostSummary(notification.post) }}%fa:quote-right%

+

%fa:quote-left%{{ getNoteSummary(notification.note) }}%fa:quote-right%

@@ -59,7 +59,7 @@ - - diff --git a/src/client/app/mobile/views/components/post-detail.sub.vue b/src/client/app/mobile/views/components/post-detail.sub.vue deleted file mode 100644 index 98d6a14cac..0000000000 --- a/src/client/app/mobile/views/components/post-detail.sub.vue +++ /dev/null @@ -1,113 +0,0 @@ - - - - - - diff --git a/src/client/app/mobile/views/components/post-detail.vue b/src/client/app/mobile/views/components/post-detail.vue index 0226ce081a..e1682e58ed 100644 --- a/src/client/app/mobile/views/components/post-detail.vue +++ b/src/client/app/mobile/views/components/post-detail.vue @@ -1,5 +1,5 @@
- +
- +
-
+

- avatar + avatar %fa:retweet% {{ name }} - がRepost + がRenote

@@ -38,33 +38,33 @@
- +
{{ tag }}
- + %fa:map-marker-alt% 位置情報
-
- +
+
- - - -
- +
@@ -84,9 +84,9 @@ import getAcct from '../../../../../acct/render'; import getUserName from '../../../../../renderers/get-user-name'; import parse from '../../../../../text/parse'; -import MkPostMenu from '../../../common/views/components/post-menu.vue'; +import MkNoteMenu from '../../../common/views/components/note-menu.vue'; import MkReactionPicker from '../../../common/views/components/reaction-picker.vue'; -import XSub from './post-detail.sub.vue'; +import XSub from './note-detail.sub.vue'; export default Vue.extend({ components: { @@ -94,7 +94,7 @@ export default Vue.extend({ }, props: { - post: { + note: { type: Object, required: true }, @@ -113,10 +113,10 @@ export default Vue.extend({ computed: { acct(): string { - return getAcct(this.post.user); + return getAcct(this.note.user); }, name(): string { - return getUserName(this.post.user); + return getUserName(this.note.user); }, pAcct(): string { return getAcct(this.p.user); @@ -124,14 +124,14 @@ export default Vue.extend({ pName(): string { return getUserName(this.p.user); }, - isRepost(): boolean { - return (this.post.repost && - this.post.text == null && - this.post.mediaIds == null && - this.post.poll == null); + isRenote(): boolean { + return (this.note.renote && + this.note.text == null && + this.note.mediaIds == null && + this.note.poll == null); }, p(): any { - return this.isRepost ? this.post.repost : this.post; + return this.isRenote ? this.note.renote : this.note; }, reactionsCount(): number { return this.p.reactionCounts @@ -155,8 +155,8 @@ export default Vue.extend({ mounted() { // Get replies if (!this.compact) { - (this as any).api('posts/replies', { - postId: this.p.id, + (this as any).api('notes/replies', { + noteId: this.p.id, limit: 8 }).then(replies => { this.replies = replies; @@ -187,8 +187,8 @@ export default Vue.extend({ this.contextFetching = true; // Fetch context - (this as any).api('posts/context', { - postId: this.p.replyId + (this as any).api('notes/context', { + noteId: this.p.replyId }).then(context => { this.contextFetching = false; this.context = context.reverse(); @@ -199,22 +199,22 @@ export default Vue.extend({ reply: this.p }); }, - repost() { + renote() { (this as any).apis.post({ - repost: this.p + renote: this.p }); }, react() { (this as any).os.new(MkReactionPicker, { source: this.$refs.reactButton, - post: this.p, + note: this.p, compact: true }); }, menu() { - (this as any).os.new(MkPostMenu, { + (this as any).os.new(MkNoteMenu, { source: this.$refs.menuButton, - post: this.p, + note: this.p, compact: true }); } @@ -225,7 +225,7 @@ export default Vue.extend({ diff --git a/src/client/app/mobile/views/components/post.sub.vue b/src/client/app/mobile/views/components/post.sub.vue deleted file mode 100644 index 909d5cb597..0000000000 --- a/src/client/app/mobile/views/components/post.sub.vue +++ /dev/null @@ -1,119 +0,0 @@ - - - - - - diff --git a/src/client/app/mobile/views/components/post.vue b/src/client/app/mobile/views/components/post.vue index eee1e80fd3..4b33c6f071 100644 --- a/src/client/app/mobile/views/components/post.vue +++ b/src/client/app/mobile/views/components/post.vue @@ -1,19 +1,19 @@ @@ -25,7 +25,7 @@ export default Vue.extend({ return { fetching: true, existMore: false, - posts: [], + notes: [], offset: 0 }; }, @@ -48,30 +48,30 @@ export default Vue.extend({ this.fetching = true; Progress.start(); - (this as any).api('posts/search', Object.assign({ + (this as any).api('notes/search', Object.assign({ limit: limit + 1 - }, parse(this.q))).then(posts => { - if (posts.length == limit + 1) { - posts.pop(); + }, parse(this.q))).then(notes => { + if (notes.length == limit + 1) { + notes.pop(); this.existMore = true; } - this.posts = posts; + this.notes = notes; this.fetching = false; Progress.done(); }); }, more() { this.offset += limit; - (this as any).api('posts/search', Object.assign({ + (this as any).api('notes/search', Object.assign({ limit: limit + 1, offset: this.offset - }, parse(this.q))).then(posts => { - if (posts.length == limit + 1) { - posts.pop(); + }, parse(this.q))).then(notes => { + if (notes.length == limit + 1) { + notes.pop(); } else { this.existMore = false; } - this.posts = this.posts.concat(posts); + this.notes = this.notes.concat(notes); }); } } @@ -79,7 +79,7 @@ export default Vue.extend({ diff --git a/src/client/app/mobile/views/pages/user/home.photos.vue b/src/client/app/mobile/views/pages/user/home.photos.vue index ecf5082072..1c59260812 100644 --- a/src/client/app/mobile/views/pages/user/home.photos.vue +++ b/src/client/app/mobile/views/pages/user/home.photos.vue @@ -5,7 +5,7 @@

%i18n:mobile.tags.mk-user-overview-photos.no-photos%

@@ -28,15 +28,15 @@ export default Vue.extend({ getAcct }, mounted() { - (this as any).api('users/posts', { + (this as any).api('users/notes', { userId: this.user.id, withMedia: true, limit: 6 - }).then(posts => { - posts.forEach(post => { - post.media.forEach(media => { + }).then(notes => { + notes.forEach(note => { + note.media.forEach(media => { if (this.images.length < 9) this.images.push({ - post, + note, media }); }); diff --git a/src/client/app/mobile/views/pages/user/home.posts.vue b/src/client/app/mobile/views/pages/user/home.posts.vue deleted file mode 100644 index 654f7f63e0..0000000000 --- a/src/client/app/mobile/views/pages/user/home.posts.vue +++ /dev/null @@ -1,57 +0,0 @@ - - - - - diff --git a/src/client/app/mobile/views/pages/user/home.vue b/src/client/app/mobile/views/pages/user/home.vue index 1afcd1f5ba..2554084969 100644 --- a/src/client/app/mobile/views/pages/user/home.vue +++ b/src/client/app/mobile/views/pages/user/home.vue @@ -1,10 +1,10 @@ diff --git a/src/client/app/mobile/views/pages/welcome.vue b/src/client/app/mobile/views/pages/welcome.vue index 17cdf93065..27baf8bee4 100644 --- a/src/client/app/mobile/views/pages/welcome.vue +++ b/src/client/app/mobile/views/pages/welcome.vue @@ -8,7 +8,7 @@
- +
@@ -70,7 +70,7 @@ export default Vue.extend({ (this as any).api('signin', { username: this.username, password: this.password, - token: this.user && this.user.account.twoFactorEnabled ? this.token : undefined + token: this.user && this.user.twoFactorEnabled ? this.token : undefined }).then(() => { location.reload(); }).catch(() => { diff --git a/src/models/user.ts b/src/models/user.ts index f86aefe9a4..906bcb533b 100644 --- a/src/models/user.ts +++ b/src/models/user.ts @@ -11,7 +11,7 @@ import config from '../config'; const User = db.get('users'); User.createIndex('username'); -User.createIndex('account.token'); +User.createIndex('token'); export default User; @@ -40,45 +40,41 @@ type IUserBase = { export interface ILocalUser extends IUserBase { host: null; - account: { - keypair: string; - email: string; - links: string[]; - password: string; - token: string; - twitter: { - accessToken: string; - accessTokenSecret: string; - userId: string; - screenName: string; - }; - line: { - userId: string; - }; - profile: { - location: string; - birthday: string; // 'YYYY-MM-DD' - tags: string[]; - }; - lastUsedAt: Date; - isBot: boolean; - isPro: boolean; - twoFactorSecret: string; - twoFactorEnabled: boolean; - twoFactorTempSecret: string; - clientSettings: any; - settings: any; + keypair: string; + email: string; + links: string[]; + password: string; + token: string; + twitter: { + accessToken: string; + accessTokenSecret: string; + userId: string; + screenName: string; }; + line: { + userId: string; + }; + profile: { + location: string; + birthday: string; // 'YYYY-MM-DD' + tags: string[]; + }; + lastUsedAt: Date; + isBot: boolean; + isPro: boolean; + twoFactorSecret: string; + twoFactorEnabled: boolean; + twoFactorTempSecret: string; + clientSettings: any; + settings: any; } export interface IRemoteUser extends IUserBase { - account: { - inbox: string; - uri: string; - publicKey: { - id: string; - publicKeyPem: string; - }; + inbox: string; + uri: string; + publicKey: { + id: string; + publicKeyPem: string; }; } @@ -150,11 +146,11 @@ export const pack = ( const fields = opts.detail ? { } : { - 'account.settings': false, - 'account.clientSettings': false, - 'account.profile': false, - 'account.keywords': false, - 'account.domains': false + settings: false, + clientSettings: false, + profile: false, + keywords: false, + domains: false }; // Populate the user if 'user' is ID @@ -188,29 +184,29 @@ export const pack = ( // Remove needless properties delete _user.latestNote; - if (!_user.host) { + if (_user.host == null) { // Remove private properties - delete _user.account.keypair; - delete _user.account.password; - delete _user.account.token; - delete _user.account.twoFactorTempSecret; - delete _user.account.twoFactorSecret; + delete _user.keypair; + delete _user.password; + delete _user.token; + delete _user.twoFactorTempSecret; + delete _user.twoFactorSecret; delete _user.usernameLower; - if (_user.account.twitter) { - delete _user.account.twitter.accessToken; - delete _user.account.twitter.accessTokenSecret; + if (_user.twitter) { + delete _user.twitter.accessToken; + delete _user.twitter.accessTokenSecret; } - delete _user.account.line; + delete _user.line; // Visible via only the official client if (!opts.includeSecrets) { - delete _user.account.email; - delete _user.account.settings; - delete _user.account.clientSettings; + delete _user.email; + delete _user.settings; + delete _user.clientSettings; } if (!opts.detail) { - delete _user.account.twoFactorEnabled; + delete _user.twoFactorEnabled; } } diff --git a/src/queue/processors/http/process-inbox.ts b/src/queue/processors/http/process-inbox.ts index eb4b62d37f..6608907a7a 100644 --- a/src/queue/processors/http/process-inbox.ts +++ b/src/queue/processors/http/process-inbox.ts @@ -36,7 +36,7 @@ export default async (job: kue.Job, done): Promise => { } else { user = await User.findOne({ host: { $ne: null }, - 'account.publicKey.id': signature.keyId + 'publicKey.id': signature.keyId }) as IRemoteUser; // アクティビティを送信してきたユーザーがまだMisskeyサーバーに登録されていなかったら登録する @@ -50,7 +50,7 @@ export default async (job: kue.Job, done): Promise => { return; } - if (!verifySignature(signature, user.account.publicKey.publicKeyPem)) { + if (!verifySignature(signature, user.publicKey.publicKeyPem)) { console.warn('signature verification failed'); done(); return; diff --git a/src/remote/activitypub/act/create/image.ts b/src/remote/activitypub/act/create/image.ts index 30a75e7377..c87423c5fd 100644 --- a/src/remote/activitypub/act/create/image.ts +++ b/src/remote/activitypub/act/create/image.ts @@ -7,7 +7,7 @@ import { IDriveFile } from '../../../../models/drive-file'; const log = debug('misskey:activitypub'); export default async function(actor: IRemoteUser, image): Promise { - if ('attributedTo' in image && actor.account.uri !== image.attributedTo) { + if ('attributedTo' in image && actor.uri !== image.attributedTo) { log(`invalid image: ${JSON.stringify(image, null, 2)}`); throw new Error('invalid image'); } diff --git a/src/remote/activitypub/act/create/index.ts b/src/remote/activitypub/act/create/index.ts index dd0b112141..7cb9b08449 100644 --- a/src/remote/activitypub/act/create/index.ts +++ b/src/remote/activitypub/act/create/index.ts @@ -9,7 +9,7 @@ import { ICreate } from '../../type'; const log = debug('misskey:activitypub'); export default async (actor: IRemoteUser, activity: ICreate): Promise => { - if ('actor' in activity && actor.account.uri !== activity.actor) { + if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/src/remote/activitypub/act/delete/index.ts b/src/remote/activitypub/act/delete/index.ts index 6c6faa1ae5..10b47dc4ca 100644 --- a/src/remote/activitypub/act/delete/index.ts +++ b/src/remote/activitypub/act/delete/index.ts @@ -7,7 +7,7 @@ import { IRemoteUser } from '../../../../models/user'; * 削除アクティビティを捌きます */ export default async (actor: IRemoteUser, activity): Promise => { - if ('actor' in activity && actor.account.uri !== activity.actor) { + if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/src/remote/activitypub/act/undo/index.ts b/src/remote/activitypub/act/undo/index.ts index 3ede9fcfb8..71f547aeb9 100644 --- a/src/remote/activitypub/act/undo/index.ts +++ b/src/remote/activitypub/act/undo/index.ts @@ -8,7 +8,7 @@ import Resolver from '../../resolver'; const log = debug('misskey:activitypub'); export default async (actor: IRemoteUser, activity: IUndo): Promise => { - if ('actor' in activity && actor.account.uri !== activity.actor) { + if ('actor' in activity && actor.uri !== activity.actor) { throw new Error('invalid actor'); } diff --git a/src/remote/activitypub/renderer/follow.ts b/src/remote/activitypub/renderer/follow.ts index 6d1ded9a95..0a1ae1a4b2 100644 --- a/src/remote/activitypub/renderer/follow.ts +++ b/src/remote/activitypub/renderer/follow.ts @@ -4,5 +4,5 @@ import { IRemoteUser } from '../../../models/user'; export default ({ username }, followee: IRemoteUser) => ({ type: 'Follow', actor: `${config.url}/@${username}`, - object: followee.account.uri + object: followee.uri }); diff --git a/src/remote/activitypub/renderer/key.ts b/src/remote/activitypub/renderer/key.ts index 85be7b1367..76e2f13bcc 100644 --- a/src/remote/activitypub/renderer/key.ts +++ b/src/remote/activitypub/renderer/key.ts @@ -6,5 +6,5 @@ export default (user: ILocalUser) => ({ id: `${config.url}/@${user.username}/publickey`, type: 'Key', owner: `${config.url}/@${user.username}`, - publicKeyPem: extractPublic(user.account.keypair) + publicKeyPem: extractPublic(user.keypair) }); diff --git a/src/remote/request.ts b/src/remote/request.ts index a375aebfbb..a0c69cf4ef 100644 --- a/src/remote/request.ts +++ b/src/remote/request.ts @@ -4,10 +4,11 @@ import { URL } from 'url'; import * as debug from 'debug'; import config from '../config'; +import { ILocalUser } from '../models/user'; const log = debug('misskey:activitypub:deliver'); -export default ({ account, username }, url, object) => new Promise((resolve, reject) => { +export default (user: ILocalUser, url, object) => new Promise((resolve, reject) => { log(`--> ${url}`); const { protocol, hostname, port, pathname, search } = new URL(url); @@ -35,8 +36,8 @@ export default ({ account, username }, url, object) => new Promise((resolve, rej sign(req, { authorizationHeaderName: 'Signature', - key: account.keypair, - keyId: `acct:${username}@${config.host}` + key: user.keypair, + keyId: `acct:${user.username}@${config.host}` }); req.end(JSON.stringify(object)); diff --git a/src/renderers/get-user-summary.ts b/src/renderers/get-user-summary.ts index 52309954d3..1bd9a7fb47 100644 --- a/src/renderers/get-user-summary.ts +++ b/src/renderers/get-user-summary.ts @@ -11,8 +11,7 @@ export default function(user: IUser): string { `${user.notesCount}投稿、${user.followingCount}フォロー、${user.followersCount}フォロワー\n`; if (isLocalUser(user)) { - const account = user.account; - string += `場所: ${account.profile.location}、誕生日: ${account.profile.birthday}\n`; + string += `場所: ${user.profile.location}、誕生日: ${user.profile.birthday}\n`; } return string + `「${user.description}」`; diff --git a/src/server/api/authenticate.ts b/src/server/api/authenticate.ts index 8566744831..adbeeb3b34 100644 --- a/src/server/api/authenticate.ts +++ b/src/server/api/authenticate.ts @@ -34,7 +34,7 @@ export default (req: express.Request) => new Promise(async (resolv if (isNativeToken(token)) { const user: IUser = await User - .findOne({ 'account.token': token }); + .findOne({ 'token': token }); if (user === null) { return reject('user not found'); diff --git a/src/server/api/bot/core.ts b/src/server/api/bot/core.ts index 1cf0522349..d41af48057 100644 --- a/src/server/api/bot/core.ts +++ b/src/server/api/bot/core.ts @@ -226,7 +226,7 @@ class SigninContext extends Context { } } else { // Compare password - const same = await bcrypt.compare(query, this.temporaryUser.account.password); + const same = await bcrypt.compare(query, this.temporaryUser.password); if (same) { this.bot.signin(this.temporaryUser); diff --git a/src/server/api/bot/interfaces/line.ts b/src/server/api/bot/interfaces/line.ts index b6b0c257e9..be3bfe33d3 100644 --- a/src/server/api/bot/interfaces/line.ts +++ b/src/server/api/bot/interfaces/line.ts @@ -112,11 +112,11 @@ class LineBot extends BotCore { data: `showtl|${user.id}` }); - if (user.account.twitter) { + if (user.twitter) { actions.push({ type: 'uri', label: 'Twitterアカウントを見る', - uri: `https://twitter.com/${user.account.twitter.screenName}` + uri: `https://twitter.com/${user.twitter.screenName}` }); } @@ -174,7 +174,7 @@ module.exports = async (app: express.Application) => { if (session == null) { const user = await User.findOne({ host: null, - 'account.line': { + 'line': { userId: sourceId } }); @@ -184,7 +184,7 @@ module.exports = async (app: express.Application) => { bot.on('signin', user => { User.update(user._id, { $set: { - 'account.line': { + 'line': { userId: sourceId } } @@ -194,7 +194,7 @@ module.exports = async (app: express.Application) => { bot.on('signout', user => { User.update(user._id, { $set: { - 'account.line': { + 'line': { userId: null } } diff --git a/src/server/api/common/signin.ts b/src/server/api/common/signin.ts index f9688790c4..8bb327694d 100644 --- a/src/server/api/common/signin.ts +++ b/src/server/api/common/signin.ts @@ -2,7 +2,7 @@ import config from '../../../config'; export default function(res, user, redirect: boolean) { const expires = 1000 * 60 * 60 * 24 * 365; // One Year - res.cookie('i', user.account.token, { + res.cookie('i', user.token, { path: '/', domain: `.${config.hostname}`, secure: config.url.substr(0, 5) === 'https', diff --git a/src/server/api/endpoints/following/create.ts b/src/server/api/endpoints/following/create.ts index 0ccac8d83d..d3cc549ca7 100644 --- a/src/server/api/endpoints/following/create.ts +++ b/src/server/api/endpoints/following/create.ts @@ -31,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/following/delete.ts b/src/server/api/endpoints/following/delete.ts index 0684b87504..0d0a6c7132 100644 --- a/src/server/api/endpoints/following/delete.ts +++ b/src/server/api/endpoints/following/delete.ts @@ -31,7 +31,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/i.ts b/src/server/api/endpoints/i.ts index 44de71d162..0be30500c4 100644 --- a/src/server/api/endpoints/i.ts +++ b/src/server/api/endpoints/i.ts @@ -5,12 +5,6 @@ import User, { pack } from '../../../models/user'; /** * Show myself - * - * @param {any} params - * @param {any} user - * @param {any} app - * @param {Boolean} isSecure - * @return {Promise} */ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => { // Serialize @@ -22,7 +16,7 @@ module.exports = (params, user, _, isSecure) => new Promise(async (res, rej) => // Update lastUsedAt User.update({ _id: user._id }, { $set: { - 'account.lastUsedAt': new Date() + lastUsedAt: new Date() } }); }); diff --git a/src/server/api/endpoints/i/2fa/done.ts b/src/server/api/endpoints/i/2fa/done.ts index 0b2e32c13f..3e824feffd 100644 --- a/src/server/api/endpoints/i/2fa/done.ts +++ b/src/server/api/endpoints/i/2fa/done.ts @@ -28,8 +28,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.twoFactorSecret': user.twoFactorTempSecret, - 'account.twoFactorEnabled': true + 'twoFactorSecret': user.twoFactorTempSecret, + 'twoFactorEnabled': true } }); diff --git a/src/server/api/endpoints/i/2fa/register.ts b/src/server/api/endpoints/i/2fa/register.ts index dc7fb959bb..bed64a2545 100644 --- a/src/server/api/endpoints/i/2fa/register.ts +++ b/src/server/api/endpoints/i/2fa/register.ts @@ -14,7 +14,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (passwordErr) return rej('invalid password param'); // Compare password - const same = await bcrypt.compare(password, user.account.password); + const same = await bcrypt.compare(password, user.password); if (!same) { return rej('incorrect password'); diff --git a/src/server/api/endpoints/i/2fa/unregister.ts b/src/server/api/endpoints/i/2fa/unregister.ts index ff2a435fee..f9d7a25f53 100644 --- a/src/server/api/endpoints/i/2fa/unregister.ts +++ b/src/server/api/endpoints/i/2fa/unregister.ts @@ -11,7 +11,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (passwordErr) return rej('invalid password param'); // Compare password - const same = await bcrypt.compare(password, user.account.password); + const same = await bcrypt.compare(password, user.password); if (!same) { return rej('incorrect password'); @@ -19,8 +19,8 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.twoFactorSecret': null, - 'account.twoFactorEnabled': false + 'twoFactorSecret': null, + 'twoFactorEnabled': false } }); diff --git a/src/server/api/endpoints/i/change_password.ts b/src/server/api/endpoints/i/change_password.ts index a38b56a216..57415083f1 100644 --- a/src/server/api/endpoints/i/change_password.ts +++ b/src/server/api/endpoints/i/change_password.ts @@ -22,7 +22,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (newPasswordErr) return rej('invalid newPassword param'); // Compare password - const same = await bcrypt.compare(currentPassword, user.account.password); + const same = await bcrypt.compare(currentPassword, user.password); if (!same) { return rej('incorrect password'); @@ -34,7 +34,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.password': hash + 'password': hash } }); diff --git a/src/server/api/endpoints/i/regenerate_token.ts b/src/server/api/endpoints/i/regenerate_token.ts index 9aa6725f8c..f9e92c1797 100644 --- a/src/server/api/endpoints/i/regenerate_token.ts +++ b/src/server/api/endpoints/i/regenerate_token.ts @@ -20,7 +20,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (passwordErr) return rej('invalid password param'); // Compare password - const same = await bcrypt.compare(password, user.account.password); + const same = await bcrypt.compare(password, user.password); if (!same) { return rej('incorrect password'); @@ -31,7 +31,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.token': secret + 'token': secret } }); diff --git a/src/server/api/endpoints/i/update.ts b/src/server/api/endpoints/i/update.ts index 279b062f52..a8caa0ebc4 100644 --- a/src/server/api/endpoints/i/update.ts +++ b/src/server/api/endpoints/i/update.ts @@ -29,12 +29,12 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re // Get 'location' parameter const [location, locationErr] = $(params.location).optional.nullable.string().pipe(isValidLocation).$; if (locationErr) return rej('invalid location param'); - if (location !== undefined) user.account.profile.location = location; + if (location !== undefined) user.profile.location = location; // Get 'birthday' parameter const [birthday, birthdayErr] = $(params.birthday).optional.nullable.string().pipe(isValidBirthday).$; if (birthdayErr) return rej('invalid birthday param'); - if (birthday !== undefined) user.account.profile.birthday = birthday; + if (birthday !== undefined) user.profile.birthday = birthday; // Get 'avatarId' parameter const [avatarId, avatarIdErr] = $(params.avatarId).optional.id().$; @@ -49,12 +49,12 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re // Get 'isBot' parameter const [isBot, isBotErr] = $(params.isBot).optional.boolean().$; if (isBotErr) return rej('invalid isBot param'); - if (isBot != null) user.account.isBot = isBot; + if (isBot != null) user.isBot = isBot; // Get 'autoWatch' parameter const [autoWatch, autoWatchErr] = $(params.autoWatch).optional.boolean().$; if (autoWatchErr) return rej('invalid autoWatch param'); - if (autoWatch != null) user.account.settings.autoWatch = autoWatch; + if (autoWatch != null) user.settings.autoWatch = autoWatch; await User.update(user._id, { $set: { @@ -62,9 +62,9 @@ module.exports = async (params, user, _, isSecure) => new Promise(async (res, re description: user.description, avatarId: user.avatarId, bannerId: user.bannerId, - 'account.profile': user.account.profile, - 'account.isBot': user.account.isBot, - 'account.settings': user.account.settings + 'profile': user.profile, + 'isBot': user.isBot, + 'settings': user.settings } }); diff --git a/src/server/api/endpoints/i/update_client_setting.ts b/src/server/api/endpoints/i/update_client_setting.ts index 10741aceba..b0d5db5ec2 100644 --- a/src/server/api/endpoints/i/update_client_setting.ts +++ b/src/server/api/endpoints/i/update_client_setting.ts @@ -22,14 +22,14 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (valueErr) return rej('invalid value param'); const x = {}; - x[`account.clientSettings.${name}`] = value; + x[`clientSettings.${name}`] = value; await User.update(user._id, { $set: x }); // Serialize - user.account.clientSettings[name] = value; + user.clientSettings[name] = value; const iObj = await pack(user, user, { detail: true, includeSecrets: true diff --git a/src/server/api/endpoints/i/update_home.ts b/src/server/api/endpoints/i/update_home.ts index 91be0714d7..ce7661ede0 100644 --- a/src/server/api/endpoints/i/update_home.ts +++ b/src/server/api/endpoints/i/update_home.ts @@ -26,7 +26,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (home) { await User.update(user._id, { $set: { - 'account.clientSettings.home': home + 'clientSettings.home': home } }); @@ -38,7 +38,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { } else { if (id == null && data == null) return rej('you need to set id and data params if home param unset'); - const _home = user.account.clientSettings.home; + const _home = user.clientSettings.home; const widget = _home.find(w => w.id == id); if (widget == null) return rej('widget not found'); @@ -47,7 +47,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.clientSettings.home': _home + 'clientSettings.home': _home } }); diff --git a/src/server/api/endpoints/i/update_mobile_home.ts b/src/server/api/endpoints/i/update_mobile_home.ts index 1efda120d5..b710e2f330 100644 --- a/src/server/api/endpoints/i/update_mobile_home.ts +++ b/src/server/api/endpoints/i/update_mobile_home.ts @@ -25,7 +25,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { if (home) { await User.update(user._id, { $set: { - 'account.clientSettings.mobileHome': home + 'clientSettings.mobileHome': home } }); @@ -37,7 +37,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { } else { if (id == null && data == null) return rej('you need to set id and data params if home param unset'); - const _home = user.account.clientSettings.mobileHome || []; + const _home = user.clientSettings.mobileHome || []; const widget = _home.find(w => w.id == id); if (widget == null) return rej('widget not found'); @@ -46,7 +46,7 @@ module.exports = async (params, user) => new Promise(async (res, rej) => { await User.update(user._id, { $set: { - 'account.clientSettings.mobileHome': _home + 'clientSettings.mobileHome': _home } }); diff --git a/src/server/api/endpoints/mute/create.ts b/src/server/api/endpoints/mute/create.ts index a7fa5f7b4b..19894d07af 100644 --- a/src/server/api/endpoints/mute/create.ts +++ b/src/server/api/endpoints/mute/create.ts @@ -30,7 +30,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/mute/delete.ts b/src/server/api/endpoints/mute/delete.ts index 687f010336..10096352ba 100644 --- a/src/server/api/endpoints/mute/delete.ts +++ b/src/server/api/endpoints/mute/delete.ts @@ -30,7 +30,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }); diff --git a/src/server/api/endpoints/notes/polls/vote.ts b/src/server/api/endpoints/notes/polls/vote.ts index 0e27f87ee2..fd4412ad35 100644 --- a/src/server/api/endpoints/notes/polls/vote.ts +++ b/src/server/api/endpoints/notes/polls/vote.ts @@ -100,7 +100,7 @@ module.exports = (params, user) => new Promise(async (res, rej) => { }); // この投稿をWatchする - if (user.account.settings.autoWatch !== false) { + if (user.settings.autoWatch !== false) { watch(user._id, note); } }); diff --git a/src/server/api/endpoints/users/recommendation.ts b/src/server/api/endpoints/users/recommendation.ts index 60483936fb..2de22da13e 100644 --- a/src/server/api/endpoints/users/recommendation.ts +++ b/src/server/api/endpoints/users/recommendation.ts @@ -32,7 +32,7 @@ module.exports = (params, me) => new Promise(async (res, rej) => { }, $or: [ { - 'account.lastUsedAt': { + 'lastUsedAt': { $gte: new Date(Date.now() - ms('7days')) } }, { diff --git a/src/server/api/private/signin.ts b/src/server/api/private/signin.ts index e0bd67d1ca..d7c4832c95 100644 --- a/src/server/api/private/signin.ts +++ b/src/server/api/private/signin.ts @@ -37,7 +37,7 @@ export default async (req: express.Request, res: express.Response) => { }, { fields: { data: false, - 'account.profile': false + 'profile': false } }) as ILocalUser; @@ -48,15 +48,13 @@ export default async (req: express.Request, res: express.Response) => { return; } - const account = user.account; - // Compare password - const same = await bcrypt.compare(password, account.password); + const same = await bcrypt.compare(password, password); if (same) { - if (account.twoFactorEnabled) { + if (user.twoFactorEnabled) { const verified = (speakeasy as any).totp.verify({ - secret: account.twoFactorSecret, + secret: user.twoFactorSecret, encoding: 'base32', token: token }); diff --git a/src/server/api/private/signup.ts b/src/server/api/private/signup.ts index 5818ba25cd..f441e1b754 100644 --- a/src/server/api/private/signup.ts +++ b/src/server/api/private/signup.ts @@ -119,44 +119,29 @@ export default async (req: express.Request, res: express.Response) => { usernameLower: username.toLowerCase(), host: null, hostLower: null, - account: { - keypair: generateKeypair(), - token: secret, - email: null, - links: null, - password: hash, - profile: { - bio: null, - birthday: null, - blood: null, - gender: null, - handedness: null, - height: null, - location: null, - weight: null - }, - settings: { - autoWatch: true - }, - clientSettings: { - home: homeData - } + keypair: generateKeypair(), + token: secret, + email: null, + links: null, + password: hash, + profile: { + bio: null, + birthday: null, + blood: null, + gender: null, + handedness: null, + height: null, + location: null, + weight: null + }, + settings: { + autoWatch: true + }, + clientSettings: { + home: homeData } }); // Response res.send(await pack(account)); - - // Create search index - if (config.elasticsearch.enable) { - const es = require('../../db/elasticsearch'); - es.index({ - index: 'misskey', - type: 'user', - id: account._id.toString(), - body: { - username: username - } - }); - } }; diff --git a/src/server/api/service/twitter.ts b/src/server/api/service/twitter.ts index 77b932b13b..da48e30a8a 100644 --- a/src/server/api/service/twitter.ts +++ b/src/server/api/service/twitter.ts @@ -40,10 +40,10 @@ module.exports = (app: express.Application) => { const user = await User.findOneAndUpdate({ host: null, - 'account.token': userToken + 'token': userToken }, { $set: { - 'account.twitter': null + 'twitter': null } }); @@ -128,7 +128,7 @@ module.exports = (app: express.Application) => { const user = await User.findOne({ host: null, - 'account.twitter.userId': result.userId + 'twitter.userId': result.userId }); if (user == null) { @@ -151,10 +151,10 @@ module.exports = (app: express.Application) => { const user = await User.findOneAndUpdate({ host: null, - 'account.token': userToken + 'token': userToken }, { $set: { - 'account.twitter': { + 'twitter': { accessToken: result.accessToken, accessTokenSecret: result.accessTokenSecret, userId: result.userId, diff --git a/src/server/api/stream/home.ts b/src/server/api/stream/home.ts index 313558851b..359ef74aff 100644 --- a/src/server/api/stream/home.ts +++ b/src/server/api/stream/home.ts @@ -74,7 +74,7 @@ export default async function(request: websocket.request, connection: websocket. // Update lastUsedAt User.update({ _id: user._id }, { $set: { - 'account.lastUsedAt': new Date() + 'lastUsedAt': new Date() } }); break; diff --git a/src/server/api/streaming.ts b/src/server/api/streaming.ts index edcf505d24..26946b524e 100644 --- a/src/server/api/streaming.ts +++ b/src/server/api/streaming.ts @@ -97,7 +97,7 @@ function authenticate(token: string): Promise { const user: IUser = await User .findOne({ host: null, - 'account.token': token + 'token': token }); resolve(user); diff --git a/src/services/following/create.ts b/src/services/following/create.ts index d919f4487f..31e3be19ed 100644 --- a/src/services/following/create.ts +++ b/src/services/following/create.ts @@ -60,13 +60,13 @@ export default async function(follower: IUser, followee: IUser, activity?) { const content = renderFollow(follower, followee); content['@context'] = context; - deliver(follower, content, followee.account.inbox).save(); + deliver(follower, content, followee.inbox).save(); } if (isRemoteUser(follower) && isLocalUser(followee)) { const content = renderAccept(activity); content['@context'] = context; - deliver(followee, content, follower.account.inbox).save(); + deliver(followee, content, follower.inbox).save(); } } diff --git a/src/services/following/delete.ts b/src/services/following/delete.ts index 364a4803b9..d79bf64f53 100644 --- a/src/services/following/delete.ts +++ b/src/services/following/delete.ts @@ -59,6 +59,6 @@ export default async function(follower: IUser, followee: IUser, activity?) { const content = renderUndo(renderFollow(follower, followee)); content['@context'] = context; - deliver(follower, content, followee.account.inbox).save(); + deliver(follower, content, followee.inbox).save(); } } diff --git a/src/services/note/create.ts b/src/services/note/create.ts index 8eee8f44af..551d618569 100644 --- a/src/services/note/create.ts +++ b/src/services/note/create.ts @@ -78,7 +78,7 @@ export default async (user: IUser, data: { host: user.host, hostLower: user.hostLower, account: isLocalUser(user) ? {} : { - inbox: user.account.inbox + inbox: user.inbox } } }; @@ -133,7 +133,7 @@ export default async (user: IUser, data: { // 投稿がリプライかつ投稿者がローカルユーザーかつリプライ先の投稿の投稿者がリモートユーザーなら配送 if (data.reply && isLocalUser(user) && isRemoteUser(data.reply._user)) { - deliver(user, content, data.reply._user.account.inbox).save(); + deliver(user, content, data.reply._user.inbox).save(); } Promise.all(followers.map(follower => { @@ -145,7 +145,7 @@ export default async (user: IUser, data: { } else { // フォロワーがリモートユーザーかつ投稿者がローカルユーザーなら投稿を配信 if (isLocalUser(user)) { - deliver(user, content, follower.account.inbox).save(); + deliver(user, content, follower.inbox).save(); } } })); @@ -242,7 +242,7 @@ export default async (user: IUser, data: { }); // この投稿をWatchする - if (isLocalUser(user) && user.account.settings.autoWatch !== false) { + if (isLocalUser(user) && user.settings.autoWatch !== false) { watch(user._id, data.reply); } @@ -277,7 +277,7 @@ export default async (user: IUser, data: { }); // この投稿をWatchする - if (isLocalUser(user) && user.account.settings.autoWatch !== false) { + if (isLocalUser(user) && user.settings.autoWatch !== false) { watch(user._id, data.renote); } diff --git a/src/services/note/reaction/create.ts b/src/services/note/reaction/create.ts index d0ce65ee54..ea51b205d0 100644 --- a/src/services/note/reaction/create.ts +++ b/src/services/note/reaction/create.ts @@ -78,7 +78,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise }); // ユーザーがローカルユーザーかつ自動ウォッチ設定がオンならばこの投稿をWatchする - if (isLocalUser(user) && user.account.settings.autoWatch !== false) { + if (isLocalUser(user) && user.settings.autoWatch !== false) { watch(user._id, note); } @@ -88,7 +88,7 @@ export default async (user: IUser, note: INote, reaction: string) => new Promise // リアクターがローカルユーザーかつリアクション対象がリモートユーザーの投稿なら配送 if (isLocalUser(user) && isRemoteUser(note._user)) { - deliver(user, content, note._user.account.inbox).save(); + deliver(user, content, note._user.inbox).save(); } //#endregion }); diff --git a/test/api.ts b/test/api.ts index 953c5aea0d..87bbb8ee16 100644 --- a/test/api.ts +++ b/test/api.ts @@ -32,7 +32,7 @@ const async = fn => (done) => { const request = (endpoint, params, me?) => new Promise((ok, ng) => { const auth = me ? { - i: me.account.token + i: me.token } : {}; _chai.request(server) @@ -157,10 +157,10 @@ describe('API', () => { res.should.have.status(200); res.body.should.be.a('object'); res.body.should.have.property('name').eql(myName); - res.body.should.have.nested.property('account.profile').a('object'); - res.body.should.have.nested.property('account.profile.location').eql(myLocation); - res.body.should.have.nested.property('account.profile.birthday').eql(myBirthday); - res.body.should.have.nested.property('account.profile.gender').eql('female'); + res.body.should.have.nested.property('profile').a('object'); + res.body.should.have.nested.property('profile.location').eql(myLocation); + res.body.should.have.nested.property('profile.birthday').eql(myBirthday); + res.body.should.have.nested.property('profile.gender').eql('female'); })); it('名前を空白にできない', async(async () => { @@ -180,8 +180,8 @@ describe('API', () => { }, me); res.should.have.status(200); res.body.should.be.a('object'); - res.body.should.have.nested.property('account.profile').a('object'); - res.body.should.have.nested.property('account.profile.birthday').eql(null); + res.body.should.have.nested.property('profile').a('object'); + res.body.should.have.nested.property('profile.birthday').eql(null); })); it('不正な誕生日の形式で怒られる', async(async () => { @@ -736,7 +736,7 @@ describe('API', () => { const me = await insertSakurako(); const res = await _chai.request(server) .post('/drive/files/create') - .field('i', me.account.token) + .field('i', me.token) .attach('file', fs.readFileSync(__dirname + '/resources/Lenna.png'), 'Lenna.png'); res.should.have.status(200); res.body.should.be.a('object'); diff --git a/tools/migration/nighthike/12.js b/tools/migration/nighthike/12.js new file mode 100644 index 0000000000..f4b61e2ee8 --- /dev/null +++ b/tools/migration/nighthike/12.js @@ -0,0 +1,58 @@ +// for Node.js interpret + +const { default: User } = require('../../../built/models/user'); +const { generate } = require('../../../built/crypto_key'); +const { default: zip } = require('@prezzemolo/zip') + +const migrate = async (user) => { + const result = await User.update(user._id, { + $unset: { + account: '' + }, + $set: { + host: null, + hostLower: null, + email: user.account.email, + links: user.account.links, + password: user.account.password, + token: user.account.token, + twitter: user.account.twitter, + line: user.account.line, + profile: user.account.profile, + lastUsedAt: user.account.lastUsedAt, + isBot: user.account.isBot, + isPro: user.account.isPro, + twoFactorSecret: user.account.twoFactorSecret, + twoFactorEnabled: user.account.twoFactorEnabled, + clientSettings: user.account.clientSettings, + settings: user.account.settings, + keypair: user.account.keypair + } + }); + return result.ok === 1; +} + +async function main() { + const count = await User.count({}); + + const dop = Number.parseInt(process.argv[2]) || 5 + const idop = ((count - (count % dop)) / dop) + 1 + + return zip( + 1, + async (time) => { + console.log(`${time} / ${idop}`) + const doc = await User.find({}, { + limit: dop, skip: time * dop + }) + return Promise.all(doc.map(migrate)) + }, + idop + ).then(a => { + const rv = [] + a.forEach(e => rv.push(...e)) + return rv + }) +} + +main().then(console.dir).catch(console.error) -- cgit v1.3.1-freya From 4753dfa4d9c872f4cde02b0d16736890475ba7ff Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 8 Apr 2018 17:15:07 +0900 Subject: oops --- src/client/app/desktop/views/components/timeline.vue | 2 +- tools/migration/nighthike/4.js | 14 +++++++++++++- 2 files changed, 14 insertions(+), 2 deletions(-) (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/views/components/timeline.vue b/src/client/app/desktop/views/components/timeline.vue index ea8f0053bc..e1f88b62f3 100644 --- a/src/client/app/desktop/views/components/timeline.vue +++ b/src/client/app/desktop/views/components/timeline.vue @@ -96,7 +96,7 @@ export default Vue.extend({ onNote(note) { // サウンドを再生する if ((this as any).os.isEnableSounds) { - const sound = new Audio(`${url}/assets/note.mp3`); + const sound = new Audio(`${url}/assets/post.mp3`); sound.volume = localStorage.getItem('soundVolume') ? parseInt(localStorage.getItem('soundVolume'), 10) / 100 : 1; sound.play(); } diff --git a/tools/migration/nighthike/4.js b/tools/migration/nighthike/4.js index d77c91ca80..5e12e64055 100644 --- a/tools/migration/nighthike/4.js +++ b/tools/migration/nighthike/4.js @@ -50,8 +50,20 @@ db.drive_files.files.renameCollection('driveFiles.files'); db.drive_files.chunks.renameCollection('driveFiles.chunks'); db.driveFiles.files.update({}, { $rename: { - 'metadata.user_id': 'metadata.userId', + 'metadata.user_id': 'metadata.userId' + } +}, false, true); +db.driveFiles.files.update({ + 'metadata.folder_id': { $ne: null } +}, { + $rename: { 'metadata.folder_id': 'metadata.folderId', + } +}, false, true); +db.driveFiles.files.update({ + 'metadata.properties.average_color': { $ne: null } +}, { + $rename: { 'metadata.properties.average_color': 'metadata.properties.avgColor' } }, false, true); -- cgit v1.3.1-freya From 6089169a3ce59ec35488c3517280b90b751c8a56 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 8 Apr 2018 17:20:46 +0900 Subject: oops --- .../app/desktop/views/components/post-detail.vue | 448 ---------------- .../app/desktop/views/components/posts.post.vue | 596 --------------------- 2 files changed, 1044 deletions(-) delete mode 100644 src/client/app/desktop/views/components/post-detail.vue delete mode 100644 src/client/app/desktop/views/components/posts.post.vue (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/views/components/post-detail.vue b/src/client/app/desktop/views/components/post-detail.vue deleted file mode 100644 index df7c33dfa8..0000000000 --- a/src/client/app/desktop/views/components/post-detail.vue +++ /dev/null @@ -1,448 +0,0 @@ - - - - - - - diff --git a/src/client/app/desktop/views/components/posts.post.vue b/src/client/app/desktop/views/components/posts.post.vue deleted file mode 100644 index d7c21dfa07..0000000000 --- a/src/client/app/desktop/views/components/posts.post.vue +++ /dev/null @@ -1,596 +0,0 @@ - - - - - - - -- cgit v1.3.1-freya From 6eefdfcb17e403b10f9be26f9d882d74726e4123 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 8 Apr 2018 17:37:16 +0900 Subject: Fix bug --- src/client/app/desktop/views/components/notes.note.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/views/components/notes.note.vue b/src/client/app/desktop/views/components/notes.note.vue index 4547ac58bb..0712069e50 100644 --- a/src/client/app/desktop/views/components/notes.note.vue +++ b/src/client/app/desktop/views/components/notes.note.vue @@ -21,7 +21,7 @@
- {{ getUserName(p) }} + {{ getUserName(p.user) }} bot @{{ getAcct(p.user) }}
-- cgit v1.3.1-freya From ba280ac380923af7b455bacdf7c717694a4065e5 Mon Sep 17 00:00:00 2001 From: syuilo Date: Sun, 8 Apr 2018 19:30:19 +0900 Subject: Fix bug --- .../app/desktop/views/components/user-preview.vue | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) (limited to 'src/client/app/desktop') diff --git a/src/client/app/desktop/views/components/user-preview.vue b/src/client/app/desktop/views/components/user-preview.vue index 3cbaa2816e..1cc53743aa 100644 --- a/src/client/app/desktop/views/components/user-preview.vue +++ b/src/client/app/desktop/views/components/user-preview.vue @@ -2,12 +2,12 @@