mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-20 15:20:18 +00:00
Chunter: Open message links without reload (#2124)
Signed-off-by: Denis Bunakalya <denis.bunakalya@xored.com>
This commit is contained in:
parent
b12ee1d8b7
commit
c7e916abd1
@ -14,7 +14,7 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
-->
|
-->
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { CheckBox, Component } from '@anticrm/ui'
|
import { CheckBox, Component, navigate, parseLocation } from '@anticrm/ui'
|
||||||
import view from '@anticrm/view'
|
import view from '@anticrm/view'
|
||||||
|
|
||||||
export let nodes: NodeListOf<any>
|
export let nodes: NodeListOf<any>
|
||||||
@ -63,8 +63,19 @@
|
|||||||
{:else if node.nodeName === 'DIV'}
|
{:else if node.nodeName === 'DIV'}
|
||||||
<div><svelte:self nodes={node.childNodes} /></div>
|
<div><svelte:self nodes={node.childNodes} /></div>
|
||||||
{:else if node.nodeName === 'A'}
|
{:else if node.nodeName === 'A'}
|
||||||
<a href={node.getAttribute('href')} target={node.getAttribute('target')}
|
<a
|
||||||
><svelte:self nodes={node.childNodes} /></a
|
href={node.getAttribute('href')}
|
||||||
|
target={node.getAttribute('target')}
|
||||||
|
on:click={(e) => {
|
||||||
|
try {
|
||||||
|
const url = new URL(node.getAttribute('href'))
|
||||||
|
|
||||||
|
if (url.origin === window.location.origin) {
|
||||||
|
e.preventDefault()
|
||||||
|
navigate(parseLocation(url))
|
||||||
|
}
|
||||||
|
} catch {}
|
||||||
|
}}><svelte:self nodes={node.childNodes} /></a
|
||||||
>
|
>
|
||||||
{:else if node.nodeName === 'LABEL'}
|
{:else if node.nodeName === 'LABEL'}
|
||||||
<svelte:self nodes={node.childNodes} />
|
<svelte:self nodes={node.childNodes} />
|
||||||
|
@ -40,5 +40,5 @@
|
|||||||
dispatch('close')
|
dispatch('close')
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<EditBox placeholder={linkPlaceholder} bind:value={link} maxWidth={'16rem'} focus />
|
<EditBox placeholder={linkPlaceholder} bind:value={link} maxWidth={'37.75rem'} focus />
|
||||||
</Card>
|
</Card>
|
||||||
|
@ -43,7 +43,7 @@ export function locationToUrl (location: PlatformLocation): string {
|
|||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
|
|
||||||
function parseLocation (location: Location): PlatformLocation {
|
export function parseLocation (location: Location | URL): PlatformLocation {
|
||||||
return {
|
return {
|
||||||
path: parsePath(location.pathname),
|
path: parsePath(location.pathname),
|
||||||
query: parseQuery(location.search),
|
query: parseQuery(location.search),
|
||||||
|
@ -19,10 +19,10 @@
|
|||||||
import core, { Doc, Ref, Space, Timestamp, WithLookup } from '@anticrm/core'
|
import core, { Doc, Ref, Space, Timestamp, WithLookup } from '@anticrm/core'
|
||||||
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
import { NotificationClientImpl } from '@anticrm/notification-resources'
|
||||||
import { createQuery } from '@anticrm/presentation'
|
import { createQuery } from '@anticrm/presentation'
|
||||||
import { getCurrentLocation, navigate } from '@anticrm/ui'
|
import { location as locationStore } from '@anticrm/ui'
|
||||||
import { afterUpdate, beforeUpdate } from 'svelte'
|
import { afterUpdate, beforeUpdate, onDestroy } from 'svelte'
|
||||||
import chunter from '../plugin'
|
import chunter from '../plugin'
|
||||||
import { getDay } from '../utils'
|
import { getDay, messageIdForScroll, shouldScrollToMessage, isMessageHighlighted, scrollAndHighLight } from '../utils'
|
||||||
import ChannelSeparator from './ChannelSeparator.svelte'
|
import ChannelSeparator from './ChannelSeparator.svelte'
|
||||||
import JumpToDateSelector from './JumpToDateSelector.svelte'
|
import JumpToDateSelector from './JumpToDateSelector.svelte'
|
||||||
import MessageComponent from './Message.svelte'
|
import MessageComponent from './Message.svelte'
|
||||||
@ -35,24 +35,31 @@
|
|||||||
|
|
||||||
let div: HTMLDivElement | undefined
|
let div: HTMLDivElement | undefined
|
||||||
let autoscroll: boolean = false
|
let autoscroll: boolean = false
|
||||||
let messageIdForScroll = ''
|
|
||||||
let isMessageHighlighted = false
|
const unsubscribe = locationStore.subscribe((newLocation) => {
|
||||||
|
const messageId = newLocation.fragment
|
||||||
|
|
||||||
|
if (!messageId) {
|
||||||
|
messageIdForScroll.set('')
|
||||||
|
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (messageId === $messageIdForScroll) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messageIdForScroll.set(messageId)
|
||||||
|
shouldScrollToMessage.set(true)
|
||||||
|
scrollAndHighLight()
|
||||||
|
})
|
||||||
|
onDestroy(unsubscribe)
|
||||||
|
|
||||||
beforeUpdate(() => {
|
beforeUpdate(() => {
|
||||||
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
||||||
})
|
})
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
if (messageIdForScroll && !isMessageHighlighted) {
|
if ($shouldScrollToMessage && !$isMessageHighlighted) {
|
||||||
const messageElement = document.getElementById(messageIdForScroll)
|
scrollAndHighLight()
|
||||||
|
|
||||||
messageElement?.scrollIntoView()
|
|
||||||
isMessageHighlighted = true
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
messageIdForScroll = ''
|
|
||||||
isMessageHighlighted = false
|
|
||||||
}, 2000)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -101,15 +108,6 @@
|
|||||||
messages = res
|
messages = res
|
||||||
newMessagesPos = newMessagesStart(messages)
|
newMessagesPos = newMessagesStart(messages)
|
||||||
notificationClient.updateLastView(space, chunter.class.ChunterSpace)
|
notificationClient.updateLastView(space, chunter.class.ChunterSpace)
|
||||||
|
|
||||||
const location = getCurrentLocation()
|
|
||||||
const messageId = location.fragment
|
|
||||||
|
|
||||||
if (messageId && location.path.length === 3) {
|
|
||||||
messageIdForScroll = messageId
|
|
||||||
location.fragment = undefined
|
|
||||||
navigate(location)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lookup: {
|
lookup: {
|
||||||
@ -230,7 +228,7 @@
|
|||||||
<JumpToDateSelector selectedDate={message.createOn} on:jumpToDate={handleJumpToDate} />
|
<JumpToDateSelector selectedDate={message.createOn} on:jumpToDate={handleJumpToDate} />
|
||||||
{/if}
|
{/if}
|
||||||
<MessageComponent
|
<MessageComponent
|
||||||
isHighlighted={messageIdForScroll === message._id && isMessageHighlighted}
|
isHighlighted={$messageIdForScroll === message._id && $isMessageHighlighted}
|
||||||
{message}
|
{message}
|
||||||
{employees}
|
{employees}
|
||||||
on:openThread
|
on:openThread
|
||||||
|
@ -24,6 +24,7 @@
|
|||||||
import { afterUpdate, beforeUpdate, createEventDispatcher } from 'svelte'
|
import { afterUpdate, beforeUpdate, createEventDispatcher } from 'svelte'
|
||||||
import { createBacklinks } from '../backlinks'
|
import { createBacklinks } from '../backlinks'
|
||||||
import chunter from '../plugin'
|
import chunter from '../plugin'
|
||||||
|
import { messageIdForScroll, shouldScrollToMessage, isMessageHighlighted, scrollAndHighLight } from '../utils'
|
||||||
import ChannelSeparator from './ChannelSeparator.svelte'
|
import ChannelSeparator from './ChannelSeparator.svelte'
|
||||||
import MsgView from './Message.svelte'
|
import MsgView from './Message.svelte'
|
||||||
|
|
||||||
@ -40,24 +41,14 @@
|
|||||||
let div: HTMLDivElement | undefined
|
let div: HTMLDivElement | undefined
|
||||||
let autoscroll: boolean = false
|
let autoscroll: boolean = false
|
||||||
let isScrollForced = false
|
let isScrollForced = false
|
||||||
let messageIdForScroll = ''
|
|
||||||
let isMessageHighlighted = false
|
|
||||||
|
|
||||||
beforeUpdate(() => {
|
beforeUpdate(() => {
|
||||||
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
autoscroll = div !== undefined && div.offsetHeight + div.scrollTop > div.scrollHeight - 20
|
||||||
})
|
})
|
||||||
|
|
||||||
afterUpdate(() => {
|
afterUpdate(() => {
|
||||||
if (messageIdForScroll && !isMessageHighlighted) {
|
if ($shouldScrollToMessage && !$isMessageHighlighted) {
|
||||||
const messageElement = document.getElementById(messageIdForScroll)
|
scrollAndHighLight()
|
||||||
|
|
||||||
messageElement?.scrollIntoView()
|
|
||||||
isMessageHighlighted = true
|
|
||||||
|
|
||||||
setTimeout(() => {
|
|
||||||
messageIdForScroll = ''
|
|
||||||
isMessageHighlighted = false
|
|
||||||
}, 2000)
|
|
||||||
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -112,15 +103,6 @@
|
|||||||
comments = res
|
comments = res
|
||||||
newMessagesPos = newMessagesStart(comments, $lastViews)
|
newMessagesPos = newMessagesStart(comments, $lastViews)
|
||||||
notificationClient.updateLastView(id, chunter.class.Message)
|
notificationClient.updateLastView(id, chunter.class.Message)
|
||||||
|
|
||||||
const location = getCurrentLocation()
|
|
||||||
const messageId = location.fragment
|
|
||||||
|
|
||||||
if (messageId && location.path.length === 4) {
|
|
||||||
messageIdForScroll = messageId
|
|
||||||
location.fragment = undefined
|
|
||||||
navigate(location)
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
lookup
|
lookup
|
||||||
@ -235,7 +217,7 @@
|
|||||||
<ChannelSeparator title={chunter.string.New} line reverse isNew />
|
<ChannelSeparator title={chunter.string.New} line reverse isNew />
|
||||||
{/if}
|
{/if}
|
||||||
<MsgView
|
<MsgView
|
||||||
isHighlighted={messageIdForScroll === comment._id && isMessageHighlighted}
|
isHighlighted={$messageIdForScroll === comment._id && $isMessageHighlighted}
|
||||||
message={comment}
|
message={comment}
|
||||||
{employees}
|
{employees}
|
||||||
thread
|
thread
|
||||||
|
@ -3,6 +3,7 @@ import contact, { EmployeeAccount, formatName } from '@anticrm/contact'
|
|||||||
import { Account, Class, Client, Obj, Ref, Space, getCurrentAccount, Timestamp } from '@anticrm/core'
|
import { Account, Class, Client, Obj, Ref, Space, getCurrentAccount, Timestamp } from '@anticrm/core'
|
||||||
import { Asset } from '@anticrm/platform'
|
import { Asset } from '@anticrm/platform'
|
||||||
import { getCurrentLocation, locationToUrl, navigate } from '@anticrm/ui'
|
import { getCurrentLocation, locationToUrl, navigate } from '@anticrm/ui'
|
||||||
|
import { writable, get } from 'svelte/store'
|
||||||
|
|
||||||
import chunter from './plugin'
|
import chunter from './plugin'
|
||||||
|
|
||||||
@ -97,3 +98,26 @@ export enum SearchType {
|
|||||||
Files,
|
Files,
|
||||||
Contacts
|
Contacts
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const messageIdForScroll = writable('')
|
||||||
|
export const shouldScrollToMessage = writable(false)
|
||||||
|
export const isMessageHighlighted = writable(false)
|
||||||
|
|
||||||
|
let highlightFinishTaskId: number
|
||||||
|
|
||||||
|
export function scrollAndHighLight (): void {
|
||||||
|
const messageElement = document.getElementById(get(messageIdForScroll))
|
||||||
|
|
||||||
|
if (messageElement == null) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
messageElement.scrollIntoView()
|
||||||
|
shouldScrollToMessage.set(false)
|
||||||
|
|
||||||
|
clearTimeout(highlightFinishTaskId)
|
||||||
|
isMessageHighlighted.set(true)
|
||||||
|
|
||||||
|
highlightFinishTaskId = window.setTimeout(() => {
|
||||||
|
isMessageHighlighted.set(false)
|
||||||
|
}, 2000)
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user