MetaEdit plugin

Hi there,
I like the idea of the plugin, and the demos you provide are impressive, but my script-fu is weak … is there a walk-through somewhere of some of the examples (the tags and the library ratings, at least?) - the gifs go too fast for me to see what’s going on, and I can’t for the life of me figure out the setup…
thanks!

2 Likes

Hey! There’s only really that which is on the repository.

Could you clarify what you are having trouble with more specifically? :slight_smile:

The two gif demos that are shown in your original post - the one with the book ratings and the one with tag support … do you have a sample setup that I could look at to figure out how you did it?

Ahh, I see. Those were taken on my own vault to demonstrate the ‘Edit Meta’ feature and how tags are supported.

Edit Meta
You can right-click any file / link and click ‘Edit Meta’, which will ask you which frontmatter property or dataview field you want to edit.

Tag support
You can change the value of a tag. If you use the MetaEdit method, it changes the last item in a tag. So if it’s #tag/nested, it would change nested.

I hope this helps a bit. It’s been a while since I changed the things shown in the GIF, so I can’t just retrieve them, unfortunately.

It took a bit of trial and error to work out the inner workings, but I was able to make metaedit work with dataviewjs. For my use case, I have a monthly note (named YYYY-MM.md) and daily note (named YYYY-MM-DD.md) that all live in the LogBook directory. The daily notes include metadata about when I start and end my day, and hours I worked. I created a file with the code below and it’s embedded it in my monthly note.

Now, I just click on hours, startTime, endTime, or note cell, and can edit the value in the monthly note without leaving the page. The only downside is that the only way to clear a value is to type a space in the modal prior to hitting enter. Would love to be able to just hit enter to clear. editMetaElement doesn’t return the content on what was entered so there’s no way to know whether a value was entered or not - if it did, I could use the update operation to clear out the value on my own.


const app = this.app;
const metaedit = app.plugins.plugins["metaedit"];

const init_dom = (row) => {
	const sel = `table.dataview.table-view-table td > span > a[data-href='${row.file.path}']`;
	const tr = dv.container.querySelector(sel).closest("tr");
	
	const labels = tr.querySelectorAll("._dataview-labels");
	for (let i = 0; i < labels.length; i++) {
		const data = labels[i].data
		const file = app.vault.getAbstractFileByPath(row.file.path);
		const prop = {key: data.name, content:data.actual, type: data.type};
		labels[i].addEventListener('click', async (evt) => {
			metaedit.controller.editMetaElement(prop, [], file);
		});
	}
}

const field = (row, name, type) => {	
	let data = {};
	data.row = row;
	data.name = name;
	data.actual = row[name];
	data.value = row[name];
	data.type = type || 1;

	const el = this.container.createEl('span', {"text": row[name] || "-"});
	el.classList.add("_dataview-labels");
	el.data = data;
	return el;
};

try {
	var workspace = dv.container.closest("div.workspace-leaf");
	var title = workspace.querySelector("div.view-header-title");
	var prefix = title.innerHTML;
	
	let pages = dv.pages('"LogBook"')
		.sort(t => t.file.name)
		.where(t => t.file.name.startsWith(`${prefix}-`) && t["type"] == "logbook-daily");

	dv.table(
		["File", "Hours", "Day", "Start Time", "End Time", "Notes", ""], 
		pages
		.map(t => [
			t.file.link, 
			field(t, 'hours'),
			t["weekday"], 
			field(t, 'startTime'),
			field(t, 'endTime'),
			field(t, 'notes')
		])
	);
	
	setTimeout(function(){
		for (let i = 0; i < pages.length; i++) {
			init_dom(pages[i]);
		}
	}, 0);
} catch (err) {
	window.console.info(err);
}

Screen Recording 2021-07-28 at 8.14.53 PM

8 Likes

I just realized that supercharged links actually does this all for you.

You can right click the link with MetaEdit enabled and click Edit Meta, too😁

2 Likes

that is so cool. it tried metaedit but couldn’t figure out how i can edit values on dataview tables. is it dependent on the script you used or it is a metaedit feature?

thanks for this great plugin.

is there a way to pre-set nested values. for example giving project.order a defined set of values. I am not sure its not supported or i am doing the syntax wrong

Very true. I’ve been playing with both plugins to get a sense of what they can do. What I really like about yours is the exposed API. That’s something supercharged links does not have.

1 Like

I’ve already responded elsewhere to this, but to people wondering; both are dependencies. The scripts utilize the MetaEdit API.

1 Like

Thank you! Nested properties are not currently supported. Have some things in the works for them.

2 Likes

Thanks for this plugin Christian. I’m trying to understand if I could theoretically batch add tags to a load of notes in the same folder and/or with some common information. I have notes of different publications which are in the folder ‘Publications’ and which contain the dataview field ‘type:: publication’. I want to add the tag #publication/academic to all of them. Could I do this by using your plugin to grab the ‘type::’ Dataview field and updating it to:
tag:: #publication/academic
type:: publication

(I need to keep the type field.)

1 Like

You can use MetaEdit to accomplish this for sure. You’d probably need to create a small script to accomplish it :slight_smile:

How doable/easy would that be for someone like me to do (i.e. someone with no experience of creating/writing scripts)?
Any pointers by any chance?
I think it’d be good value for others too because I’ve seen it asked many times in the discord server by people like me.
Thanks again Christian!

Sorry realised I didn’t use ‘reply’ in my comment so you might not have seen it.

Sorry if this is answered elsewhere, I searched far and wide.
Is there any way to batch edit a selection of notes, links or dataview records? I seem to remember doing this, but I suppose I might have done it with search and replace in an external editor.
(Later) Ahh that’s it, I probably selected a folder and used the contextual menu “add Yaml property to all files in this folder (and subfolders)”.
Nevertheless, does anyone have a better solution?

3 Likes

I will attempt to answer you both, @kenanmike & @jwb, since your questions are somewhat similar.

MetaEdit currently provides one way to do mass editing, which is the context menu which adds a YAML property to files in a folder. This was my first go at adding support, and I have been working on something much grander since. However, that takes a lot of time, because there are many other things that I also need to do to achieve it.

Instead, a fine solution - which works for me - is to use the API and do some scripting.
I use QuickAdd to run my scripts through macros.

I mostly do so on a case-by-case basis, but try to abstract over the specific needs if it makes sense to do so. This also allows me to share scripts which might serve as inspiration:

For mass editing, the general idea is to get all the files you wish to target (through the Obsidian API), and then using the MetaEdit API update function on them.

I hope this helps :slight_smile:

5 Likes

Thanks a lot for this! Haven’t done any programming in 20 years, but managed to modify the dataviewjs example to do an autoprop when clicking the button.

My challenge though, is this: The API seems only to allow for updating existing properties, and not add new ones… I’d love for my button to create the property if it does not already exist, instead of… doing nothing :man_shrugging:

Any pointers appreciated if it is actually possible… Thanks :slight_smile:

Hey! So, there’s actually an undocumented API function called createYamlProperty. The way I usually approach it is to first check if a given property exists, and then either create or update it using the API:

// MetaEdit API Interface functions
autoprop: (propertyName: string) => void;
update: (propertyName: string, propertyValue: string, file: TFile | string) => Promise<void>;
getPropertyValue: (propertyName: string, file: (TFile | string)) => Promise<any>;
getFilesWithProperty: (propertyName: string) => TFile[];
createYamlProperty: (propertyName: string, propertyValue: string, file: TFile | string) => Promise<void>;
getPropertiesInFile: (file: TFile | string) => Promise<Property[]>;
6 Likes