Skip to content

Commit

Permalink
Refactor and add tests
Browse files Browse the repository at this point in the history
  • Loading branch information
nicojeske committed Feb 26, 2023
1 parent 5c4b64a commit d432a00
Show file tree
Hide file tree
Showing 7 changed files with 3,184 additions and 146 deletions.
1 change: 1 addition & 0 deletions .github/workflows/publish.yml
Expand Up @@ -25,6 +25,7 @@ jobs:
node-version: ${{ matrix.node-version }}
cache: 'yarn'
- run: yarn install
- run: yarn test
- run: yarn build
- uses: "marvinpinto/action-automatic-releases@latest"
id: publish
Expand Down
6 changes: 6 additions & 0 deletions babel.config.js
@@ -0,0 +1,6 @@
module.exports = {
presets: [
['@babel/preset-env', {targets: {node: 'current'}}],
'@babel/preset-typescript',
],
};
153 changes: 10 additions & 143 deletions main.ts
@@ -1,17 +1,13 @@
import {App, MarkdownView, Plugin, PluginSettingTab, Setting, TFile} from 'obsidian';
import { Util, ReplaceTerm, HandleZoomParams } from 'src/Util';


interface MouseWheelZoomSettings {
initialSize: number;
modifierKey: ModifierKey;
stepSize: number;
}

interface HandleZoomParams {
sizeMatchRegExp: RegExp;
replaceSizeExist: ReplaceTerm;
replaceSizeNotExist: ReplaceTerm;
}

enum ModifierKey {
ALT = "AltLeft",
CTRL = "ControlLeft",
Expand All @@ -24,27 +20,6 @@ const DEFAULT_SETTINGS: MouseWheelZoomSettings = {
initialSize: 500
}

/**
* ReplaceTerm enables us to store the parameters for a replacement to add a new size parameter.
*/
class ReplaceTerm {
replaceFrom: (oldSize: number) => string;
replaceWith: (newSize: number) => string;

constructor(replaceFrom: (oldSize: number) => string, replaceWith: (newSize: number) => string) {
this.replaceFrom = replaceFrom;
this.replaceWith = replaceWith;
}

public getReplaceFromString(oldSize: number): string {
return this.replaceFrom(oldSize);
}

public getReplaceWithString(newSize: number): string {
return this.replaceWith(newSize);
}
}

export default class MouseWheelZoomPlugin extends Plugin {
settings: MouseWheelZoomSettings;
isKeyHeldDown = false;
Expand Down Expand Up @@ -111,16 +86,13 @@ export default class MouseWheelZoomPlugin extends Plugin {
private async handleZoom(evt: WheelEvent, eventTarget: Element) {
const imageUri = eventTarget.attributes.getNamedItem("src").textContent;

const target = eventTarget;

const activeFile: TFile = await this.getActivePaneWithImage(eventTarget);

let fileText = await this.app.vault.read(activeFile)
const originalFileText = fileText;

// Get paremeters like the regex or the replacement terms based on the fact if the image is locally stored or not.

const zoomParams: HandleZoomParams = this.getZoomParams(imageUri, fileText, target);
const zoomParams: HandleZoomParams = this.getZoomParams(imageUri, fileText, eventTarget);

// Check if there is already a size parameter for this image.
const sizeMatches = fileText.match(zoomParams.sizeMatchRegExp);
Expand Down Expand Up @@ -166,125 +138,27 @@ export default class MouseWheelZoomPlugin extends Plugin {
}))
}

/**
* For a given file content decide if a string is inside a table
* @param searchString string
* @param fileValue file content
* @private
*/
private static isInTable(searchString: string, fileValue: string) {
return fileValue.search(new RegExp(`^\\|.+${searchString}.+\\|$`, "m")) !== -1
}


/**
* Get the image name from a given src uri
* @param imageUri uri of the image
* @private
*/
private static getImageNameFromUri(imageUri: string) {
imageUri = decodeURI(imageUri)
let imageName = imageUri.match(/([\w\d\s\.]+)\?/)[1];
// Handle linux not correctly decoding the %2F before the Filename to a \
if (imageName.substr(0, 2) === "2F") {
imageName = imageName.slice(2)
}
return imageName
}

private getZoomParams(imageUri: string, fileText: string, target: Element) {
if (imageUri.contains("http")) {
return this.getRemoteImageZoomParams(imageUri, fileText)
return Util.getRemoteImageZoomParams(imageUri, fileText)
} else if (imageUri.contains("app://local")) {
const imageName = MouseWheelZoomPlugin.getImageNameFromUri(imageUri);
return this.getLocalImageZoomParams(imageName, fileText)
const imageName = Util.getLocalImageNameFromUri(imageUri);
return Util.getLocalImageZoomParams(imageName, fileText)
} else if (target.classList.value.match("excalidraw-svg.*")) {
const src = target.attributes.getNamedItem("filesource").textContent;
// remove ".md" from the end of the src
const imageName = src.substring(0, src.length - 3);
// Only get text after "/"
const imageNameAfterSlash = imageName.substring(imageName.lastIndexOf("/") + 1);
return this.getLocalImageZoomParams(imageNameAfterSlash, fileText)
return Util.getLocalImageZoomParams(imageNameAfterSlash, fileText)
}

throw new Error("Image is not zoomable")
}

/**
* Get the parameters needed to handle the zoom for a remote image
* @param imageUri URI of the image
* @param fileText content of the current file
* @returns parameters to handle the zoom
*/
private getRemoteImageZoomParams(imageUri: string, fileText: string): HandleZoomParams {
const isInTable = MouseWheelZoomPlugin.isInTable(imageUri, fileText)
// Separator to use for the replacement
const sizeSeparator = isInTable ? "\\|" : "|"
// Separator to use for the regex: isInTable ? \\\| : \|
const regexSeparator = isInTable ? "\\\\\\|" : "\\|"

const sizeMatchRegExp = new RegExp(`${regexSeparator}(\\d+)]${escapeRegex("("+imageUri+")")}`);

const replaceSizeExistFrom = (oldSize: number) => `${sizeSeparator}${oldSize}](${imageUri})`;
const replaceSizeExistWith = (newSize: number) => `${sizeSeparator}${newSize}](${imageUri})`;

const replaceSizeNotExistsFrom = (oldSize: number) => `](${imageUri})`;
const replaceSizeNotExistsWith = (newSize: number) => `${sizeSeparator}${newSize}](${imageUri})`;

const replaceSizeExist = new ReplaceTerm(replaceSizeExistFrom, replaceSizeExistWith);
const replaceSizeNotExist = new ReplaceTerm(replaceSizeNotExistsFrom, replaceSizeNotExistsWith);

return {
sizeMatchRegExp: sizeMatchRegExp,
replaceSizeExist: replaceSizeExist,
replaceSizeNotExist: replaceSizeNotExist,
}
}

/**
* Get the parameters needed to handle the zoom for a local image
* @param imageName Name of the image
* @param fileText content of the current file
* @returns parameters to handle the zoom
*/
private getLocalImageZoomParams(imageName: string, fileText: string): HandleZoomParams {
const isInTable = MouseWheelZoomPlugin.isInTable(imageName, fileText)
// Separator to use for the replacement
const sizeSeparator = isInTable ? "\\|" : "|"
// Separator to use for the regex: isInTable ? \\\| : \|
const regexSeparator = isInTable ? "\\\\\\|" : "\\|"

// If after the imageName in filetext follows a "|" then it means that the image is already zoomed
const imageNamePosition = fileText.indexOf(imageName);

const stringAfterFileName = fileText.substring(imageNamePosition + imageName.length)
// Handle the case where behind the imageName there are more attributes like |ctr for ITS Theme by attaching them to the imageName
const regExpMatchArray = stringAfterFileName.match(/([^\]]*?)\\?\|\d+]]|([^\]]*?)]]|/);
if (regExpMatchArray) {
if (!!regExpMatchArray[1]) {
imageName += regExpMatchArray[1]
} else if (!!regExpMatchArray[2]) {
imageName += regExpMatchArray[2]
}
}

const sizeMatchRegExp = new RegExp(`${escapeRegex(imageName)}${regexSeparator}(\\d+)`);

const replaceSizeExistFrom = (oldSize: number) => `${imageName}${sizeSeparator}${oldSize}`;
const replaceSizeExistWith = (newSize: number) => `${imageName}${sizeSeparator}${newSize}`;

const replaceSizeNotExistsFrom = (oldSize: number) => `${imageName}`;
const replaceSizeNotExistsWith = (newSize: number) => `${imageName}${sizeSeparator}${newSize}`;

const replaceSizeExist = new ReplaceTerm(replaceSizeExistFrom, replaceSizeExistWith);
const replaceSizeNotExist = new ReplaceTerm(replaceSizeNotExistsFrom, replaceSizeNotExistsWith);

return {
sizeMatchRegExp: sizeMatchRegExp,
replaceSizeExist: replaceSizeExist,
replaceSizeNotExist: replaceSizeNotExist,
}
}




async loadSettings() {
Expand Down Expand Up @@ -394,13 +268,6 @@ class MouseWheelZoomSettingsTab extends PluginSettingTab {
}
}

/**
* Function to escape a string into a valid searchable string for a regex
* @param string string to escape
* @returns escaped string
*/
function escapeRegex(string: string) {
return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&');
}



9 changes: 8 additions & 1 deletion package.json
Expand Up @@ -5,16 +5,23 @@
"main": "main.js",
"scripts": {
"dev": "rollup --config rollup.config.js -w",
"build": "rollup --config rollup.config.js --environment BUILD:production"
"build": "rollup --config rollup.config.js --environment BUILD:production",
"test": "jest"
},
"keywords": [],
"author": "Nico Jeske",
"license": "MIT",
"devDependencies": {
"@babel/core": "^7.21.0",
"@babel/preset-env": "^7.20.2",
"@babel/preset-typescript": "^7.21.0",
"@rollup/plugin-commonjs": "^18.0.0",
"@rollup/plugin-node-resolve": "^11.2.1",
"@rollup/plugin-typescript": "^8.2.1",
"@types/jest": "^29.4.0",
"@types/node": "^14.14.37",
"babel-jest": "^29.4.3",
"jest": "^29.4.3",
"obsidian": "^0.12.0",
"rollup": "^2.32.1",
"tslib": "^2.2.0",
Expand Down

0 comments on commit d432a00

Please sign in to comment.