-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
Changes to allow editing multiple comments #18887
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
59fe227
86d5731
45f1df6
653da33
0447950
b7b39d2
c463ea8
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -10,62 +10,86 @@ interface Current { | |
| chapterId: string; | ||
| path: Tree.Path; | ||
| node: Tree.Node; | ||
| commentId: string; | ||
| focusId?: string; | ||
| } | ||
|
|
||
| export class CommentForm { | ||
| current = prop<Current | null>(null); | ||
| opening = prop(false); | ||
| currents = new Map<string, Current>(); | ||
| opening = prop<string | null>(null); | ||
| newComment = false; | ||
|
|
||
| setnewComment = (newComment: boolean) => { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. namingConventions |
||
| this.newComment = newComment; | ||
| }; | ||
|
|
||
| constructor(readonly root: AnalyseCtrl) {} | ||
|
|
||
| submit = (text: string) => this.current() && this.doSubmit(text); | ||
| makeKey(chapterId: string, path: Tree.Path, commentId: string): string { | ||
| return `${chapterId}:${path}:${commentId}`; | ||
| } | ||
|
|
||
| submit = (key: string, el: HTMLInputElement) => { | ||
| const current = this.currents.get(key); | ||
| if (current) { | ||
| this.currents.forEach((cur, _) => { | ||
| cur.focusId = undefined; | ||
| }); | ||
| this.currents.get(key)!.focusId = el.id; | ||
| this.doSubmit(current.chapterId, current.path, current.commentId, el.value); | ||
| } | ||
| }; | ||
|
|
||
| doSubmit = throttle(500, (text: string) => { | ||
| const cur = this.current(); | ||
| if (cur) this.root.study!.makeChange('setComment', { ch: cur.chapterId, path: cur.path, text }); | ||
| doSubmit = throttle(500, (chapterId: string, path: Tree.Path, commentId: string, text: string) => { | ||
| this.root.study!.makeChange('setComment', { ch: chapterId, path, id: commentId, text }); | ||
| }); | ||
|
|
||
| start = (chapterId: string, path: Tree.Path, node: Tree.Node): void => { | ||
| this.opening(true); | ||
| this.current({ chapterId, path, node }); | ||
| start = (chapterId: string, path: Tree.Path, node: Tree.Node, commentId: string): void => { | ||
| const key = this.makeKey(chapterId, path, commentId); | ||
| this.opening(key); | ||
| this.currents.set(key, { chapterId, path, node, commentId }); | ||
| this.root.userJump(path); | ||
| }; | ||
|
|
||
| onSetPath = (chapterId: string, path: Tree.Path, node: Tree.Node): void => { | ||
| const cur = this.current(); | ||
| if (cur && (path !== cur.path || chapterId !== cur.chapterId || cur.node !== node)) { | ||
| cur.chapterId = chapterId; | ||
| cur.path = path; | ||
| cur.node = node; | ||
| } | ||
| this.currents.forEach(cur => { | ||
| if (path !== cur.path || chapterId !== cur.chapterId || cur.node !== node) { | ||
| cur.chapterId = chapterId; | ||
| cur.path = path; | ||
| cur.node = node; | ||
| } | ||
| }); | ||
| }; | ||
|
|
||
| delete = (chapterId: string, path: Tree.Path, id: string) => { | ||
| this.root.study!.makeChange('deleteComment', { ch: chapterId, path, id }); | ||
| }; | ||
|
|
||
| clear = () => { | ||
| this.currents.clear(); | ||
| }; | ||
| } | ||
|
|
||
| export const viewDisabled = (root: AnalyseCtrl, why: string): VNode => | ||
| h('div.study__comments', [currentComments(root, true), h('div.study__message', why)]); | ||
|
|
||
| export function view(root: AnalyseCtrl): VNode { | ||
| const study = root.study!, | ||
| ctrl = study.commentForm, | ||
| current = ctrl.current(); | ||
| if (!current) return viewDisabled(root, 'Select a move to comment'); | ||
| function renderTextarea(root: AnalyseCtrl, ctrl: CommentForm, current: Current, key: string): VNode { | ||
| const study = root.study!; | ||
| const setupTextarea = (vnode: VNode, old?: VNode) => { | ||
| const el = vnode.elm as HTMLInputElement; | ||
| const newKey = current.chapterId + current.path; | ||
|
|
||
| if (old?.data!.path !== newKey) { | ||
| const el = vnode.elm as HTMLTextAreaElement; | ||
| if (old?.data!.key !== key) { | ||
| const mine = (current.node.comments || []).find(function (c) { | ||
| return isAuthorObj(c.by) && c.by.id && c.by.id === ctrl.root.opts.userId; | ||
| return ( | ||
| isAuthorObj(c.by) && c.by.id && c.by.id === ctrl.root.opts.userId && c.id === current.commentId | ||
| ); | ||
| }); | ||
| el.value = mine ? mine.text : ''; | ||
| } | ||
| vnode.data!.path = newKey; | ||
| vnode.data!.key = key; | ||
|
|
||
| if (ctrl.opening()) { | ||
| if (ctrl.opening() === key) { | ||
| requestAnimationFrame(() => el.focus()); | ||
| ctrl.opening(false); | ||
| ctrl.opening(null); | ||
| } | ||
| }; | ||
|
|
||
|
|
@@ -75,12 +99,12 @@ export function view(root: AnalyseCtrl): VNode { | |
| [ | ||
| currentComments(root, !study.members.canContribute()), | ||
| h('form.form3', [ | ||
| h('textarea#comment-text.form-control', { | ||
| h(`textarea#${key}.form-control`, { | ||
| hook: { | ||
| insert(vnode) { | ||
| setupTextarea(vnode); | ||
| const el = vnode.elm as HTMLInputElement; | ||
| el.oninput = () => setTimeout(() => ctrl.submit(el.value), 50); | ||
| el.oninput = () => setTimeout(() => ctrl.submit(key, el), 50); | ||
| const heightStore = storage.make('study.comment.height'); | ||
| el.onmouseup = () => heightStore.set('' + el.offsetHeight); | ||
| el.style.height = parseInt(heightStore.get() || '80') + 'px'; | ||
|
|
@@ -89,10 +113,53 @@ export function view(root: AnalyseCtrl): VNode { | |
| if (e.code === 'Escape') el.blur(); | ||
| }); | ||
| }, | ||
| postpatch: (old, vnode) => setupTextarea(vnode, old), | ||
| postpatch: (old, vnode) => { | ||
| setupTextarea(vnode, old); | ||
| const el = vnode.elm as HTMLInputElement; | ||
| if (ctrl.currents.get(key)?.focusId === el.id) el.focus(); | ||
| el.oninput = () => setTimeout(() => ctrl.submit(key, el), 50); | ||
| }, | ||
| }, | ||
| }), | ||
| ]), | ||
| ], | ||
| ); | ||
| } | ||
|
|
||
| export function view(root: AnalyseCtrl): VNode { | ||
| const study = root.study!; | ||
| const commForm = study.commentForm; | ||
|
|
||
| const commentKeys = new Set( | ||
| (root.node.comments || []).map(c => commForm.makeKey(study.vm.chapterId, root.path, c.id)), | ||
| ); | ||
|
|
||
| const rerender = Array.from(commForm.currents.keys()).some(key => !commentKeys.has(key)); | ||
| const comments = root.node.comments || []; | ||
| if (rerender || commForm.currents.size === 0) { | ||
| if (!commForm.newComment) commForm.clear(); | ||
| commForm.setnewComment(false); | ||
| comments.forEach(comment => { | ||
| commForm.start(study.vm.chapterId, root.path, root.node, comment.id); | ||
| }); | ||
| } | ||
|
|
||
| if (commForm.currents.size === 0) { | ||
| return viewDisabled(root, 'Select a move to comment'); | ||
| } | ||
|
|
||
| return h( | ||
| 'div.study__comments', | ||
| { | ||
| hook: onInsert(() => root.enableWiki(root.data.game.variant.key === 'standard')), | ||
| }, | ||
| [ | ||
| h( | ||
| 'div.study__comment-forms', | ||
| Array.from(commForm.currents.entries()).map(([key, current]) => { | ||
| return renderTextarea(root, commForm, current, key); | ||
| }), | ||
| ), | ||
| h('div.analyse__wiki.study__wiki.force-ltr'), | ||
| ], | ||
| ); | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -26,7 +26,7 @@ export function render(ctrl: AnalyseCtrl): VNode { | |
| const commentHook: Hooks = bind( | ||
| 'click', | ||
| () => { | ||
| study.commentForm.start(study.vm.chapterId, ctrl.path, ctrl.node); | ||
| // ctrl.node.comments?.forEach((comment) => ctrl.study!.commentForm.start(ctrl.study!.vm.chapterId, ctrl.path, ctrl.node, comment.id)); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. dead code?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's a valid question.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. #18467 But with - I think I will be able refine code to be less complex. |
||
| study.vm.toolTab('comments'); | ||
| requestIdleCallback( | ||
| () => | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
so these tests show that without the comment ID, each modification to a comment adds a new comment.
it looks like a good place for tests that show how comment IDs work