Skip to content

Commit

Permalink
feat: overriding attachments
Browse files Browse the repository at this point in the history
Allow overriding attachment in a modal, support regex and some keywords

Allow to send outside of the default image path or configured root
  • Loading branch information
Mara-Li committed Dec 23, 2023
1 parent 91d2bb1 commit 66e7373
Show file tree
Hide file tree
Showing 8 changed files with 233 additions and 33 deletions.
27 changes: 25 additions & 2 deletions src/conversion/file_path.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from "obsidian";

import {
FIND_REGEX,
FolderSettings,
FrontmatterConvert,
GitHubPublisherSettings,
Expand Down Expand Up @@ -411,6 +412,7 @@ export function getImagePath(
return regexOnFileName(imagePath, settings);
}


/**
* Create filepath in github Repository based on settings and frontmatter for image
* @param {TFile} file : Source file
Expand All @@ -421,7 +423,7 @@ export function getImagePath(

function createImagePath(file: TFile,
settings: GitHubPublisherSettings,
sourceFrontmatter: FrontmatterConvert | null):string {
sourceFrontmatter: FrontmatterConvert | null): string {
if (!sourceFrontmatter || !sourceFrontmatter.attachmentLinks) {
if (settings.embed.useObsidianFolder) {
if (settings.upload.behavior === FolderSettings.yaml) {
Expand All @@ -433,7 +435,28 @@ function createImagePath(file: TFile,
}
}
const defaultImageFolder = settings.embed.folder;
if (defaultImageFolder.length > 0) {
//find in override
const isOverridden = settings.embed.overrideAttachments.filter((override) => {
const isRegex = override.path.match(FIND_REGEX);
const regex = isRegex ? new RegExp(isRegex[1], isRegex[2]) : undefined;
return (
regex?.test(file.path)
|| file.path === override.path
|| override.path.contains("{{all}}"))
&& !override.destination.contains("{{default}}");
});
if (isOverridden.length > 0) {
let filePath = file.path;
for (const override of isOverridden) {
const isRegex = override.path.match(FIND_REGEX);
const regex = isRegex ? new RegExp(isRegex[1], isRegex[2]) : null;
const dest = override.destination.replace("{{name}}", file.name);
filePath = regex ? normalizePath(filePath.replace(regex, dest)) : normalizePath(filePath.replace(override.path, dest));
}
console.log("Overridden path: ", filePath, " for ", file.name);
return filePath;
}
else if (defaultImageFolder.length > 0) {
return normalizePath(`${defaultImageFolder}/${file.name}`);
} else if (settings.upload.defaultName.length > 0) {
return normalizePath(`${settings.upload.defaultName}/${file.name}`);
Expand Down
16 changes: 16 additions & 0 deletions src/i18n/locales/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
"desc": "This will convert any properties or dataview inline field into properties tags. Separate fields with a comma.",
"exclude": {
"desc": "This will exclude value from being converted. Separate fields with a comma.",
"placeholder": "Field value",
"title": "Exclude value from conversion"
},
"inlineTags": {
Expand Down Expand Up @@ -232,6 +233,8 @@
"title": "Default attachment folder"
},
"forcePush": {
"all": "Use {{all}} to change the destination of all attachments (and/or force them to be sent).",
"default": "Use {{default}} to use the default destination path.",
"desc": "The following extensions will always be published, regardless of the last sending date.",
"info": "By default, attachments are only sent if they have been modified since they were last sent, or if they do not exist in the repository.",
"separateByComma": "Separate extensions with commas. \nYou can use regex by enclosing it with \"/\", like /regex/. Use {{all}} to force all attachments to be sent.",
Expand All @@ -252,6 +255,14 @@
"title": "Change embed markup"
},
"notes": "Embed notes",
"overrides": {
"desc": "Allow to send an attachment into a specific path and force push attachments.",
"modal": {
"dest": "Destination",
"path": "Path or extension",
"title": "Override attachments path"
}
},
"title": "Attachment & embed note config",
"transferImage": {
"title": "Transfer attachments"
Expand Down Expand Up @@ -408,6 +419,8 @@
"title": "Useful links"
}
},
"overrides": {
},
"plugin": {
"copyLink": {
"baselink": {
Expand Down Expand Up @@ -484,6 +497,9 @@
"invalidRegex": "An error has occurred: {{- e}}",
"modal": {
"desc": "Replace text in the file with the given value. Enclose the text with \"//\" to use regex.",
"force": "Force push",
"keywords": "Keywords",
"name": "Use {{name}} to use the filename.",
"title": {
"all": "Folder path & filename replacer",
"only": "Replace filename",
Expand Down
17 changes: 16 additions & 1 deletion src/i18n/locales/fr.json
Original file line number Diff line number Diff line change
Expand Up @@ -195,6 +195,7 @@
"desc": "Ceci convertira tous les champs des propriétés/dataview en tags. Séparez les champs par une virgule.",
"exclude": {
"desc": "Exclusion de champs de la conversion. Séparer les valeurs par une virgule.",
"placeholder": "Valeur du chemin",
"title": "Exclusion de tags"
},
"inlineTags": {
Expand Down Expand Up @@ -232,9 +233,10 @@
"title": "Dossier de pièces-jointes par défaut"
},
"forcePush": {
"all": "Utiliser {{all}} pour modifier la destination de toutes les pièces jointes (et/ou forcer leur envoie).",
"default": "Utiliser {{default}} pour utiliser le chemin de destination par défaut.",
"desc": "Les extensions suivantes seront toujours publiées, quelque soit la dernière date d'envoi.",
"info": "Par défaut, les pièces-jointes ne sont envoyés que si elles ont été modifiées depuis leur dernier envoi, ou si elles n'existent pas dans le dépôt.",
"separateByComma": "Séparer les extensions par des virgules. Vous pouvez utiliser des regex en les encadrant par \"/\", comme /regex/. Utiliser {{all}} pour forcer l'envoi de toutes les pièces-jointes.",
"title": "Forcer l'envoi des pièces-jointes"
},
"imagePath": {
Expand All @@ -252,6 +254,14 @@
"title": "Changer les balises d'embed"
},
"notes": "Note (Markdown)",
"overrides": {
"desc": "Permet d'envoyer une pièce jointe dans un chemin spécifique et de forcer les pièces jointes à être poussées.",
"modal": {
"dest": "Destination",
"path": "Chemin ou extension",
"title": "Remplacer le chemin des pièces jointes"
}
},
"title": "Embed",
"transferImage": {
"title": "Envoyer les pièces-jointes intégrées dans un fichier dans le dépôt."
Expand Down Expand Up @@ -408,6 +418,8 @@
"title": "Liens utiles"
}
},
"overrides": {
},
"plugin": {
"copyLink": {
"baselink": {
Expand Down Expand Up @@ -484,6 +496,9 @@
"invalidRegex": "Une erreur est survenue : {{- e}}",
"modal": {
"desc": "Replace des textes dans le fichier par la valeur donnée. Vous pouvez encadrer le texte à remplacer avec \"//\" pour utiliser un regex.",
"force": "Forcer l'envoi",
"keywords": "Mots clés",
"name": "Utiliser {{name}} pour utiliser le nom du fichier.",
"title": {
"all": "Remplacement du nom ou du chemin du fichier",
"only": "Remplacement du titre uniquement",
Expand Down
32 changes: 13 additions & 19 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import {
import { migrateToken } from "./settings/migrate";
import {ExportModal, ImportLoadPreset, ImportModal, loadAllPresets} from "./settings/modals/import_export";
import {ModalAddingNewRepository} from "./settings/modals/manage_repo";
import { ModalRegexFilePathName, ModalRegexOnContents } from "./settings/modals/regex_edition";
import { ModalRegexFilePathName, ModalRegexOnContents, OverrideAttachmentsModal } from "./settings/modals/regex_edition";
import { TokenEditPath } from "./settings/modals/token_path";
import {
autoCleanCondition,
Expand Down Expand Up @@ -799,7 +799,8 @@ export class GithubPublisherSettingsTab extends PluginSettingTab {
.setName(i18next.t("settings.conversion.tags.exclude.title"))
.setDesc(i18next.t("settings.conversion.tags.exclude.desc"))
.addTextArea((text) => {
text.setPlaceholder("field value")
text
.setPlaceholder(i18next.t("settings.conversion.tags.exclude.placeholder"))
.setValue(
textSettings.tags.exclude.join(",")
)
Expand Down Expand Up @@ -866,24 +867,17 @@ export class GithubPublisherSettingsTab extends PluginSettingTab {
});
}

const descAboutForcePush = document.createDocumentFragment();
descAboutForcePush.createEl("div", {text: i18next.t("settings.embed.forcePush.info")});
descAboutForcePush.createEl("div", {text: i18next.t("settings.embed.forcePush.desc")});
descAboutForcePush.createEl("div", {text: i18next.t("settings.embed.forcePush.separateByComma")});

new Setting(this.settingsPage)
.setName(i18next.t("settings.embed.forcePush.title"))
.setDesc(descAboutForcePush)
.setClass("mini")
.addTextArea((text) => {
text.setPlaceholder("pdf, svg, mp4")
.setValue(embedSettings.forcePushAttachments?.join(", "))
.onChange(async (value) => {
embedSettings.forcePushAttachments = value
.split(/[,\n]\W*/)
.map((item) => item.trim())
.filter((item) => item.length > 0);
await this.plugin.saveSettings();
.setName(i18next.t("settings.embed.overrides.modal.title"))
.setDesc(i18next.t("settings.embed.overrides.desc"))
.addButton((button) => {
button
.setIcon("pencil")
.onClick(async () => {
new OverrideAttachmentsModal(this.app, this.settings, this.copy(embedSettings.overrideAttachments), (async result => {
embedSettings.overrideAttachments = result;
await this.plugin.saveSettings();
})).open();
});
});
}
Expand Down
9 changes: 7 additions & 2 deletions src/settings/interface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ export interface GitHubPublisherSettings {
}
embed: {
attachments: boolean;
forcePushAttachments: string[];
overrideAttachments: OverrideAttachments[];
useObsidianFolder?: boolean;
keySendFile: string[];
notes: boolean;
Expand Down Expand Up @@ -272,7 +272,7 @@ export const DEFAULT_SETTINGS: Partial<GitHubPublisherSettings> = {
},
embed: {
attachments: true,
forcePushAttachments: [],
overrideAttachments: [],
keySendFile: [],
notes: false,
folder: "",
Expand Down Expand Up @@ -392,5 +392,10 @@ export interface Preset {
settings: GitHubPublisherSettings;
}

export interface OverrideAttachments {
path: string;
destination: string;
forcePush: boolean;
}

export const FIND_REGEX = /^\/(.*)\/[igmsuy]*$/;
139 changes: 138 additions & 1 deletion src/settings/modals/regex_edition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import i18next from "i18next";
import {App, Modal, Notice, Setting} from "obsidian";
import { escapeRegex } from "src/conversion/links";

import {FolderSettings, GitHubPublisherSettings, RegexReplace, TextCleaner, TypeOfEditRegex} from "../interface";
import {FolderSettings, GitHubPublisherSettings, OverrideAttachments, RegexReplace, TextCleaner, TypeOfEditRegex} from "../interface";

function isRegexValid(regexString: string) {
try {
Expand All @@ -20,6 +20,143 @@ function isRegexValid(regexString: string) {
}
}

export class OverrideAttachmentsModal extends Modal {
settings: GitHubPublisherSettings;
allOverrides: OverrideAttachments[];
onSubmit: (result: OverrideAttachments[]) => void;
constructor(
app: App,
settings: GitHubPublisherSettings,
allOverrides : OverrideAttachments[],
onSubmit: (result: OverrideAttachments[]) => void) {
super(app);
this.allOverrides = allOverrides;
this.settings = settings;
this.onSubmit = onSubmit;
}

forbiddenValue(value: string): {value: string, isForbidden: boolean} {
if (!isRegexValid(value).isValid) {
const error = isRegexValid(value).error;
new Notice(i18next.t("settings.regexReplacing.invalidRegex", {e: error}));
return {
value: "",
isForbidden: true
};
} else if (value.match(/[\\><:"|?*]/) && !value.match(/^\/(.*)\/[gmisuvdy]*$/)) {
new Notice(i18next.t("settings.regexReplacing.forbiddenValue", { what: i18next.t("common.path.folder"), forbiddenChar: value.match(/[\\><:"|?*]/)![0] }));
return {
value: "",
isForbidden: true
};
}
return {
value,
isForbidden: false
};
}
onOpen(): void {
const { contentEl } = this;
contentEl.empty();
contentEl.addClasses(["github-publisher", "modals", "regex", "file-path-name"]);
contentEl.createEl("h2", { text: i18next.t("settings.embed.overrides.modal.title") });
contentEl.createEl("p", { text: i18next.t("settings.regexReplacing.modal.desc") });
contentEl.createEl("h3", {text: i18next.t("settings.regexReplacing.modal.keywords")});
const ul = contentEl.createEl("ul", {cls: "keywords"});
ul.createEl("li", {text: i18next.t("settings.embed.forcePush.all")});
ul.createEl("li", {text: i18next.t("settings.embed.forcePush.default")});
ul.createEl("li", {text: i18next.t("settings.regexReplacing.modal.name")});
contentEl.createEl("h3", {text: i18next.t("settings.regexReplacing.modal.force")});
contentEl.createEl("p", { text: i18next.t("settings.embed.forcePush.info") });

if (!this.settings.embed.overrideAttachments) {
this.settings.embed.overrideAttachments = [];
}
for (const override of this.allOverrides) {
const sett = new Setting(contentEl)
.setClass("entry")
.addText((text) => {
text.setPlaceholder(i18next.t("settings.embed.overrides.modal.path"))
.setValue(override.path)
.onChange((value) => {
override.path = value;
sett.controlEl.setAttribute("value", value);
});
})
.addText((text) => {
text.setPlaceholder(i18next.t("settings.embed.overrides.modal.dest"))
.setValue(override.destination)
.onChange((value) => {
override.destination = value;
sett.controlEl.setAttribute("replace", value);
});
})
.addToggle((toggle) => {
toggle
.setTooltip(i18next.t("settings.embed.forcePush.title"))
.setValue(override.forcePush)
.onChange((value) => {
override.forcePush = value;
});
});
sett.controlEl.setAttribute("value", override.path);
sett.controlEl.setAttribute("replace", override.destination);
sett.addExtraButton((button) => {
button
.setIcon("trash")
.onClick(() => {
this.allOverrides.splice(this.allOverrides.indexOf(override), 1);
this.onOpen();
});
});
}

new Setting(contentEl)
.addButton((button) => {
button
.setIcon("plus")
.onClick(() => {
this.allOverrides.push({
path: "",
destination: "",
forcePush: false
});
this.onOpen();
});
})
.addButton((button) => {
button
.setButtonText(i18next.t("common.save"))
.onClick(() => {
const canBeValidated: boolean[] = [];
this.allOverrides.forEach((override) => {
const isForbiddenEntry = this.forbiddenValue(override.path);
const isForbiddenReplace = this.forbiddenValue(override.destination);
canBeValidated.push(isForbiddenEntry.isForbidden);
canBeValidated.push(isForbiddenReplace.isForbidden);
if (isForbiddenEntry.isForbidden || isForbiddenReplace.isForbidden) {
override.path = isForbiddenEntry.value as string;
override.destination = isForbiddenReplace.value as string;
const faultyInputValue = contentEl.querySelector(`[value="${escapeRegex(override.path)}"] input`);
const faultyInputReplace = contentEl.querySelector(`[replace="${escapeRegex(override.destination)}"] input`);
faultyInputValue?.classList.add("error");
faultyInputReplace?.classList.add("error");
}
});
if (!canBeValidated.includes(true)) {
//remove empty regex
this.onSubmit(this.allOverrides);
this.close();
}
});
});
}
onClose(): void {
const { contentEl } = this;
contentEl.empty();
}
}

export class ModalRegexFilePathName extends Modal {
settings: GitHubPublisherSettings;
allRegex: RegexReplace[];
Expand Down
Loading

0 comments on commit 66e7373

Please sign in to comment.