From e74b6441f67f8674ead88cf1e42f976cd2636830 Mon Sep 17 00:00:00 2001 From: Aaron Gascoigne Date: Tue, 23 Apr 2024 20:50:26 -0400 Subject: [PATCH 1/5] Disable padding on long lines If lines start to wrap the formating breaks. --- jgclark.Summaries/src/summaryHelpers.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/jgclark.Summaries/src/summaryHelpers.js b/jgclark.Summaries/src/summaryHelpers.js index 330e98726..ee5473b1c 100644 --- a/jgclark.Summaries/src/summaryHelpers.js +++ b/jgclark.Summaries/src/summaryHelpers.js @@ -720,7 +720,13 @@ export async function generateProgressUpdate(occObjs: Array, peri // Include sparklines only if this period is a month or less const showSparklines = (requestToShowSparklines && daysBetween <= 31) // Get length of longest progress term (to use with sparklines) - const maxTermLen = Math.max(...occObjs.map((m) => m.term.length)) + let maxTermLen = Math.max(...occObjs.map((m) => m.term.length)) + + // Disable padding if lines wrap + if (maxTermLen > 50) { + logDebug('generateProgressUpdate', `maxTermLen is ${maxTermLen} disabling padding as lines will wrap`) + maxTermLen = 0 + } let outputArray: Array = [] for (let occObj of occObjs) { From a34a94e79d9e367e2f648f660b72a849bcf097f4 Mon Sep 17 00:00:00 2001 From: Aaron Gascoigne Date: Tue, 23 Apr 2024 20:51:33 -0400 Subject: [PATCH 2/5] Clean up documentation Typos Resize images --- jgclark.Summaries/README.md | 11 ++++++----- .../{checklist-2.png => checklist_count.png} | Bin .../{checklist-1.png => checklist_refnote.png} | Bin .../{checklist.png => checklist_settings.png} | Bin jgclark.Summaries/plugin.json | 4 ++-- 5 files changed, 8 insertions(+), 7 deletions(-) rename jgclark.Summaries/{checklist-2.png => checklist_count.png} (100%) rename jgclark.Summaries/{checklist-1.png => checklist_refnote.png} (100%) rename jgclark.Summaries/{checklist.png => checklist_settings.png} (100%) diff --git a/jgclark.Summaries/README.md b/jgclark.Summaries/README.md index 5bbec723c..ff2e9bca2 100644 --- a/jgclark.Summaries/README.md +++ b/jgclark.Summaries/README.md @@ -57,22 +57,23 @@ All notes in the special folders (@Archive, @Templates and @Trash) are **ignored Note: **Why use `@run(...)` (mentions) rather than `#run(...)` (hashtags)**? Well, it just felt more right to use `@run(...)` as there are already `@done(...)` and `@repeat(...)` mentions in use in NotePlan that include a value in the brackets. And in NotePlan, hashtags that end with a number ignore the fractional part (e.g. `#run/5.3` ignores the `.3`) but they are not ignored inside `@run(5.3)`. However, you _can_ use a `#hashtag/value` if you don't mind this limitation. -## Tracking checklist completetion +## Tracking checklist completion -To track checklist completion you must create a referance checklist in the template folder: +To track checklist completion you must create a reference checklist in the template folder: + +Checklist completion -![alt text](checklist-1.png) Add the title of this template to settings: -![alt text](checklist.png) + Checklist settings If you want to use this template in another note it can be imported using `<%- import("Daily tasks”) -%>` Completion is tracked using the 'appendProgressUpdate' command -![alt text](checklist-2.png) + Checklist count ## 'heatmap for complete tasks' command This displays a 'heatmap' chart of many tasks you've completed on each day (see example above). It uses the `@done(...)` dates in all daily, weekly and project notes over the number of weeks you specify to look back (via the 'Chart Duration (in weeks)' setting). If you set this to 0, the plugin will generate a sensible longish period between 6 and 12 months. It also counts completed tasks without `@done(...)` dates on Calendar notes, and assumes the tasks were completed on the day or start of week in question. diff --git a/jgclark.Summaries/checklist-2.png b/jgclark.Summaries/checklist_count.png similarity index 100% rename from jgclark.Summaries/checklist-2.png rename to jgclark.Summaries/checklist_count.png diff --git a/jgclark.Summaries/checklist-1.png b/jgclark.Summaries/checklist_refnote.png similarity index 100% rename from jgclark.Summaries/checklist-1.png rename to jgclark.Summaries/checklist_refnote.png diff --git a/jgclark.Summaries/checklist.png b/jgclark.Summaries/checklist_settings.png similarity index 100% rename from jgclark.Summaries/checklist.png rename to jgclark.Summaries/checklist_settings.png diff --git a/jgclark.Summaries/plugin.json b/jgclark.Summaries/plugin.json index 98edb1161..d8a8eff5d 100644 --- a/jgclark.Summaries/plugin.json +++ b/jgclark.Summaries/plugin.json @@ -8,8 +8,8 @@ "plugin.author": "Jonathan Clark", "plugin.url": "https://github.com/NotePlan/plugins/tree/main/jgclark.Summaries/", "plugin.changelog": "https://github.com/NotePlan/plugins/blob/main/jgclark.Summaries/CHANGELOG.md", - "plugin.version": "0.22.0", - "plugin.lastUpdateInfo": "0.22.0: Add support for checklist progress.\n0.21.0: Add Mermaid charting command. Fix to simple weekly CSV generation.\n0.20.3: Bug fix for progressUpdate() in templates.\n0.20.2: Added x-callback options for /periodStats.\n0.20.1: fix refresh after '/append progress update' command. Logging change.\n0.20.0: add new '/today progress' and '/heatmap for tag' commands, and add refresh button to /periodStats output.\n0.19.3: bug fixes on 'weekly stats generation' commands.\n0.19.2: change date library.\n0.19.1: bug fix\n. 0.19.0: adds totals and averages for hashtags as well. Improve output of averages.", + "plugin.version": "0.22.1", + "plugin.lastUpdateInfo": "0.22.1 Fix formatting with long lines.\n0.22.0: Add support for checklist progress.\n0.21.0: Add Mermaid charting command. Fix to simple weekly CSV generation.\n0.20.3: Bug fix for progressUpdate() in templates.\n0.20.2: Added x-callback options for /periodStats.\n0.20.1: fix refresh after '/append progress update' command. Logging change.\n0.20.0: add new '/today progress' and '/heatmap for tag' commands, and add refresh button to /periodStats output.\n0.19.3: bug fixes on 'weekly stats generation' commands.\n0.19.2: change date library.\n0.19.1: bug fix\n. 0.19.0: adds totals and averages for hashtags as well. Improve output of averages.", "plugin.dependencies": [], "plugin.script": "script.js", "plugin.isRemote": "false", From 6930b259befca8889b8825b37a3b00475b719332 Mon Sep 17 00:00:00 2001 From: Aaron Gascoigne Date: Wed, 24 Apr 2024 13:55:39 -0400 Subject: [PATCH 3/5] Add trucateString helper from SugarJs From https://github.com/andrewplummer/Sugar/ --- helpers/stringTransforms.js | 100 +++++++++++++++++++++++++++++++----- 1 file changed, 87 insertions(+), 13 deletions(-) diff --git a/helpers/stringTransforms.js b/helpers/stringTransforms.js index 7624549e5..18308387c 100644 --- a/helpers/stringTransforms.js +++ b/helpers/stringTransforms.js @@ -39,9 +39,7 @@ export function changeBareLinksToHTMLLink(original: string, addWebIcon: boolean // clo(captures, `${String(captures.length)} results from bare URL matches:`) for (const capture of captures) { const linkURL = capture[3] - const URLForDisplay = (truncateIfNecessary && linkURL.length > 20) - ? linkURL.slice(0, 50) + '...' - : linkURL + const URLForDisplay = truncateIfNecessary && linkURL.length > 20 ? linkURL.slice(0, 50) + '...' : linkURL // logDebug('changeBareLinksToHTMLLink', `${linkURL} / ${URLForDisplay}`) if (addWebIcon) { // not displaying icon @@ -359,11 +357,11 @@ export function encodeRFC3986URIComponent(input: string): string { .replace(/\[/g, '%5B') .replace(/\]/g, '%5D') .replace(/!/g, '%21') - .replace(/'/g, "%27") + .replace(/'/g, '%27') .replace(/\(/g, '%28') .replace(/\)/g, '%29') .replace(/\*/g, '%2A') - // .replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`) + // .replace(/[!'()*]/g, (c) => `%${c.charCodeAt(0).toString(16).toUpperCase()}`) } /** @@ -374,13 +372,89 @@ export function encodeRFC3986URIComponent(input: string): string { * @returns {string} */ export function decodeRFC3986URIComponent(input: string): string { - const decodedSpecials = input - .replace(/%5B/g, '[') - .replace(/%5D/g, ']') - .replace(/%21/g, '!') - .replace(/%27/g, "'") - .replace(/%28/g, '(') - .replace(/%29/g, ')') - .replace(/%2A/g, '*') + const decodedSpecials = input.replace(/%5B/g, '[').replace(/%5D/g, ']').replace(/%21/g, '!').replace(/%27/g, "'").replace(/%28/g, '(').replace(/%29/g, ')').replace(/%2A/g, '*') return decodeURIComponent(decodedSpecials) } + +/** + * @method truncateOnWord(length, [from] = 'right', [ellipsis] = '...') + * @returns String + * @short Truncates a string without splitting up words. + * @extra [from] can be `'right'`, `'left'`, or `'middle'`. If the string is + * shorter than `length`, [ellipsis] will not be added. A "word" is + * defined as any sequence of non-whitespace characters. + * + * @example + * + * 'here we go'.truncateOnWord(5) -> 'here...' + * 'here we go'.truncateOnWord(5, 'left') -> '...we go' + * + * @param {number} length + * @param {string} [from] can be `'right'`, `'left'`, or `'middle'`. + * @param {boolean} [fromLeft] - whether to truncate from the left or not + * + * @author Sugar.js https://github.com/andrewplummer/Sugar/blob/b757c66c4e6361af710431117eadcafc5c7d42bc/lib/string.js + **/ +function truncateOnWord(str: string, limit: number, fromLeft: boolean = false): string { + if (fromLeft) { + return truncateOnWord(str.split('').reverse().join(''), limit).split('').reverse().join('') + } + // WhiteSpace/LineTerminator as defined in ES5.1 plus Unicode characters in the Space, Separator category. + const TRIM_CHARS = '\u0009\u000A\u000B\u000C\u000D\u0020\u00A0\u1680\u180E\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200A\u202F\u205F\u2028\u2029\u3000\uFEFF' + const TRUNC_REG = RegExp(`(?=[${TRIM_CHARS}])`) + const words = str.split(TRUNC_REG) + let count = 0 + const result = [] + + for (const word of words) { + count += word.length + if (count <= limit) { + result.push(word) + } else { + break + } + } + + return result.join('') +} + +/** + * @method truncateString(length, [from] = 'right', [split] = true) + * @returns String + * @short Truncates a string. + * @extra [from] can be `'right'`, `'left'`, or `'middle'`. If the string is + * shorter than `length`, [ellipsis] will not be added. + * + * @example + * + * 'sittin on the dock'.truncate(10) -> 'sittin on ...' + * 'sittin on the dock'.truncate(10, 'left') -> '...n the dock' + * 'sittin on the dock'.truncate(10, 'middle') -> 'sitti... dock' + * + * @param {number} length + * @param {string} [from] can be `'right'`, `'left'`, or `'middle'`. + * @param {boolean} [split] - whether to split on words or not + * + * @author Sugar.js https://github.com/andrewplummer/Sugar/blob/b757c66c4e6361af710431117eadcafc5c7d42bc/lib/string.js + **/ +export function truncateString(str: string, length: number, from: string, splitOnWord: boolean = true): string { + let str1, str2, len1, len2 + if (str.length <= length) { + return str.toString() + } + const ellipsisStr = '...' + switch (from) { + case 'left': + str2 = splitOnWord ? truncateOnWord(str, length, true) : str.slice(str.length - length) + return ellipsisStr + str2 + case 'middle': + len1 = Math.ceil(length / 2) + len2 = Math.floor(length / 2) + str1 = splitOnWord ? truncateOnWord(str, len1) : str.slice(0, len1) + str2 = splitOnWord ? truncateOnWord(str, len2, true) : str.slice(str.length - len2) + return str1 + ellipsisStr + str2 + default: + str1 = splitOnWord ? truncateOnWord(str, length) : str.slice(0, length) + return str1 + ellipsisStr + } +} From 207ead89058ddc91331476ea2cab8bd63c3cba67 Mon Sep 17 00:00:00 2001 From: Aaron Gascoigne Date: Wed, 24 Apr 2024 13:57:18 -0400 Subject: [PATCH 4/5] Truncate summaries prior to padding --- jgclark.Summaries/src/summaryHelpers.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/jgclark.Summaries/src/summaryHelpers.js b/jgclark.Summaries/src/summaryHelpers.js index ee5473b1c..274d4978e 100644 --- a/jgclark.Summaries/src/summaryHelpers.js +++ b/jgclark.Summaries/src/summaryHelpers.js @@ -30,6 +30,7 @@ import { isHashtagWanted, isMentionWanted, } from '@helpers/search' +import { truncateString } from '@helpers/stringTransforms' //------------------------------------------------------------------------------ // Get settings @@ -719,17 +720,15 @@ export async function generateProgressUpdate(occObjs: Array, peri const daysBetween = toDateMom.diff(fromDateMom, 'days') // Include sparklines only if this period is a month or less const showSparklines = (requestToShowSparklines && daysBetween <= 31) - // Get length of longest progress term (to use with sparklines) - let maxTermLen = Math.max(...occObjs.map((m) => m.term.length)) - - // Disable padding if lines wrap - if (maxTermLen > 50) { - logDebug('generateProgressUpdate', `maxTermLen is ${maxTermLen} disabling padding as lines will wrap`) - maxTermLen = 0 + if (showSparklines) { + // Truncate lines to avoid line wrapping + occObjs.forEach((m) => m.term = truncateString(m.term, 60, 'middle')) } + // Get length of longest progress term (to use with sparklines) + const maxTermLen = Math.max(...occObjs.map((m) => m.term.length)) - let outputArray: Array = [] - for (let occObj of occObjs) { + const outputArray: Array = [] + for (const occObj of occObjs) { // occObj.logValuesMap() let thisOutput = '' switch (style) { From 4684198039b145cf0e29adde3ac4f41655f4dc50 Mon Sep 17 00:00:00 2001 From: Aaron Gascoigne Date: Wed, 24 Apr 2024 17:59:56 -0400 Subject: [PATCH 5/5] Render template and remove links Signed-off-by: Aaron Gascoigne --- helpers/stringTransforms.js | 9 +++++++++ jgclark.Summaries/src/summaryHelpers.js | 23 ++++++++++++++++++----- 2 files changed, 27 insertions(+), 5 deletions(-) diff --git a/helpers/stringTransforms.js b/helpers/stringTransforms.js index 18308387c..cb98598fd 100644 --- a/helpers/stringTransforms.js +++ b/helpers/stringTransforms.js @@ -458,3 +458,12 @@ export function truncateString(str: string, length: number, from: string, splitO return str1 + ellipsisStr } } + +/** + * Remove text between () inclusive + * @param {string} str + * @returns {string} + */ +export function removeTextBetweenParentheses(str: string): string { + return str.replace(/\(.*?\)/g, '') +} \ No newline at end of file diff --git a/jgclark.Summaries/src/summaryHelpers.js b/jgclark.Summaries/src/summaryHelpers.js index 274d4978e..12d7b3efb 100644 --- a/jgclark.Summaries/src/summaryHelpers.js +++ b/jgclark.Summaries/src/summaryHelpers.js @@ -30,7 +30,11 @@ import { isHashtagWanted, isMentionWanted, } from '@helpers/search' -import { truncateString } from '@helpers/stringTransforms' +import { + removeTextBetweenParentheses, + truncateString, +} from '@helpers/stringTransforms' +import NPTemplating from 'NPTemplating' //------------------------------------------------------------------------------ // Get settings @@ -720,10 +724,19 @@ export async function generateProgressUpdate(occObjs: Array, peri const daysBetween = toDateMom.diff(fromDateMom, 'days') // Include sparklines only if this period is a month or less const showSparklines = (requestToShowSparklines && daysBetween <= 31) - if (showSparklines) { - // Truncate lines to avoid line wrapping - occObjs.forEach((m) => m.term = truncateString(m.term, 60, 'middle')) - } + + await occObjs.forEach(async (m) => { + if (m.term.includes('<%') && m.term.includes('%>')) { + m.term = await NPTemplating.render(m.term) + logError('generateProgressUpdate', `rendered term: ${m.term}`) + } + if (showSparklines) { + m.term = truncateString(removeTextBetweenParentheses(m.term), 60, 'middle') + } + }) + + logError('generateProgressUpdate', `this should be after the await`) + // Get length of longest progress term (to use with sparklines) const maxTermLen = Math.max(...occObjs.map((m) => m.term.length))