Merge branch 'develop'
This commit is contained in:
		
						commit
						73ac2632c2
					
				
							
								
								
									
										15
									
								
								CHANGELOG.md
								
								
								
								
							
							
						
						
									
										15
									
								
								CHANGELOG.md
								
								
								
								
							|  | @ -17,6 +17,21 @@ npm i -g ts-node | |||
| npm run migrate | ||||
| ``` | ||||
| 
 | ||||
| 11.23.0 (2019/06/23) | ||||
| -------------------- | ||||
| ### ✨Improvements | ||||
| * ホーム/デッキのカスタマイズ情報を複数のデバイスで同期できるように | ||||
| * ホーム/デッキのカスタマイズ情報の複数プリセット切り替え | ||||
| * サーバー情報にRedisのバージョンを追加 | ||||
| * ServiceWorker有効化 | ||||
| * MisskeyPagesでリストの要素数を取得する関数を追加 | ||||
| * URLプレビューでハッシュだけ違うプレビューカードは表示しないように | ||||
| * URLプレビューをユーザーロケールで出し分けるように | ||||
| * リモートの凍結されたアカウントからのアクティビティはすべて無視するように | ||||
| 
 | ||||
| ### 🐛Fixes | ||||
| * フォロー解除してもフォローボタンがフォロー中のままになる問題を修正 | ||||
| 
 | ||||
| 11.22.0 (2019/06/18) | ||||
| -------------------- | ||||
| ### ✨Improvements | ||||
|  |  | |||
|  | @ -1298,5 +1298,7 @@ pages: | |||
|         arg2: "Seznamy" | ||||
|       _pick: | ||||
|         arg1: "Seznamy" | ||||
|       _listLen: | ||||
|         arg1: "Seznamy" | ||||
|     types: | ||||
|       array: "Seznamy" | ||||
|  |  | |||
|  | @ -1844,6 +1844,8 @@ pages: | |||
|       _pick: | ||||
|         arg1: "Lister" | ||||
|         arg2: "Position" | ||||
|       _listLen: | ||||
|         arg1: "Lister" | ||||
|       number: "Tal" | ||||
|       stringToNumber: "Tekst til tal" | ||||
|       _stringToNumber: | ||||
|  |  | |||
|  | @ -929,5 +929,7 @@ pages: | |||
|         arg2: "Listen" | ||||
|       _pick: | ||||
|         arg1: "Listen" | ||||
|       _listLen: | ||||
|         arg1: "Listen" | ||||
|     types: | ||||
|       array: "Listen" | ||||
|  |  | |||
|  | @ -270,6 +270,9 @@ common: | |||
|     disable-via-mobile: "Don't mark the post as 'from mobile'" | ||||
|     load-raw-images: "Show attached images in original quality" | ||||
|     load-remote-media: "Show media from a remote server" | ||||
|     sync: "Sync" | ||||
|     home-profile: "Home profile" | ||||
|     deck-profile: "Deck profile" | ||||
|   search: "Search" | ||||
|   delete: "Delete" | ||||
|   loading: "Loading" | ||||
|  | @ -1103,7 +1106,10 @@ admin/views/index.vue: | |||
|   abuse: "Abuse" | ||||
|   queue: "Job Queue" | ||||
|   logs: "Logs" | ||||
|   db: "Database" | ||||
|   back-to-misskey: "Back to Misskey" | ||||
| admin/views/db.vue: | ||||
|   tables: "Tables" | ||||
| admin/views/dashboard.vue: | ||||
|   dashboard: "Dashboard" | ||||
|   accounts: "Accounts" | ||||
|  | @ -1941,6 +1947,8 @@ pages: | |||
|       _pick: | ||||
|         arg1: "Lists" | ||||
|         arg2: "Position" | ||||
|       _listLen: | ||||
|         arg1: "Lists" | ||||
|       number: "Number" | ||||
|       stringToNumber: "Text to number" | ||||
|       _stringToNumber: | ||||
|  |  | |||
|  | @ -1109,5 +1109,7 @@ pages: | |||
|         arg2: "Listas" | ||||
|       _pick: | ||||
|         arg1: "Listas" | ||||
|       _listLen: | ||||
|         arg1: "Listas" | ||||
|     types: | ||||
|       array: "Listas" | ||||
|  |  | |||
|  | @ -265,6 +265,7 @@ common: | |||
|     disable-via-mobile: "Enlever la mention publié via 'mobile'" | ||||
|     load-raw-images: "Afficher les photos jointes dans leur qualité originale" | ||||
|     load-remote-media: "Afficher les médias depuis le serveur distant" | ||||
|     sync: "Synchroniser" | ||||
|   search: "Recherche" | ||||
|   delete: "Supprimer" | ||||
|   loading: "Chargement en cours …" | ||||
|  | @ -724,6 +725,7 @@ common/views/components/user-group-editor.vue: | |||
|   transfer: "Transférer de groupe" | ||||
|   transferred: "Groupe transféré" | ||||
|   remove-user: "Enlever un utilisateur de ce groupe" | ||||
|   delete-are-you-sure: "Désirez-vous vraiment supprimer le groupe $1 ?" | ||||
|   deleted: "Supprimé" | ||||
|   invite: "Inviter" | ||||
|   invited: "Invitation envoyée avec succès" | ||||
|  | @ -1088,7 +1090,10 @@ admin/views/index.vue: | |||
|   abuse: "Abus" | ||||
|   queue: "File d’attente" | ||||
|   logs: "Journaux" | ||||
|   db: "Base de données" | ||||
|   back-to-misskey: "Retour vers Misskey" | ||||
| admin/views/db.vue: | ||||
|   tables: "Tables" | ||||
| admin/views/dashboard.vue: | ||||
|   dashboard: "Tableau de bord" | ||||
|   accounts: "Comptes" | ||||
|  | @ -1875,6 +1880,8 @@ pages: | |||
|       _pick: | ||||
|         arg1: "Listes" | ||||
|         arg2: "Position" | ||||
|       _listLen: | ||||
|         arg1: "Listes" | ||||
|       number: "Numérique" | ||||
|       stringToNumber: "Chaîne en chiffres" | ||||
|       _stringToNumber: | ||||
|  |  | |||
|  | @ -282,6 +282,9 @@ common: | |||
|     disable-via-mobile: "「モバイルからの投稿」フラグを付けない" | ||||
|     load-raw-images: "添付された画像を高画質で表示する" | ||||
|     load-remote-media: "リモートサーバーのメディアを表示する" | ||||
|     sync: "同期" | ||||
|     home-profile: "ホームのプロファイル" | ||||
|     deck-profile: "デッキのプロファイル" | ||||
| 
 | ||||
|   search: "検索" | ||||
|   delete: "削除" | ||||
|  | @ -2148,6 +2151,9 @@ pages: | |||
|       _pick: | ||||
|         arg1: "リスト" | ||||
|         arg2: "位置" | ||||
|       listLen: "リストの長さを取得" | ||||
|       _listLen: | ||||
|         arg1: "リスト" | ||||
|       number: "数値" | ||||
|       stringToNumber: "テキストを数値に" | ||||
|       _stringToNumber: | ||||
|  |  | |||
|  | @ -1254,5 +1254,7 @@ pages: | |||
|         arg2: "リスト" | ||||
|       _pick: | ||||
|         arg1: "リスト" | ||||
|       _listLen: | ||||
|         arg1: "リスト" | ||||
|     types: | ||||
|       array: "リスト" | ||||
|  |  | |||
|  | @ -116,7 +116,7 @@ common: | |||
|     local-only-message: "이 글은 로컬에만 공개되어 있습니다" | ||||
|     click-to-tagging: "클릭하여 태그 넣기" | ||||
|     visibility: "공개 범위" | ||||
|     geolocation-alert: "사용 중인 장치에서는 위치 정보를 사용할 수 없습니다" | ||||
|     geolocation-alert: "사용 중이신 장치에서는 위치 정보를 사용할 수 없습니다" | ||||
|     error: "오류" | ||||
|     enter-username: "사용자명을 입력해주세요" | ||||
|     add-visible-user: "사용자 추가" | ||||
|  | @ -270,6 +270,9 @@ common: | |||
|     disable-via-mobile: "작성하는 글에 \"모바일에서 작성함\" 을 붙이지 않음" | ||||
|     load-raw-images: "첨부 이미지를 고품질로 표시" | ||||
|     load-remote-media: "원격 서버의 미디어를 표시" | ||||
|     sync: "동기화" | ||||
|     home-profile: "홈 프로필" | ||||
|     deck-profile: "덱 프로필" | ||||
|   search: "검색" | ||||
|   delete: "삭제" | ||||
|   loading: "로드 중" | ||||
|  | @ -286,7 +289,7 @@ common: | |||
|   is-remote-user: "이 사용자 정보는 정확하지 않을 수 있습니다." | ||||
|   is-remote-post: "이 글 정보는 복사본입니다." | ||||
|   view-on-remote: "정확한 정보 보기" | ||||
|   renoted-by: "{user}이(가) 리노트" | ||||
|   renoted-by: "{user}님이 리노트" | ||||
|   no-notes: "글이 없습니다" | ||||
|   turn-on-darkmode: "어둠에 삼켜져라" | ||||
|   turn-off-darkmode: "빛이 있으라" | ||||
|  | @ -1103,7 +1106,10 @@ admin/views/index.vue: | |||
|   abuse: "스팸 신고" | ||||
|   queue: "작업 대기열" | ||||
|   logs: "로그" | ||||
|   db: "데이터베이스" | ||||
|   back-to-misskey: "Misskey로 돌아가기" | ||||
| admin/views/db.vue: | ||||
|   tables: "테이블" | ||||
| admin/views/dashboard.vue: | ||||
|   dashboard: "대시보드" | ||||
|   accounts: "계정" | ||||
|  | @ -1126,7 +1132,7 @@ admin/views/queue.vue: | |||
|   states: | ||||
|     active: "처리중" | ||||
|     delayed: "지연됨" | ||||
|     waiting: "대기열에 들어감" | ||||
|     waiting: "대기열에 있음" | ||||
|   result-is-truncated: "결과는 생략되었습니다" | ||||
|   other-queues: "기타 큐" | ||||
| admin/views/logs.vue: | ||||
|  | @ -1941,6 +1947,8 @@ pages: | |||
|       _pick: | ||||
|         arg1: "리스트" | ||||
|         arg2: "위치" | ||||
|       _listLen: | ||||
|         arg1: "리스트" | ||||
|       number: "수치" | ||||
|       stringToNumber: "텍스트를 수치로" | ||||
|       _stringToNumber: | ||||
|  |  | |||
|  | @ -623,5 +623,7 @@ pages: | |||
|         arg2: "Lijsten" | ||||
|       _pick: | ||||
|         arg1: "Lijsten" | ||||
|       _listLen: | ||||
|         arg1: "Lijsten" | ||||
|     types: | ||||
|       array: "Lijsten" | ||||
|  |  | |||
|  | @ -503,5 +503,7 @@ pages: | |||
|         arg2: "Lister" | ||||
|       _pick: | ||||
|         arg1: "Lister" | ||||
|       _listLen: | ||||
|         arg1: "Lister" | ||||
|     types: | ||||
|       array: "Lister" | ||||
|  |  | |||
|  | @ -1219,5 +1219,7 @@ pages: | |||
|         arg2: "Listy" | ||||
|       _pick: | ||||
|         arg1: "Listy" | ||||
|       _listLen: | ||||
|         arg1: "Listy" | ||||
|     types: | ||||
|       array: "Listy" | ||||
|  |  | |||
|  | @ -26,6 +26,13 @@ common: | |||
|   do-not-copy-paste: "Пожалуйста, не вводите и не вставляйте сюда код. Аккаунту может угрожать опасность." | ||||
|   load-more: "Загрузить больше" | ||||
|   enter-password: "Пожалуйста, введите ваш пароль" | ||||
|   2fa: "Двухфакторная аутентификация" | ||||
|   customize-home: "Настройка домашней страницы" | ||||
|   dark-mode: "Тёмная тема" | ||||
|   signin: "Войти" | ||||
|   signup: "Регистрация" | ||||
|   signout: "Выйти" | ||||
|   reload-to-apply-the-setting: "Вам необходимо перезагрузить страницу, чтобы применить настройки. Вы хотите перезагрузить сейчас?" | ||||
|   customization-tips: | ||||
|     title: "Советы по настройке" | ||||
|     gotit: "Понятно!" | ||||
|  | @ -51,7 +58,14 @@ common: | |||
|   month-and-day: "{day}.{month}" | ||||
|   trash: "Мусорное ведро" | ||||
|   drive: "Drive" | ||||
|   pages: "Страницы" | ||||
|   messaging: "Чат" | ||||
|   timeline: "Лента" | ||||
|   followers: "Подписчики" | ||||
|   favorites: "Избранное" | ||||
|   post-form: | ||||
|     reply: "Ответить" | ||||
|     create-poll: "Создать опрос" | ||||
|   weekday-short: | ||||
|     sunday: "Вс" | ||||
|     monday: "Пн" | ||||
|  |  | |||
|  | @ -270,6 +270,9 @@ common: | |||
|     disable-via-mobile: "不要将帖子标记为“来自手机”" | ||||
|     load-raw-images: "以原始质量显示附加图像" | ||||
|     load-remote-media: "显示来自远程服务器的媒体" | ||||
|     sync: "同步" | ||||
|     home-profile: "定制首页数据" | ||||
|     deck-profile: "定制Deck数据" | ||||
|   search: "搜索" | ||||
|   delete: "删除" | ||||
|   loading: "正在加载中" | ||||
|  | @ -859,7 +862,7 @@ desktop/views/components/crop-window.vue: | |||
|   cancel: "取消" | ||||
|   ok: "确定" | ||||
| desktop/views/components/drive-window.vue: | ||||
|   used: "使用中" | ||||
|   used: "已使用" | ||||
| desktop/views/components/drive.file.vue: | ||||
|   avatar: "头像" | ||||
|   banner: "背景" | ||||
|  | @ -1016,7 +1019,7 @@ desktop/views/components/settings.apps.vue: | |||
|   no-apps: "没有已连接的应用程序" | ||||
| common/views/components/drive-settings.vue: | ||||
|   max: "容量" | ||||
|   in-use: "正在使用" | ||||
|   in-use: "已使用" | ||||
|   stats: "统计" | ||||
| common/views/components/mute-and-block.vue: | ||||
|   mute-and-block: "屏蔽/拉黑" | ||||
|  | @ -1103,7 +1106,10 @@ admin/views/index.vue: | |||
|   abuse: "举报垃圾信息" | ||||
|   queue: "作业队列" | ||||
|   logs: "登录" | ||||
|   db: "数据库" | ||||
|   back-to-misskey: "返回 Misskey" | ||||
| admin/views/db.vue: | ||||
|   tables: "表格" | ||||
| admin/views/dashboard.vue: | ||||
|   dashboard: "Dashboard" | ||||
|   accounts: "账户" | ||||
|  | @ -1518,7 +1524,7 @@ desktop/views/widgets/users.vue: | |||
|   refresh: "更多" | ||||
|   no-one: "不是!" | ||||
| mobile/views/components/drive.vue: | ||||
|   used: "使用中" | ||||
|   used: "已使用" | ||||
|   folder-count: "文件夹" | ||||
|   count-separator: "," | ||||
|   file-count: "文件" | ||||
|  | @ -1941,6 +1947,8 @@ pages: | |||
|       _pick: | ||||
|         arg1: "列表" | ||||
|         arg2: "位置" | ||||
|       _listLen: | ||||
|         arg1: "列表" | ||||
|       number: "数值" | ||||
|       stringToNumber: "文本到数字" | ||||
|       _stringToNumber: | ||||
|  |  | |||
|  | @ -1,7 +1,7 @@ | |||
| { | ||||
| 	"name": "misskey", | ||||
| 	"author": "syuilo <i@syuilo.com>", | ||||
| 	"version": "11.22.0", | ||||
| 	"version": "11.23.0", | ||||
| 	"codename": "daybreak", | ||||
| 	"repository": { | ||||
| 		"type": "git", | ||||
|  |  | |||
|  | @ -60,9 +60,9 @@ export default function <T extends object>(data: { | |||
| 
 | ||||
| 			save() { | ||||
| 				if (this.platform == 'deck') { | ||||
| 					this.$store.commit('device/updateDeckColumn', this.column); | ||||
| 					this.$store.commit('updateDeckColumn', this.column); | ||||
| 				} else { | ||||
| 					this.$store.commit('device/updateWidget', this.widget); | ||||
| 					this.$store.commit('updateWidget', this.widget); | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
|  |  | |||
|  | @ -83,9 +83,19 @@ export default (opts: Opts = {}) => ({ | |||
| 			if (this.appearNote.text) { | ||||
| 				const ast = parse(this.appearNote.text); | ||||
| 				// TODO: 再帰的にURL要素がないか調べる
 | ||||
| 				return unique(ast | ||||
| 				const urls = unique(ast | ||||
| 					.filter(t => ((t.node.type == 'url' || t.node.type == 'link') && t.node.props.url && !t.node.props.silent)) | ||||
| 					.map(t => t.node.props.url)); | ||||
| 
 | ||||
| 				// unique without hash
 | ||||
| 				// [ http://a/#1, http://a/#2, http://b/#3 ] => [ http://a/#1, http://b/#3 ]
 | ||||
| 				const removeHash = x => x.replace(/#[^#]*$/, ''); | ||||
| 
 | ||||
| 				return urls.reduce((array, url) => { | ||||
| 					const removed = removeHash(url); | ||||
| 					if (!array.map(x => removeHash(x)).includes(removed)) array.push(url); | ||||
| 					return array; | ||||
| 				}, []); | ||||
| 			} else { | ||||
| 				return null; | ||||
| 			} | ||||
|  |  | |||
|  | @ -131,6 +131,13 @@ | |||
| 				</section> | ||||
| 			</section> | ||||
| 
 | ||||
| 			<section> | ||||
| 				<header>{{ $t('@._settings.sync') }}</header> | ||||
| 				<ui-input v-if="$root.isMobile" v-model="mobileHomeProfile" :datalist="Object.keys($store.state.settings.mobileHomeProfiles)">{{ $t('@._settings.home-profile') }}</ui-input> | ||||
| 				<ui-input v-else v-model="homeProfile" :datalist="Object.keys($store.state.settings.homeProfiles)">{{ $t('@._settings.home-profile') }}</ui-input> | ||||
| 				<ui-input v-model="deckProfile" :datalist="Object.keys($store.state.settings.deckProfiles)">{{ $t('@._settings.deck-profile') }}</ui-input> | ||||
| 			</section> | ||||
| 
 | ||||
| 			<section> | ||||
| 				<header>{{ $t('@._settings.web-search-engine') }}</header> | ||||
| 				<ui-input v-model="webSearchEngine">{{ $t('@._settings.web-search-engine') }}<template #desc>{{ $t('@._settings.web-search-engine-desc') }}</template></ui-input> | ||||
|  | @ -500,6 +507,21 @@ export default Vue.extend({ | |||
| 			get() { return this.$store.state.device.mobileNotificationPosition; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'mobileNotificationPosition', value }); } | ||||
| 		}, | ||||
| 
 | ||||
| 		homeProfile: { | ||||
| 			get() { return this.$store.state.device.homeProfile; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'homeProfile', value }); } | ||||
| 		}, | ||||
| 
 | ||||
| 		mobileHomeProfile: { | ||||
| 			get() { return this.$store.state.device.mobileHomeProfile; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'mobileHomeProfile', value }); } | ||||
| 		}, | ||||
| 
 | ||||
| 		deckProfile: { | ||||
| 			get() { return this.$store.state.device.deckProfile; }, | ||||
| 			set(value) { this.$store.commit('device/set', { key: 'deckProfile', value }); } | ||||
| 		}, | ||||
| 	}, | ||||
| 	created() { | ||||
| 		this.$root.getMeta().then(meta => { | ||||
|  |  | |||
|  | @ -30,7 +30,7 @@ | |||
| <script lang="ts"> | ||||
| import Vue from 'vue'; | ||||
| import i18n from '../../../i18n'; | ||||
| import { url as local } from '../../../config'; | ||||
| import { url as local, lang } from '../../../config'; | ||||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	i18n: i18n('common/views/components/url-preview.vue'), | ||||
|  | @ -89,10 +89,10 @@ export default Vue.extend({ | |||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		const url = new URL(this.url); | ||||
| 		const requestUrl = new URL(this.url); | ||||
| 
 | ||||
| 		if (this.detail && url.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(url.pathname)) { | ||||
| 			this.tweetUrl = url; | ||||
| 		if (this.detail && requestUrl.hostname == 'twitter.com' && /^\/.+\/status(es)?\/\d+/.test(requestUrl.pathname)) { | ||||
| 			this.tweetUrl = requestUrl; | ||||
| 			const twttr = (window as any).twttr || {}; | ||||
| 			const loadTweet = () => twttr.widgets.load(this.$refs.tweet); | ||||
| 
 | ||||
|  | @ -113,10 +113,15 @@ export default Vue.extend({ | |||
| 			return; | ||||
| 		} | ||||
| 
 | ||||
| 		if (url.hostname === 'music.youtube.com') | ||||
| 			url.hostname = 'youtube.com'; | ||||
| 		if (requestUrl.hostname === 'music.youtube.com') { | ||||
| 			requestUrl.hostname = 'youtube.com'; | ||||
| 		} | ||||
| 
 | ||||
| 		fetch(`/url?url=${encodeURIComponent(this.url)}`).then(res => { | ||||
| 		const requestLang = (lang || 'ja-JP').replace('ja-KS', 'ja-JP'); | ||||
| 
 | ||||
| 		requestUrl.hash = ''; | ||||
| 
 | ||||
| 		fetch(`/url?url=${encodeURIComponent(requestUrl.href)}&lang=${requestLang}`).then(res => { | ||||
| 			res.json().then(info => { | ||||
| 				if (info.url == null) return; | ||||
| 				this.title = info.title; | ||||
|  |  | |||
|  | @ -146,7 +146,8 @@ export default Vue.extend({ | |||
| 
 | ||||
| 		toggleActive() { | ||||
| 			if (!this.isStacked) return; | ||||
| 			const vms = this.$store.state.device.deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id)); | ||||
| 			const deck = this.$store.state.device.deckProfile ? this.$store.state.settings.deckProfiles[this.$store.state.device.deckProfile] : this.$store.state.device.deck; | ||||
| 			const vms = deck.layout.find(ids => ids.indexOf(this.column.id) != -1).map(id => this.getColumnVm(id)); | ||||
| 			if (this.active && countIf(vm => vm.$el.classList.contains('active'), vms) == 1) return; | ||||
| 			this.active = !this.active; | ||||
| 		}, | ||||
|  | @ -179,50 +180,50 @@ export default Vue.extend({ | |||
| 						} | ||||
| 					}).then(({ canceled, result: name }) => { | ||||
| 						if (canceled) return; | ||||
| 						this.$store.commit('device/renameDeckColumn', { id: this.column.id, name }); | ||||
| 						this.$store.commit('renameDeckColumn', { id: this.column.id, name }); | ||||
| 					}); | ||||
| 				} | ||||
| 			}, null, { | ||||
| 				icon: 'arrow-left', | ||||
| 				text: this.$t('swap-left'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/swapLeftDeckColumn', this.column.id); | ||||
| 					this.$store.commit('swapLeftDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			}, { | ||||
| 				icon: 'arrow-right', | ||||
| 				text: this.$t('swap-right'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/swapRightDeckColumn', this.column.id); | ||||
| 					this.$store.commit('swapRightDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			}, this.isStacked ? { | ||||
| 				icon: faArrowUp, | ||||
| 				text: this.$t('swap-up'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/swapUpDeckColumn', this.column.id); | ||||
| 					this.$store.commit('swapUpDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			} : undefined, this.isStacked ? { | ||||
| 				icon: faArrowDown, | ||||
| 				text: this.$t('swap-down'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/swapDownDeckColumn', this.column.id); | ||||
| 					this.$store.commit('swapDownDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			} : undefined, null, { | ||||
| 				icon: ['far', 'window-restore'], | ||||
| 				text: this.$t('stack-left'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/stackLeftDeckColumn', this.column.id); | ||||
| 					this.$store.commit('stackLeftDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			}, this.isStacked ? { | ||||
| 				icon: faWindowMaximize, | ||||
| 				text: this.$t('pop-right'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/popRightDeckColumn', this.column.id); | ||||
| 					this.$store.commit('popRightDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			} : undefined, null, { | ||||
| 				icon: ['far', 'trash-alt'], | ||||
| 				text: this.$t('remove'), | ||||
| 				action: () => { | ||||
| 					this.$store.commit('device/removeDeckColumn', this.column.id); | ||||
| 					this.$store.commit('removeDeckColumn', this.column.id); | ||||
| 				} | ||||
| 			}]; | ||||
| 
 | ||||
|  | @ -306,7 +307,7 @@ export default Vue.extend({ | |||
| 
 | ||||
| 			const id = e.dataTransfer.getData('mk-deck-column'); | ||||
| 			if (id != null && id != '') { | ||||
| 				this.$store.commit('device/swapDeckColumn', { | ||||
| 				this.$store.commit('swapDeckColumn', { | ||||
| 					a: this.column.id, | ||||
| 					b: id | ||||
| 				}); | ||||
|  |  | |||
|  | @ -90,7 +90,7 @@ export default Vue.extend({ | |||
| 
 | ||||
| 	methods: { | ||||
| 		onChangeSettings(v) { | ||||
| 			this.$store.commit('device/updateDeckColumn', this.column); | ||||
| 			this.$store.commit('updateDeckColumn', this.column); | ||||
| 		}, | ||||
| 
 | ||||
| 		focus() { | ||||
|  |  | |||
|  | @ -25,20 +25,25 @@ import * as uuid from 'uuid'; | |||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	i18n: i18n('deck'), | ||||
| 
 | ||||
| 	components: { | ||||
| 		XColumnCore | ||||
| 	}, | ||||
| 
 | ||||
| 	computed: { | ||||
| 		deck() { | ||||
| 			return this.$store.getters.deck; | ||||
| 		}, | ||||
| 
 | ||||
| 		columns(): any[] { | ||||
| 			if (this.$store.state.device.deck == null) return []; | ||||
| 			return this.$store.state.device.deck.columns; | ||||
| 			if (this.deck == null) return []; | ||||
| 			return this.deck.columns; | ||||
| 		}, | ||||
| 
 | ||||
| 		layout(): any[] { | ||||
| 			if (this.$store.state.device.deck == null) return []; | ||||
| 			if (this.$store.state.device.deck.layout == null) return this.$store.state.device.deck.columns.map(c => [c.id]); | ||||
| 			return this.$store.state.device.deck.layout; | ||||
| 			if (this.deck == null) return []; | ||||
| 			if (this.deck.layout == null) return this.deck.columns.map(c => [c.id]); | ||||
| 			return this.deck.layout; | ||||
| 		}, | ||||
| 
 | ||||
| 		style(): any { | ||||
|  | @ -75,7 +80,7 @@ export default Vue.extend({ | |||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		if (this.$store.state.device.deck == null) { | ||||
| 		if (this.deck == null) { | ||||
| 			const deck = { | ||||
| 				columns: [/*{ | ||||
| 					type: 'widgets', | ||||
|  | @ -101,10 +106,7 @@ export default Vue.extend({ | |||
| 
 | ||||
| 			deck.layout = deck.columns.map(c => [c.id]); | ||||
| 
 | ||||
| 			this.$store.commit('device/set', { | ||||
| 				key: 'deck', | ||||
| 				value: deck | ||||
| 			}); | ||||
| 			this.$store.commit('setDeck', deck); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
|  | @ -129,7 +131,7 @@ export default Vue.extend({ | |||
| 					icon: 'home', | ||||
| 					text: this.$t('@deck.home'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'home' | ||||
| 						}); | ||||
|  | @ -138,7 +140,7 @@ export default Vue.extend({ | |||
| 					icon: ['far', 'comments'], | ||||
| 					text: this.$t('@deck.local'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'local' | ||||
| 						}); | ||||
|  | @ -147,7 +149,7 @@ export default Vue.extend({ | |||
| 					icon: 'share-alt', | ||||
| 					text: this.$t('@deck.hybrid'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'hybrid' | ||||
| 						}); | ||||
|  | @ -156,7 +158,7 @@ export default Vue.extend({ | |||
| 					icon: 'globe', | ||||
| 					text: this.$t('@deck.global'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'global' | ||||
| 						}); | ||||
|  | @ -165,7 +167,7 @@ export default Vue.extend({ | |||
| 					icon: 'at', | ||||
| 					text: this.$t('@deck.mentions'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'mentions' | ||||
| 						}); | ||||
|  | @ -174,7 +176,7 @@ export default Vue.extend({ | |||
| 					icon: ['far', 'envelope'], | ||||
| 					text: this.$t('@deck.direct'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'direct' | ||||
| 						}); | ||||
|  | @ -195,7 +197,7 @@ export default Vue.extend({ | |||
| 							showCancelButton: true | ||||
| 						}); | ||||
| 						if (canceled) return; | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'list', | ||||
| 							list: lists.find(l => l.id === listId) | ||||
|  | @ -210,7 +212,7 @@ export default Vue.extend({ | |||
| 							input: true | ||||
| 						}).then(({ canceled, result: title }) => { | ||||
| 							if (canceled) return; | ||||
| 							this.$store.commit('device/addDeckColumn', { | ||||
| 							this.$store.commit('addDeckColumn', { | ||||
| 								id: uuid(), | ||||
| 								type: 'hashtag', | ||||
| 								tagTlId: this.$store.state.settings.tagTimelines.find(x => x.title == title).id | ||||
|  | @ -221,7 +223,7 @@ export default Vue.extend({ | |||
| 					icon: ['far', 'bell'], | ||||
| 					text: this.$t('@deck.notifications'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'notifications' | ||||
| 						}); | ||||
|  | @ -230,7 +232,7 @@ export default Vue.extend({ | |||
| 					icon: 'calculator', | ||||
| 					text: this.$t('@deck.widgets'), | ||||
| 					action: () => { | ||||
| 						this.$store.commit('device/addDeckColumn', { | ||||
| 						this.$store.commit('addDeckColumn', { | ||||
| 							id: uuid(), | ||||
| 							type: 'widgets', | ||||
| 							widgets: [] | ||||
|  |  | |||
|  | @ -110,7 +110,7 @@ export default Vue.extend({ | |||
| 		}, | ||||
| 
 | ||||
| 		addWidget() { | ||||
| 			this.$store.commit('device/addDeckWidget', { | ||||
| 			this.$store.commit('addDeckWidget', { | ||||
| 				id: this.column.id, | ||||
| 				widget: { | ||||
| 					name: this.widgetAdderSelected, | ||||
|  | @ -123,14 +123,14 @@ export default Vue.extend({ | |||
| 		}, | ||||
| 
 | ||||
| 		removeWidget(widget) { | ||||
| 			this.$store.commit('device/removeDeckWidget', { | ||||
| 			this.$store.commit('removeDeckWidget', { | ||||
| 				id: this.column.id, | ||||
| 				widget | ||||
| 			}); | ||||
| 		}, | ||||
| 
 | ||||
| 		saveWidgets() { | ||||
| 			this.$store.commit('device/updateDeckColumn', this.column); | ||||
| 			this.$store.commit('updateDeckColumn', this.column); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|  |  | |||
|  | @ -4,6 +4,7 @@ | |||
| 	<p>Machine: {{ meta.machine }}</p> | ||||
| 	<p>Node: {{ meta.node }}</p> | ||||
| 	<p>PSQL: {{ meta.psql }}</p> | ||||
| 	<p>Redis: {{ meta.redis }}</p> | ||||
| 	<p>Version: {{ meta.version }} </p> | ||||
| </div> | ||||
| </template> | ||||
|  |  | |||
|  | @ -84,6 +84,7 @@ import XWelcome from '../pages/welcome.vue'; | |||
| 
 | ||||
| export default Vue.extend({ | ||||
| 	i18n: i18n('desktop/views/components/home.vue'), | ||||
| 
 | ||||
| 	components: { | ||||
| 		XDraggable, | ||||
| 		XWelcome | ||||
|  | @ -102,7 +103,7 @@ export default Vue.extend({ | |||
| 	computed: { | ||||
| 		home(): any[] { | ||||
| 			if (this.$store.getters.isSignedIn) { | ||||
| 				return this.$store.state.device.home || []; | ||||
| 				return this.$store.getters.home || []; | ||||
| 			} else { | ||||
| 				return [{ | ||||
| 					name: 'instance', | ||||
|  | @ -138,7 +139,9 @@ export default Vue.extend({ | |||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		if (this.$store.getters.isSignedIn) { | ||||
| 		if (!this.$store.getters.isSignedIn) return; | ||||
| 
 | ||||
| 		if (this.$store.getters.home == null) { | ||||
| 			const defaultDesktopHomeWidgets = { | ||||
| 				left: [ | ||||
| 					'profile', | ||||
|  | @ -183,9 +186,7 @@ export default Vue.extend({ | |||
| 			} | ||||
| 			//#endregion | ||||
| 
 | ||||
| 			if (this.$store.state.device.home == null) { | ||||
| 				this.$store.commit('device/setHome', _defaultDesktopHomeWidgets); | ||||
| 			} | ||||
| 			this.$store.commit('setHome', _defaultDesktopHomeWidgets); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
|  | @ -223,7 +224,7 @@ export default Vue.extend({ | |||
| 		}, | ||||
| 
 | ||||
| 		addWidget() { | ||||
| 			this.$store.commit('device/addHomeWidget', { | ||||
| 			this.$store.commit('addHomeWidget', { | ||||
| 				name: this.widgetAdderSelected, | ||||
| 				id: uuid(), | ||||
| 				place: 'left', | ||||
|  | @ -234,7 +235,7 @@ export default Vue.extend({ | |||
| 		saveHome() { | ||||
| 			const left = this.widgets.left; | ||||
| 			const right = this.widgets.right; | ||||
| 			this.$store.commit('device/setHome', left.concat(right)); | ||||
| 			this.$store.commit('setHome', left.concat(right)); | ||||
| 			for (const w of left) w.place = 'left'; | ||||
| 			for (const w of right) w.place = 'right'; | ||||
| 		}, | ||||
|  | @ -245,7 +246,7 @@ export default Vue.extend({ | |||
| 
 | ||||
| 		focus() { | ||||
| 			(this.$refs.content as any).focus(); | ||||
| 		} | ||||
| 		}, | ||||
| 	} | ||||
| }); | ||||
| </script> | ||||
|  |  | |||
|  | @ -173,10 +173,9 @@ export default class MiOS extends EventEmitter { | |||
| 
 | ||||
| 			// Init service worker
 | ||||
| 			if (this.shouldRegisterSw) { | ||||
| 				// #4813
 | ||||
| 				//this.getMeta().then(data => {
 | ||||
| 				//	this.registerSw(data.swPublickey);
 | ||||
| 				//});
 | ||||
| 				this.getMeta().then(data => { | ||||
| 					this.registerSw(data.swPublickey); | ||||
| 				}); | ||||
| 			} | ||||
| 		}; | ||||
| 
 | ||||
|  |  | |||
|  | @ -72,13 +72,13 @@ export default Vue.extend({ | |||
| 
 | ||||
| 	computed: { | ||||
| 		widgets(): any[] { | ||||
| 			return this.$store.state.device.mobileHome; | ||||
| 			return this.$store.getters.mobileHome || []; | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
| 	created() { | ||||
| 		if (this.widgets.length == 0) { | ||||
| 			this.$store.commit('device/setMobileHome', [{ | ||||
| 			this.$store.commit('setMobileHome', [{ | ||||
| 				name: 'calendar', | ||||
| 				id: 'a', data: {} | ||||
| 			}, { | ||||
|  | @ -98,6 +98,12 @@ export default Vue.extend({ | |||
| 				id: 'g', data: {} | ||||
| 			}]); | ||||
| 		} | ||||
| 
 | ||||
| 		this.$watch('$store.getters.mobileHome', () => { | ||||
| 			this.$store.dispatch('settings/updateMobileHomeProfile'); | ||||
| 		}, { | ||||
| 			deep: true | ||||
| 		}); | ||||
| 	}, | ||||
| 
 | ||||
| 	mounted() { | ||||
|  | @ -122,7 +128,7 @@ export default Vue.extend({ | |||
| 		}, | ||||
| 
 | ||||
| 		addWidget() { | ||||
| 			this.$store.commit('device/addMobileHomeWidget', { | ||||
| 			this.$store.commit('addMobileHomeWidget', { | ||||
| 				name: this.widgetAdderSelected, | ||||
| 				id: uuid(), | ||||
| 				data: {} | ||||
|  | @ -130,11 +136,11 @@ export default Vue.extend({ | |||
| 		}, | ||||
| 
 | ||||
| 		removeWidget(widget) { | ||||
| 			this.$store.commit('device/removeMobileHomeWidget', widget); | ||||
| 			this.$store.commit('removeMobileHomeWidget', widget); | ||||
| 		}, | ||||
| 
 | ||||
| 		saveHome() { | ||||
| 			this.$store.commit('device/setMobileHome', this.widgets); | ||||
| 			this.$store.commit('setMobileHome', this.widgets); | ||||
| 		} | ||||
| 	} | ||||
| }); | ||||
|  |  | |||
|  | @ -1,3 +1,4 @@ | |||
| import Vue from 'vue'; | ||||
| import Vuex from 'vuex'; | ||||
| import createPersistedState from 'vuex-persistedstate'; | ||||
| import * as nestedProperty from 'nested-property'; | ||||
|  | @ -34,12 +35,15 @@ const defaultSettings = { | |||
| 	gamesReversiShowBoardLabels: false, | ||||
| 	gamesReversiUseAvatarStones: true, | ||||
| 	disableAnimatedMfm: false, | ||||
| 	homeProfiles: {}, | ||||
| 	mobileHomeProfiles: {}, | ||||
| 	deckProfiles: {}, | ||||
| }; | ||||
| 
 | ||||
| const defaultDeviceSettings = { | ||||
| 	home: null, | ||||
| 	mobileHome: [], | ||||
| 	deck: null, | ||||
| 	homeProfile: 'Default', | ||||
| 	mobileHomeProfile: 'Default', | ||||
| 	deckProfile: 'Default', | ||||
| 	deckMode: false, | ||||
| 	deckColumnAlign: 'center', | ||||
| 	deckColumnWidth: 'normal', | ||||
|  | @ -82,7 +86,13 @@ export default (os: MiOS) => new Vuex.Store({ | |||
| 	}, | ||||
| 
 | ||||
| 	getters: { | ||||
| 		isSignedIn: state => state.i != null | ||||
| 		isSignedIn: state => state.i != null, | ||||
| 
 | ||||
| 		home: state => state.settings.homeProfiles[state.device.homeProfile], | ||||
| 
 | ||||
| 		mobileHome: state => state.settings.mobileHomeProfiles[state.device.mobileHomeProfile], | ||||
| 
 | ||||
| 		deck: state => state.settings.deckProfiles[state.device.deckProfile], | ||||
| 	}, | ||||
| 
 | ||||
| 	mutations: { | ||||
|  | @ -112,6 +122,216 @@ export default (os: MiOS) => new Vuex.Store({ | |||
| 		clearBehindNotes(state) { | ||||
| 			state.behindNotes = []; | ||||
| 			document.title = os.instanceName; | ||||
| 		}, | ||||
| 
 | ||||
| 		setHome(state, data) { | ||||
| 			Vue.set(state.settings.homeProfiles, state.device.homeProfile, data); | ||||
| 			os.store.dispatch('settings/updateHomeProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		setDeck(state, data) { | ||||
| 			Vue.set(state.settings.deckProfiles, state.device.deckProfile, data); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		addHomeWidget(state, widget) { | ||||
| 			state.settings.homeProfiles[state.device.homeProfile].unshift(widget); | ||||
| 			os.store.dispatch('settings/updateHomeProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		setMobileHome(state, data) { | ||||
| 			Vue.set(state.settings.mobileHomeProfiles, state.device.mobileHomeProfile, data); | ||||
| 			os.store.dispatch('settings/updateMobileHomeProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		updateWidget(state, x) { | ||||
| 			let w; | ||||
| 
 | ||||
| 			//#region Desktop home
 | ||||
| 			const home = state.settings.homeProfiles[state.device.homeProfile]; | ||||
| 			if (home) { | ||||
| 				w = home.find(w => w.id == x.id); | ||||
| 				if (w) { | ||||
| 					w.data = x.data; | ||||
| 					os.store.dispatch('settings/updateHomeProfile'); | ||||
| 				} | ||||
| 			} | ||||
| 			//#endregion
 | ||||
| 
 | ||||
| 			//#region Mobile home
 | ||||
| 			const mobileHome = state.settings.mobileHomeProfiles[state.device.mobileHomeProfile]; | ||||
| 			if (mobileHome) { | ||||
| 				w = mobileHome.find(w => w.id == x.id); | ||||
| 				if (w) { | ||||
| 					w.data = x.data; | ||||
| 					os.store.dispatch('settings/updateMobileHomeProfile'); | ||||
| 				} | ||||
| 			} | ||||
| 			//#endregion
 | ||||
| 		}, | ||||
| 
 | ||||
| 		addMobileHomeWidget(state, widget) { | ||||
| 			state.settings.mobileHomeProfiles[state.device.mobileHomeProfile].unshift(widget); | ||||
| 			os.store.dispatch('settings/updateMobileHomeProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		removeMobileHomeWidget(state, widget) { | ||||
| 			Vue.set('state.settings.mobileHomeProfiles', state.device.mobileHomeProfile, state.settings.mobileHomeProfiles[state.device.mobileHomeProfile].filter(w => w.id != widget.id)); | ||||
| 			os.store.dispatch('settings/updateMobileHomeProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		addDeckColumn(state, column) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			if (column.name == undefined) column.name = null; | ||||
| 			deck.columns.push(column); | ||||
| 			deck.layout.push([column.id]); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		removeDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			deck.columns = deck.columns.filter(c => c.id != id); | ||||
| 			deck.layout = deck.layout.map(ids => erase(id, ids)); | ||||
| 			deck.layout = deck.layout.filter(ids => ids.length > 0); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		swapDeckColumn(state, x) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const a = x.a; | ||||
| 			const b = x.b; | ||||
| 			const aX = deck.layout.findIndex(ids => ids.indexOf(a) != -1); | ||||
| 			const aY = deck.layout[aX].findIndex(id => id == a); | ||||
| 			const bX = deck.layout.findIndex(ids => ids.indexOf(b) != -1); | ||||
| 			const bY = deck.layout[bX].findIndex(id => id == b); | ||||
| 			deck.layout[aX][aY] = b; | ||||
| 			deck.layout[bX][bY] = a; | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		swapLeftDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			deck.layout.some((ids, i) => { | ||||
| 				if (ids.indexOf(id) != -1) { | ||||
| 					const left = deck.layout[i - 1]; | ||||
| 					if (left) { | ||||
| 						// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 						//state.deck.layout[i - 1] = state.deck.layout[i];
 | ||||
| 						//state.deck.layout[i] = left;
 | ||||
| 						deck.layout.splice(i - 1, 1, deck.layout[i]); | ||||
| 						deck.layout.splice(i, 1, left); | ||||
| 					} | ||||
| 					return true; | ||||
| 				} | ||||
| 			}); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		swapRightDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			deck.layout.some((ids, i) => { | ||||
| 				if (ids.indexOf(id) != -1) { | ||||
| 					const right = deck.layout[i + 1]; | ||||
| 					if (right) { | ||||
| 						// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 						//state.deck.layout[i + 1] = state.deck.layout[i];
 | ||||
| 						//state.deck.layout[i] = right;
 | ||||
| 						deck.layout.splice(i + 1, 1, deck.layout[i]); | ||||
| 						deck.layout.splice(i, 1, right); | ||||
| 					} | ||||
| 					return true; | ||||
| 				} | ||||
| 			}); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		swapUpDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const ids = deck.layout.find(ids => ids.indexOf(id) != -1); | ||||
| 			ids.some((x, i) => { | ||||
| 				if (x == id) { | ||||
| 					const up = ids[i - 1]; | ||||
| 					if (up) { | ||||
| 						// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 						//ids[i - 1] = id;
 | ||||
| 						//ids[i] = up;
 | ||||
| 						ids.splice(i - 1, 1, id); | ||||
| 						ids.splice(i, 1, up); | ||||
| 					} | ||||
| 					return true; | ||||
| 				} | ||||
| 			}); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		swapDownDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const ids = deck.layout.find(ids => ids.indexOf(id) != -1); | ||||
| 			ids.some((x, i) => { | ||||
| 				if (x == id) { | ||||
| 					const down = ids[i + 1]; | ||||
| 					if (down) { | ||||
| 						// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 						//ids[i + 1] = id;
 | ||||
| 						//ids[i] = down;
 | ||||
| 						ids.splice(i + 1, 1, id); | ||||
| 						ids.splice(i, 1, down); | ||||
| 					} | ||||
| 					return true; | ||||
| 				} | ||||
| 			}); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		stackLeftDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const i = deck.layout.findIndex(ids => ids.indexOf(id) != -1); | ||||
| 			deck.layout = deck.layout.map(ids => erase(id, ids)); | ||||
| 			const left = deck.layout[i - 1]; | ||||
| 			if (left) deck.layout[i - 1].push(id); | ||||
| 			deck.layout = deck.layout.filter(ids => ids.length > 0); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		popRightDeckColumn(state, id) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const i = deck.layout.findIndex(ids => ids.indexOf(id) != -1); | ||||
| 			deck.layout = deck.layout.map(ids => erase(id, ids)); | ||||
| 			deck.layout.splice(i + 1, 0, [id]); | ||||
| 			deck.layout = deck.layout.filter(ids => ids.length > 0); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		addDeckWidget(state, x) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const column = deck.columns.find(c => c.id == x.id); | ||||
| 			if (column == null) return; | ||||
| 			column.widgets.unshift(x.widget); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		removeDeckWidget(state, x) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const column = deck.columns.find(c => c.id == x.id); | ||||
| 			if (column == null) return; | ||||
| 			column.widgets = column.widgets.filter(w => w.id != x.widget.id); | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		renameDeckColumn(state, x) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			const column = deck.columns.find(c => c.id == x.id); | ||||
| 			if (column == null) return; | ||||
| 			column.name = x.name; | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		}, | ||||
| 
 | ||||
| 		updateDeckColumn(state, x) { | ||||
| 			const deck = state.settings.deckProfiles[state.device.deckProfile]; | ||||
| 			let column = deck.columns.find(c => c.id == x.id); | ||||
| 			if (column == null) return; | ||||
| 			column = x; | ||||
| 			os.store.dispatch('settings/updateDeckProfile'); | ||||
| 		} | ||||
| 	}, | ||||
| 
 | ||||
|  | @ -159,176 +379,6 @@ export default (os: MiOS) => new Vuex.Store({ | |||
| 				setVisibility(state, visibility) { | ||||
| 					state.visibility = visibility; | ||||
| 				}, | ||||
| 
 | ||||
| 				setHome(state, data) { | ||||
| 					state.home = data; | ||||
| 				}, | ||||
| 
 | ||||
| 				addHomeWidget(state, widget) { | ||||
| 					state.home.unshift(widget); | ||||
| 				}, | ||||
| 
 | ||||
| 				setMobileHome(state, data) { | ||||
| 					state.mobileHome = data; | ||||
| 				}, | ||||
| 
 | ||||
| 				updateWidget(state, x) { | ||||
| 					let w; | ||||
| 
 | ||||
| 					//#region Desktop home
 | ||||
| 					if (state.home) { | ||||
| 						w = state.home.find(w => w.id == x.id); | ||||
| 						if (w) { | ||||
| 							w.data = x.data; | ||||
| 						} | ||||
| 					} | ||||
| 					//#endregion
 | ||||
| 
 | ||||
| 					//#region Mobile home
 | ||||
| 					if (state.mobileHome) { | ||||
| 						w = state.mobileHome.find(w => w.id == x.id); | ||||
| 						if (w) { | ||||
| 							w.data = x.data; | ||||
| 						} | ||||
| 					} | ||||
| 					//#endregion
 | ||||
| 				}, | ||||
| 
 | ||||
| 				addMobileHomeWidget(state, widget) { | ||||
| 					state.mobileHome.unshift(widget); | ||||
| 				}, | ||||
| 
 | ||||
| 				removeMobileHomeWidget(state, widget) { | ||||
| 					state.mobileHome = state.mobileHome.filter(w => w.id != widget.id); | ||||
| 				}, | ||||
| 
 | ||||
| 				addDeckColumn(state, column) { | ||||
| 					if (column.name == undefined) column.name = null; | ||||
| 					state.deck.columns.push(column); | ||||
| 					state.deck.layout.push([column.id]); | ||||
| 				}, | ||||
| 
 | ||||
| 				removeDeckColumn(state, id) { | ||||
| 					state.deck.columns = state.deck.columns.filter(c => c.id != id); | ||||
| 					state.deck.layout = state.deck.layout.map(ids => erase(id, ids)); | ||||
| 					state.deck.layout = state.deck.layout.filter(ids => ids.length > 0); | ||||
| 				}, | ||||
| 
 | ||||
| 				swapDeckColumn(state, x) { | ||||
| 					const a = x.a; | ||||
| 					const b = x.b; | ||||
| 					const aX = state.deck.layout.findIndex(ids => ids.indexOf(a) != -1); | ||||
| 					const aY = state.deck.layout[aX].findIndex(id => id == a); | ||||
| 					const bX = state.deck.layout.findIndex(ids => ids.indexOf(b) != -1); | ||||
| 					const bY = state.deck.layout[bX].findIndex(id => id == b); | ||||
| 					state.deck.layout[aX][aY] = b; | ||||
| 					state.deck.layout[bX][bY] = a; | ||||
| 				}, | ||||
| 
 | ||||
| 				swapLeftDeckColumn(state, id) { | ||||
| 					state.deck.layout.some((ids, i) => { | ||||
| 						if (ids.indexOf(id) != -1) { | ||||
| 							const left = state.deck.layout[i - 1]; | ||||
| 							if (left) { | ||||
| 								// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 								//state.deck.layout[i - 1] = state.deck.layout[i];
 | ||||
| 								//state.deck.layout[i] = left;
 | ||||
| 								state.deck.layout.splice(i - 1, 1, state.deck.layout[i]); | ||||
| 								state.deck.layout.splice(i, 1, left); | ||||
| 							} | ||||
| 							return true; | ||||
| 						} | ||||
| 					}); | ||||
| 				}, | ||||
| 
 | ||||
| 				swapRightDeckColumn(state, id) { | ||||
| 					state.deck.layout.some((ids, i) => { | ||||
| 						if (ids.indexOf(id) != -1) { | ||||
| 							const right = state.deck.layout[i + 1]; | ||||
| 							if (right) { | ||||
| 								// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 								//state.deck.layout[i + 1] = state.deck.layout[i];
 | ||||
| 								//state.deck.layout[i] = right;
 | ||||
| 								state.deck.layout.splice(i + 1, 1, state.deck.layout[i]); | ||||
| 								state.deck.layout.splice(i, 1, right); | ||||
| 							} | ||||
| 							return true; | ||||
| 						} | ||||
| 					}); | ||||
| 				}, | ||||
| 
 | ||||
| 				swapUpDeckColumn(state, id) { | ||||
| 					const ids = state.deck.layout.find(ids => ids.indexOf(id) != -1); | ||||
| 					ids.some((x, i) => { | ||||
| 						if (x == id) { | ||||
| 							const up = ids[i - 1]; | ||||
| 							if (up) { | ||||
| 								// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 								//ids[i - 1] = id;
 | ||||
| 								//ids[i] = up;
 | ||||
| 								ids.splice(i - 1, 1, id); | ||||
| 								ids.splice(i, 1, up); | ||||
| 							} | ||||
| 							return true; | ||||
| 						} | ||||
| 					}); | ||||
| 				}, | ||||
| 
 | ||||
| 				swapDownDeckColumn(state, id) { | ||||
| 					const ids = state.deck.layout.find(ids => ids.indexOf(id) != -1); | ||||
| 					ids.some((x, i) => { | ||||
| 						if (x == id) { | ||||
| 							const down = ids[i + 1]; | ||||
| 							if (down) { | ||||
| 								// https://vuejs.org/v2/guide/list.html#Caveats
 | ||||
| 								//ids[i + 1] = id;
 | ||||
| 								//ids[i] = down;
 | ||||
| 								ids.splice(i + 1, 1, id); | ||||
| 								ids.splice(i, 1, down); | ||||
| 							} | ||||
| 							return true; | ||||
| 						} | ||||
| 					}); | ||||
| 				}, | ||||
| 
 | ||||
| 				stackLeftDeckColumn(state, id) { | ||||
| 					const i = state.deck.layout.findIndex(ids => ids.indexOf(id) != -1); | ||||
| 					state.deck.layout = state.deck.layout.map(ids => erase(id, ids)); | ||||
| 					const left = state.deck.layout[i - 1]; | ||||
| 					if (left) state.deck.layout[i - 1].push(id); | ||||
| 					state.deck.layout = state.deck.layout.filter(ids => ids.length > 0); | ||||
| 				}, | ||||
| 
 | ||||
| 				popRightDeckColumn(state, id) { | ||||
| 					const i = state.deck.layout.findIndex(ids => ids.indexOf(id) != -1); | ||||
| 					state.deck.layout = state.deck.layout.map(ids => erase(id, ids)); | ||||
| 					state.deck.layout.splice(i + 1, 0, [id]); | ||||
| 					state.deck.layout = state.deck.layout.filter(ids => ids.length > 0); | ||||
| 				}, | ||||
| 
 | ||||
| 				addDeckWidget(state, x) { | ||||
| 					const column = state.deck.columns.find(c => c.id == x.id); | ||||
| 					if (column == null) return; | ||||
| 					column.widgets.unshift(x.widget); | ||||
| 				}, | ||||
| 
 | ||||
| 				removeDeckWidget(state, x) { | ||||
| 					const column = state.deck.columns.find(c => c.id == x.id); | ||||
| 					if (column == null) return; | ||||
| 					column.widgets = column.widgets.filter(w => w.id != x.widget.id); | ||||
| 				}, | ||||
| 
 | ||||
| 				renameDeckColumn(state, x) { | ||||
| 					const column = state.deck.columns.find(c => c.id == x.id); | ||||
| 					if (column == null) return; | ||||
| 					column.name = x.name; | ||||
| 				}, | ||||
| 
 | ||||
| 				updateDeckColumn(state, x) { | ||||
| 					let column = state.deck.columns.find(c => c.id == x.id); | ||||
| 					if (column == null) return; | ||||
| 					column = x; | ||||
| 				} | ||||
| 			} | ||||
| 		}, | ||||
| 
 | ||||
|  | @ -361,6 +411,42 @@ export default (os: MiOS) => new Vuex.Store({ | |||
| 						}); | ||||
| 					} | ||||
| 				}, | ||||
| 
 | ||||
| 				updateHomeProfile(ctx) { | ||||
| 					const profiles = ctx.state.homeProfiles; | ||||
| 					ctx.commit('set', { | ||||
| 						key: 'homeProfiles', | ||||
| 						value: profiles | ||||
| 					}); | ||||
| 					os.api('i/update-client-setting', { | ||||
| 						name: 'homeProfiles', | ||||
| 						value: profiles | ||||
| 					}); | ||||
| 				}, | ||||
| 
 | ||||
| 				updateMobileHomeProfile(ctx) { | ||||
| 					const profiles = ctx.state.mobileHomeProfiles; | ||||
| 					ctx.commit('set', { | ||||
| 						key: 'mobileHomeProfiles', | ||||
| 						value: profiles | ||||
| 					}); | ||||
| 					os.api('i/update-client-setting', { | ||||
| 						name: 'mobileHomeProfiles', | ||||
| 						value: profiles | ||||
| 					}); | ||||
| 				}, | ||||
| 
 | ||||
| 				updateDeckProfile(ctx) { | ||||
| 					const profiles = ctx.state.deckProfiles; | ||||
| 					ctx.commit('set', { | ||||
| 						key: 'deckProfiles', | ||||
| 						value: profiles | ||||
| 					}); | ||||
| 					os.api('i/update-client-setting', { | ||||
| 						name: 'deckProfiles', | ||||
| 						value: profiles | ||||
| 					}); | ||||
| 				}, | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
|  |  | |||
|  | @ -157,12 +157,14 @@ export const mfmLanguage = P.createLanguage({ | |||
| 			let url: string; | ||||
| 			if (!match) { | ||||
| 				const match = text.match(/^<(https?:\/\/.*?)>/); | ||||
| 				if (!match) | ||||
| 				if (!match) { | ||||
| 					return P.makeFailure(i, 'not a url'); | ||||
| 				} | ||||
| 				url = match[1]; | ||||
| 				i += 2; | ||||
| 			} else | ||||
| 			} else { | ||||
| 				url = match[0]; | ||||
| 			} | ||||
| 			url = removeOrphanedBrackets(url); | ||||
| 			while (url.endsWith('.') || url.endsWith(',')) { | ||||
| 				if (url.endsWith('.')) url = url.substr(0, url.lastIndexOf('.')); | ||||
|  |  | |||
|  | @ -171,6 +171,7 @@ export class ASEvaluator { | |||
| 			numberToString: (a: number) => a.toString(), | ||||
| 			splitStrByLine: (a: string) => a.split('\n'), | ||||
| 			pick: (list: any[], i: number) => list[i - 1], | ||||
| 			listLen: (list: any[]) => list.length, | ||||
| 			random: (probability: number) => Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * 100) < probability, | ||||
| 			rannum: (min: number, max: number) => min + Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * (max - min + 1)), | ||||
| 			randomPick: (list: any[]) => list[Math.floor(seedrandom(`${this.opts.randomSeed}:${block.id}`)() * list.length)], | ||||
|  |  | |||
|  | @ -74,6 +74,7 @@ export const funcDefs: Record<string, { in: any[]; out: any; category: string; i | |||
| 	numberToString:  { in: ['number'],                     out: 'string',      category: 'convert',    icon: faExchangeAlt, }, | ||||
| 	splitStrByLine:  { in: ['string'],                     out: 'stringArray', category: 'convert',    icon: faExchangeAlt, }, | ||||
| 	pick:            { in: [null, 'number'],               out: null,          category: 'list',       icon: faIndent, }, | ||||
| 	listLen:         { in: [null],                         out: 'number',      category: 'list',       icon: faIndent, }, | ||||
| 	rannum:          { in: ['number', 'number'],           out: 'number',      category: 'random',     icon: faDice, }, | ||||
| 	dailyRannum:     { in: ['number', 'number'],           out: 'number',      category: 'random',     icon: faDice, }, | ||||
| 	seedRannum:      { in: [null, 'number', 'number'],     out: 'number',      category: 'random',     icon: faDice, }, | ||||
|  |  | |||
|  | @ -15,6 +15,8 @@ import block from './block'; | |||
| import { apLogger } from '../logger'; | ||||
| 
 | ||||
| const self = async (actor: IRemoteUser, activity: Object): Promise<void> => { | ||||
| 	if (actor.isSuspended) return; | ||||
| 
 | ||||
| 	switch (activity.type) { | ||||
| 	case 'Create': | ||||
| 		await create(actor, activity); | ||||
|  |  | |||
|  | @ -7,6 +7,7 @@ import * as pkg from '../../../../package.json'; | |||
| import { Emojis } from '../../../models'; | ||||
| import { types, bool } from '../../../misc/schema'; | ||||
| import { getConnection } from 'typeorm'; | ||||
| import redis from '../../../db/redis'; | ||||
| 
 | ||||
| export const meta = { | ||||
| 	stability: 'stable', | ||||
|  | @ -116,6 +117,7 @@ export default define(meta, async (ps, me) => { | |||
| 		os: os.platform(), | ||||
| 		node: process.version, | ||||
| 		psql: await getConnection().query('SHOW server_version').then(x => x[0].server_version), | ||||
| 		redis: redis.server_info.redis_version, | ||||
| 
 | ||||
| 		cpu: { | ||||
| 			model: os.cpus()[0].model, | ||||
|  |  | |||
|  | @ -20,6 +20,8 @@ import { Users, Notes, Emojis, UserProfiles, Pages } from '../../models'; | |||
| import parseAcct from '../../misc/acct/parse'; | ||||
| import getNoteSummary from '../../misc/get-note-summary'; | ||||
| import { ensure } from '../../prelude/ensure'; | ||||
| import { getConnection } from 'typeorm'; | ||||
| import redis from '../../db/redis'; | ||||
| 
 | ||||
| const client = `${__dirname}/../../client/`; | ||||
| 
 | ||||
|  | @ -250,6 +252,8 @@ router.get('/info', async ctx => { | |||
| 		machine: os.hostname(), | ||||
| 		os: os.platform(), | ||||
| 		node: process.version, | ||||
| 		psql: await getConnection().query('SHOW server_version').then(x => x[0].server_version), | ||||
| 		redis: redis.server_info.redis_version, | ||||
| 		cpu: { | ||||
| 			model: os.cpus()[0].model, | ||||
| 			cores: os.cpus().length | ||||
|  |  | |||
|  | @ -12,18 +12,20 @@ module.exports = async (ctx: Koa.BaseContext) => { | |||
| 	const meta = await fetchMeta(); | ||||
| 
 | ||||
| 	logger.info(meta.summalyProxy | ||||
| 		? `(Proxy) Getting preview of ${ctx.query.url} ...` | ||||
| 		: `Getting preview of ${ctx.query.url} ...`); | ||||
| 		? `(Proxy) Getting preview of ${ctx.query.url}@${ctx.query.lang} ...` | ||||
| 		: `Getting preview of ${ctx.query.url}@${ctx.query.lang} ...`); | ||||
| 
 | ||||
| 	try { | ||||
| 		const summary = meta.summalyProxy ? await request.get({ | ||||
| 			url: meta.summalyProxy, | ||||
| 			qs: { | ||||
| 				url: ctx.query.url | ||||
| 				url: ctx.query.url, | ||||
| 				lang: ctx.query.lang || 'ja-JP' | ||||
| 			}, | ||||
| 			json: true | ||||
| 		}) : await summaly(ctx.query.url, { | ||||
| 			followRedirects: false | ||||
| 			followRedirects: false, | ||||
| 			lang: ctx.query.lang || 'ja-JP' | ||||
| 		}); | ||||
| 
 | ||||
| 		logger.succ(`Got preview of ${ctx.query.url}: ${summary.title}`); | ||||
|  |  | |||
|  | @ -85,6 +85,12 @@ html | |||
| 				tr | ||||
| 					th Node version | ||||
| 					td= node | ||||
| 				tr | ||||
| 					th PSQL version | ||||
| 					td= psql | ||||
| 				tr | ||||
| 					th Redis version | ||||
| 					td= redis | ||||
| 				tr | ||||
| 					th Machine | ||||
| 					td= machine | ||||
|  |  | |||
|  | @ -22,7 +22,7 @@ export default async function(follower: User, followee: User, silent = false) { | |||
| 		return; | ||||
| 	} | ||||
| 
 | ||||
| 	Followings.delete(following.id); | ||||
| 	await Followings.delete(following.id); | ||||
| 
 | ||||
| 	//#region Decrement following count
 | ||||
| 	Users.decrement({ id: follower.id }, 'followingCount', 1); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue