fix: Fix Sideview (#8235)
* Fix #7890 * a- * 3度目の正直 * fix * ✌️ * update CHANGELOG Co-authored-by: syuilo <Syuilotan@yahoo.co.jp>
This commit is contained in:
		
							parent
							
								
									141c999acd
								
							
						
					
					
						commit
						ae3abc2126
					
				
					 4 changed files with 194 additions and 224 deletions
				
			
		|  | @ -22,6 +22,7 @@ | ||||||
| - 投稿フォームのハッシュタグ保持フィールドが動作しない問題を修正 | - 投稿フォームのハッシュタグ保持フィールドが動作しない問題を修正 | ||||||
| - Add `img-src` and `media-src` directives to `Content-Security-Policy` for | - Add `img-src` and `media-src` directives to `Content-Security-Policy` for | ||||||
|   files and media proxy |   files and media proxy | ||||||
|  | - サイドビューが動かないのを修正 | ||||||
| - ensure that specified users does not get duplicates | - ensure that specified users does not get duplicates | ||||||
| 
 | 
 | ||||||
| ## 12.102.1 (2022/01/27) | ## 12.102.1 (2022/01/27) | ||||||
|  |  | ||||||
|  | @ -23,8 +23,9 @@ const props = withDefaults(defineProps<{ | ||||||
| 	behavior: null, | 	behavior: null, | ||||||
| }); | }); | ||||||
| 
 | 
 | ||||||
| const navHook = inject('navHook', null); | type Navigate = (path: string, record?: boolean) => void; | ||||||
| const sideViewHook = inject('sideViewHook', null); | const navHook = inject<null | Navigate>('navHook', null); | ||||||
|  | const sideViewHook = inject<null | Navigate>('sideViewHook', null); | ||||||
| 
 | 
 | ||||||
| const active = $computed(() => { | const active = $computed(() => { | ||||||
| 	if (props.activeClass == null) return false; | 	if (props.activeClass == null) return false; | ||||||
|  |  | ||||||
|  | @ -4,7 +4,7 @@ | ||||||
| 		<header class="header" @contextmenu.prevent.stop="onContextmenu"> | 		<header class="header" @contextmenu.prevent.stop="onContextmenu"> | ||||||
| 			<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-chevron-left"></i></button> | 			<button v-if="history.length > 0" class="_button" @click="back()"><i class="fas fa-chevron-left"></i></button> | ||||||
| 			<button v-else class="_button" style="pointer-events: none;"><!-- マージンのバランスを取るためのダミー --></button> | 			<button v-else class="_button" style="pointer-events: none;"><!-- マージンのバランスを取るためのダミー --></button> | ||||||
| 			<span class="title">{{ pageInfo.title }}</span> | 			<span class="title" v-text="pageInfo?.title" /> | ||||||
| 			<button class="_button" @click="close()"><i class="fas fa-times"></i></button> | 			<button class="_button" @click="close()"><i class="fas fa-times"></i></button> | ||||||
| 		</header> | 		</header> | ||||||
| 		<MkHeader class="pageHeader" :info="pageInfo"/> | 		<MkHeader class="pageHeader" :info="pageInfo"/> | ||||||
|  | @ -13,99 +13,89 @@ | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts" setup> | ||||||
| import { defineComponent } from 'vue'; | import { provide } from 'vue'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
| import copyToClipboard from '@/scripts/copy-to-clipboard'; | import copyToClipboard from '@/scripts/copy-to-clipboard'; | ||||||
| import { resolve } from '@/router'; | import { resolve, router } from '@/router'; | ||||||
| import { url } from '@/config'; | import { url as root } from '@/config'; | ||||||
| import * as symbols from '@/symbols'; | import * as symbols from '@/symbols'; | ||||||
|  | import { i18n } from '@/i18n'; | ||||||
| 
 | 
 | ||||||
| export default defineComponent({ | provide('navHook', navigate); | ||||||
| 	provide() { |  | ||||||
| 		return { |  | ||||||
| 			navHook: (path) => { |  | ||||||
| 				this.navigate(path); |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
| 
 | 
 | ||||||
| 	data() { | let path: string | null = $ref(null); | ||||||
| 		return { | let component: ReturnType<typeof resolve>['component'] | null = $ref(null); | ||||||
| 			path: null, | let props: any | null = $ref(null); | ||||||
| 			component: null, | let pageInfo: any | null = $ref(null); | ||||||
| 			props: {}, | let history: string[] = $ref([]); | ||||||
| 			pageInfo: null, |  | ||||||
| 			history: [], |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
| 
 | 
 | ||||||
| 	computed: { | let url = $computed(() => `${root}${path}`); | ||||||
| 		url(): string { |  | ||||||
| 			return url + this.path; |  | ||||||
| 		} |  | ||||||
| 	}, |  | ||||||
| 
 | 
 | ||||||
| 	methods: { | function changePage(page) { | ||||||
| 		changePage(page) { | 	if (page == null) return; | ||||||
| 			if (page == null) return; | 	if (page[symbols.PAGE_INFO]) { | ||||||
| 			if (page[symbols.PAGE_INFO]) { | 		pageInfo = page[symbols.PAGE_INFO]; | ||||||
| 				this.pageInfo = page[symbols.PAGE_INFO]; |  | ||||||
| 			} |  | ||||||
| 		}, |  | ||||||
| 
 |  | ||||||
| 		navigate(path, record = true) { |  | ||||||
| 			if (record && this.path) this.history.push(this.path); |  | ||||||
| 			this.path = path; |  | ||||||
| 			const { component, props } = resolve(path); |  | ||||||
| 			this.component = component; |  | ||||||
| 			this.props = props; |  | ||||||
| 		}, |  | ||||||
| 
 |  | ||||||
| 		back() { |  | ||||||
| 			this.navigate(this.history.pop(), false); |  | ||||||
| 		}, |  | ||||||
| 
 |  | ||||||
| 		close() { |  | ||||||
| 			this.path = null; |  | ||||||
| 			this.component = null; |  | ||||||
| 			this.props = {}; |  | ||||||
| 		}, |  | ||||||
| 
 |  | ||||||
| 		onContextmenu(ev: MouseEvent) { |  | ||||||
| 			os.contextMenu([{ |  | ||||||
| 				type: 'label', |  | ||||||
| 				text: this.path, |  | ||||||
| 			}, { |  | ||||||
| 				icon: 'fas fa-expand-alt', |  | ||||||
| 				text: this.$ts.showInPage, |  | ||||||
| 				action: () => { |  | ||||||
| 					this.$router.push(this.path); |  | ||||||
| 					this.close(); |  | ||||||
| 				} |  | ||||||
| 			}, { |  | ||||||
| 				icon: 'fas fa-window-maximize', |  | ||||||
| 				text: this.$ts.openInWindow, |  | ||||||
| 				action: () => { |  | ||||||
| 					os.pageWindow(this.path); |  | ||||||
| 					this.close(); |  | ||||||
| 				} |  | ||||||
| 			}, null, { |  | ||||||
| 				icon: 'fas fa-external-link-alt', |  | ||||||
| 				text: this.$ts.openInNewTab, |  | ||||||
| 				action: () => { |  | ||||||
| 					window.open(this.url, '_blank'); |  | ||||||
| 					this.close(); |  | ||||||
| 				} |  | ||||||
| 			}, { |  | ||||||
| 				icon: 'fas fa-link', |  | ||||||
| 				text: this.$ts.copyLink, |  | ||||||
| 				action: () => { |  | ||||||
| 					copyToClipboard(this.url); |  | ||||||
| 				} |  | ||||||
| 			}], ev); |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function navigate(_path: string, record = true) { | ||||||
|  | 	if (record && path) history.push($$(path).value); | ||||||
|  | 	path = _path; | ||||||
|  | 	const resolved = resolve(path); | ||||||
|  | 	component = resolved.component; | ||||||
|  | 	props = resolved.props; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function back() { | ||||||
|  | 	const prev = history.pop(); | ||||||
|  | 	if (prev) navigate(prev, false); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function close() { | ||||||
|  | 	path = null; | ||||||
|  | 	component = null; | ||||||
|  | 	props = {}; | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function onContextmenu(ev: MouseEvent) { | ||||||
|  | 	os.contextMenu([{ | ||||||
|  | 		type: 'label', | ||||||
|  | 		text: path || '', | ||||||
|  | 	}, { | ||||||
|  | 		icon: 'fas fa-expand-alt', | ||||||
|  | 		text: i18n.ts.showInPage, | ||||||
|  | 		action: () => { | ||||||
|  | 			if (path) router.push(path); | ||||||
|  | 			close(); | ||||||
|  | 		} | ||||||
|  | 	}, { | ||||||
|  | 		icon: 'fas fa-window-maximize', | ||||||
|  | 		text: i18n.ts.openInWindow, | ||||||
|  | 		action: () => { | ||||||
|  | 			if (path) os.pageWindow(path); | ||||||
|  | 			close(); | ||||||
|  | 		} | ||||||
|  | 	}, null, { | ||||||
|  | 		icon: 'fas fa-external-link-alt', | ||||||
|  | 		text: i18n.ts.openInNewTab, | ||||||
|  | 		action: () => { | ||||||
|  | 			window.open(url, '_blank'); | ||||||
|  | 			close(); | ||||||
|  | 		} | ||||||
|  | 	}, { | ||||||
|  | 		icon: 'fas fa-link', | ||||||
|  | 		text: i18n.ts.copyLink, | ||||||
|  | 		action: () => { | ||||||
|  | 			copyToClipboard(url); | ||||||
|  | 		} | ||||||
|  | 	}], ev); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | defineExpose({ | ||||||
|  | 	navigate, | ||||||
|  | 	back, | ||||||
|  | 	close, | ||||||
| }); | }); | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -20,7 +20,7 @@ | ||||||
| 		</main> | 		</main> | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
| 	<XSideView v-if="isDesktop" ref="side" class="side"/> | 	<XSideView v-if="isDesktop" ref="sideEl" class="side"/> | ||||||
| 
 | 
 | ||||||
| 	<div v-if="isDesktop" ref="widgetsEl" class="widgets"> | 	<div v-if="isDesktop" ref="widgetsEl" class="widgets"> | ||||||
| 		<XWidgets @mounted="attachSticky"/> | 		<XWidgets @mounted="attachSticky"/> | ||||||
|  | @ -31,9 +31,9 @@ | ||||||
| 	<div v-if="isMobile" class="buttons"> | 	<div v-if="isMobile" class="buttons"> | ||||||
| 		<button class="button nav _button" @click="drawerMenuShowing = true"><i class="fas fa-bars"></i><span v-if="menuIndicated" class="indicator"><i class="fas fa-circle"></i></span></button> | 		<button class="button nav _button" @click="drawerMenuShowing = true"><i class="fas fa-bars"></i><span v-if="menuIndicated" class="indicator"><i class="fas fa-circle"></i></span></button> | ||||||
| 		<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><i class="fas fa-home"></i></button> | 		<button class="button home _button" @click="$route.name === 'index' ? top() : $router.push('/')"><i class="fas fa-home"></i></button> | ||||||
| 		<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button> | 		<button class="button notifications _button" @click="$router.push('/my/notifications')"><i class="fas fa-bell"></i><span v-if="$i?.hasUnreadNotification" class="indicator"><i class="fas fa-circle"></i></span></button> | ||||||
| 		<button class="button widget _button" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button> | 		<button class="button widget _button" @click="widgetsShowing = true"><i class="fas fa-layer-group"></i></button> | ||||||
| 		<button class="button post _button" @click="post()"><i class="fas fa-pencil-alt"></i></button> | 		<button class="button post _button" @click="os.post()"><i class="fas fa-pencil-alt"></i></button> | ||||||
| 	</div> | 	</div> | ||||||
| 
 | 
 | ||||||
| 	<transition :name="$store.state.animation ? 'menuDrawer-back' : ''"> | 	<transition :name="$store.state.animation ? 'menuDrawer-back' : ''"> | ||||||
|  | @ -64,155 +64,133 @@ | ||||||
| </div> | </div> | ||||||
| </template> | </template> | ||||||
| 
 | 
 | ||||||
| <script lang="ts"> | <script lang="ts" setup> | ||||||
| import { defineComponent, defineAsyncComponent, provide, onMounted, computed, ref, watch } from 'vue'; | import { defineAsyncComponent, provide, onMounted, computed, ref, watch } from 'vue'; | ||||||
| import { instanceName } from '@/config'; | import { instanceName } from '@/config'; | ||||||
| import { StickySidebar } from '@/scripts/sticky-sidebar'; | import { StickySidebar } from '@/scripts/sticky-sidebar'; | ||||||
| import XSidebar from '@/ui/_common_/sidebar.vue'; |  | ||||||
| import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; | import XDrawerMenu from '@/ui/_common_/sidebar-for-mobile.vue'; | ||||||
| import XCommon from './_common_/common.vue'; | import XCommon from './_common_/common.vue'; | ||||||
| import XSideView from './classic.side.vue'; | import XSideView from './classic.side.vue'; | ||||||
| import * as os from '@/os'; | import * as os from '@/os'; | ||||||
| import * as symbols from '@/symbols'; | import * as symbols from '@/symbols'; | ||||||
| import { defaultStore } from '@/store'; | import { defaultStore } from '@/store'; | ||||||
| import * as EventEmitter from 'eventemitter3'; |  | ||||||
| import { menuDef } from '@/menu'; | import { menuDef } from '@/menu'; | ||||||
| import { useRoute } from 'vue-router'; | import { useRoute } from 'vue-router'; | ||||||
| import { i18n } from '@/i18n'; | import { i18n } from '@/i18n'; | ||||||
|  | import { $i } from '@/account'; | ||||||
|  | const XWidgets = defineAsyncComponent(() => import('./universal.widgets.vue')); | ||||||
|  | const XSidebar = defineAsyncComponent(() => import('@/ui/_common_/sidebar.vue')); | ||||||
| 
 | 
 | ||||||
| const DESKTOP_THRESHOLD = 1100; | const DESKTOP_THRESHOLD = 1100; | ||||||
| const MOBILE_THRESHOLD = 500; | const MOBILE_THRESHOLD = 500; | ||||||
| 
 | 
 | ||||||
| export default defineComponent({ | const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD); | ||||||
| 	components: { | const isMobile = ref(window.innerWidth <= MOBILE_THRESHOLD); | ||||||
| 		XCommon, | window.addEventListener('resize', () => { | ||||||
| 		XSidebar, | 	isMobile.value = window.innerWidth <= MOBILE_THRESHOLD; | ||||||
| 		XDrawerMenu, |  | ||||||
| 		XWidgets: defineAsyncComponent(() => import('./universal.widgets.vue')), |  | ||||||
| 		XSideView, // NOTE: dynamic importするとAsyncComponentWrapperが間に入るせいでref取得できなくて面倒になる |  | ||||||
| 	}, |  | ||||||
| 
 |  | ||||||
| 	setup() { |  | ||||||
| 		const isDesktop = ref(window.innerWidth >= DESKTOP_THRESHOLD); |  | ||||||
| 		const isMobile = ref(window.innerWidth <= MOBILE_THRESHOLD); |  | ||||||
| 		window.addEventListener('resize', () => { |  | ||||||
| 			isMobile.value = window.innerWidth <= MOBILE_THRESHOLD; |  | ||||||
| 		}); |  | ||||||
| 
 |  | ||||||
| 		const pageInfo = ref(); |  | ||||||
| 		const widgetsEl = ref<HTMLElement>(); |  | ||||||
| 		const widgetsShowing = ref(false); |  | ||||||
| 
 |  | ||||||
| 		const sideViewController = new EventEmitter(); |  | ||||||
| 
 |  | ||||||
| 		provide('sideViewHook', isDesktop.value ? (url) => { |  | ||||||
| 			sideViewController.emit('navigate', url); |  | ||||||
| 		} : null); |  | ||||||
| 
 |  | ||||||
| 		const menuIndicated = computed(() => { |  | ||||||
| 			for (const def in menuDef) { |  | ||||||
| 				if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから |  | ||||||
| 				if (menuDef[def].indicated) return true; |  | ||||||
| 			} |  | ||||||
| 			return false; |  | ||||||
| 		}); |  | ||||||
| 
 |  | ||||||
| 		const drawerMenuShowing = ref(false); |  | ||||||
| 
 |  | ||||||
| 		const route = useRoute(); |  | ||||||
| 		watch(route, () => { |  | ||||||
| 			drawerMenuShowing.value = false; |  | ||||||
| 		}); |  | ||||||
| 
 |  | ||||||
| 		document.documentElement.style.overflowY = 'scroll'; |  | ||||||
| 
 |  | ||||||
| 		if (defaultStore.state.widgets.length === 0) { |  | ||||||
| 			defaultStore.set('widgets', [{ |  | ||||||
| 				name: 'calendar', |  | ||||||
| 				id: 'a', place: 'right', data: {} |  | ||||||
| 			}, { |  | ||||||
| 				name: 'notifications', |  | ||||||
| 				id: 'b', place: 'right', data: {} |  | ||||||
| 			}, { |  | ||||||
| 				name: 'trends', |  | ||||||
| 				id: 'c', place: 'right', data: {} |  | ||||||
| 			}]); |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		onMounted(() => { |  | ||||||
| 			if (!isDesktop.value) { |  | ||||||
| 				window.addEventListener('resize', () => { |  | ||||||
| 					if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true; |  | ||||||
| 				}, { passive: true }); |  | ||||||
| 			} |  | ||||||
| 		}); |  | ||||||
| 
 |  | ||||||
| 		const changePage = (page) => { |  | ||||||
| 			if (page == null) return; |  | ||||||
| 			if (page[symbols.PAGE_INFO]) { |  | ||||||
| 				pageInfo.value = page[symbols.PAGE_INFO]; |  | ||||||
| 				document.title = `${pageInfo.value.title} | ${instanceName}`; |  | ||||||
| 			} |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		const onContextmenu = (ev) => { |  | ||||||
| 			const isLink = (el: HTMLElement) => { |  | ||||||
| 				if (el.tagName === 'A') return true; |  | ||||||
| 				if (el.parentElement) { |  | ||||||
| 					return isLink(el.parentElement); |  | ||||||
| 				} |  | ||||||
| 			}; |  | ||||||
| 			if (isLink(ev.target)) return; |  | ||||||
| 			if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return; |  | ||||||
| 			if (window.getSelection().toString() !== '') return; |  | ||||||
| 			const path = route.path; |  | ||||||
| 			os.contextMenu([{ |  | ||||||
| 				type: 'label', |  | ||||||
| 				text: path, |  | ||||||
| 			}, { |  | ||||||
| 				icon: 'fas fa-columns', |  | ||||||
| 				text: i18n.ts.openInSideView, |  | ||||||
| 				action: () => { |  | ||||||
| 					this.$refs.side.navigate(path); |  | ||||||
| 				} |  | ||||||
| 			}, { |  | ||||||
| 				icon: 'fas fa-window-maximize', |  | ||||||
| 				text: i18n.ts.openInWindow, |  | ||||||
| 				action: () => { |  | ||||||
| 					os.pageWindow(path); |  | ||||||
| 				} |  | ||||||
| 			}], ev); |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		const attachSticky = (el) => { |  | ||||||
| 			const sticky = new StickySidebar(widgetsEl.value); |  | ||||||
| 			window.addEventListener('scroll', () => { |  | ||||||
| 				sticky.calc(window.scrollY); |  | ||||||
| 			}, { passive: true }); |  | ||||||
| 		}; |  | ||||||
| 
 |  | ||||||
| 		return { |  | ||||||
| 			pageInfo, |  | ||||||
| 			isDesktop, |  | ||||||
| 			isMobile, |  | ||||||
| 			widgetsEl, |  | ||||||
| 			widgetsShowing, |  | ||||||
| 			drawerMenuShowing, |  | ||||||
| 			menuIndicated, |  | ||||||
| 			wallpaper: localStorage.getItem('wallpaper') != null, |  | ||||||
| 			changePage, |  | ||||||
| 			top: () => { |  | ||||||
| 				window.scroll({ top: 0, behavior: 'smooth' }); |  | ||||||
| 			}, |  | ||||||
| 			onTransition: () => { |  | ||||||
| 				if (window._scroll) window._scroll(); |  | ||||||
| 			}, |  | ||||||
| 			post: os.post, |  | ||||||
| 			onContextmenu, |  | ||||||
| 			attachSticky, |  | ||||||
| 		}; |  | ||||||
| 	}, |  | ||||||
| }); | }); | ||||||
|  | 
 | ||||||
|  | const pageInfo = ref(); | ||||||
|  | const widgetsEl = $ref<HTMLElement>(); | ||||||
|  | const widgetsShowing = ref(false); | ||||||
|  | 
 | ||||||
|  | let sideEl = $ref<InstanceType<typeof XSideView>>(); | ||||||
|  | 
 | ||||||
|  | provide('sideViewHook', isDesktop.value ? (url) => { | ||||||
|  | 	sideEl.navigate(url); | ||||||
|  | } : null); | ||||||
|  | 
 | ||||||
|  | const menuIndicated = computed(() => { | ||||||
|  | 	for (const def in menuDef) { | ||||||
|  | 		if (def === 'notifications') continue; // 通知は下にボタンとして表示されてるから | ||||||
|  | 		if (menuDef[def].indicated) return true; | ||||||
|  | 	} | ||||||
|  | 	return false; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const drawerMenuShowing = ref(false); | ||||||
|  | 
 | ||||||
|  | const route = useRoute(); | ||||||
|  | watch(route, () => { | ||||||
|  | 	drawerMenuShowing.value = false; | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | document.documentElement.style.overflowY = 'scroll'; | ||||||
|  | 
 | ||||||
|  | if (defaultStore.state.widgets.length === 0) { | ||||||
|  | 	defaultStore.set('widgets', [{ | ||||||
|  | 		name: 'calendar', | ||||||
|  | 		id: 'a', place: 'right', data: {} | ||||||
|  | 	}, { | ||||||
|  | 		name: 'notifications', | ||||||
|  | 		id: 'b', place: 'right', data: {} | ||||||
|  | 	}, { | ||||||
|  | 		name: 'trends', | ||||||
|  | 		id: 'c', place: 'right', data: {} | ||||||
|  | 	}]); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | onMounted(() => { | ||||||
|  | 	if (!isDesktop.value) { | ||||||
|  | 		window.addEventListener('resize', () => { | ||||||
|  | 			if (window.innerWidth >= DESKTOP_THRESHOLD) isDesktop.value = true; | ||||||
|  | 		}, { passive: true }); | ||||||
|  | 	} | ||||||
|  | }); | ||||||
|  | 
 | ||||||
|  | const changePage = (page) => { | ||||||
|  | 	if (page == null) return; | ||||||
|  | 	if (page[symbols.PAGE_INFO]) { | ||||||
|  | 		pageInfo.value = page[symbols.PAGE_INFO]; | ||||||
|  | 		document.title = `${pageInfo.value.title} | ${instanceName}`; | ||||||
|  | 	} | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const onContextmenu = (ev) => { | ||||||
|  | 	const isLink = (el: HTMLElement) => { | ||||||
|  | 		if (el.tagName === 'A') return true; | ||||||
|  | 		if (el.parentElement) { | ||||||
|  | 			return isLink(el.parentElement); | ||||||
|  | 		} | ||||||
|  | 	}; | ||||||
|  | 	if (isLink(ev.target)) return; | ||||||
|  | 	if (['INPUT', 'TEXTAREA', 'IMG', 'VIDEO', 'CANVAS'].includes(ev.target.tagName) || ev.target.attributes['contenteditable']) return; | ||||||
|  | 	if (window.getSelection()?.toString() !== '') return; | ||||||
|  | 	const path = route.path; | ||||||
|  | 	os.contextMenu([{ | ||||||
|  | 		type: 'label', | ||||||
|  | 		text: path, | ||||||
|  | 	}, { | ||||||
|  | 		icon: 'fas fa-columns', | ||||||
|  | 		text: i18n.ts.openInSideView, | ||||||
|  | 		action: () => { | ||||||
|  | 			sideEl.navigate(path); | ||||||
|  | 		} | ||||||
|  | 	}, { | ||||||
|  | 		icon: 'fas fa-window-maximize', | ||||||
|  | 		text: i18n.ts.openInWindow, | ||||||
|  | 		action: () => { | ||||||
|  | 			os.pageWindow(path); | ||||||
|  | 		} | ||||||
|  | 	}], ev); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | const attachSticky = (el) => { | ||||||
|  | 	const sticky = new StickySidebar(widgetsEl); | ||||||
|  | 	window.addEventListener('scroll', () => { | ||||||
|  | 		sticky.calc(window.scrollY); | ||||||
|  | 	}, { passive: true }); | ||||||
|  | }; | ||||||
|  | 
 | ||||||
|  | function top() { | ||||||
|  | 	window.scroll({ top: 0, behavior: 'smooth' }); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function onTransition() { | ||||||
|  | 	if (window._scroll) window._scroll(); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | const wallpaper = localStorage.getItem('wallpaper') != null; | ||||||
| </script> | </script> | ||||||
| 
 | 
 | ||||||
| <style lang="scss" scoped> | <style lang="scss" scoped> | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue