<% << tp.date.now(“YYYY-MM-DD”, -1) 📅 tp.date.now(“YYYY-MM-DD”, -1) >> %>

Footnotes

Verify Meta Hashing Periodically

  • Obsidian plugins required: Dataview, Meta Bind, JS Engine

Table of Contents + SHABIT (8-space SHA-256 hash)1


// Function to compute SHA-256 hash
async function sha256(message) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex;
}
 
// Function to compute SHA-256 hash and return the first 8 characters
async function sha256Short(message, length) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex.slice(0, length);
}
 
let sha256tid = sha256Short("SHA-256", 8);
 
// Get the current active file
let activeFile = app.workspace.getActiveFile();
 
// Ensure the active file is available
if (activeFile) {
    // Fetch the current note's content
    let fileContent = await app.vault.read(activeFile);
    
    // Use a regular expression to find all headers and their content
    let headers = fileContent.match(/^(#{1,6})\s(.+)$([\s\S]*?)(?=^#{1,6}\s|\Z)/gm);
    
    const tableData = headers.map(header => {
        let level = header.match(/^(#{1,6})/)[0];
        let title = header.match(/^#{1,6}\s(.+)$/m)[1];
        let content = header.replace(/^#{1,6}\s.+$/m, '').trim();
        let hash = sha256Short(title, 8);
        return [level + " " + title, hash, content];
    });
    
    // Define table headers 
    const tableHeaders = ["Header", "SHABIT", "Notes"];
    
    dv.markdownTable(tableHeaders, tableData);
} else {
    dv.paragraph("No active file found.");
}

Switcher: BUTTON[light-mode, dark-mode]

Meta-Bind


style: primary
label: Run JavaScript File
action:
  type: js
  file: Notes/Scripts/HelloFuture.js
style: primary
label: Greet the World
action:
  type: inlineJS
  code: "console.log('Hello World!');"
style: destructive
label: Light Mode
id: light-mode
hidden: false
actions:
  - type: command
    command: theme:use-light
style: primary
label: Dark Mode
id: dark-mode
hidden: false
actions:
  - type: command
    command: theme:use-dark

Circular transclusion detected: Notes/Footnotes-Hash-Magic

Meta Bind Tagger

Tags: INPUT[inlineList:tags]

{tags} as tags
{activeHeader} as activeHeader
---
async function sha256Short(message, length) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex.slice(0, length);
}
const tags = context.bound.tags.map(x => `option(${x})`).join(", ");
const str = `\`INPUT[inlineSelect(${tags}):selected]\``;
const hid = await sha256Short(str, 8);
return engine.markdown.create(str+"#"+hid);

Templater


Table of Contents 8

<%* // Get input from user - specify maximum header level to be displayed (default = 3) let header_limit = await tp.system.prompt(“Show Contents Down to Which Header Level (1-6)?”, “3”);

let headers = await tp.file.content
    .split('\n') // split file into lines
    .filter(t => t.match(/^[#]+\s+/gi)) // only get headers
    .map(h => {
        let header_level = h.split(' ')[0].match(/#/g).length;
        // get header text without special characters like '[' and ']'
        //let header_text = h.substring(h.indexOf(' ') + 1).replace(/[\[\]]+/g, '');
        // get header text without removing any special characters
        let header_text = h.substring(h.indexOf(' ') + 1);
    // get header text URL as it is in the file (DON'T REMOVE SPECIAL CHARS OR LINK TO HEADER WON'T WORK)
        let header_url = h.substring(h.indexOf(' ') + 1);
        
        // Wikilinks style output:
        //let header_link = `[[${tp.file.title}#header_url|${header_text}]]`
	
        // Non-wikilinks style output:
        let file_title= tp.file.title.replace(/ /g, '%20');   // Replace spaces in file names with '%20'
        header_url = header_url.replace(/ /g, '%20');         // Replace spaces in urls with '%20'
        let header_link = `[${header_text}](${file_title}.md#${header_url})`


        // Output ALL header levels
        // prepend block-quote (>), indentation and bullet-point (-)
        //return `>${'    '.repeat(header_level - 1) + '- ' + header_link}`;

        // Output headers up to specified level
        if ( header_level <= header_limit) {
            return `>${'    '.repeat(header_level - 1) + '- ' + header_link}`;
        }

    })
    .join('\n')
    
    // If not using all headers, empty lines are inserted where non-displayed headers should be.
    // This removes any blank lines
    while (headers.includes("\n\n")) { headers= headers.replace(/\n\n/g,'\n'); }

%><% headers %>

DataviewJS


V1

// Function to compute SHA-256 hash
async function sha256(message) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex;
}
 
// Function to compute SHA-256 hash and return the first 8 characters
async function sha256Short(message, length) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex.slice(0, length); // Return the first 8 characters of the hash
}
 
 
let sha256tid = sha256Short("SHA-256", 8);
 
// Get the current active file
let activeFile = app.workspace.getActiveFile();
 
// Ensure the active file is available
if (activeFile) {
    // Fetch the current note's content
    let fileContent = await app.vault.read(activeFile);
 
    // Use a regular expression to find all headers
    let headers = fileContent.match(/^#+\s.+/gm);
 
    // Display the headers with their SHA-256 hashes
    if (headers) {
        for (let header of headers) {
            let trimmedHeader = header.trim();
            let headerHash = await sha256Short(trimmedHeader, 8);
            dv.paragraph(`*${trimmedHeader}* [^${headerHash}]`);
        }
    } else {
        dv.paragraph("No headers found in this note.");
    }
} else {
    dv.paragraph("No active file found.");
}
 

V2

// Function to compute SHA-256 hash and return the first 8 characters
async function sha256Short(message, length) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex.slice(0, length); // Return the first 8 characters of the hash
}
 
 
let sha256tid = sha256Short("SHA-256", 8);
 
// Get the current active file
let activeFile = app.workspace.getActiveFile();
 
// Ensure the active file is available
if (activeFile) {
    // Fetch the current note's content
    let fileContent = await app.vault.read(activeFile);
 
    // Use a regular expression to find all headers
    let headers = fileContent.match(/^#+\s.+/gm);
 
    // Display the headers with their SHA-256 hashes
    if (headers) {
        for (let header of headers) {
            let trimmedHeader = header.trim();
            let headerHash = await sha256Short(trimmedHeader, 8);
            dv.paragraph(`*${trimmedHeader}* [^${headerHash}]`);
        }
    } else {
        dv.paragraph("No headers found in this note.");
    }
} else {
    dv.paragraph("No active file found.");
}
 

V3

// Function to compute SHA-256 hash and return the first 8 characters
async function sha256Short(message, length) {
    const msgBuffer = new TextEncoder().encode(message);
    const hashBuffer = await crypto.subtle.digest('SHA-256', msgBuffer);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    const hashHex = hashArray.map(b => ('00' + b.toString(16)).slice(-2)).join('');
    return hashHex.slice(0, length); // Return the first 8 characters of the hash
}
 
// Get the current active file
let activeFile = app.workspace.getActiveFile();
 
// Ensure the active file is available
if (activeFile) {
    // Fetch the current note's content
    let fileContent = await app.vault.read(activeFile);
 
    // Use a regular expression to find all headers
    let headers = fileContent.match(/^#+\s.+/gm);
    let markdownContents = ""
 
    // Display the headers with their SHA-256 hashes
    if (headers) {
        for (let header of headers) {
            let trimmedHeader = header.trim();
            let headerHash = await sha256Short(trimmedHeader, 8);
            markdownContents += `${trimmedHeader} [^${headerHash}]\n`
        }
        markdownContents += "\n"
		return engine.markdown.create(markdownContents);
    } else {
        return engine.markdown.create("No headers found in this note.");
    }
} else {
    return engine.markdown.create("No active file found.");
}

Footnotes

  1. SHA-256 is set as the[Default Hashing Algorithm] because it is a widely-adopted, secure cryptographic hash function that provides a good balance of security, performance, and output size for many applications, including data integrity verification.