Skip to content

Commit

Permalink
Merge pull request #4289 from serlo/fix/link-absolute-serlo-urls-in-i…
Browse files Browse the repository at this point in the history
…ntegrations

fix(link-plugin): Allow absolute serlo urls in integrations
  • Loading branch information
CodingDive authored Nov 20, 2024
2 parents 74da59f + 431b251 commit e565853
Show file tree
Hide file tree
Showing 13 changed files with 60 additions and 26 deletions.
6 changes: 3 additions & 3 deletions packages/editor/src/core/editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,21 +6,21 @@ import {
} from '@editor/editor-ui/save/local-storage-notice'
import { getEditorVersion } from '@editor/package/editor-version'
import { cn } from '@editor/utils/cn'
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { useContext, useState, useMemo } from 'react'
import { useState, useMemo } from 'react'
import { HotkeysProvider } from 'react-hotkeys-hook'
import { Provider } from 'react-redux'

import { DndWrapper } from './components/dnd-wrapper'
import { InnerDocument } from './inner-document'
import type { EditorProps } from './types'
import { createStore } from '../store'
import { useIsSerlo } from './hooks/use-is-serlo'

/**
* Renders a single editor for an Serlo Editor document
*/
export function Editor(props: EditorProps) {
const { isSerlo } = useContext(SerloOnlyFeaturesContext)
const isSerlo = useIsSerlo()
const [useStored, setUseStored] = useState(false)

const storedState = getStateFromLocalStorage()
Expand Down
7 changes: 7 additions & 0 deletions packages/editor/src/core/hooks/use-is-serlo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { useContext } from 'react'

export function useIsSerlo(): boolean {
const isSerlo = useContext(SerloOnlyFeaturesContext).isSerlo
return isSerlo ?? false
}
9 changes: 5 additions & 4 deletions packages/editor/src/core/hooks/use-serlo-quickbar-data.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useEditStrings } from '@editor/i18n/edit-strings-provider'
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { useContext, useEffect, useState } from 'react'
import { useEffect, useState } from 'react'

import { useIsSerlo } from './use-is-serlo'

export function useSerloQuickbarData(shouldNotFetch?: boolean) {
const { lang } = useEditStrings()
const isSerloLinkSearchActive =
useContext(SerloOnlyFeaturesContext).isSerlo && lang === 'de'
const isSerlo = useIsSerlo()
const isSerloLinkSearchActive = isSerlo && lang === 'de'

const [quickbarData, setQuickbarData] = useState<QuickbarData | null>(null)

Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/i18n/strings/de/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,9 @@ export const editStrings = {
'Sorry, dieses Plugin kannst du hier nicht einfügen.',
linkOverlay: {
placeholder: 'Suchbegriff oder "/1234"',
placeholderNonSerlo: 'Link',
inputLabel: 'Suche einen Inhalt oder füge einen Link ein',
inputLabelNonSerlo: 'Füge einen Link ein',
edit: 'Link bearbeiten',
remove: 'Link entfernen',
customLink: 'Eigener Link',
Expand Down
2 changes: 2 additions & 0 deletions packages/editor/src/i18n/strings/en/edit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -310,7 +310,9 @@ export const editStrings = {
'Sorry, pasting this plugin here is not allowed.',
linkOverlay: {
placeholder: 'https://… or /1234',
placeholderNonSerlo: 'https://',
inputLabel: 'Paste or type a link',
inputLabelNonSerlo: 'Insert a link',
edit: 'Edit Link',
remove: 'Remove Link',
customLink: 'Custom Link',
Expand Down
6 changes: 3 additions & 3 deletions packages/editor/src/plugins/exercise/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import { AddButton } from '@editor/editor-ui'
import { EditorTooltip } from '@editor/editor-ui/editor-tooltip'
import { FaIcon } from '@editor/editor-ui/fa-icon'
Expand All @@ -9,9 +10,8 @@ import {
useAppSelector,
} from '@editor/store'
import { cn } from '@editor/utils/cn'
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { faTrashAlt } from '@fortawesome/free-solid-svg-icons'
import { Suspense, lazy, useContext, useEffect, useState } from 'react'
import { Suspense, lazy, useEffect, useState } from 'react'

import { type ExerciseProps } from '.'
import { InteractiveExercisesSelection } from './components/interactive-exercises-selection'
Expand All @@ -33,7 +33,7 @@ export function ExerciseEditor(props: ExerciseProps) {
licenseId,
hideInteractiveInitially,
} = state
const { isSerlo } = useContext(SerloOnlyFeaturesContext)
const isSerlo = useIsSerlo()
const editorStrings = useEditStrings()
const exStrings = editorStrings.plugins.exercise

Expand Down
6 changes: 3 additions & 3 deletions packages/editor/src/plugins/image/components/editor-image.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import { serloDomain } from '@editor/utils/serlo-domain'
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { ImgHTMLAttributes, useContext } from 'react'
import { ImgHTMLAttributes } from 'react'

/**
* Proxies external editor images via cloudflare worker
* Temporary fix for privacy reasons. Long term we want to upload
* images to our own bucket instead
*/
export function EditorImage(props: ImgHTMLAttributes<HTMLImageElement>) {
const isSerlo = useContext(SerloOnlyFeaturesContext).isSerlo
const isSerlo = useIsSerlo()
return <img {...props} src={getSrc(isSerlo, props.src)} />
}

Expand Down
4 changes: 3 additions & 1 deletion packages/editor/src/plugins/injection/toolbar.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import { EditorModal } from '@editor/editor-ui/editor-modal'
import { FaIcon } from '@editor/editor-ui/fa-icon'
import { PluginToolbar } from '@editor/editor-ui/plugin-toolbar'
Expand All @@ -22,6 +23,7 @@ export const InjectionToolbar = ({
setShowSettingsModal: Dispatch<SetStateAction<boolean>>
}) => {
const [idState, setIdState] = useState(state.value)
const isSerlo = useIsSerlo()

const injectionStrings = useEditStrings().plugins.injection

Expand All @@ -40,7 +42,7 @@ export const InjectionToolbar = ({
// cleanup pasted links
setTimeout(() => {
const inputUrl = (e.target as HTMLInputElement).value
const cleanUrl = getCleanUrl(inputUrl)
const cleanUrl = getCleanUrl(inputUrl, isSerlo)
if (cleanUrl !== inputUrl) setIdState(cleanUrl)
})
}
Expand Down
6 changes: 3 additions & 3 deletions packages/editor/src/plugins/solution/editor.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import { showToastNotice } from '@editor/editor-ui/show-toast-notice'
import { useEditStrings } from '@editor/i18n/edit-strings-provider'
import { SerloAddButton } from '@editor/plugin/helpers/serlo-editor-button'
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { Suspense, lazy, useContext, useEffect, useState } from 'react'
import { Suspense, lazy, useEffect, useState } from 'react'

import type { SolutionProps } from '.'
import { SolutionRenderer } from './renderer'
Expand All @@ -20,7 +20,7 @@ const SerloLicenseChooser = lazy(() =>
export function SolutionEditor({ state, focused }: SolutionProps) {
const { prerequisite, strategy, licenseId } = state
const solutionStrings = useEditStrings().templatePlugins.solution
const { isSerlo } = useContext(SerloOnlyFeaturesContext)
const isSerlo = useIsSerlo()

const [showPrerequisiteLinkTool, setShowPrerequisiteLinkTool] =
useState<boolean>(false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import { FaIcon } from '@editor/editor-ui/fa-icon'
import { useEditStrings } from '@editor/i18n/edit-strings-provider'
import { faXmark } from '@fortawesome/free-solid-svg-icons'
Expand All @@ -22,6 +23,7 @@ export function EditModeInput({
}) {
const inputRef = useRef<HTMLInputElement>(null)
const { lang } = useEditStrings()
const isSerlo = useIsSerlo()

useEffect(() => {
if (!shouldFocus) return
Expand All @@ -40,7 +42,7 @@ export function EditModeInput({
// cleanup pasted links
setTimeout(() => {
const inputUrl = (e.target as HTMLInputElement).value
const cleanUrl = getCleanUrl(inputUrl, lang)
const cleanUrl = getCleanUrl(inputUrl, isSerlo, lang)
if (cleanUrl !== inputUrl) setQuery(cleanUrl)
})
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import {
findResults,
useSerloQuickbarData,
Expand Down Expand Up @@ -39,6 +40,8 @@ export function LinkOverlayEditMode({
const { lang } = editStrings
const overlayStrings = editStrings.plugins.text.linkOverlay

const isSerlo = useIsSerlo()

const { quickbarData } = useSerloQuickbarData(noAutocomplete)

useEffect(() => {
Expand All @@ -57,7 +60,7 @@ export function LinkOverlayEditMode({

const hasResult = activeIndex < results.length
const href = hasResult ? `/${results[activeIndex].entry.id}` : query
const cleanUrl = getCleanUrl(href, lang)
const cleanUrl = getCleanUrl(href, isSerlo, lang)
const title = hasResult ? results[activeIndex].entry.title : undefined

if (
Expand Down Expand Up @@ -98,15 +101,23 @@ export function LinkOverlayEditMode({

return (
<>
<label className="block px-side pt-4">{overlayStrings.inputLabel}</label>
<label className="block px-side pt-4">
{isSerlo
? overlayStrings.inputLabel
: overlayStrings.inputLabelNonSerlo}
</label>
<div className="relative w-[27rem]">
<EditModeInput
query={query}
onKeyDown={onKeyDown}
setQuery={setQuery}
shouldFocus={shouldFocus}
value={value}
placeholder={overlayStrings.placeholder}
placeholder={
isSerlo
? overlayStrings.placeholder
: overlayStrings.placeholderNonSerlo
}
/>
</div>
{query ? (
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { useIsSerlo } from '@editor/core/hooks/use-is-serlo'
import {
getLinkElement,
isLinkActive,
} from '@editor/editor-ui/plugin-toolbar/text-controls/utils/link'
import { SlateOverlay } from '@editor/editor-ui/slate-overlay'
import { useEditStrings } from '@editor/i18n/edit-strings-provider'
import { SerloOnlyFeaturesContext } from '@editor/utils/serlo-extra-context'
import { useContext, useEffect, useState } from 'react'
import { useEffect, useState } from 'react'
import { Range, Transforms } from 'slate'
import { ReactEditor, useSlate } from 'slate-react'

Expand All @@ -23,8 +23,8 @@ export function LinkControls() {
const editor = useSlate()
const { selection } = editor

const isSerloLinkSearchActive =
useContext(SerloOnlyFeaturesContext).isSerlo && lang === 'de'
const isSerlo = useIsSerlo()
const isSerloLinkSearchActive = isSerlo && lang === 'de'

useEffect(() => {
if (!selection) return
Expand Down
9 changes: 8 additions & 1 deletion packages/editor/src/plugins/text/utils/link.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,11 @@
export function getCleanUrl(inputUrl: string, instance?: string) {
export function getCleanUrl(
inputUrl: string,
isSerlo: boolean,
instance?: string
) {
// currently we only do normalizing for the links on serlo.org
if (!isSerlo) return inputUrl

const testId = parseInt(
inputUrl.match(
/https?:\/\/([a-z]{2}\.)?serlo\.org(\/[a-z]+)?\/([1-9]?[0-9]+)/
Expand Down

0 comments on commit e565853

Please sign in to comment.