mirror of
https://github.com/alberti42/obsidian-plugins-annotations.git
synced 2026-07-22 10:10:24 +00:00
fixed a bug where we could not click on Markdown links when the annotation are not editable.
This commit is contained in:
parent
400e4033e1
commit
cf977f7e73
3 changed files with 239 additions and 216 deletions
231
src/annotation_control.ts
Normal file
231
src/annotation_control.ts
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
// annotationControl.ts
|
||||
|
||||
import PluginsAnnotations from "main";
|
||||
import { MarkdownRenderer, Platform } from "obsidian";
|
||||
import { AnnotationType, isPluginAnnotation, parseAnnotation } from "types";
|
||||
|
||||
export class annotationControl {
|
||||
private clickedLink: boolean;
|
||||
|
||||
constructor(private plugin: PluginsAnnotations, private annotation_container:HTMLDivElement, private annotation_div:HTMLDivElement,pluginId:string,pluginName:string) {
|
||||
|
||||
this.clickedLink = false;
|
||||
|
||||
if(this.plugin.settings.editable) {
|
||||
annotation_div.contentEditable = 'true';
|
||||
annotation_div.classList.add('plugin-comment-annotation-editable');
|
||||
} else {
|
||||
annotation_div.contentEditable = 'false';
|
||||
annotation_div.classList.remove('plugin-comment-annotation-editable');
|
||||
}
|
||||
|
||||
const placeholder = (this.plugin.settings.label_placeholder).replace(/\$\{plugin_name\}/g, pluginName);
|
||||
|
||||
let isPlaceholder = this.plugin.settings.annotations[pluginId] ? false : true;
|
||||
let annotationDesc:string;
|
||||
let annoType:AnnotationType;
|
||||
|
||||
if(!isPlaceholder && isPluginAnnotation(this.plugin.settings.annotations[pluginId])) {
|
||||
const annotation = this.plugin.settings.annotations[pluginId];
|
||||
annotationDesc = annotation.desc;
|
||||
annoType = annotation.type;
|
||||
} else {
|
||||
annotationDesc = placeholder.trim();
|
||||
annoType = AnnotationType.html;
|
||||
|
||||
annotation_div.classList.add('plugin-comment-placeholder');
|
||||
if (this.plugin.settings.hide_placeholders) { // if it is a placeholder
|
||||
if(this.plugin.settings.editable) { // if fields can be edited, set the placeholder tag
|
||||
annotation_container.classList.add('plugin-comment-placeholder');
|
||||
} else { // if fields cannot be edited, just simply hide placeholders
|
||||
annotation_container.classList.add('plugin-comment-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// let clickedLinkObj = { status: false };
|
||||
|
||||
// Initial render
|
||||
this.renderAnnotation(annotation_div,annoType,annotationDesc);
|
||||
|
||||
// Handle mousedown event to check if a link was clicked
|
||||
let clickedLinkk = false;
|
||||
annotation_div.addEventListener('mousedown', (event:MouseEvent) => {
|
||||
console.log("MOUSE DOWN");
|
||||
if(!this.plugin.settings.editable) { return; }
|
||||
if (event.target && (event.target as HTMLElement).tagName === 'A') {
|
||||
clickedLinkk = true;
|
||||
} else {
|
||||
clickedLinkk = false;
|
||||
}
|
||||
console.log("CLICKED LINK:",clickedLinkk);
|
||||
});
|
||||
|
||||
// Prevent click event propagation to parent
|
||||
annotation_div.addEventListener('click', (event:MouseEvent) => {
|
||||
console.log("CLICK EVENT");
|
||||
console.log(this.plugin.settings);
|
||||
if(this.plugin.settings.editable) {
|
||||
event.stopPropagation();
|
||||
console.log("EDITABLE");
|
||||
// the focus event will handle the rest
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
});
|
||||
|
||||
// Remove placeholder class when user starts typing
|
||||
annotation_div.addEventListener('focus', (event:FocusEvent) => {
|
||||
console.log("FOCUS");
|
||||
if(!this.plugin.settings.editable) { return; }
|
||||
if (isPlaceholder) {
|
||||
if (this.plugin.settings.delete_placeholder_string_on_insertion) {
|
||||
annotation_div.innerText = '';
|
||||
}
|
||||
annotation_div.classList.remove('plugin-comment-placeholder');
|
||||
if (this.plugin.settings.hide_placeholders) {
|
||||
// we remove 'plugin-comment-placeholder' only when 'this.plugin.settings.hide_placeholders' is true
|
||||
// when 'this.plugin.settings.hide_placeholders' is false, the class is not set and does not need to be removed.
|
||||
annotation_container.classList.remove('plugin-comment-placeholder');
|
||||
}
|
||||
|
||||
const text = annotation_div.innerText; // text without html markup
|
||||
annotation_div.innerText = text; // this removes all html markup for editing
|
||||
|
||||
// Force a DOM reflow by reading the offsetHeight (or another property)
|
||||
annotation_div.offsetHeight;
|
||||
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(annotation_div);
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
} else {
|
||||
// Only update annotation_div.innerText if not clicking on a link
|
||||
if (!clickedLinkk) {
|
||||
let preamble;
|
||||
switch(annoType) {
|
||||
case AnnotationType.html:
|
||||
preamble = 'html:';
|
||||
break;
|
||||
case AnnotationType.markdown:
|
||||
preamble = 'markdown:';
|
||||
break;
|
||||
case AnnotationType.text:
|
||||
preamble = 'text:';
|
||||
break;
|
||||
default:
|
||||
preamble = 'markdown:';
|
||||
}
|
||||
|
||||
annotation_div.innerText = preamble + '\n' + annotationDesc;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Save the comment on input change and update inputTriggered status
|
||||
annotation_div.addEventListener('input', (event: Event) => {
|
||||
if(!this.plugin.settings.editable) return;
|
||||
isPlaceholder = false;
|
||||
});
|
||||
|
||||
// Add placeholder class back if no changes are made
|
||||
annotation_div.addEventListener('blur', (event:FocusEvent) => {
|
||||
if(!this.plugin.settings.editable) { return; }
|
||||
|
||||
const {annoType: type, annoDesc: content} = parseAnnotation(annotation_div.innerText.trim());
|
||||
|
||||
if (isPlaceholder || content === '') { // placeholder
|
||||
annotation_div.innerHTML = placeholder;
|
||||
delete this.plugin.settings.annotations[pluginId];
|
||||
annotation_div.classList.add('plugin-comment-placeholder');
|
||||
if (this.plugin.settings.hide_placeholders) {
|
||||
annotation_container.classList.add('plugin-comment-placeholder');
|
||||
}
|
||||
isPlaceholder = true;
|
||||
annotationDesc = '';
|
||||
annoType = AnnotationType.html;
|
||||
} else {
|
||||
isPlaceholder = false;
|
||||
|
||||
annotationDesc = content.trim();
|
||||
annoType = type;
|
||||
|
||||
this.plugin.settings.annotations[pluginId] = {
|
||||
desc: annotationDesc,
|
||||
name: pluginName,
|
||||
type: type,
|
||||
};
|
||||
annotation_div.classList.remove('plugin-comment-placeholder');
|
||||
|
||||
this.renderAnnotation(annotation_div,type,content);
|
||||
}
|
||||
this.plugin.debouncedSaveAnnotations();
|
||||
});
|
||||
}
|
||||
|
||||
async renderAnnotation(annotation_div: HTMLElement, annoType:AnnotationType, desc:string) {
|
||||
annotation_div.innerText = '';
|
||||
switch(annoType) {
|
||||
case AnnotationType.text: {
|
||||
const p = document.createElement('p');
|
||||
p.dir = 'auto';
|
||||
const label = this.create_label();
|
||||
if(label) {
|
||||
p.appendChild(label);
|
||||
p.appendText(desc);
|
||||
}
|
||||
else {
|
||||
p.innerText = desc;
|
||||
}
|
||||
annotation_div.appendChild(p);
|
||||
break;
|
||||
}
|
||||
case AnnotationType.html: {
|
||||
const label = Platform.isMobile ? this.plugin.settings.label_mobile : this.plugin.settings.label_desktop;
|
||||
const desc_with_label = desc.replace(/\$\{label\}/g, label);
|
||||
annotation_div.innerHTML = desc_with_label;
|
||||
this.handleAnnotationLinks(annotation_div);
|
||||
break;
|
||||
}
|
||||
case AnnotationType.markdown: {
|
||||
const label = Platform.isMobile ? this.plugin.settings.label_mobile : this.plugin.settings.label_desktop;
|
||||
const desc_with_label = label + desc;
|
||||
await MarkdownRenderer.renderMarkdown(desc_with_label, annotation_div, '', this.plugin);
|
||||
this.handleAnnotationLinks(annotation_div);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
create_label(): HTMLSpanElement | null {
|
||||
const label = Platform.isMobile ? this.plugin.settings.label_mobile : this.plugin.settings.label_desktop;
|
||||
if(label.trim() === "") {
|
||||
return null;
|
||||
} else {
|
||||
const span = document.createElement('span');
|
||||
span.innerHTML = label;
|
||||
span.classList.add('plugin-comment-label');
|
||||
return span;
|
||||
}
|
||||
}
|
||||
|
||||
// Helper function to parse links and add click listeners
|
||||
handleAnnotationLinks(element: HTMLElement) {
|
||||
const links = element.querySelectorAll('a');
|
||||
links.forEach(link => {
|
||||
console.log(element);
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
const href = link.getAttribute('href');
|
||||
if (href) {
|
||||
this.plugin.app.workspace.openLinkText(href, '', false);
|
||||
this.plugin.app.setting.close(); // Close the settings pane when a link is clicked
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
219
src/main.ts
219
src/main.ts
|
|
@ -5,7 +5,6 @@ import {
|
|||
Setting,
|
||||
SettingTab,
|
||||
Platform,
|
||||
MarkdownRenderer,
|
||||
Plugins,
|
||||
PluginManifest,
|
||||
FileSystemAdapter,
|
||||
|
|
@ -14,7 +13,7 @@ import {
|
|||
// App,
|
||||
} from 'obsidian';
|
||||
import { around } from 'monkey-around';
|
||||
import { AnnotationType, isPluginAnnotation, isPluginsAnnotationsSettings, parseAnnotation, PluginAnnotationDict, PluginBackup, PluginsAnnotationsSettings } from './types';
|
||||
import { isPluginsAnnotationsSettings, PluginAnnotationDict, PluginBackup, PluginsAnnotationsSettings } from './types';
|
||||
import { PluginAnnotationDict_1_4_0, PluginsAnnotationsSettings_1_4_0, PluginsAnnotationsSettings_1_3_0, isPluginAnnotationDictFormat_1_3_0, isSettingsFormat_1_3_0, isSettingsFormat_1_4_0, parseAnnotation_1_4_0, } from 'types_legacy'
|
||||
import { DEFAULT_SETTINGS_1_3_0, DEFAULT_SETTINGS_1_4_0 } from './defaults_legacy';
|
||||
import { DEFAULT_SETTINGS } from 'defaults';
|
||||
|
|
@ -22,6 +21,7 @@ import { PluginsAnnotationsSettingTab } from 'settings_tab'
|
|||
import * as path from 'path';
|
||||
import { readAnnotationsFromMdFile, writeAnnotationsToMdFile } from 'manageAnnotations';
|
||||
import { sortPluginAnnotationsByName } from 'utils';
|
||||
import { annotationControl } from 'annotation_control';
|
||||
|
||||
export default class PluginsAnnotations extends Plugin {
|
||||
settings: PluginsAnnotationsSettings = structuredClone(DEFAULT_SETTINGS);
|
||||
|
|
@ -397,217 +397,6 @@ export default class PluginsAnnotations extends Plugin {
|
|||
}
|
||||
}
|
||||
|
||||
// Helper function to parse links and add click listeners
|
||||
handleAnnotationLinks(element: HTMLElement) {
|
||||
const links = element.querySelectorAll('a');
|
||||
links.forEach(link => {
|
||||
console.log(element);
|
||||
link.addEventListener('click', (event) => {
|
||||
event.preventDefault();
|
||||
const href = link.getAttribute('href');
|
||||
if (href) {
|
||||
this.app.workspace.openLinkText(href, '', false);
|
||||
this.app.setting.close(); // Close the settings pane when a link is clicked
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
create_label(): HTMLSpanElement | null {
|
||||
const label = Platform.isMobile ? this.settings.label_mobile : this.settings.label_desktop;
|
||||
if(label.trim() === "") {
|
||||
return null;
|
||||
} else {
|
||||
const span = document.createElement('span');
|
||||
span.innerHTML = label;
|
||||
span.classList.add('plugin-comment-label');
|
||||
return span;
|
||||
}
|
||||
}
|
||||
|
||||
async renderAnnotation(annotation_div: HTMLElement, annoType:AnnotationType, desc:string) {
|
||||
annotation_div.innerText = '';
|
||||
switch(annoType) {
|
||||
case AnnotationType.text: {
|
||||
const p = document.createElement('p');
|
||||
p.dir = 'auto';
|
||||
const label = this.create_label();
|
||||
if(label) {
|
||||
p.appendChild(label);
|
||||
p.appendText(desc);
|
||||
}
|
||||
else {
|
||||
p.innerText = desc;
|
||||
}
|
||||
annotation_div.appendChild(p);
|
||||
break;
|
||||
}
|
||||
case AnnotationType.html: {
|
||||
const label = Platform.isMobile ? this.settings.label_mobile : this.settings.label_desktop;
|
||||
const desc_with_label = desc.replace(/\$\{label\}/g, label);
|
||||
annotation_div.innerHTML = desc_with_label;
|
||||
this.handleAnnotationLinks(annotation_div);
|
||||
break;
|
||||
}
|
||||
case AnnotationType.markdown: {
|
||||
const label = Platform.isMobile ? this.settings.label_mobile : this.settings.label_desktop;
|
||||
const desc_with_label = label + desc;
|
||||
await MarkdownRenderer.renderMarkdown(desc_with_label, annotation_div, '', this);
|
||||
this.handleAnnotationLinks(annotation_div);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configureAnnotation(annotation_container:HTMLDivElement,annotation_div:HTMLDivElement,pluginId:string,pluginName:string) {
|
||||
|
||||
if(this.settings.editable) {
|
||||
annotation_div.contentEditable = 'true';
|
||||
annotation_div.classList.add('plugin-comment-annotation-editable');
|
||||
} else {
|
||||
annotation_div.contentEditable = 'false';
|
||||
annotation_div.classList.remove('plugin-comment-annotation-editable');
|
||||
}
|
||||
|
||||
const placeholder = (this.settings.label_placeholder).replace(/\$\{plugin_name\}/g, pluginName);
|
||||
|
||||
let isPlaceholder = this.settings.annotations[pluginId] ? false : true;
|
||||
let annotationDesc:string;
|
||||
let annoType:AnnotationType;
|
||||
|
||||
if(!isPlaceholder && isPluginAnnotation(this.settings.annotations[pluginId])) {
|
||||
const annotation = this.settings.annotations[pluginId];
|
||||
annotationDesc = annotation.desc;
|
||||
annoType = annotation.type;
|
||||
} else {
|
||||
annotationDesc = placeholder.trim();
|
||||
annoType = AnnotationType.html;
|
||||
|
||||
annotation_div.classList.add('plugin-comment-placeholder');
|
||||
if (this.settings.hide_placeholders) { // if it is a placeholder
|
||||
if(this.settings.editable) { // if fields can be edited, set the placeholder tag
|
||||
annotation_container.classList.add('plugin-comment-placeholder');
|
||||
} else { // if fields cannot be edited, just simply hide placeholders
|
||||
annotation_container.classList.add('plugin-comment-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Initial render
|
||||
this.renderAnnotation(annotation_div,annoType,annotationDesc);
|
||||
|
||||
// Handle mousedown event to check if a link was clicked
|
||||
let clickedLink = false;
|
||||
annotation_div.addEventListener('mousedown', (event:MouseEvent) => {
|
||||
console.log("MOUSE DOWN");
|
||||
if(!this.settings.editable) { return; }
|
||||
if (event.target && (event.target as HTMLElement).tagName === 'A') {
|
||||
clickedLink = true;
|
||||
} else {
|
||||
clickedLink = false;
|
||||
}
|
||||
console.log("CLICKED LINK:",clickedLink);
|
||||
});
|
||||
|
||||
// Prevent click event propagation to parent
|
||||
annotation_div.addEventListener('click', (event:MouseEvent) => {
|
||||
console.log("CLICK EVENT");
|
||||
// if(!this.settings.editable) { return; }
|
||||
event.stopPropagation();
|
||||
});
|
||||
|
||||
// Remove placeholder class when user starts typing
|
||||
annotation_div.addEventListener('focus', (event:FocusEvent) => {
|
||||
console.log("FOCUS");
|
||||
if(!this.settings.editable) { return; }
|
||||
if (isPlaceholder) {
|
||||
if (this.settings.delete_placeholder_string_on_insertion) {
|
||||
annotation_div.innerText = '';
|
||||
}
|
||||
annotation_div.classList.remove('plugin-comment-placeholder');
|
||||
if (this.settings.hide_placeholders) {
|
||||
// we remove 'plugin-comment-placeholder' only when 'this.settings.hide_placeholders' is true
|
||||
// when 'this.settings.hide_placeholders' is false, the class is not set and does not need to be removed.
|
||||
annotation_container.classList.remove('plugin-comment-placeholder');
|
||||
}
|
||||
|
||||
const text = annotation_div.innerText; // text without html markup
|
||||
annotation_div.innerText = text; // this removes all html markup for editing
|
||||
|
||||
// Force a DOM reflow by reading the offsetHeight (or another property)
|
||||
annotation_div.offsetHeight;
|
||||
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(annotation_div);
|
||||
const selection = window.getSelection();
|
||||
if (selection) {
|
||||
selection.removeAllRanges();
|
||||
selection.addRange(range);
|
||||
}
|
||||
} else {
|
||||
// Only update annotation_div.innerText if not clicking on a link
|
||||
if (!clickedLink) {
|
||||
let preamble;
|
||||
switch(annoType) {
|
||||
case AnnotationType.html:
|
||||
preamble = 'html:';
|
||||
break;
|
||||
case AnnotationType.markdown:
|
||||
preamble = 'markdown:';
|
||||
break;
|
||||
case AnnotationType.text:
|
||||
preamble = 'text:';
|
||||
break;
|
||||
default:
|
||||
preamble = 'markdown:';
|
||||
}
|
||||
|
||||
annotation_div.innerText = preamble + '\n' + annotationDesc;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Save the comment on input change and update inputTriggered status
|
||||
annotation_div.addEventListener('input', (event: Event) => {
|
||||
if(!this.settings.editable) return;
|
||||
isPlaceholder = false;
|
||||
});
|
||||
|
||||
// Add placeholder class back if no changes are made
|
||||
annotation_div.addEventListener('blur', (event:FocusEvent) => {
|
||||
if(!this.settings.editable) { return; }
|
||||
|
||||
const {annoType: type, annoDesc: content} = parseAnnotation(annotation_div.innerText.trim());
|
||||
|
||||
if (isPlaceholder || content === '') { // placeholder
|
||||
annotation_div.innerHTML = placeholder;
|
||||
delete this.settings.annotations[pluginId];
|
||||
annotation_div.classList.add('plugin-comment-placeholder');
|
||||
if (this.settings.hide_placeholders) {
|
||||
annotation_container.classList.add('plugin-comment-placeholder');
|
||||
}
|
||||
isPlaceholder = true;
|
||||
annotationDesc = '';
|
||||
annoType = AnnotationType.html;
|
||||
} else {
|
||||
isPlaceholder = false;
|
||||
|
||||
annotationDesc = content.trim();
|
||||
annoType = type;
|
||||
|
||||
this.settings.annotations[pluginId] = {
|
||||
desc: annotationDesc,
|
||||
name: pluginName,
|
||||
type: type,
|
||||
};
|
||||
annotation_div.classList.remove('plugin-comment-placeholder');
|
||||
|
||||
this.renderAnnotation(annotation_div,type,content);
|
||||
}
|
||||
this.debouncedSaveAnnotations();
|
||||
});
|
||||
}
|
||||
|
||||
async addIcon(tab: SettingTab) {
|
||||
// Add new icon to the existing icons container
|
||||
const headingContainer = tab.containerEl.querySelector('.setting-item-heading .setting-item-control');
|
||||
|
|
@ -636,6 +425,8 @@ export default class PluginsAnnotations extends Plugin {
|
|||
|
||||
newIcon.addEventListener('click', (event:MouseEvent) => {
|
||||
this.settings.editable = !this.settings.editable;
|
||||
console.log("NEW EDITABLE:");
|
||||
console.log(this.settings)
|
||||
this.debouncedSaveAnnotations();
|
||||
if(this.settings.editable) {
|
||||
newIcon.setAttribute('aria-label', 'Click to lock personal annotations');
|
||||
|
|
@ -709,7 +500,7 @@ export default class PluginsAnnotations extends Plugin {
|
|||
const annotation_div = document.createElement('div');
|
||||
annotation_div.className = 'plugin-comment-annotation';
|
||||
|
||||
this.configureAnnotation(annotation_container,annotation_div,pluginId,pluginName);
|
||||
new annotationControl(this,annotation_container,annotation_div,pluginId,pluginName);
|
||||
|
||||
annotation_container.appendChild(annotation_div);
|
||||
descriptionDiv.appendChild(annotation_container);
|
||||
|
|
|
|||
|
|
@ -63,8 +63,9 @@ export class PluginsAnnotationsSettingTab extends PluginSettingTab {
|
|||
list_uninstalled_label.settingEl.remove();
|
||||
}
|
||||
}));
|
||||
// Render the annotation inside the temporary div
|
||||
this.plugin.renderAnnotation(pluginSetting.descEl, uninstalledPlugins[pluginId].type, uninstalledPlugins[pluginId].desc);
|
||||
// Render the annotation
|
||||
// FIXME
|
||||
// this.plugin.renderAnnotation(pluginSetting.descEl, uninstalledPlugins[pluginId].type, uninstalledPlugins[pluginId].desc);
|
||||
pluginSetting.descEl.classList.add('plugin-comment-annotation');
|
||||
pluginSetting.settingEl.classList.add('plugin-comment-uninstalled');
|
||||
});
|
||||
|
|
|
|||
Loading…
Reference in a new issue