Help for Managing Exams

Topic : Part 2/2

Summary
  • How to group each h_row of aoh_rows by h_row.Title? (DVJS20)
  • How to embed the “area” and “cover” fields into the callout box of Admonitions? (DVJS10:M13 or DVJS20:M13)

DVJS20_TABLE_key_value_pairs_via_RegExp_and_Obsidian_API_groupBy_Title

Summary

Main DVJS

Code Name Data type Group By Purposes Remark
DVJS20
_TABLE
_key_value_pairs
_via_RegExp
_and_Obsidian_API
_groupBy_Title
callout:
a multi-line string

(A variable)
aoh_rows:
an array of JavaScript Objects
yes 1.To get key-value pairs via RegExp and Obsidian API
2.To group by h_row.Title
3.To display the result as a table
1.To require the plugin admonition

2.The DVJS20 is based on the DVJS10.
2.1 The M41 is modified.
2.2 The M51 is added.
2.3 The M61 is modified.

Notes

Summary

Q1: What the following code is the same as? (M31.FR10 + M31.FR12)

Summary_Q1
Original Example: Q1 (To be explained)
```dataviewjs
// M31. gather the formatted data :
// #####################################################################
for (const page of pages) {
    
    
    // M31.FR10 define file:
    // #####################################################################
    const file = app.vault.getAbstractFileByPath(page.file.path);


    // M31.FR12 define contents: Read the file contents
    // #####################################################################
    const contents = await app.vault.read(file);


 
}
```

A1_11: M31.FR10 + M31.FR12 = M31.FR13

Another Example: A1_11
```dataviewjs
// M31. gather the formatted data :
// #####################################################################
for (const page of pages) {
    

    // M31.FR10 define file:
    // #####################################################################
    // const file = app.vault.getAbstractFileByPath(page.file.path);


    // M31.FR12 define contents: Read the file contents
    // #####################################################################
    // const contents = await app.vault.read(file);


    // M31.FR13 define contents: Read the file contents
    // s_entire_content_of_md_file
    // #####################################################################
    let contents = await app.vault.readRaw(page.file.path);


   
}
```

Q2: How to get a string from an embedded image with the path “E:/Q27_test_data_images/computer science/Q27 General01.jpg”?

Summary_Q1
Original Example: Q2 (To be outputed)
```md
cover: ![|150](file:///E:/Q27_test_data_images/computer%20science/Q27%20General01.jpg)
```

A2_21:

Another Example: A2_21
```dataviewjs
// D11. define sStartPath:
// #####################################################################
const sStartPath = "E:/Q27_test_data_images/computer science/";


// D13. define sStartPath:
// #####################################################################
let sEndPath = "Q27 General01.jpg";


// D21. define sFilePath:
// #####################################################################
let sFilePath = sStartPath + sEndPath;


// D23. update sFilePath:
// Note: if you have spaces in the file path, they have to be url-encoded
//       or the link won't work in some systems (e.g. GitHub). –
// #####################################################################
sFilePath = sFilePath.replace(/\s/g, "%20");


// D31. define s_embedded_image:
// #####################################################################
let s_embedded_image = "![|150](file:///" + sFilePath + ")";


// D51. output s_embedded_image: Code Element
// #####################################################################
dv.span("`" + s_embedded_image + "`");
```

Screenshots(A2_21)

//=>![|150](file:///E:/Q27_test_data_images/computer%20science/Q27%20General01.jpg)


Code DVJS20_TABLE_key_value_pairs_via_RegExp_and_Obsidian_API_groupBy_Title

Summary_code
title: DVJS20_TABLE_key_value_pairs_via_RegExp_and_Obsidian_API_groupBy_Title => 0.To require the plugin admonition 1.To get key-value pairs via RegExp and Obsidian API 2.To group by h_row.Title 3.To display the result as a table
collapse: open
icon: 
color: 
```dataviewjs
// M11. define pages: gather all relevant pages
// #####################################################################
const pages = dv.pages(
    '"100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data"'
);


// M13. define regex: find the contents of a specifically formatted callout
// REGEX_CALLOUT_BOX_OF_ADMONITION
// input:
// 
// ```ad-abstract
// title: Explain Recursion (5)
// area: General
// cover: ![|150](file:///E:/Q27_test_data_images/Q27_General01.jpg)
// For an explaition of recursion, please look up Recursion
// ```
// 
// output:
// Title="Explain Recursion"
// Points="5"
// Area="General"
// Cover="![|150](file:///E:/Q27_test_data_images/Q27_General01.jpg)"
// Content="For an explaition of recursion, please look up Recursion\n"
//
// OS       Abbreviation  Escape sequence
// Windows : CR+LF         \r\n
// UNIX    : LF            \n
// MAC     : CR            \r
//
// 1.Following Unix, Obsidian under different operating systems uses 
//   LF alone as a line terminator in a markdown file.
// 2.In other words, a markdown file created in Obsidian under different 
//   operating systems uses LF alone as a line terminator.
// 3.Howerver, a read-only markdown file with CR+LF(or CR) as a line 
//   terminator still keeps its original newline. Obsidian cannot transform 
// a newline into LF because the file does not have write permission.
// 4.Therefore, if there is no read-only markdown file,
//  uses LF alone like `let regex_Newline = /(?=\n)/g;`. 
// Otherwise, uses `let regex_Newline = /(?=\r?\n|\r)/g;`
// 
// non-greedy y*?
// non-greedy y+?
// Named Capture Group(?<Name>y)
// #####################################################################
// const regex = /```ad-(\w+)\r?\ntitle:(.+?)\((\d*?)\)\r?\n(.+?)```/
const regex =
    /```ad-(\w+)\r?\ntitle:\s*(?<Title>.+?)\s*\((?<Points>\d*?)\)\r?\narea:\s*(?<Area>.+?)\s*\r?\ncover:\s*(?<Cover>.+?)\s*\r?\n(?<Content>.+?)```/;



// M21. define aoh_rows : a JavaScript array
// #####################################################################
let aoh_rows = [];


// M23. update aoh_rows : 
// transform a JavaScript array into a Dataview data array by using dv.array
// #####################################################################
aoh_rows = dv.array(aoh_rows);


// M31. gather the formatted data :
// #####################################################################
for (const page of pages) {
    
    // M31.FR10 define file:
    // #####################################################################
    const file = app.vault.getAbstractFileByPath(page.file.path);


    // M31.FR12 define contents: Read the file contents
    // #####################################################################
    const contents = await app.vault.read(file);


    // M31.FR14 Extract the summary via regex :
    // g modifier: global. All matches (don't return after first match)
    // s modifier: single line. Dot matches newline characters
    // #####################################################################
    for (const callout of contents.match(new RegExp(regex, "sg")) || []) {
        

        // M31.FR14.FR11 define match :
        // s modifier: single line. Dot matches newline characters
        // ##################################################################### 
        const match = callout.match(new RegExp(regex, "s"));


        // M31.FR14.FR13 push the key/value pairs into the array aoh_rows:
        // #####################################################################
        // aoh_rows.push([match[2], match[3],match[4],match[5], page.file.link]);
        // aoh_rows["values"].push({
        //     Title: match[2],
        //     Points: match[3],
        //     Area: match[4],
        //     Content: match[5],
        //     Link: page.file.link,
        // }); 
        aoh_rows["values"].push({
            Title: match.groups?.Title,
            Points: match.groups?.Points,
            Area: match.groups?.Area,
            Cover: match.groups?.Cover,           
            Content: match.groups?.Content,
            Name_Of_File: page.file.name,
            Path_Of_File: page.file.path,          
            Link_Of_File: page.file.link,
        }); 

    }
}


// M39. dedbug output aoh_rows:
// #####################################################################
// dv.span("The following is the content of the `aoh_rows` from the DVJS20.<br>");
// aoh_rows.forEach((h_row) => {
//     if (h_row.Name_Of_File === "dic_19680301") {
//         dv.span(JSON.stringify(h_row, null, 2), "\n");
//     }
// });



// The following is the content of the aoh_rows from the DVJS20.
// [
//     {
//         Title: "Explain Recursion",
//         Points: "5",
//         Area: "General",
//         Cover: "![|150](file:///E:/Q27_test_data_images/Q27_General01.jpg)", //=>It is rendered as a image.
//         Content: "For an explaition of recursion, please look up Recursion\n",
//         Name_Of_File: "dic_19680301",
//         Path_Of_File:
//             "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
//         Link_Of_File: {
//             path: "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
//             embed: false,
//             type: "file",
//         },
//     },
//     {
//         Title: "Explain Mergesort",
//         Points: "3",
//         Area: "Sorting",
//         Cover: "![|150](file:///E:/Q27_test_data_images/Q27_Sorting01.jpg)", //=>It is rendered as a image.
//         Content: "It is 42\n",
//         Name_Of_File: "dic_19680301",
//         Path_Of_File:
//             "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
//         Link_Of_File: {
//             path: "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
//             embed: false,
//             type: "file",
//         },
//     },
//     {
//         Title: "Explain Iteration",
//         Points: "2",
//         Area: "Loop",
//         Cover: "![|150](file:///E:/Q27_test_data_images/Q27_Loop01.jpg)", //=>It is rendered as a image.
//         Content: "It is the opposite of recursion\n",
//         Name_Of_File: "dic_19680301",
//         Path_Of_File:
//             "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
//         Link_Of_File: {
//             path: "100_Project/01_dataviewjs/01_by_example/Q27_Admonition/Q27_test_data/03/dic_19680301.md",
//             embed: false,
//             type: "file",
//         },
//     },
// ];



// M41. filter and sort aoh_rows:
// #####################################################################
// aoh_rows = aoh_rows
//     .where((h_row) => h_row.Area)
//     // .where((h_row) => dv.func.contains(h_row.Title, "Explain"))
//     .where((h_row) =>
//         /Iteration|Mergesort|Recursion/.test(h_row.Title)
//     )
//     .sort((h_row) => h_row.Title, "asc");


// M51. define groups: 
// groupBy_CASE:To group each `h_row` of the `aoh_rows` by `h_row.Title` AS `G1` 
//              (G1=group.rows)(key=group.key)
// (comments)sort_CASE:To sort each `G1` of the `group.rows` by `group.key` in descending order
// #####################################################################
let groups = aoh_rows
    .groupBy((h_row) => h_row.Title);  // groupBy: (default) in ascending order
    //.sort((group) => group.key, "desc");


// M61. Output aoh_rows as a table: 
// #####################################################################
//dv.span(aoh_rows);
dv.table(
    ["Area", "Cover", "Question", "Points", "Content", "Exame"],
    groups.map((group) => [
        group.rows.Area[0],
        group.rows.Cover[0],  
        group.rows.Title[0],
        group.rows.Points,
        group.rows.Content,
        group.rows.Link_Of_File.join(", "),
    ])
);



```

Screenshots(DVJS20)


Reference

Summary

The codes

To link/embed Local images

The local images

The online images

Obsidian_API