Skip to content

Commit

Permalink
Added captioning for external images. Updated version. [main] Cleaned…
Browse files Browse the repository at this point in the history
… up imports.
  • Loading branch information
bicarlsen committed Dec 13, 2021
1 parent 9ad5127 commit 3f52533
Show file tree
Hide file tree
Showing 5 changed files with 146 additions and 12 deletions.
2 changes: 1 addition & 1 deletion manifest.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"id": "obsidian-image-caption",
"name": "Image Caption",
"version": "0.0.8",
"version": "0.0.9",
"minAppVersion": "0.12.19",
"description": "Add captions to images.",
"author": "bicarlsen",
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "obsidian-image-caption",
"version": "0.0.8",
"version": "0.0.9",
"description": "Add captions to images in Obsidian.",
"main": "main.js",
"scripts": {
Expand Down
7 changes: 4 additions & 3 deletions src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ import {
} from 'obsidian';

import {
captionObserver,
processImageCaption
processInternalImageCaption,
processExternalImageCaption
} from './md_processor';


Expand Down Expand Up @@ -36,7 +36,8 @@ export default class ImageCaptionPlugin extends Plugin {
await this.loadSettings();

this.caption_observers = [];
this.registerMarkdownPostProcessor( processImageCaption( this ) );
this.registerMarkdownPostProcessor( processInternalImageCaption( this ) );
this.registerMarkdownPostProcessor( processExternalImageCaption( this ) );

this.addStylesheet();
this.addSettingTab( new ImageCaptionSettingTab( this.app, this ) );
Expand Down
146 changes: 139 additions & 7 deletions src/md_processor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,19 @@ import {
import ImageCaptionPlugin from './main';


export function captionObserver( plugin: Plugin, ctx: MarkdownPostProcessorContext ) {

/**
* Registers a Mutation Observer on an image to add a caption.
* The observer is unregistered after the caption has been added.
* Meant to be used for internal embeds.
*
* @param plugin [Plugin]
* @param ctx [MarkdownPostProcessorContext]
* @returns [MutationObserver]
*/
export function internalCaptionObserver(
plugin: Plugin,
ctx: MarkdownPostProcessorContext
) {
return new MutationObserver( ( mutations, observer ) => {
for ( const mutation of mutations ) {
if ( !mutation.target.matches( 'span.image-embed' ) ) {
Expand Down Expand Up @@ -41,6 +52,47 @@ export function captionObserver( plugin: Plugin, ctx: MarkdownPostProcessorConte
}


/**
* Registers a Mutation Observer on an image to add a caption.
* The observer is unregistered after the caption has been added.
* Meant to be used for external embeds.
*
* @param plugin [Plugin]
* @returns [MutationObserver]
*/
export function externalCaptionObserver(
plugin: Plugin
) {
return new MutationObserver( ( mutations, observer ) => {
let update = false;
for ( const mutation of mutations ) {
const captions = [ ...mutation.addedNodes ].filter(
( elm: HTMLElement ) => {
return elm.matches( ImageCaptionPlugin.caption_selector )
}
);

if ( captions.length ) {
// new caption exists
update = true;
}
}

if ( update ) {
updateFigureIndices();
plugin.removeObserver( observer );
}
} );
}


/**
* Parses text to extract the caption.
*
* @param text [string] Text to parse.
* @param delimeter [string[]] Delimeter(s) used to indeicate caption text.
* @returns [string] Caption text.
*/
function parseCaptionText( text: string, delimeter: string[] ): string | null {
if ( delimeter.length === 0 ) {
return text;
Expand Down Expand Up @@ -70,11 +122,18 @@ function parseCaptionText( text: string, delimeter: string[] ): string | null {
return '';
}

const start_offset = delimeter[ 0 ].length; // exclude starting delimeter
const start_offset = delimeter[ 0 ].length; // exclude starting delimeter
return text.slice( start + start_offset, end );
}


/**
* Adds a caption to an image.
*
* @param target [HTMLElement] Parent element for the caption.
* @param caption_text [string] Text to add for the caption.
* @returns [MarkdownRenderChild] Caption element that was added to the target as the caption.
*/
function addCaption(
target: HTMLElement,
caption_text: string
Expand All @@ -88,11 +147,14 @@ function addCaption(
}


/**
* Updates index data for images.
*/
function updateFigureIndices() {
document.querySelectorAll( 'div.workspace-leaf' ).forEach(
( container : HTMLElement ) => {
( workspace: HTMLElement ) => {
let index = 1;
container.querySelectorAll( ImageCaptionPlugin.caption_selector ).forEach(
workspace.querySelectorAll( ImageCaptionPlugin.caption_selector ).forEach(
( el: HTMLElement ) => {
el.dataset.imageCaptionIndex = index;
index += 1;
Expand All @@ -103,7 +165,13 @@ function updateFigureIndices() {
}


export function processImageCaption(
/**
* Registers MutationObservers on internal images.
*
* @param plugin [Plugin]
* @returns [(HTMLElement, MarkdownPostProcessorContext) => void] Function that registers internal images to have a caption added to them.
*/
export function processInternalImageCaption(
plugin: Plugin
): ( el: HTMLElement, ctx: MarkdownPostProcessorContext ) => void {

Expand All @@ -115,7 +183,7 @@ export function processImageCaption(
( container: HTMLElement ) => {
// must listen for class changes because images
// may be loaded after this run
const observer = captionObserver( plugin, ctx );
const observer = internalCaptionObserver( plugin, ctx );
observer.observe(
container,
{ attributes: true, attributesFilter: [ 'class' ] }
Expand All @@ -125,4 +193,68 @@ export function processImageCaption(
}
);
};
}


/**
* Adds caption to external images.
*
* @param plugin [Plugin]
* @returns [(HTMLElement, MarkdownPostProcessorContext) => void] Function that registers external images to have a caption added to them.
*/
export function processExternalImageCaption(
plugin: Plugin
): ( el: HTMLElement, ctx: MarkdownPostProcessorContext ) => void {

return function (
el: HTMLElement,
ctx: MarkdownPostProcessorContext
): void {
const container_css_class = 'obsidian-image-caption-external-embed';

elms = [ ...el.querySelectorAll( 'img' ) ];
elms.filter( ( elm: HTMLElement ) => {
// filter out internal images
return ! elm.closest( 'span.internal-embed' );
} ).forEach(
( img: HTMLElement ) => {
if ( img.closest( `.${container_css_class}` ) ) {
// caption already added
return;
}

let caption_text = img.getAttribute( 'alt' );
caption_text = parseCaptionText( caption_text, plugin.settings.delimeter );
if ( caption_text === null ) {
// empty caption
return;
}

// create container
// const parent = img.parentNode;
const container = document.createElement( 'span' );
container.addClass( container_css_class );

// observe container for caption to be added
const observer = externalCaptionObserver( plugin, ctx );
observer.observe(
container,
{ childList: true }
);

plugin.addObserver( observer );

// insert container into DOM
img.replaceWith( container );
container.appendChild( img );

// add caption
const caption = addCaption( container, caption_text );

ctx.addChild( new MarkdownRenderChild( container ) );
ctx.addChild( caption );
// setTimeout( updateFigureIndices, 5 );
}
);
};
}
1 change: 1 addition & 0 deletions versions.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
{
"0.0.9": "0.12.19",
"0.0.8": "0.12.19",
"0.0.7": "0.12.19",
"0.0.6": "0.12.19",
Expand Down

0 comments on commit 3f52533

Please sign in to comment.