diff --git a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContent.swift b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContent.swift
index ab2cea59d..0df5750b3 100644
--- a/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContent.swift
+++ b/apple/OmnivoreKit/Sources/App/Views/WebReader/WebReaderContent.swift
@@ -88,6 +88,7 @@ struct WebReaderContent {
window.localStorage.setItem("theme", "\(themeKey)")
window.prefersHighContrastFont = \(prefersHighContrastText)
window.enableHighlightBar = \(isMacApp)
+ window.enableSelectToHighlight = true
diff --git a/apple/OmnivoreKit/Sources/Views/Article/OmnivoreWebView.swift b/apple/OmnivoreKit/Sources/Views/Article/OmnivoreWebView.swift
index 7405e4777..a76c02c4b 100644
--- a/apple/OmnivoreKit/Sources/Views/Article/OmnivoreWebView.swift
+++ b/apple/OmnivoreKit/Sources/Views/Article/OmnivoreWebView.swift
@@ -196,15 +196,17 @@ public final class OmnivoreWebView: WKWebView {
private func setDefaultMenu() {
currentMenu = .defaultMenu
- if #available(iOS 16.0, *) {
- // on iOS16 we use menuBuilder to create these items
- } else {
- let annotate = UIMenuItem(title: "Annotate", action: #selector(annotateSelection))
- let highlight = UIMenuItem(title: LocalText.genericHighlight, action: #selector(highlightSelection))
- // let share = UIMenuItem(title: "Share", action: #selector(shareSelection))
+ setHighlightMenu()
- UIMenuController.shared.menuItems = [highlight, /* share, */ annotate]
- }
+// if #available(iOS 16.0, *) {
+// // on iOS16 we use menuBuilder to create these items
+// } else {
+// let annotate = UIMenuItem(title: "Annotate", action: #selector(annotateSelection))
+// let highlight = UIMenuItem(title: LocalText.genericHighlight, action: #selector(highlightSelection))
+// // let share = UIMenuItem(title: "Share", action: #selector(shareSelection))
+//
+// UIMenuController.shared.menuItems = [highlight, /* share, */ annotate]
+// }
}
private func setHighlightMenu() {
@@ -230,7 +232,8 @@ public final class OmnivoreWebView: WKWebView {
}
@objc func menuDidHide() {
- setDefaultMenu()
+ // setDefaultMenu()
+ setHighlightMenu()
}
// swiftlint:disable:next line_length
diff --git a/packages/web/components/templates/article/HighlightsLayer.tsx b/packages/web/components/templates/article/HighlightsLayer.tsx
index c29fec273..4dda397db 100644
--- a/packages/web/components/templates/article/HighlightsLayer.tsx
+++ b/packages/web/components/templates/article/HighlightsLayer.tsx
@@ -73,10 +73,7 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
Highlight | undefined
>(undefined)
- const [selectionData, setSelectionData] = useSelection(
- highlightLocations,
- false //noteModal.open,
- )
+ const [selectionData, setSelectionData] = useSelection(highlightLocations)
const [labelsTarget, setLabelsTarget] = useState(
undefined
@@ -192,6 +189,41 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
[props.highlightBarDisabled]
)
+ const selectionPercentPos = (selection: Selection): number | undefined => {
+ if (
+ selection.rangeCount > 0 &&
+ window &&
+ window.document.scrollingElement
+ ) {
+ const percent =
+ (selection.getRangeAt(0).getBoundingClientRect().y + window.scrollY) /
+ window.document.scrollingElement.scrollHeight
+ return Math.min(Math.max(0, percent * 100), 100)
+ }
+ return undefined
+ }
+
+ const selectionAnchorIndex = (selection: Selection): number | undefined => {
+ if (selection.rangeCount > 0) {
+ const containerElement = () => {
+ const node = selection.getRangeAt(0).startContainer
+ if (node.nodeType == Node.ELEMENT_NODE) {
+ return node as HTMLElement
+ }
+ return node.parentElement
+ }
+ let walk = containerElement()
+ while (walk) {
+ const idx = Number(walk.getAttribute('data-omnivore-anchor-idx'))
+ if (idx > 0) {
+ return idx
+ }
+ walk = walk.parentElement
+ }
+ }
+ return undefined
+ }
+
const createHighlightFromSelection = async (
selection: SelectionAttributes,
note?: string
@@ -203,6 +235,8 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
existingHighlights: highlights,
highlightStartEndOffsets: highlightLocations,
annotation: note,
+ highlightPositionPercent: selectionPercentPos(selection.selection),
+ highlightPositionAnchorIndex: selectionAnchorIndex(selection.selection),
},
props.articleMutations
)
@@ -258,20 +292,6 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
]
)
- const scrollToHighlight = (id: string) => {
- const foundElement = document.querySelector(
- `[omnivore-highlight-id="${id}"]`
- )
- if (foundElement) {
- foundElement.scrollIntoView({
- block: 'center',
- behavior: 'smooth',
- })
- window.location.hash = `#${id}`
- props.setShowHighlightsModal(false)
- }
- }
-
// Detect mouseclick on a highlight -- call `setFocusedHighlight` when highlight detected
const handleClickHighlight = useCallback(
(event: MouseEvent) => {
@@ -424,6 +444,23 @@ export function HighlightsLayer(props: HighlightsLayerProps): JSX.Element {
]
)
+ useEffect(() => {
+ ;(async () => {
+ if (
+ 'enableSelectToHighlight' in window &&
+ window.enableSelectToHighlight &&
+ selectionData
+ ) {
+ // console.log('auto highlight: ', selectionData.selection.toString())
+ await createHighlightCallback('none', undefined)
+ selectionData.selection.collapseToStart()
+ // handleClickHighlight(selectionData.mouseEvent)
+ // setSelectionData(null)
+ // window.getSelection()?.removeAllRanges()
+ }
+ })()
+ }, [selectionData, setSelectionData])
+
const dispatchHighlightError = (action: string, error: unknown) => {
if (props.isAppleAppEmbed) {
window?.webkit?.messageHandlers.highlightAction?.postMessage({
diff --git a/packages/web/lib/highlights/createHighlight.ts b/packages/web/lib/highlights/createHighlight.ts
index 7262e3252..045f28819 100644
--- a/packages/web/lib/highlights/createHighlight.ts
+++ b/packages/web/lib/highlights/createHighlight.ts
@@ -18,6 +18,8 @@ type CreateHighlightInput = {
annotation?: string
existingHighlights: Highlight[]
highlightStartEndOffsets: HighlightLocation[]
+ highlightPositionPercent?: number
+ highlightPositionAnchorIndex?: number
}
type CreateHighlightOutput = {
@@ -30,7 +32,6 @@ export async function createHighlight(
input: CreateHighlightInput,
articleMutations: ArticleMutations
): Promise {
-
if (!input.selection.selection) {
return {}
}
@@ -65,7 +66,10 @@ export async function createHighlight(
annotations.push(annotation)
}
})
- removeHighlights(input.selection.overlapHighlights, input.highlightStartEndOffsets)
+ removeHighlights(
+ input.selection.overlapHighlights,
+ input.highlightStartEndOffsets
+ )
}
const highlightAttributes = makeHighlightNodeAttributes(
@@ -83,6 +87,8 @@ export async function createHighlight(
patch,
annotation: annotations.length > 0 ? annotations.join('\n') : undefined,
articleId: input.articleId,
+ highlightPositionPercent: input.highlightPositionPercent,
+ highlightPositionAnchorIndex: input.highlightPositionAnchorIndex,
}
let highlight: Highlight | undefined
@@ -98,7 +104,9 @@ export async function createHighlight(
($0) => !input.selection.overlapHighlights.includes($0.id)
)
} else {
- highlight = await articleMutations.createHighlightMutation(newHighlightAttributes)
+ highlight = await articleMutations.createHighlightMutation(
+ newHighlightAttributes
+ )
}
if (highlight) {
diff --git a/packages/web/lib/highlights/useSelection.tsx b/packages/web/lib/highlights/useSelection.tsx
index 5070b182e..10fb104fc 100644
--- a/packages/web/lib/highlights/useSelection.tsx
+++ b/packages/web/lib/highlights/useSelection.tsx
@@ -7,10 +7,8 @@ import {
import type { SelectionAttributes } from './highlightHelpers'
export function useSelection(
- highlightLocations: HighlightLocation[],
- isDisabled: boolean
+ highlightLocations: HighlightLocation[]
): [SelectionAttributes | null, (x: SelectionAttributes | null) => void] {
- const disabled = isDisabled
const [selectionAttributes, setSelectionAttributes] =
useState(null)
@@ -142,10 +140,6 @@ export function useSelection(
}, [selectionAttributes?.selection])
useEffect(() => {
- if (disabled) {
- return
- }
-
document.addEventListener('mouseup', handleFinishTouch)
document.addEventListener('touchend', handleFinishTouch)
document.addEventListener('contextmenu', handleFinishTouch)
@@ -157,7 +151,7 @@ export function useSelection(
document.removeEventListener('contextmenu', handleFinishTouch)
document.removeEventListener('copyTextSelection', copyTextSelection)
}
- }, [highlightLocations, handleFinishTouch, disabled, copyTextSelection])
+ }, [highlightLocations, handleFinishTouch, copyTextSelection])
return [selectionAttributes, setSelectionAttributes]
}
diff --git a/packages/web/lib/networking/fragments/highlightFragment.ts b/packages/web/lib/networking/fragments/highlightFragment.ts
index fc7bfabb2..d7ca16cf4 100644
--- a/packages/web/lib/networking/fragments/highlightFragment.ts
+++ b/packages/web/lib/networking/fragments/highlightFragment.ts
@@ -13,6 +13,8 @@ export const highlightFragment = gql`
createdByMe
updatedAt
sharedAt
+ highlightPositionPercent
+ highlightPositionAnchorIndex
labels {
id
name
@@ -34,6 +36,8 @@ export type Highlight = {
updatedAt: string
sharedAt: string
labels?: Label[]
+ highlightPositionPercent?: number
+ highlightPositionAnchorIndex?: number
}
export type User = {