Skip to content

Commit

Permalink
⤵️ Local download links (#162)
Browse files Browse the repository at this point in the history
* ⤵️ Local download links See #158
* 🏷 Updates to theme v0.3.3
  • Loading branch information
rowanc1 authored Jun 29, 2023
1 parent 277f4a0 commit dedbb1d
Show file tree
Hide file tree
Showing 6 changed files with 112 additions and 103 deletions.
14 changes: 7 additions & 7 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -64,26 +64,26 @@
"@jupyterlab/notebook": "^4.0.0",
"@jupyterlab/rendermime": "^4.0.0",
"@jupyterlab/translation": "^4.0.0",
"@myst-theme/diagrams": "^0.3.2",
"@myst-theme/frontmatter": "^0.3.2",
"@myst-theme/providers": "^0.3.2",
"@myst-theme/diagrams": "^0.3.3",
"@myst-theme/frontmatter": "^0.3.3",
"@myst-theme/providers": "^0.3.3",
"katex": "^0.15.2",
"myst-ext-card": "^1.0.0",
"myst-ext-exercise": "^1.0.0",
"myst-ext-grid": "^1.0.0",
"myst-ext-proof": "^1.0.0",
"myst-ext-tabs": "^1.0.0",
"myst-frontmatter": "^1.0.1",
"myst-parser": "^1.0.1",
"myst-to-react": "^0.3.2",
"myst-transforms": "^1.0.1"
"myst-parser": "^1.0.2",
"myst-to-react": "^0.3.3",
"myst-transforms": "^1.0.2"
},
"devDependencies": {
"@babel/core": "^7.0.0",
"@babel/preset-env": "^7.0.0",
"@jupyterlab/builder": "^4.0.0",
"@jupyterlab/testutils": "^4.0.0",
"@myst-theme/styles": "^0.3.2",
"@myst-theme/styles": "^0.3.3",
"@tailwindcss/typography": "^0.5.8",
"@types/jest": "^29.2.0",
"@types/json-schema": "^7.0.11",
Expand Down
2 changes: 1 addition & 1 deletion src/MySTMarkdownCell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ export class MySTMarkdownCell
}

// The notebook update is asynchronous
renderNotebook(this.parent as StaticNotebook);
await renderNotebook(this.parent as StaticNotebook);

// Let's wait for this cell to be rendered
await this._mystWidget.renderPromise;
Expand Down
86 changes: 45 additions & 41 deletions src/links.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,16 @@
import React from 'react';
import type { Plugin } from 'unified';
import type { Root, Link } from 'myst-spec';
import { selectAll } from 'unist-util-select';
import { URLExt } from '@jupyterlab/coreutils';
import type { LinkProps } from '@myst-theme/providers';
import { IRenderMime } from '@jupyterlab/rendermime';
import { updateLinkTextIfEmpty } from 'myst-transforms';

/**
* Handle an anchor node.
* NOTE: This is copied from @jupyterlab/rendermime renderers.ts
* ideally this should be removed and exported from there?
* Originally from @jupyterlab/rendermime renderers.ts
*/
function handleAnchor(
async function handleAnchor(
anchor: HTMLAnchorElement,
resolver: IRenderMime.IResolver,
linkHandler: IRenderMime.ILinkHandler | undefined
Expand All @@ -24,41 +23,37 @@ function handleAnchor(
: URLExt.isLocal(href);
// Bail if it is not a file-like url.
if (!href || !isLocal) {
return Promise.resolve(undefined);
return;
}
// Remove the hash until we can handle it.
const hash = anchor.hash;
if (hash) {
// Handle internal link in the file.
if (hash === href) {
anchor.target = '_self';
return Promise.resolve(undefined);
return;
}
// For external links, remove the hash until we have hash handling.
href = href.replace(hash, '');
}
// Get the appropriate file path.
return resolver
.resolveUrl(href)
.then(urlPath => {
// decode encoded url from url to api path
const path = decodeURIComponent(urlPath);
// Handle the click override.
if (linkHandler) {
linkHandler.handleLink(anchor, path, hash);
}
// Get the appropriate file download path.
return resolver.getDownloadUrl(urlPath);
})
.then(url => {
// Set the visible anchor.
anchor.href = url + hash;
})
.catch(err => {
// If there was an error getting the url,
// just make it an empty link.
anchor.href = '';
});
try {
// Get the appropriate file path.
const urlPath = await resolver.resolveUrl(href);
// decode encoded url from url to api path
const path = decodeURIComponent(urlPath);
// Handle the click override.
if (linkHandler) {
linkHandler.handleLink(anchor, path, hash);
}
// Get the appropriate file download path.
const url = await resolver.getDownloadUrl(urlPath);
// Set the visible anchor.
anchor.href = url + hash;
} catch (error) {
// If there was an error getting the url,
// just make it an empty link.
anchor.href = '';
}
}

export const linkFactory =
Expand Down Expand Up @@ -92,17 +87,26 @@ export async function internalLinksTransform(
opts: Options
): Promise<void> {
const links = selectAll('link,linkBlock', tree) as Link[];
links.forEach(async link => {
if (!link || !link.url) return;
const resolver = opts.resolver;
const isLocal = resolver?.isLocal
? resolver.isLocal(link.url)
: URLExt.isLocal(link.url);
if (isLocal) (link as any).internal = true;
});
await Promise.all(
links.map(async link => {
if (!link || !link.url) return;
const resolver = opts.resolver;
const href = link.url;
updateLinkTextIfEmpty(link, href);
const isLocal = resolver?.isLocal
? resolver.isLocal(href)
: URLExt.isLocal(href);
if (!isLocal) return;
if (!resolver) return;
if ((link as any).static) {
// TODO: remove hash
const urlPath = await resolver.resolveUrl(href);
const url = await resolver.getDownloadUrl(urlPath);
(link as any).urlSource = href;
link.url = url;
} else {
(link as any).internal = true;
}
})
);
}

export const internalLinksPlugin: Plugin<[Options], Root, Root> =
opts => tree => {
internalLinksTransform(tree, opts);
};
1 change: 1 addition & 0 deletions src/mime.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ export class RenderedMySTMarkdown
this.node.dataset['mimeType'] = MIME_TYPE;
this.addClass('jp-RenderedMySTMarkdown');
}

async renderModel(model: IRenderMime.IMimeModel): Promise<void> {
if ((window as any).trigger) {
throw Error('triggered!');
Expand Down
18 changes: 11 additions & 7 deletions src/myst.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ import { StaticNotebook } from '@jupyterlab/notebook';
import { IRenderMimeRegistry } from '@jupyterlab/rendermime';
import { IRenderMime } from '@jupyterlab/rendermime-interfaces';
import { imageUrlSourceTransform } from './images';
import { internalLinksPlugin } from './links';
import { internalLinksTransform } from './links';
import { addCiteChildrenPlugin } from './citations';
import { evalRole } from './roles';
import { IUserExpressionMetadata } from './metadata';
Expand Down Expand Up @@ -119,12 +119,12 @@ export async function processArticleMDAST(
.use(linksPlugin, { transformers: linkTransforms })
.use(footnotesPlugin)
.use(resolveReferencesPlugin, { state })
.use(internalLinksPlugin, { resolver })
.use(addCiteChildrenPlugin)
.use(keysPlugin)
.runSync(mdast as any, file);

// Go through all links and replace the source if they are local
await internalLinksTransform(mdast, { resolver });
await imageUrlSourceTransform(mdast, { resolver });

return {
Expand All @@ -143,10 +143,10 @@ export function buildNotebookMDAST(mystCells: IMySTMarkdownCell[]): any {
return { type: 'root', children: blocks };
}

export function processNotebookMDAST(
export async function processNotebookMDAST(
mdast: any,
resolver: IRenderMime.IResolver | undefined
): IMySTDocumentState {
): Promise<IMySTDocumentState> {
const linkTransforms = [
new WikiTransformer(),
new GithubTransformer(),
Expand Down Expand Up @@ -185,11 +185,12 @@ export function processNotebookMDAST(
.use(linksPlugin, { transformers: linkTransforms })
.use(footnotesPlugin)
.use(resolveReferencesPlugin, { state })
.use(internalLinksPlugin, { resolver: resolver })
.use(addCiteChildrenPlugin)
.use(keysPlugin)
.runSync(mdast as any, file);

await internalLinksTransform(mdast, { resolver });

if (file.messages.length > 0) {
// TODO: better error messages in the future
console.error(file.messages.map(m => m.message).join('\n'));
Expand All @@ -215,7 +216,7 @@ export async function processCellMDAST(
return mdast;
}

export function renderNotebook(notebook: StaticNotebook) {
export async function renderNotebook(notebook: StaticNotebook) {
const mystCells = notebook.widgets.filter(isMySTMarkdownCell).filter(
// In the future, we may want to process the code cells as well, but not now
cell => cell.fragmentMDAST !== undefined
Expand All @@ -225,7 +226,10 @@ export function renderNotebook(notebook: StaticNotebook) {
references,
frontmatter,
mdast: processedMDAST
} = processNotebookMDAST(mdast, notebook.rendermime.resolver ?? undefined);
} = await processNotebookMDAST(
mdast,
notebook.rendermime.resolver ?? undefined
);

mystCells.forEach((cell, index) => {
if (cell.rendered) {
Expand Down
Loading

0 comments on commit dedbb1d

Please sign in to comment.