feat: Initial clean release of CHM
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
一些检查失败了
automerge / automerge (push) Has been cancelled
react-native-android-build-apk / AssembleRelease (push) Has been cancelled
Build macOS M1 / Main (push) Has been cancelled
Joplin Continuous Integration / Main (macos-15-intel) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / Main (ubuntu-22.04-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-11-vs2026-arm) (push) Has been cancelled
Joplin Continuous Integration / Main (windows-2025) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04) (push) Has been cancelled
Joplin Continuous Integration / ServerDockerImage (ubuntu-22.04-arm) (push) Has been cancelled
Joplin UI tests / Main (ubuntu-22.04) (push) Has been cancelled
Joplin UI tests / Main (windows-2025) (push) Has been cancelled
Joplin UI tests / Mobile (push) Has been cancelled
Close stale issues / ProcessStaleIssues (push) Has been cancelled
这个提交包含在:
@@ -0,0 +1,29 @@
|
||||
import usePrevious from './usePrevious';
|
||||
import { EffectCallback, useEffect } from 'react';
|
||||
|
||||
export default function useEffectDebugger(effectHook: EffectCallback, dependencies: unknown[], dependencyNames: string[] = []) {
|
||||
const previousDeps = usePrevious(dependencies, []);
|
||||
|
||||
const changedDeps = dependencies.reduce((accum: Record<string, { before: unknown; after: unknown }>, dependency: unknown, index: number) => {
|
||||
if (dependency !== previousDeps[index]) {
|
||||
const keyName = dependencyNames[index] || index;
|
||||
return {
|
||||
...accum,
|
||||
[keyName]: {
|
||||
before: previousDeps[index],
|
||||
after: dependency,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return accum;
|
||||
}, {});
|
||||
|
||||
if (Object.keys(changedDeps).length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[use-effet-debugger] ', changedDeps);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
useEffect(effectHook, dependencies);
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
// This uses a ResizeObserver -- be careful to prevent infinite loops (should be stopped
|
||||
// early and print a warning). See https://developer.mozilla.org/en-US/docs/Web/API/ResizeObserver#observation_errors
|
||||
const useElementHeight = (container: HTMLElement|null) => {
|
||||
const [height, setHeight] = useState(container?.clientHeight ?? 0);
|
||||
|
||||
useEffect(() => {
|
||||
if (!container) return () => {};
|
||||
const observer = new ResizeObserver(() => {
|
||||
setHeight(container.clientHeight);
|
||||
});
|
||||
observer.observe(container);
|
||||
|
||||
return () => {
|
||||
observer.disconnect();
|
||||
};
|
||||
}, [container]);
|
||||
|
||||
return height;
|
||||
};
|
||||
|
||||
export default useElementHeight;
|
||||
@@ -0,0 +1,29 @@
|
||||
import usePrevious from './usePrevious';
|
||||
import { Ref, useImperativeHandle } from 'react';
|
||||
|
||||
export default function useImperativeHandleDebugger<T>(ref: Ref<T>, effectHook: ()=> T, dependencies: unknown[], dependencyNames: string[] = []) {
|
||||
const previousDeps = usePrevious(dependencies, []);
|
||||
|
||||
const changedDeps = dependencies.reduce((accum: Record<string, { before: unknown; after: unknown }>, dependency: unknown, index: number) => {
|
||||
if (dependency !== previousDeps[index]) {
|
||||
const keyName = dependencyNames[index] || index;
|
||||
return {
|
||||
...accum,
|
||||
[keyName]: {
|
||||
before: previousDeps[index],
|
||||
after: dependency,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
return accum;
|
||||
}, {});
|
||||
|
||||
if (Object.keys(changedDeps).length) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('[use-imperativeHandler-debugger] ', changedDeps);
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @seiyab/react-hooks/exhaustive-deps -- Old code before rule was applied
|
||||
useImperativeHandle(ref, effectHook, dependencies);
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
import { PluginStates } from '@joplin/lib/services/plugins/reducer';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
import markupLanguageUtils from '@joplin/lib/utils/markupLanguageUtils';
|
||||
import Setting from '@joplin/lib/models/Setting';
|
||||
import shim from '@joplin/lib/shim';
|
||||
|
||||
import { themeStyle } from '@joplin/lib/theme';
|
||||
import Note from '@joplin/lib/models/Note';
|
||||
import { ResourceInfos } from '../NoteEditor/utils/types';
|
||||
import { resourceFullPath } from '@joplin/lib/models/utils/resourceUtils';
|
||||
import { RenderOptions } from '@joplin/renderer/types';
|
||||
import getPluginSettingValue from '@joplin/lib/services/plugins/utils/getPluginSettingValue';
|
||||
import { ScrollbarSize } from '@joplin/lib/models/settings/builtInMetadata';
|
||||
|
||||
export interface MarkupToHtmlOptions extends RenderOptions {
|
||||
resourceInfos?: ResourceInfos;
|
||||
replaceResourceInternalToExternalLinks?: boolean;
|
||||
}
|
||||
|
||||
interface HookDependencies {
|
||||
themeId: number;
|
||||
customCss: string;
|
||||
plugins: PluginStates;
|
||||
whiteBackgroundNoteRendering: boolean;
|
||||
scrollbarSize: ScrollbarSize;
|
||||
baseFontFamily: string;
|
||||
}
|
||||
|
||||
export default function useMarkupToHtml(deps: HookDependencies) {
|
||||
const { themeId, customCss, plugins, whiteBackgroundNoteRendering, scrollbarSize, baseFontFamily } = deps;
|
||||
|
||||
const resourceBaseUrl = useMemo(() => {
|
||||
return `joplin-content://note-viewer/${Setting.value('resourceDir')}/`;
|
||||
}, []);
|
||||
|
||||
const markupToHtml = useMemo(() => {
|
||||
return markupLanguageUtils.newMarkupToHtml(plugins, {
|
||||
resourceBaseUrl,
|
||||
customCss: customCss || '',
|
||||
});
|
||||
}, [plugins, customCss, resourceBaseUrl]);
|
||||
|
||||
return useCallback(async (markupLanguage: number, md: string, options: MarkupToHtmlOptions|null = null) => {
|
||||
options = {
|
||||
replaceResourceInternalToExternalLinks: false,
|
||||
resourceInfos: {},
|
||||
platformName: shim.platformName(),
|
||||
...options,
|
||||
};
|
||||
|
||||
md = md || '';
|
||||
|
||||
const theme = themeStyle(themeId);
|
||||
let resources: ResourceInfos = {};
|
||||
|
||||
if (options.replaceResourceInternalToExternalLinks) {
|
||||
md = await Note.replaceResourceInternalToExternalLinks(md, { useAbsolutePaths: true });
|
||||
} else {
|
||||
resources = options.resourceInfos;
|
||||
}
|
||||
|
||||
delete options.replaceResourceInternalToExternalLinks;
|
||||
|
||||
const result = await markupToHtml.render(markupLanguage, md, theme, {
|
||||
codeTheme: theme.codeThemeCss,
|
||||
resources: resources,
|
||||
postMessageSyntax: 'ipcProxySendToHost',
|
||||
splitted: true,
|
||||
externalAssetsOnly: true,
|
||||
codeHighlightCacheKey: 'useMarkupToHtml',
|
||||
settingValue: getPluginSettingValue,
|
||||
whiteBackgroundNoteRendering,
|
||||
scrollbarSize: scrollbarSize,
|
||||
baseFontFamily,
|
||||
itemIdToUrl: (id: string, urlParameters = '') => {
|
||||
if (!(id in resources) || !resources[id]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return resourceFullPath(resources[id].item, resourceBaseUrl) + urlParameters;
|
||||
},
|
||||
globalSettings: {
|
||||
'markdown.plugin.abc.options': Setting.value('markdown.plugin.abc.options'),
|
||||
},
|
||||
...options,
|
||||
});
|
||||
|
||||
return result;
|
||||
}, [themeId, markupToHtml, baseFontFamily, whiteBackgroundNoteRendering, scrollbarSize, resourceBaseUrl]);
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
import { useEffect, useRef } from 'react';
|
||||
|
||||
export default function usePrevious<T>(value: T, initialValue: T = null): T {
|
||||
const ref = useRef(initialValue);
|
||||
useEffect(() => {
|
||||
ref.current = value;
|
||||
});
|
||||
return ref.current;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
// Use this to show which props have been changed within a component.
|
||||
//
|
||||
// Usage: usePropsDebugger(props);
|
||||
|
||||
import useEffectDebugger from './useEffectDebugger';
|
||||
|
||||
export default function usePropsDebugger(props: Record<string, unknown>) {
|
||||
const dependencies: unknown[] = [];
|
||||
const dependencyNames: string[] = [];
|
||||
|
||||
for (const k in props) {
|
||||
dependencies.push(props[k]);
|
||||
dependencyNames.push(k);
|
||||
}
|
||||
|
||||
useEffectDebugger(() => {}, dependencies, dependencyNames);
|
||||
}
|
||||
在新工单中引用
屏蔽一个用户