From 472b78da37f703eebd7706566e7cdc02179eb753 Mon Sep 17 00:00:00 2001 From: Mike <16690476+cakechaser@users.noreply.github.com> Date: Wed, 24 Aug 2022 19:08:20 +0300 Subject: [PATCH] Queries are now executed with Dataview API --- README.md | 10 +- functions.ts | 541 ++++++++++++++----------------- functions_old.ts | 293 +++++++++++++++++ main.ts | 4 +- obsidian-timeline.code-workspace | 7 - settings.ts | 2 +- 6 files changed, 550 insertions(+), 307 deletions(-) create mode 100644 functions_old.ts delete mode 100644 obsidian-timeline.code-workspace diff --git a/README.md b/README.md index d3eea2a..d5cf0ca 100644 --- a/README.md +++ b/README.md @@ -25,17 +25,19 @@ Query example: ~~~markdown ```release-timeline table -release_year, alias_name +year_field, alias_field from [[CRPG]] and [[Isometric games]] +where year_field > 2000 sort desc ``` ~~~ Query elements: -- `table` - (optional) may be present in the beginning of each query for compatibility with Dataview. -- `year_field` - name of the field in the notes metadata containing the year or date. `release_year` in the example above. +- `table` - needs to be present in the beginning of each query +- `year_field` - name of the field in the notes metadata containing the year or date. - `alias_field` - (optional) name of the field in the notes metadata containing the alternative name of the note. Useful in case you want to show titles with characters not allowed in file names, such as `:`. In case some notes don't contain a field with this name, the standard name of the note will be used. -- `from ...` - conditions defining the notes that will be used to build the timeline. Syntax is the same as in Dataview. +- `from ...` - (optional) conditions defining the notes that will be used to build the timeline. Syntax is the same as in Dataview. +- `where ...` - (optional) conditions definining filters applied in the query. Syntax is the same as in Dataview. - `sort (asc|desc)` - (optional) sort order of the items in the timeline. If not provided, the default order from plugin settings will be used (desc by default). ## Options diff --git a/functions.ts b/functions.ts index 1288bec..f49424c 100644 --- a/functions.ts +++ b/functions.ts @@ -1,293 +1,248 @@ -import ReleaseTimeline from "main"; -import { getAPI, isPluginEnabled, DataviewAPI } from "obsidian-dataview"; -import { moment } from "obsidian"; -import { create } from "domain"; - -export default class HelpFunctions { - - plugin: ReleaseTimeline; - - constructor(plugin: ReleaseTimeline) { - this.plugin = plugin; - } - - createRowSeparator() { - const newTdSeparator = createEl("td", { cls: "td-separator" }); - const rowSeparator = createEl("tr"); - rowSeparator.appendChild(newTdSeparator); - - return rowSeparator; - }; - - createRowYear( { val, cls, rowspanNb } = {} ) { - const newTh = createEl("th", {text: val}) - newTh.setAttribute("scope", "row"); - newTh.setAttribute("class", cls); - if ( typeof rowspanNb !== 'undefined' ) { newTh.setAttribute("rowspan", rowspanNb) }; - - return newTh; - }; - - createRowItem( { fileName, fileAlias, cls } = {} ) { - const newTd = document.createElement("td"); - if ( typeof cls !== 'undefined' ) { newTd.setAttribute("class", cls) }; - newTd.classList.add("bullet-points"); - - const newLink = createEl("a", {cls: "internal-link", text: fileAlias}); - newLink.setAttribute("data-href", fileName); - - newTd.appendChild(newLink); - - return newTd; - }; - - createNewRow(...args) { - - const newRow = document.createElement("tr"); - - args.forEach((arg, index) => { - newRow.appendChild(arg); - }); - - return newRow; - }; - - createErrorMsg(errorText) { - const errorTbl = createEl("table", { cls: "release-timeline" } ); - const newI = createEl("i", {text: errorText}) - errorTbl.appendChild(newI); - - return errorTbl; - }; - - createTimelineTable(timeline, aliasName) { - - const newTbl = document.createElement("table"); - newTbl.classList.add("release-timeline") - - //create table body - const newTbody = document.createElement("tbody"); - - //check to create an empty row separator - let isLongRow = 0; - - // check if too many years are selected - let minYear = Math.min(...timeline.key.values); - let maxYear = Math.max(...timeline.key.values); - - if (maxYear - minYear > 5000 && this.plugin.settings.collapseEmptyYears == false) { - let errorTbl = this.createErrorMsg("Error: More than 5000 years in selection and \"Collapse years\" option is not enabled. Enable this option in plugin settings to build the timeline."); - return errorTbl; - }; - - - //create rows for table - let prevYear = timeline[0].key; - - timeline.forEach(item => { - - //year - let key = item.key; - //array of titles, sorted by name - //let value = item.rows.values.map(k => k.file.name).sort(); - - let value = item.rows.values.map(k => [k.file.name, typeof k[aliasName] !== 'undefined' ? k[aliasName] : k.file.name]);//.sort((a, b) => b[0] - a[0]); - - //create separator if previous row was long - if (isLongRow == 1) { newTbody.appendChild(this.createRowSeparator()) }; - - //create empty rows - let yearDiff = Math.abs(key - prevYear); - let collapseRows = this.plugin.settings.collapseEmptyYears; - let collapseLimit = Number(this.plugin.settings.collapseLimit) || 2; - - if ( yearDiff > 1) { - - //if collapse rows is on - create 1 row - if ( collapseRows && yearDiff > 2 && yearDiff > collapseLimit ) { - - let yearRange = key > prevYear ? `${prevYear + 1} - ${key - 1}` : `${key + 1} - ${prevYear - 1}`; - - const rowYear = this.createRowYear( { val: yearRange, cls: 'year-nonexisting' } ); - const rowItem = this.createRowItem( { fileName: "", fileAlias: "" } ); - const newRow = this.createNewRow(rowYear, rowItem); - newTbody.appendChild(newRow); - - //if collapse rows is off - create all rows - } else { - - for (let j = 1; j < yearDiff; j++) { - - let i = (key > prevYear) ? prevYear + j : prevYear - j; - - const rowYear = this.createRowYear( { val: i, cls: 'year-nonexisting' } ); - const rowItem = this.createRowItem( { fileName: "", fileAlias: "" } ); - const newRow = this.createNewRow(rowYear, rowItem); - newTbody.appendChild(newRow); - }; - - }; - - isLongRow = 0; - - }; - - //create real rows - //create row with 1 element - if ( value.length == 1 ) { - - isLongRow = 0; - - const rowYear = this.createRowYear( { val: key, cls: 'year-existing' } ); - const rowItem = this.createRowItem( { fileName: value[0][0], fileAlias: value[0][1] } ); - const newRow = this.createNewRow(rowYear, rowItem); - newTbody.appendChild(newRow); - - //create rows with multiple elements - } else { - - //create separator if prev row was short, but this one is long - if (isLongRow == 0) { newTbody.appendChild(this.createRowSeparator()); }; - isLongRow = 1; - - //create 1st row - const rowYear = this.createRowYear( { val: key, cls: 'year-existing', rowspanNb: value.length } ); - const rowItem = this.createRowItem( { fileName: value[0][0], fileAlias: value[0][1], cls: "td-first" } ); - const newRow = this.createNewRow(rowYear, rowItem); - newTbody.appendChild(newRow); - - //create 2nd+ rows - for (let i = 1; i < value.length; i++) { - - const rowItem = this.createRowItem( { fileName: value[i][0], fileAlias: value[i][1], cls: "td-next" } ); - const newRow = this.createNewRow(rowItem); - newTbody.appendChild(newRow); - - }; - - }; - - prevYear = key; - - }); - - //append table body to table - newTbl.appendChild(newTbody); - - return newTbl; - }; - - parseQueryFrom(content: string) { - - let regExFrom = /(?<=from)(.*?)(where|sort|$)/; - let queryFrom = content.match(regExFrom)[1].trim(); - - return queryFrom; - }; - - parseQueryYear(content: string) { - - let regExYear = /(?:table|table without id)?(.*?)(?=from)/; - let queryYearColumnMatch = content.match(regExYear)[1].trim(); - let queryYearColumn = queryYearColumnMatch.split(',')[0]; - - return queryYearColumn; - }; - - parseQueryWhere(content: string) { - - let regExWhere = /where(.*)/; - let queryWhereMatch = content.match(regExWhere); - - let queryWhere = queryWhereMatch === null ? '' : queryWhereMatch[1].trim(); - queryWhere = queryWhere.replace(' and ', ' && ').replace(' or ', ' || '); - - return queryWhere; - }; - - - parseQuerySortOrder(content: string) { - - let regExSortOrder = /sort(?:.*)? (desc|asc)/; - - let settingsSort = this.plugin.settings.defaultSortOrder; - - let querySortOrderMatch = content.match(regExSortOrder); - - let querySortOrder; - if (querySortOrderMatch === null) { - return settingsSort; - } else { - querySortOrder = querySortOrderMatch[1].trim(); - return querySortOrder; - } - - }; - - parseAliasName(content: string) { - - let regExAliasName = /(?:table|table without id)?,(.*?)(?=from)/; - - let queryAliasMatch = content.match(regExAliasName); - - if ( queryAliasMatch == null) { - return null; - } - else { - return content.match(regExAliasName)[1].trim(); - } - - } - - renderTimeline(content: string) { - - const dv = getAPI(); - - if ( typeof dv == 'undefined' ) { return this.createErrorMsg('Dataview is not installed. The Release Timeline plugin requires Dataview to properly function.'); } - - content = content.replace(/[\r\n]+/g," ").toLocaleLowerCase(); - - try { - var queryFrom = this.parseQueryFrom(content); - } - catch(error) { - return this.createErrorMsg("Error parsing the 'FROM' statement"); - } - - try { - var queryYearColumn = this.parseQueryYear(content); - } - catch(error) { - return this.createErrorMsg("Error getting the 'Year' field"); - } - - //let queryWhere = this.parseQueryWhere(content); - - let querySortOrder = this.parseQuerySortOrder(content); - - let aliasName = this.parseAliasName(content); - - //get results from dataview - try { - var results = dv.pages(queryFrom) - .filter(k => typeof k[queryYearColumn] !== 'undefined' && k[queryYearColumn] !== null) - .mutate(k => k[queryYearColumn] = moment( k[queryYearColumn].toString() ).format('YYYY') ) - .filter(k => k[queryYearColumn] != "Invalid date") - .mutate(k => k[queryYearColumn] = Number(k[queryYearColumn]) ) - .groupBy(k => k[queryYearColumn]) - .sort(k => k.key, querySortOrder); - } - catch(error) { - return this.createErrorMsg("Error from dataview: " + error.message) - } - - if (results.length == 0) { - return this.createErrorMsg("No results"); - } - else { - return this.createTimelineTable(results, aliasName); - } - - } - -} +import ReleaseTimeline from "main"; +import { getAPI, isPluginEnabled, DataviewAPI } from "obsidian-dataview"; +import { moment } from "obsidian"; +import { create } from "domain"; + +export default class HelpFunctions { + + plugin: ReleaseTimeline; + + constructor(plugin: ReleaseTimeline) { + this.plugin = plugin; + } + + createErrorMsg(errorText) { + const errorTbl = createEl("table", { cls: "release-timeline" } ); + const newI = createEl("i", {text: errorText}) + errorTbl.appendChild(newI); + + return errorTbl; + }; + + async renderTimeline(content: string) { + + const dv = getAPI(); + + if ( typeof dv == 'undefined' ) { return this.createErrorMsg('Dataview is not installed. The Release Timeline plugin requires Dataview to properly function.'); } + + var sortOrder = this.parseQuerySortOrder(content); + + //get results from dataview + try { + + var results; + var results0 = await dv.query(content); + let a = results0.value.values; + + let b = a.filter(x => typeof x[1] !== 'undefined' && x[1] !== null); + //b.forEach(x => x[1].constructor.name == 'DateTime' ? x[1]=x[1].c.year : x[1]=x[1]); + + b.forEach(x => x[1] = moment( x[1].toString() ).format('YYYY')) + b = b.filter(x => x[1] != "Invalid date") + + //b = b.filter(x => typeof x != 'number') + + b.forEach(x => x[0] = x[0].path.match(/([^\/]+(?=\.)).md/)[1]); + b.forEach(x => x[2]==null ? x[2]=x[0] : 1); + + results = dv.array(b); + results = results.groupBy(x => x[1]); + + results = results.sort(k => k.key, sortOrder); + + } + catch(error) { + return this.createErrorMsg("Error from dataview: " + error.message) + } + + if (results.length == 0) { + return this.createErrorMsg("No results"); + } + else { + return this.createTimelineTable(results); + } + + } + + createTimelineTable(timeline) { + + const newTbl = document.createElement("table"); + newTbl.classList.add("release-timeline") + + //create table body + const newTbody = document.createElement("tbody"); + + //check to create an empty row separator + let isLongRow = 0; + + // check if too many years are selected + + let minYear = Math.min(...timeline.key.values); + let maxYear = Math.max(...timeline.key.values); + + if (maxYear - minYear > 5000 && this.plugin.settings.collapseEmptyYears == false) { + let errorTbl = this.createErrorMsg("Error: More than 5000 years in selection and \"Collapse years\" option is not enabled. Enable this option in plugin settings to build the timeline."); + return errorTbl; + }; + + + //create rows for table + let prevYear = timeline[0].key; + + timeline.forEach(item => { + + //year + let key = item.key; + //array of titles, sorted by name + //let value = item.rows.values.map(k => k.file.name).sort(); + //[[filename1, alias1], [filename2, alias2], ..] + //let value = item.rows.values.map(k => [k.file.name, typeof k[aliasName] !== 'undefined' ? k[aliasName] : k.file.name]);//.sort((a, b) => b[0] - a[0]); + + let value = item.rows.values.map(k => [k[0], k[2]]); + + //create separator if previous row was long + if (isLongRow == 1) { newTbody.appendChild(this.createRowSeparator()) }; + + //create empty rows + let yearDiff = Math.abs(key - prevYear); + let collapseRows = this.plugin.settings.collapseEmptyYears; + let collapseLimit = Number(this.plugin.settings.collapseLimit) || 2; + + if ( yearDiff > 1) { + + //if collapse rows is on - create 1 row + if ( collapseRows && yearDiff > 2 && yearDiff > collapseLimit ) { + + let yearRange = key > prevYear ? `${prevYear + 1} - ${key - 1}` : `${key + 1} - ${prevYear - 1}`; + + const rowYear = this.createRowYear( { val: yearRange, cls: 'year-nonexisting' } ); + const rowItem = this.createRowItem( { fileName: "", fileAlias: "" } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + + //if collapse rows is off - create all rows + } else { + + for (let j = 1; j < yearDiff; j++) { + + let i = (key > prevYear) ? prevYear + j : prevYear - j; + + const rowYear = this.createRowYear( { val: i, cls: 'year-nonexisting' } ); + const rowItem = this.createRowItem( { fileName: "", fileAlias: "" } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + }; + + }; + + isLongRow = 0; + + }; + + //create real rows + //create row with 1 element + if ( value.length == 1 ) { + + isLongRow = 0; + + const rowYear = this.createRowYear( { val: key, cls: 'year-existing' } ); + const rowItem = this.createRowItem( { fileName: value[0][0], fileAlias: value[0][1] } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + + //create rows with multiple elements + } else { + + //create separator if prev row was short, but this one is long + if (isLongRow == 0) { newTbody.appendChild(this.createRowSeparator()); }; + isLongRow = 1; + + //create 1st row + const rowYear = this.createRowYear( { val: key, cls: 'year-existing', rowspanNb: value.length } ); + const rowItem = this.createRowItem( { fileName: value[0][0], fileAlias: value[0][1], cls: "td-first" } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + + //create 2nd+ rows + for (let i = 1; i < value.length; i++) { + + const rowItem = this.createRowItem( { fileName: value[i][0], fileAlias: value[i][1], cls: "td-next" } ); + const newRow = this.createNewRow(rowItem); + newTbody.appendChild(newRow); + + }; + + }; + + prevYear = key; + + }); + + //append table body to table + newTbl.appendChild(newTbody); + + return newTbl; + }; + + createRowSeparator() { + const newTdSeparator = createEl("td", { cls: "td-separator" }); + const rowSeparator = createEl("tr"); + rowSeparator.appendChild(newTdSeparator); + + return rowSeparator; + }; + + createRowYear( { val, cls, rowspanNb } = {} ) { + const newTh = createEl("th", {text: val}) + newTh.setAttribute("scope", "row"); + newTh.setAttribute("class", cls); + if ( typeof rowspanNb !== 'undefined' ) { newTh.setAttribute("rowspan", rowspanNb) }; + + return newTh; + }; + + createRowItem( { fileName, fileAlias, cls } = {} ) { + const newTd = document.createElement("td"); + if ( typeof cls !== 'undefined' ) { newTd.setAttribute("class", cls) }; + newTd.classList.add("bullet-points"); + + const newLink = createEl("a", {cls: "internal-link", text: fileAlias}); + newLink.setAttribute("data-href", fileName); + + newTd.appendChild(newLink); + + return newTd; + }; + + createNewRow(...args) { + + const newRow = document.createElement("tr"); + + args.forEach((arg, index) => { + newRow.appendChild(arg); + }); + + return newRow; + }; + + parseQuerySortOrder(content: string) { + + let regExSortOrder = /sort(?:.*)? (desc|asc)/; + + let settingsSort = this.plugin.settings.defaultSortOrder; + + content = content.replace(/[\r\n]+/g," ").toLocaleLowerCase(); + + let querySortOrderMatch = content.match(regExSortOrder); + + let querySortOrder; + if (querySortOrderMatch === null) { + return settingsSort; + } else { + querySortOrder = querySortOrderMatch[1].trim(); + return querySortOrder; + } + + }; + +} \ No newline at end of file diff --git a/functions_old.ts b/functions_old.ts new file mode 100644 index 0000000..c883b05 --- /dev/null +++ b/functions_old.ts @@ -0,0 +1,293 @@ +import ReleaseTimeline from "main"; +import { getAPI, isPluginEnabled, DataviewAPI } from "obsidian-dataview"; +import { moment } from "obsidian"; +import { create } from "domain"; + +export default class HelpFunctions { + + plugin: ReleaseTimeline; + + constructor(plugin: ReleaseTimeline) { + this.plugin = plugin; + } + + createRowSeparator() { + const newTdSeparator = createEl("td", { cls: "td-separator" }); + const rowSeparator = createEl("tr"); + rowSeparator.appendChild(newTdSeparator); + + return rowSeparator; + }; + + createRowYear( { val, cls, rowspanNb } = {} ) { + const newTh = createEl("th", {text: val}) + newTh.setAttribute("scope", "row"); + newTh.setAttribute("class", cls); + if ( typeof rowspanNb !== 'undefined' ) { newTh.setAttribute("rowspan", rowspanNb) }; + + return newTh; + }; + + createRowItem( { fileName, fileAlias, cls } = {} ) { + const newTd = document.createElement("td"); + if ( typeof cls !== 'undefined' ) { newTd.setAttribute("class", cls) }; + newTd.classList.add("bullet-points"); + + const newLink = createEl("a", {cls: "internal-link", text: fileAlias}); + newLink.setAttribute("data-href", fileName); + + newTd.appendChild(newLink); + + return newTd; + }; + + createNewRow(...args) { + + const newRow = document.createElement("tr"); + + args.forEach((arg, index) => { + newRow.appendChild(arg); + }); + + return newRow; + }; + + createErrorMsg(errorText) { + const errorTbl = createEl("table", { cls: "release-timeline" } ); + const newI = createEl("i", {text: errorText}) + errorTbl.appendChild(newI); + + return errorTbl; + }; + + createTimelineTable(timeline, aliasName) { + + const newTbl = document.createElement("table"); + newTbl.classList.add("release-timeline") + + //create table body + const newTbody = document.createElement("tbody"); + + //check to create an empty row separator + let isLongRow = 0; + + // check if too many years are selected + let minYear = Math.min(...timeline.key.values); + let maxYear = Math.max(...timeline.key.values); + + if (maxYear - minYear > 5000 && this.plugin.settings.collapseEmptyYears == false) { + let errorTbl = this.createErrorMsg("Error: More than 5000 years in selection and \"Collapse years\" option is not enabled. Enable this option in plugin settings to build the timeline."); + return errorTbl; + }; + + + //create rows for table + let prevYear = timeline[0].key; + + timeline.forEach(item => { + + //year + let key = item.key; + //array of titles, sorted by name + //let value = item.rows.values.map(k => k.file.name).sort(); + //[[filename1, alias1], [filename2, alias2], ..] + let value = item.rows.values.map(k => [k.file.name, typeof k[aliasName] !== 'undefined' ? k[aliasName] : k.file.name]);//.sort((a, b) => b[0] - a[0]); + + //create separator if previous row was long + if (isLongRow == 1) { newTbody.appendChild(this.createRowSeparator()) }; + + //create empty rows + let yearDiff = Math.abs(key - prevYear); + let collapseRows = this.plugin.settings.collapseEmptyYears; + let collapseLimit = Number(this.plugin.settings.collapseLimit) || 2; + + if ( yearDiff > 1) { + + //if collapse rows is on - create 1 row + if ( collapseRows && yearDiff > 2 && yearDiff > collapseLimit ) { + + let yearRange = key > prevYear ? `${prevYear + 1} - ${key - 1}` : `${key + 1} - ${prevYear - 1}`; + + const rowYear = this.createRowYear( { val: yearRange, cls: 'year-nonexisting' } ); + const rowItem = this.createRowItem( { fileName: "", fileAlias: "" } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + + //if collapse rows is off - create all rows + } else { + + for (let j = 1; j < yearDiff; j++) { + + let i = (key > prevYear) ? prevYear + j : prevYear - j; + + const rowYear = this.createRowYear( { val: i, cls: 'year-nonexisting' } ); + const rowItem = this.createRowItem( { fileName: "", fileAlias: "" } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + }; + + }; + + isLongRow = 0; + + }; + + //create real rows + //create row with 1 element + if ( value.length == 1 ) { + + isLongRow = 0; + + const rowYear = this.createRowYear( { val: key, cls: 'year-existing' } ); + const rowItem = this.createRowItem( { fileName: value[0][0], fileAlias: value[0][1] } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + + //create rows with multiple elements + } else { + + //create separator if prev row was short, but this one is long + if (isLongRow == 0) { newTbody.appendChild(this.createRowSeparator()); }; + isLongRow = 1; + + //create 1st row + const rowYear = this.createRowYear( { val: key, cls: 'year-existing', rowspanNb: value.length } ); + const rowItem = this.createRowItem( { fileName: value[0][0], fileAlias: value[0][1], cls: "td-first" } ); + const newRow = this.createNewRow(rowYear, rowItem); + newTbody.appendChild(newRow); + + //create 2nd+ rows + for (let i = 1; i < value.length; i++) { + + const rowItem = this.createRowItem( { fileName: value[i][0], fileAlias: value[i][1], cls: "td-next" } ); + const newRow = this.createNewRow(rowItem); + newTbody.appendChild(newRow); + + }; + + }; + + prevYear = key; + + }); + + //append table body to table + newTbl.appendChild(newTbody); + + return newTbl; + }; + + parseQueryFrom(content: string) { + + let regExFrom = /(?<=from)(.*?)(where|sort|$)/; + let queryFrom = content.match(regExFrom)[1].trim(); + + return queryFrom; + }; + + parseQueryYear(content: string) { + + let regExYear = /(?:table|table without id)?(.*?)(?=from)/; + let queryYearColumnMatch = content.match(regExYear)[1].trim(); + let queryYearColumn = queryYearColumnMatch.split(',')[0]; + + return queryYearColumn; + }; + + parseQueryWhere(content: string) { + + let regExWhere = /where(.*)/; + let queryWhereMatch = content.match(regExWhere); + + let queryWhere = queryWhereMatch === null ? '' : queryWhereMatch[1].trim(); + queryWhere = queryWhere.replace(' and ', ' && ').replace(' or ', ' || '); + + return queryWhere; + }; + + + parseQuerySortOrder(content: string) { + + let regExSortOrder = /sort(?:.*)? (desc|asc)/; + + let settingsSort = this.plugin.settings.defaultSortOrder; + + let querySortOrderMatch = content.match(regExSortOrder); + + let querySortOrder; + if (querySortOrderMatch === null) { + return settingsSort; + } else { + querySortOrder = querySortOrderMatch[1].trim(); + return querySortOrder; + } + + }; + + parseAliasName(content: string) { + + let regExAliasName = /(?:table|table without id)?,(.*?)(?=from)/; + + let queryAliasMatch = content.match(regExAliasName); + + if ( queryAliasMatch == null) { + return null; + } + else { + return content.match(regExAliasName)[1].trim(); + } + + } + + renderTimeline(content: string) { + + const dv = getAPI(); + + if ( typeof dv == 'undefined' ) { return this.createErrorMsg('Dataview is not installed. The Release Timeline plugin requires Dataview to properly function.'); } + + content = content.replace(/[\r\n]+/g," ").toLocaleLowerCase(); + + try { + var queryFrom = this.parseQueryFrom(content); + } + catch(error) { + return this.createErrorMsg("Error parsing the 'FROM' statement"); + } + + try { + var queryYearColumn = this.parseQueryYear(content); + } + catch(error) { + return this.createErrorMsg("Error getting the 'Year' field"); + } + + //let queryWhere = this.parseQueryWhere(content); + + let querySortOrder = this.parseQuerySortOrder(content); + + let aliasName = this.parseAliasName(content); + + //get results from dataview + try { + var results = dv.pages(queryFrom) + .filter(k => typeof k[queryYearColumn] !== 'undefined' && k[queryYearColumn] !== null) + .mutate(k => k[queryYearColumn] = moment( k[queryYearColumn].toString() ).format('YYYY') ) + .filter(k => k[queryYearColumn] != "Invalid date") + .mutate(k => k[queryYearColumn] = Number(k[queryYearColumn]) ) + .groupBy(k => k[queryYearColumn]) + .sort(k => k.key, querySortOrder); + } + catch(error) { + return this.createErrorMsg("Error from dataview: " + error.message) + } + + if (results.length == 0) { + return this.createErrorMsg("No results"); + } + else { + return this.createTimelineTable(results, aliasName); + } + + } + +} \ No newline at end of file diff --git a/main.ts b/main.ts index a8dfe82..2a22fb9 100644 --- a/main.ts +++ b/main.ts @@ -25,7 +25,7 @@ export default class ReleaseTimeline extends Plugin { this.registerMarkdownCodeBlockProcessor('release-timeline', async (content: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => { - let timelineTable = this.HelpFunctions.renderTimeline(content); + let timelineTable = await this.HelpFunctions.renderTimeline(content); //render el.appendChild(timelineTable); @@ -53,4 +53,4 @@ export default class ReleaseTimeline extends Plugin { async saveSettings() { await this.saveData(this.settings); } -} +} \ No newline at end of file diff --git a/obsidian-timeline.code-workspace b/obsidian-timeline.code-workspace deleted file mode 100644 index ef9f5d2..0000000 --- a/obsidian-timeline.code-workspace +++ /dev/null @@ -1,7 +0,0 @@ -{ - "folders": [ - { - "path": "." - } - ] -} \ No newline at end of file diff --git a/settings.ts b/settings.ts index 611193c..3d7c122 100644 --- a/settings.ts +++ b/settings.ts @@ -88,4 +88,4 @@ export class SampleSettingTab extends PluginSettingTab { } -} +} \ No newline at end of file