diff --git a/models/board/src/index.ts b/models/board/src/index.ts index d6a41dae54..30137159c6 100644 --- a/models/board/src/index.ts +++ b/models/board/src/index.ts @@ -284,7 +284,9 @@ export function createModel (builder: Builder): void { input: 'any', category: board.category.Card, target: board.class.Card, - context: { mode: 'context', application: board.app.Board, group: 'create' } + keyBinding: ['Enter'], + context: { mode: 'context', application: board.app.Board, group: 'create' }, + override: [view.action.Open] }, board.action.Open ) diff --git a/models/contact/src/index.ts b/models/contact/src/index.ts index f0c20a20a6..ded151543d 100644 --- a/models/contact/src/index.ts +++ b/models/contact/src/index.ts @@ -30,7 +30,7 @@ import { Persons, Status } from '@hcengineering/contact' -import { Class, DateRangeMode, Domain, Ref, Timestamp, DOMAIN_MODEL, IndexKind } from '@hcengineering/core' +import { Class, DateRangeMode, Domain, DOMAIN_MODEL, IndexKind, Ref, Timestamp } from '@hcengineering/core' import { Builder, Collection, @@ -48,7 +48,7 @@ import attachment from '@hcengineering/model-attachment' import chunter from '@hcengineering/model-chunter' import core, { TAccount, TAttachedDoc, TDoc, TSpace } from '@hcengineering/model-core' import presentation from '@hcengineering/model-presentation' -import view, { actionTemplates, createAction, ViewAction, Viewlet } from '@hcengineering/model-view' +import view, { createAction, ViewAction, Viewlet } from '@hcengineering/model-view' import workbench from '@hcengineering/model-workbench' import type { Asset, IntlString, Resource } from '@hcengineering/platform' import setting from '@hcengineering/setting' @@ -498,15 +498,6 @@ export function createModel (builder: Builder): void { contact.completion.OrganizationCategory ) - createAction(builder, { - ...actionTemplates.open, - target: contact.class.Contact, - context: { - mode: ['browser', 'context'], - group: 'create' - } - }) - createAction( builder, { diff --git a/models/document/src/index.ts b/models/document/src/index.ts index ad6aaaa2b9..fef7f68beb 100644 --- a/models/document/src/index.ts +++ b/models/document/src/index.ts @@ -245,11 +245,15 @@ export function createModel (builder: Builder): void { createAction(builder, { ...actionTemplates.open, + actionProps: { + component: document.component.EditDoc + }, target: document.class.Document, context: { mode: ['browser', 'context'], group: 'create' - } + }, + override: [view.action.Open] }) builder.mixin(document.class.DocumentVersion, core.class.Class, view.mixin.CollectionEditor, { editor: document.component.DocumentVersions diff --git a/models/gmail/src/index.ts b/models/gmail/src/index.ts index 0b1d9312ab..4cafea3be3 100644 --- a/models/gmail/src/index.ts +++ b/models/gmail/src/index.ts @@ -179,7 +179,7 @@ export function createModel (builder: Builder): void { label: gmail.string.WrtieEmail, icon: contact.icon.Email, keyBinding: [], - input: 'none', + input: 'any', category: contact.category.Contact, target: contact.class.Contact, context: { diff --git a/models/recruit/src/index.ts b/models/recruit/src/index.ts index 544f9c044b..44f6cea666 100644 --- a/models/recruit/src/index.ts +++ b/models/recruit/src/index.ts @@ -620,7 +620,7 @@ export function createModel (builder: Builder): void { }, label: recruit.string.CreateTalent, icon: recruit.icon.Create, - keyBinding: ['c'], + keyBinding: ['keyC'], input: 'none', category: recruit.category.Recruit, target: core.class.Doc, @@ -720,7 +720,7 @@ export function createModel (builder: Builder): void { }, input: 'focus', category: recruit.category.Recruit, - keyBinding: ['e'], + keyBinding: ['keyE'], target: recruit.class.Vacancy, context: { mode: ['context', 'browser'], diff --git a/models/tags/src/index.ts b/models/tags/src/index.ts index 8224f782f5..0da6471556 100644 --- a/models/tags/src/index.ts +++ b/models/tags/src/index.ts @@ -117,6 +117,10 @@ export function createModel (builder: Builder): void { component: tags.component.TagsFilter }) + builder.mixin(tags.class.TagElement, core.class.Class, view.mixin.IgnoreActions, { + actions: [view.action.Open] + }) + builder.createDoc( view.class.FilterMode, core.space.Model, diff --git a/models/tracker/src/index.ts b/models/tracker/src/index.ts index ac88e688f5..ade5354f58 100644 --- a/models/tracker/src/index.ts +++ b/models/tracker/src/index.ts @@ -48,7 +48,7 @@ import { import attachment from '@hcengineering/model-attachment' import chunter from '@hcengineering/model-chunter' import core, { DOMAIN_SPACE, TAttachedDoc, TDoc, TSpace, TType } from '@hcengineering/model-core' -import view, { classPresenter, createAction } from '@hcengineering/model-view' +import view, { actionTemplates, classPresenter, createAction } from '@hcengineering/model-view' import workbench, { createNavigateAction } from '@hcengineering/model-workbench' import notification from '@hcengineering/notification' import { Asset, IntlString } from '@hcengineering/platform' @@ -1053,6 +1053,29 @@ export function createModel (builder: Builder): void { tracker.category.Tracker ) + createAction( + builder, + { + action: view.actionImpl.ShowPopup, + actionProps: { + component: tracker.component.CreateIssue, + element: 'top' + }, + label: tracker.string.NewIssue, + icon: tracker.icon.Issue, + keyBinding: ['keyC'], + input: 'none', + category: tracker.category.Tracker, + target: tracker.class.Issue, + context: { + mode: ['browser'], + application: tracker.app.Tracker, + group: 'create' + } + }, + tracker.action.NewSubIssue + ) + createAction( builder, { @@ -1156,6 +1179,32 @@ export function createModel (builder: Builder): void { } }) + createAction(builder, { + ...actionTemplates.open, + actionProps: { + component: tracker.component.EditIssue + }, + target: tracker.class.Issue, + context: { + mode: ['browser', 'context'], + group: 'create' + }, + override: [view.action.Open] + }) + + createAction(builder, { + ...actionTemplates.open, + actionProps: { + component: tracker.component.EditIssueTemplate + }, + target: tracker.class.IssueTemplate, + context: { + mode: ['browser', 'context'], + group: 'create' + }, + override: [view.action.Open] + }) + builder.mixin(tracker.class.Issue, core.class.Class, view.mixin.ClassFilters, { filters: ['status', 'priority', 'assignee', 'project', 'sprint', 'estimation', 'dueDate', 'modifiedOn'] }) @@ -1182,6 +1231,27 @@ export function createModel (builder: Builder): void { sort: { rank: SortingOrder.Ascending } } + createAction(builder, { + action: view.actionImpl.ShowPopup, + actionProps: { + component: tracker.component.TimeSpendReportPopup, + fillProps: { + _object: 'issue' + } + }, + label: tracker.string.TimeSpendReportAdd, + icon: tracker.icon.TimeReport, + input: 'focus', + keyBinding: ['keyT'], + category: tracker.category.Tracker, + target: tracker.class.Issue, + context: { + mode: ['context', 'browser'], + application: tracker.app.Tracker, + group: 'edit' + } + }) + createAction( builder, { @@ -1198,12 +1268,12 @@ export function createModel (builder: Builder): void { }, label: tracker.string.Status, icon: tracker.icon.CategoryBacklog, - keyBinding: [], - input: 'none', + keyBinding: ['keyS->keyS'], + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { - mode: ['context'], + mode: ['context', 'browser'], application: tracker.app.Tracker, group: 'edit' } @@ -1222,12 +1292,12 @@ export function createModel (builder: Builder): void { }, label: tracker.string.Priority, icon: tracker.icon.PriorityHigh, - keyBinding: [], - input: 'none', + keyBinding: ['keyP-keyR'], + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { - mode: ['context'], + mode: ['context', 'browser'], application: tracker.app.Tracker, group: 'edit' } @@ -1247,12 +1317,12 @@ export function createModel (builder: Builder): void { }, label: tracker.string.Assignee, icon: contact.icon.Person, - keyBinding: [], - input: 'none', + keyBinding: ['keyA'], + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { - mode: ['context'], + mode: ['context', 'browser'], application: tracker.app.Tracker, group: 'edit' } @@ -1274,12 +1344,12 @@ export function createModel (builder: Builder): void { }, label: tracker.string.Project, icon: tracker.icon.Project, - keyBinding: [], - input: 'none', + keyBinding: ['keyP->keyP'], + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { - mode: ['context'], + mode: ['context', 'browser'], application: tracker.app.Tracker, group: 'edit' } @@ -1307,12 +1377,12 @@ export function createModel (builder: Builder): void { }, label: tracker.string.Sprint, icon: tracker.icon.Sprint, - keyBinding: [], - input: 'none', + keyBinding: ['keyS->keyP'], + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { - mode: ['context'], + mode: ['context', 'browser'], application: tracker.app.Tracker, group: 'edit' } @@ -1334,8 +1404,8 @@ export function createModel (builder: Builder): void { }, label: tracker.string.SetDueDate, icon: tracker.icon.DueDate, - keyBinding: [], - input: 'none', + keyBinding: ['keyD'], + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { @@ -1356,7 +1426,7 @@ export function createModel (builder: Builder): void { label: tracker.string.CopyIssueId, icon: tracker.icon.CopyID, keyBinding: [], - input: 'none', + input: 'focus', category: tracker.category.Tracker, target: tracker.class.Issue, context: { @@ -1377,7 +1447,7 @@ export function createModel (builder: Builder): void { label: tracker.string.CopyIssueTitle, icon: tracker.icon.CopyBranch, keyBinding: [], - input: 'none', + input: 'focus', category: tracker.category.Tracker, target: tracker.class.Issue, context: { @@ -1398,7 +1468,7 @@ export function createModel (builder: Builder): void { label: tracker.string.CopyIssueUrl, icon: tracker.icon.CopyURL, keyBinding: [], - input: 'none', + input: 'focus', category: tracker.category.Tracker, target: tracker.class.Issue, context: { @@ -1416,7 +1486,7 @@ export function createModel (builder: Builder): void { label: tracker.string.MoveToTeam, icon: view.icon.Move, keyBinding: [], - input: 'none', + input: 'any', category: tracker.category.Tracker, target: tracker.class.Issue, context: { @@ -1465,7 +1535,7 @@ export function createModel (builder: Builder): void { label: tracker.string.Duplicate, icon: tracker.icon.Duplicate, keyBinding: [], - input: 'none', + input: 'focus', category: tracker.category.Tracker, target: tracker.class.Issue, context: { diff --git a/models/tracker/src/plugin.ts b/models/tracker/src/plugin.ts index 1bfbfc5646..b006899de4 100644 --- a/models/tracker/src/plugin.ts +++ b/models/tracker/src/plugin.ts @@ -41,7 +41,8 @@ export default mergeIds(trackerId, tracker, { // Required to pass build without errorsF Nope: '' as AnyComponent, SprintSelector: '' as AnyComponent, - IssueStatistics: '' as AnyComponent + IssueStatistics: '' as AnyComponent, + TimeSpendReportPopup: '' as AnyComponent }, app: { Tracker: '' as Ref diff --git a/models/view/src/index.ts b/models/view/src/index.ts index 194fb7e8ca..d12f7e72cf 100644 --- a/models/view/src/index.ts +++ b/models/view/src/index.ts @@ -731,6 +731,17 @@ export function createModel (builder: Builder): void { target: core.class.Doc, context: { mode: ['context', 'browser', 'editor'] } }) + + createAction( + builder, + { + ...actionTemplates.open, + target: core.class.Doc, + category: view.category.Editor, + context: { mode: ['browser', 'context'], group: 'edit' } + }, + view.action.Open + ) } export default view diff --git a/packages/presentation/src/components/AssigneePopup.svelte b/packages/presentation/src/components/AssigneePopup.svelte index 21a719f8fb..aa5b0303d3 100644 --- a/packages/presentation/src/components/AssigneePopup.svelte +++ b/packages/presentation/src/components/AssigneePopup.svelte @@ -137,11 +137,6 @@ key.stopPropagation() handleSelection(key, selection) } - if (key.code === 'Escape') { - key.preventDefault() - key.stopPropagation() - dispatch('close') - } } const manager = createFocusManager() diff --git a/packages/presentation/src/components/ObjectPopup.svelte b/packages/presentation/src/components/ObjectPopup.svelte index 9ef6044815..060564a035 100644 --- a/packages/presentation/src/components/ObjectPopup.svelte +++ b/packages/presentation/src/components/ObjectPopup.svelte @@ -137,11 +137,6 @@ key.stopPropagation() handleSelection(key, objects, selection) } - if (key.code === 'Escape') { - key.preventDefault() - key.stopPropagation() - dispatch('close') - } } const manager = createFocusManager() diff --git a/packages/ui/src/components/ColorPopup.svelte b/packages/ui/src/components/ColorPopup.svelte index 8f0b745862..c863160565 100644 --- a/packages/ui/src/components/ColorPopup.svelte +++ b/packages/ui/src/components/ColorPopup.svelte @@ -16,9 +16,9 @@ import type { IntlString } from '@hcengineering/platform' import { translate } from '@hcengineering/platform' import { createEventDispatcher, onMount } from 'svelte' + import { deviceOptionsStore, resizeObserver } from '..' import { getPlatformColor } from '../colors' import ListView from './ListView.svelte' - import { resizeObserver, deviceOptionsStore } from '..' export let placeholder: IntlString | undefined = undefined export let placeholderParam: any | undefined = undefined @@ -62,11 +62,6 @@ key.stopPropagation() handleSelection(key, selection) } - if (key.code === 'Escape') { - key.preventDefault() - key.stopPropagation() - dispatch('close') - } } let input: HTMLElement onMount(() => { diff --git a/packages/ui/src/components/DropdownLabelsPopup.svelte b/packages/ui/src/components/DropdownLabelsPopup.svelte index 24f63a2007..65ae814d57 100644 --- a/packages/ui/src/components/DropdownLabelsPopup.svelte +++ b/packages/ui/src/components/DropdownLabelsPopup.svelte @@ -16,11 +16,11 @@ import type { IntlString } from '@hcengineering/platform' import { translate } from '@hcengineering/platform' import { createEventDispatcher, onMount } from 'svelte' - import type { DropdownTextItem } from '../types' + import { deviceOptionsStore, resizeObserver } from '..' import plugin from '../plugin' + import type { DropdownTextItem } from '../types' import CheckBox from './CheckBox.svelte' import ListView from './ListView.svelte' - import { resizeObserver, deviceOptionsStore } from '..' export let placeholder: IntlString = plugin.string.SearchDots export let items: DropdownTextItem[] @@ -76,11 +76,6 @@ key.stopPropagation() handleSelection(key, selection) } - if (key.code === 'Escape') { - key.preventDefault() - key.stopPropagation() - dispatch('close') - } } function isSelected ( diff --git a/packages/ui/src/components/DropdownPopup.svelte b/packages/ui/src/components/DropdownPopup.svelte index 78b57dd202..a86706ee2c 100644 --- a/packages/ui/src/components/DropdownPopup.svelte +++ b/packages/ui/src/components/DropdownPopup.svelte @@ -16,11 +16,11 @@ import type { Asset, IntlString } from '@hcengineering/platform' import { translate } from '@hcengineering/platform' import { createEventDispatcher, onMount } from 'svelte' - import type { AnySvelteComponent, ListItem } from '../types' + import { deviceOptionsStore, resizeObserver } from '..' import plugin from '../plugin' + import type { AnySvelteComponent, ListItem } from '../types' import Icon from './Icon.svelte' import ListView from './ListView.svelte' - import { resizeObserver, deviceOptionsStore } from '..' export let icon: Asset | AnySvelteComponent export let placeholder: IntlString = plugin.string.SearchDots @@ -69,11 +69,6 @@ key.stopPropagation() handleSelection(key, selection) } - if (key.code === 'Escape') { - key.preventDefault() - key.stopPropagation() - dispatch('close') - } } diff --git a/packages/ui/src/components/DropdownRecordPopup.svelte b/packages/ui/src/components/DropdownRecordPopup.svelte index 30d79c0bf3..7e07144fb0 100644 --- a/packages/ui/src/components/DropdownRecordPopup.svelte +++ b/packages/ui/src/components/DropdownRecordPopup.svelte @@ -15,10 +15,10 @@ diff --git a/packages/ui/src/components/SelectPopup.svelte b/packages/ui/src/components/SelectPopup.svelte index dd876c214c..851d009295 100644 --- a/packages/ui/src/components/SelectPopup.svelte +++ b/packages/ui/src/components/SelectPopup.svelte @@ -15,15 +15,15 @@ => ({ StatusRefPresenter, RelatedIssuesSection, RelatedIssueSelector, - DeleteProjectPresenter + DeleteProjectPresenter, + TimeSpendReportPopup }, completion: { IssueQuery: async (client: Client, query: string, filter?: { in?: RelatedDocument[], nin?: RelatedDocument[] }) => diff --git a/plugins/view-resources/src/actionImpl.ts b/plugins/view-resources/src/actionImpl.ts index 2d27c75153..67abdd61d7 100644 --- a/plugins/view-resources/src/actionImpl.ts +++ b/plugins/view-resources/src/actionImpl.ts @@ -11,7 +11,7 @@ import { showPanel, showPopup } from '@hcengineering/ui' -import { Action, ViewContext } from '@hcengineering/view' +import { ViewContext } from '@hcengineering/view' import MoveView from './components/Move.svelte' import { contextStore } from './context' import view from './plugin' @@ -96,12 +96,13 @@ export function select (evt: Event | undefined, offset: 1 | -1 | 0, of?: Doc, di } } -function SelectItem (doc: Doc | undefined, evt: Event): void { - if (doc !== undefined) { +function SelectItem (doc: Doc | Doc[] | undefined, evt: Event): void { + const focus = $focusStore.focus + if (focus !== undefined) { selectionStore.update((selection) => { - const ind = selection.findIndex((it) => it._id === doc._id) + const ind = selection.findIndex((it) => it._id === focus._id) if (ind === -1) { - selection.push(doc) + selection.push(focus) } else { selection.splice(ind, 1) } @@ -122,10 +123,10 @@ function SelectItemAll (doc: Doc | undefined, evt: Event): void { evt.preventDefault() } -const MoveUp = (doc: Doc | undefined, evt: Event): void => select(evt, -1, doc, 'vertical') -const MoveDown = (doc: Doc | undefined, evt: Event): void => select(evt, 1, doc, 'vertical') -const MoveLeft = (doc: Doc | undefined, evt: Event): void => select(evt, -1, doc, 'horizontal') -const MoveRight = (doc: Doc | undefined, evt: Event): void => select(evt, 1, doc, 'horizontal') +const MoveUp = (doc: Doc | undefined, evt: Event): void => select(evt, -1, $focusStore.focus, 'vertical') +const MoveDown = (doc: Doc | undefined, evt: Event): void => select(evt, 1, $focusStore.focus, 'vertical') +const MoveLeft = (doc: Doc | undefined, evt: Event): void => select(evt, -1, $focusStore.focus, 'horizontal') +const MoveRight = (doc: Doc | undefined, evt: Event): void => select(evt, 1, $focusStore.focus, 'horizontal') function ShowActions (doc: Doc | Doc[] | undefined, evt: Event): void { evt.preventDefault() @@ -143,9 +144,17 @@ function ShowPreview (doc: Doc | undefined, evt: Event): void { evt.preventDefault() } -function Open (doc: Doc, evt: Event): void { +function Open ( + doc: Doc, + evt: Event, + props: + | { + component?: AnyComponent + } + | undefined +): void { evt.preventDefault() - showPanel(view.component.EditDoc, doc._id, Hierarchy.mixinOrClass(doc), 'content') + showPanel(props?.component ?? view.component.EditDoc, doc._id, Hierarchy.mixinOrClass(doc), 'content') } /** @@ -319,7 +328,7 @@ function ValueSelector ( doc: Doc | Doc[], evt: Event, props: { - action: Action + actionPopup: AnyComponent attribute: string @@ -340,9 +349,7 @@ function ValueSelector ( placeholder?: IntlString } ): void { - if (props.action.actionPopup !== undefined) { - showPopup(props.action.actionPopup, { ...props, ...props.action.actionProps, value: doc, width: 'large' }, 'top') - } + showPopup(view.component.ValueSelector, { ...props, value: doc, width: 'large' }, 'top') } async function getPopupAlignment ( diff --git a/plugins/view-resources/src/actions.ts b/plugins/view-resources/src/actions.ts index 0d1a5501b8..b50770d053 100644 --- a/plugins/view-resources/src/actions.ts +++ b/plugins/view-resources/src/actions.ts @@ -148,9 +148,6 @@ export function filterActions ( if (role < AccountRole.Maintainer && action.secured === true) { continue } - if (action.override !== undefined) { - overrideRemove.push(...action.override) - } if (action.query !== undefined) { const r = matchQuery([doc], action.query, doc._class, hierarchy) if (r.length === 0) { @@ -161,6 +158,9 @@ export function filterActions ( (hierarchy.isDerived(doc._class, action.target) && client.getHierarchy().isDerived(action.target, derived)) || (hierarchy.isMixin(action.target) && hierarchy.hasMixin(doc, action.target)) ) { + if (action.override !== undefined) { + overrideRemove.push(...action.override) + } result.push(action) } } diff --git a/plugins/view-resources/src/components/ActionHandler.svelte b/plugins/view-resources/src/components/ActionHandler.svelte index 1b8edd96f5..13493f691f 100644 --- a/plugins/view-resources/src/components/ActionHandler.svelte +++ b/plugins/view-resources/src/components/ActionHandler.svelte @@ -38,6 +38,9 @@ }) let lastKey: KeyboardEvent | undefined + let sequences: Action>[] = [] + let delayedAction: (() => Promise) | undefined + let timer: number | undefined async function getCurrentActions ( context: { @@ -70,23 +73,39 @@ ) } function m (s1: string, s2: string): boolean { - return s1 === s2.toLowerCase() + return s1 === s2 } - function matchKey (key: KeyboardEvent, pattern: string, lastKey?: KeyboardEvent): boolean { + + function findKeySequence (pattern: string, key: KeyboardEvent): boolean { + const lc = pattern.toLowerCase() + const pfp = (keyPrefix(key) + key.key).toLowerCase() + const pfp2 = (keyPrefix(key) + key.code).toLowerCase() + return lc.startsWith(`${pfp}->`) || lc.startsWith(`${pfp2}->`) + } + + function getSequences ( + key: KeyboardEvent, + currentActions: Action>[] + ): Action>[] { + const res = currentActions.filter((p) => p.keyBinding?.find((p) => findKeySequence(p, key))) + return res + } + + function matchKeySequence (key: KeyboardEvent, pattern: string, lastKey: KeyboardEvent): boolean { const fp = (keyPrefix(key) + key.key).toLowerCase() const fp2 = (keyPrefix(key) + key.code).toLowerCase() const lc = pattern.toLowerCase() - if (m(fp, lc) || m(fp2, lc)) { - return true - } - if (lastKey !== undefined) { - // Check with last key - const pfp = (keyPrefix(key) + lastKey.key).toLowerCase() - const pfp2 = (keyPrefix(key) + lastKey.code).toLowerCase() + const pfp = (keyPrefix(lastKey) + lastKey.key).toLowerCase() + const pfp2 = (keyPrefix(lastKey) + lastKey.code).toLowerCase() - return m(`${pfp}->${fp}`, lc) || m(`${pfp2}->${fp}`, lc) || m(`${pfp}->${fp2}`, lc) || m(`${pfp2}->${fp2}`, lc) - } - return false + return m(`${pfp}->${fp}`, lc) || m(`${pfp2}->${fp}`, lc) || m(`${pfp}->${fp2}`, lc) || m(`${pfp2}->${fp2}`, lc) + } + + function matchKey (key: KeyboardEvent, pattern: string): boolean { + const fp = (keyPrefix(key) + key.key).toLowerCase() + const fp2 = (keyPrefix(key) + key.code).toLowerCase() + const lc = pattern.toLowerCase() + return m(fp, lc) || m(fp2, lc) } async function handleKeys (evt: KeyboardEvent): Promise { @@ -114,6 +133,7 @@ if (ctx.mode === 'none') { return } + clearTimeout(timer) const docs = getSelection($focusStore, $selectionStore) @@ -121,22 +141,56 @@ // Retrieve actual list of actions for input context currentActions = await getContextActions(client, docs, { ...ctx, mode: 'input' }) } - for (const a of currentActions) { - // TODO: Handle multiple keys here - if (a.keyBinding?.find((it) => matchKey(evt, it, lastKey)) !== undefined) { - lastKey = undefined - const action = await getResource(a.action) - if (action !== undefined) { - await action($focusStore.focus, evt, a.actionProps) + currentActions = currentActions.filter((p) => p.keyBinding !== undefined && p.keyBinding.length > 0) + if (lastKey !== undefined) { + for (const a of sequences) { + // TODO: Handle multiple keys here + if (a.keyBinding?.find((it) => (lastKey ? matchKeySequence(evt, it, lastKey) : false)) !== undefined) { + const action = await getResource(a.action) + if (action !== undefined) { + sequences = [] + lastKey = undefined + delayedAction = undefined + return await action(docs, evt, a.actionProps) + } } } } + sequences = getSequences(evt, currentActions) + let found = false + for (const a of currentActions) { + // TODO: Handle multiple keys here + if (a.keyBinding?.find((it) => matchKey(evt, it)) !== undefined) { + const action = await getResource(a.action) + if (action !== undefined) { + if (sequences.length === 0) { + lastKey = undefined + sequences = [] + delayedAction = undefined + return await action(docs, evt, a.actionProps) + } else { + delayedAction = async () => await action(docs, evt, a.actionProps) + found = true + } + } + } + } + if (!found && delayedAction) { + delayedAction() + delayedAction = undefined + } + lastKey = evt - setTimeout(() => { + timer = setTimeout(() => { lastKey = undefined - }, 500) + sequences = [] + if (delayedAction !== undefined) { + delayedAction() + delayedAction = undefined + } + }, 300) } let presenter: AnyComponent | undefined diff --git a/plugins/view-resources/src/components/ActionsPopup.svelte b/plugins/view-resources/src/components/ActionsPopup.svelte index b38209a628..05d0c63fea 100644 --- a/plugins/view-resources/src/components/ActionsPopup.svelte +++ b/plugins/view-resources/src/components/ActionsPopup.svelte @@ -147,11 +147,6 @@ key.stopPropagation() handleSelection(key, selection) } - if (key.code === 'Escape') { - key.preventDefault() - key.stopPropagation() - closePopup() - } } function formatKey (key: string): string[][] { const thens = key.split('->') diff --git a/plugins/view-resources/src/components/ValueSelector.svelte b/plugins/view-resources/src/components/ValueSelector.svelte index be77607e78..68825c7b34 100644 --- a/plugins/view-resources/src/components/ValueSelector.svelte +++ b/plugins/view-resources/src/components/ValueSelector.svelte @@ -33,6 +33,7 @@ const dispatch = createEventDispatcher() const changeStatus = async (newStatus: any) => { + console.log('CHANGE VALUE', newStatus) if (newStatus === '#null') { newStatus = null return @@ -118,7 +119,10 @@ {#if values} changeStatus(evt.detail)} + on:close={(evt) => { + console.log(evt) + changeStatus(evt.detail) + }} placeholder={placeholder ?? view.string.Filter} searchable {width} @@ -133,7 +137,10 @@ {searchField} allowDeselect={true} selected={current} - on:close={(evt) => changeStatus(evt.detail === null ? null : evt.detail?._id)} + on:close={(evt) => { + console.log(evt) + changeStatus(evt.detail === null ? null : evt.detail?._id) + }} placeholder={placeholder ?? view.string.Filter} {width} {size}