I created a customizable index code for Dataview

I was looking for a good plugin to automatically create indexes, but I couldn’t find one for my needs. So I made this JavaScript code in Dataview that can handle tags to omit files and sort them as you like.

// Config
const skipFolders = input['arg2']
const filesGoBeforeFolders = input['arg3']
const shouldReverseAlpha = input['arg4']

// Tags
const index = 'index'
const skipIndexing = 'skip indexing'

// Making arrays and objects for the directory tree
const paths = dv.pages('"'+input['arg1']+'"')
const tree = []
paths.values.forEach((page, i) => {
	const parts = page.file.path.split('/')
	let current = tree
	parts.slice(skipFolders).forEach((part, j) => {
		let item = current.find(_item => _item.hasOwnProperty(part))
		if (!item) {
			// is the current part a file?
			if (j === parts.length-1 - skipFolders) {
				item = { [part.slice(0,-3)]: paths.values[i].file.path }
				if (page[skipIndexing]) {
					return
				}
				if (page[index]) {
					item[index] = page[index]
				}
			} else {
				item = { [part]: [] }
			}
			current.push(item)
		}
		current = item[part]
	})
})
// console.log(JSON.stringify(tree, null, 2))

// Sorting
function sortTree(dic) {
	if (shouldReverseAlpha) {
		dic.sort().reverse()
	} else {
		dic.sort()
	}
	dic.sort((a,b) => {
		itemAName = Object.keys(a)[0]
		itemBName = Object.keys(b)[0]
		itemAIsAFolder = typeof a[itemAName] !== 'string'
		itemBIsAFolder = typeof b[itemBName] !== 'string'
		if (itemAIsAFolder && itemBIsAFolder) {
			return itemAName.localeCompare(itemBName) * (shouldReverseAlpha?-1:1)
		}
		else if (itemAIsAFolder || itemBIsAFolder) {
			return (itemAIsAFolder?
				(filesGoBeforeFolders?1:-1) : (filesGoBeforeFolders?-1:1))
		}
		aHasIndex = a.hasOwnProperty(index)
		bHasIndex = b.hasOwnProperty(index)
		if (aHasIndex && bHasIndex) {
			return a[index] - b[index]
		} else if (aHasIndex || bHasIndex) {
			return aHasIndex? -1 : 1
		}
		return itemAName.localeCompare(itemBName)*(shouldReverseAlpha?-1:1)
	})
	for (const i in dic) {
		itemName = Object.keys(dic[i])[0]
		// Is it a folder?
		if (typeof dic[i][itemName] !== 'string') {
			sortTree(dic[i][itemName])
		} else {
		}
	}
}
sortTree(tree)

// Formating
function linkFormat(path, display = path, embed = false) {
	return embed == true ? '![['+path+'|'+display+']]'
		: '[['+path+'|'+display+']]'
}
function getTreeFormat(dirArr, nesting=0, parentFolderName='') {
	let content = ''
	dirArr.forEach(i => {
		const itemName = Object.keys(i)[0]
		const header = nesting>5?6:nesting+1
		// Is it a folder?
		if (typeof i[itemName] !== 'string') {
			if (i[itemName].some(child => {
				let childName = Object.keys(child)[0]
				if (childName === itemName) {
					content += '    '.repeat(nesting)
						+'- '+'#'.repeat(header)
						+' '+linkFormat(child[childName], itemName)+'\n'
					return true
				}
				return false
			})) {
				content += getTreeFormat(i[itemName], nesting+1, itemName)
			} else {
				content += '    '.repeat(nesting)+'- '+
					'#'.repeat(header)+' '+itemName+'\n'
				content += getTreeFormat(i[itemName], nesting+1)
			}
		} else if (parentFolderName !== itemName) {
			content += '    '.repeat(nesting)+'- '+
			linkFormat(i[itemName], itemName)+'\n'
		}
	})
	return content
}

dv.paragraph(getTreeFormat(tree))

Then, to use the code in a note, you must include the following code in dataviewjs to initialize variables. This way, you can change it more easily without opening the code file.

await dv.view('dvscripts/jsfile', {
	arg1: 'Contenido', // The folder path
	arg2: 1, // How many folder levels should it skip
	arg3:true, // Should files go febore folders?
	arg4:false // Should reverse the alphabetical order?
})

Maybe this code isn’t very clean, but it works and provides a solution for those looking for an alternative way to create indexes.

Screenshot 2024-09-13 021814

As you can tell, ‘Papilas Gustativas’ should go after ‘Corpúsculo…’ because of the alphabetical order, but I added the index property to ‘Papilas…’ and the others don’t have that property.

1 Like