-
-
Notifications
You must be signed in to change notification settings - Fork 43
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
Better block creation #24
base: master
Are you sure you want to change the base?
Changes from all commits
788a9b5
84f092c
0e285d2
2f9c753
f80fee2
fb774a4
ca17c2c
2721f7f
6b9851d
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 |
---|---|---|
@@ -1,34 +1,21 @@ | ||
import { getFirstTopLevelBlock } from '../../utils/dom'; | ||
import { DOM } from '../../utils/dom'; | ||
import { Roam} from '../../utils/roam'; | ||
|
||
export const createDemo = async () => { | ||
await Roam.createBlockAtBottom(); | ||
Roam.writeText('bottom-block'); | ||
await Roam.createBlockAtBottom(false, 'bottom-block'); | ||
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. reverse the order of arguments to match other functions |
||
|
||
await Roam.createBlockAtTop(); | ||
Roam.writeText('top-block'); | ||
|
||
await Roam.createFirstChild(); | ||
Roam.writeText('first child'); | ||
|
||
await Roam.createFirstChild(); | ||
Roam.writeText('grandchild'); | ||
|
||
await Roam.activateBlock(getFirstTopLevelBlock()); | ||
await Roam.createLastChild(); | ||
Roam.writeText('second child'); | ||
|
||
await Roam.createFirstChild(); | ||
Roam.writeText('grandchild'); | ||
|
||
await Roam.activateBlock(getFirstTopLevelBlock()); | ||
await Roam.createDeepestLastDescendant() | ||
Roam.writeText('deepest descendant*'); | ||
await Roam.createBlockAtTop(false, 'top-block'); | ||
await Roam.createFirstChild('first child'); | ||
await Roam.createFirstChild('grandchild'); | ||
|
||
await Roam.activateBlock(DOM.getFirstTopLevelBlock()); | ||
await Roam.createLastChild('second child'); | ||
await Roam.createFirstChild('grandchild'); | ||
|
||
await Roam.activateBlock(getFirstTopLevelBlock()); | ||
await Roam.createSiblingBelow() | ||
Roam.writeText('3rd top block'); | ||
await Roam.activateBlock(DOM.getFirstTopLevelBlock()); | ||
await Roam.createDeepestLastDescendant('deepest descendant*'); | ||
|
||
await Roam.createSiblingAbove() | ||
Roam.writeText('2nd top block'); | ||
await Roam.activateBlock(DOM.getFirstTopLevelBlock()); | ||
await Roam.createSiblingBelow('3rd top block'); | ||
await Roam.createSiblingAbove('2nd top block'); | ||
}; |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,41 +1,116 @@ | ||
export type ValueElement = HTMLTextAreaElement | HTMLInputElement | HTMLSelectElement; | ||
|
||
export function getActiveEditElement(): ValueElement { | ||
// stolen from Surfingkeys. Needs work. | ||
|
||
let element = document.activeElement; | ||
// on some pages like chrome://history/, input is in shadowRoot of several other recursive shadowRoots. | ||
while (element?.shadowRoot) { | ||
if (element.shadowRoot.activeElement) { | ||
element = element.shadowRoot.activeElement; | ||
} else { | ||
const subElement = element.shadowRoot.querySelector('input, textarea, select'); | ||
if (subElement) { | ||
element = subElement; | ||
export const DOM = { | ||
getActiveEditElement(): ValueElement { | ||
// stolen from Surfingkeys. Needs work. | ||
|
||
let element = document.activeElement; | ||
// on some pages like chrome://history/, input is in shadowRoot of several other recursive shadowRoots. | ||
while (element?.shadowRoot) { | ||
if (element.shadowRoot.activeElement) { | ||
element = element.shadowRoot.activeElement; | ||
} else { | ||
const subElement = element.shadowRoot.querySelector('input, textarea, select'); | ||
if (subElement) { | ||
element = subElement; | ||
} | ||
break; | ||
} | ||
break; | ||
} | ||
} | ||
return element as ValueElement; | ||
} | ||
|
||
export function getTopLevelBlocks() { | ||
return document.querySelector('.roam-article div .flex-v-box') as HTMLElement; | ||
} | ||
|
||
export function getLastTopLevelBlock() { | ||
const lastChild = getTopLevelBlocks().lastChild as HTMLElement; | ||
return lastChild.querySelector('.roam-block, textarea') as HTMLElement; | ||
} | ||
|
||
export function getFirstTopLevelBlock() { | ||
const firstChild = getTopLevelBlocks().firstChild as HTMLElement; | ||
return firstChild.querySelector('.roam-block, textarea') as HTMLElement; | ||
return element as ValueElement; | ||
}, | ||
|
||
getTopLevelBlocks() { | ||
return document.querySelector('.roam-article div .flex-v-box') as HTMLElement; | ||
}, | ||
|
||
getLastTopLevelBlock() { | ||
const lastChild = this.getTopLevelBlocks().lastChild as HTMLElement; | ||
return lastChild.querySelector('.roam-block, textarea') as HTMLElement; | ||
}, | ||
|
||
getFirstTopLevelBlock() { | ||
const firstChild = this.getTopLevelBlocks().firstChild as HTMLElement; | ||
return firstChild.querySelector('.roam-block, textarea') as HTMLElement; | ||
}, | ||
|
||
|
||
getInputEvent() { | ||
return new Event('input', { | ||
bubbles: true, | ||
cancelable: true, | ||
}); | ||
}, | ||
|
||
async detectChange(fn: () => void, el?: HTMLElement){ | ||
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. maybe |
||
const targetNode = el || document.querySelector('.roam-body-main') as HTMLElement; | ||
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. make it a default parameter value? |
||
const config = { attributes: true, childList: true, subtree: true }; | ||
return new Promise(async resolve => { | ||
//@ts-ignore unused arg | ||
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. you can just name it |
||
const callback = function(mutationsList:MutationRecord[], observer: MutationObserver) { | ||
resolve('mutated') | ||
observer.disconnect(); | ||
}; | ||
const observer = new MutationObserver(callback); | ||
observer.observe(targetNode, config); | ||
await fn(); | ||
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. my IDE tells me that the await is redundant here. or should fn return promise? |
||
}) | ||
}, | ||
|
||
getBlockContainer(element?: HTMLElement) { | ||
let parent = null; | ||
let el = element || document.querySelector('textarea') as HTMLElement | ||
while(el && !parent){ | ||
if (el.parentElement?.className?.includes('flex-v-box roam-block-container')) { | ||
parent = el?.parentElement; | ||
} | ||
el = el?.parentElement as HTMLElement; | ||
} | ||
Comment on lines
+63
to
+68
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. you can query for parent with particular class - see example in my cr https://github.com/roam-unofficial/roam-toolkit/pull/22/files#diff-7f9ad9f2be2cc289f31a201fca94d43cR24 |
||
return parent as HTMLElement | ||
}, | ||
|
||
getBlockParent(element: HTMLElement){ | ||
return this.getBlockContainer(this.getBlockContainer(element)); | ||
}, | ||
|
||
isTopLevelBlock(element: HTMLElement){ | ||
return !this.getBlockParent(element); | ||
}, | ||
|
||
hasChildren(element: HTMLElement){ | ||
return !!this.getBlockChildren(element)?.length; | ||
}, | ||
|
||
getBlockChildren(element: HTMLElement) : HTMLCollection{ | ||
const childrenDiv = this.getBlockContainer(element)?.lastChild as HTMLElement; | ||
return childrenDiv?.children; | ||
}, | ||
getNthChild(element: HTMLElement, n:number){ | ||
return this.getBlockChildren(element)?.[n].querySelector('.roam-block') as HTMLElement; | ||
}, | ||
getFirstChild(element: HTMLElement){ | ||
return this.getNthChild(element, 0); | ||
}, | ||
getLastChild(element: HTMLElement){ | ||
return this.getNthChild(element,this.getBlockChildren(element).length-1); | ||
}, | ||
hasSiblings(element: HTMLElement) { | ||
return !!this.getSiblings(element) | ||
}, | ||
getSiblings(element: HTMLElement): HTMLCollection { | ||
if (this.isTopLevelBlock(element)) { | ||
return this.getBlockContainer(element)?.parentElement?.children as HTMLCollection | ||
} else { | ||
return this.getBlockChildren(this.getBlockParent(element)) | ||
} | ||
}, | ||
getNthSibling(element:HTMLElement, n:number) { | ||
return this.getSiblings(element)?.[n].querySelector('.roam-block'); | ||
}, | ||
getFirstSibling(element: HTMLElement){ | ||
return this.getNthSibling(element, 0); | ||
}, | ||
getLastSibling(element: HTMLElement){ | ||
return this.getNthSibling(element,this.getSiblings(element).length-1); | ||
}, | ||
} | ||
Comment on lines
+107
to
116
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. I think we should just apply Similarly for the children |
||
|
||
export function getInputEvent() { | ||
return new Event('input', { | ||
bubbles: true, | ||
cancelable: true, | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,18 +6,18 @@ export const Keyboard = { | |
UP_ARROW: 38, | ||
RIGHT_ARROW: 39, | ||
DOWN_ARROW: 40, | ||
BASE_DELAY: 20, | ||
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. is that a minimal viable delay now? :( |
||
BASE_DELAY: 50, | ||
|
||
async simulateKey(code: number, delayOverride: number = 0, opts?: KeyboardEventInit) { | ||
const event = new KeyboardEvent('keydown', { | ||
bubbles: true, | ||
cancelable: true, | ||
// @ts-ignore | ||
// @ts-ignore | ||
keyCode: code, | ||
...opts | ||
}); | ||
document?.activeElement?.dispatchEvent(event); | ||
return delay(delayOverride ||this.BASE_DELAY); | ||
document?.activeElement?.dispatchEvent(event) | ||
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. ? |
||
return delay(delayOverride || this.BASE_DELAY); | ||
}, | ||
async pressEnter(delayOverride: number = 0) { | ||
return this.simulateKey(13, delayOverride) | ||
|
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.
seems to duplicate code above