Action
KPIs (you get what you practice)
UPDATES
almost 3 years ago
Bug fix and minor cosmetic adjustments
Requires Matt Gemmell’s MGCheckListPrompt action. https://actions.getdrafts.com/g/10X
A basic habit tracker. Searches your drafts for keywords and phrases surrounded by @(…) syntax and displays a log of the most recent instances of those keywords/phrases with a flag of how long ago they were last logged.
Steps
-
includeAction
name MGCheckListPrompt Library
-
script
// FUNCTIONS // escape characters for regex function escapeRegex(string) { return string.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); } // relative time formatting: https://stackoverflow.com/a/37802747 function timeDifference(previous) { var prefix = "Logged " var suffix = "" var output = "" var current = new Date() var msPerMinute = 60 * 1000; var msPerHour = msPerMinute * 60; var msPerDay = msPerHour * 24; var msPerMonth = msPerDay * 30; var msPerYear = msPerDay * 365; var elapsed = current - previous; if (elapsed < msPerMinute || elapsed < msPerHour || elapsed < msPerDay) { output = 'within the last 24 hours'; } else if (elapsed < msPerMonth) { if (Math.round(elapsed/msPerDay)==1) { output = 'yesterday'; } else { output = '~' + Math.round(elapsed/msPerDay) + ' days ago'; } } else if (elapsed < msPerYear) { if (Math.round(elapsed/msPerMonth)==1) { output = 'last month'; } else { output = '~' + Math.round(elapsed/msPerMonth) + ' months ago'; } } else { if (Math.round(elapsed/msPerYear)==1) { output = 'last year'; } else { output = '~' + Math.round(elapsed/msPerYear) + ' years ago'; } } return prefix + output + suffix } // sort the array function compare(a, b) { const varA = a.forSort; const varB = b.forSort; let comparison = 0; if (varA > varB) { comparison = -1; } else if (varA < varB) { comparison = 1; } return comparison; }
-
script
var ignoreResultsTaggedWith = "filter output" var fullDraftsAsContext = false var searchScope = "inbox" // Options: "inbox", "archive", "flagged", "trash","all". var modOrCreated = "created" // Options: "modified", "created" var mocProp = modOrCreated + "At" var i = 0; var instances = [] var myTitle = "" var myInfo = "" var searchStr = "@(" var searchReg = /@\(.+?\)/g var queries = "" let drafts = Draft.query(searchStr, searchScope,[],[ignoreResultsTaggedWith],modOrCreated,false) while(drafts[i]){ hits = drafts[i].lines.filter(element => element.match(searchReg) ) var n=0 while(hits[n]){ descr = hits[n] // let separator = drafts[i].tags.join() == "" ? "" : " | " let regex = /(\B#(\d*[A-Za-z_-]+\w*)\b(?!;))/g let inlineTags = regex.test(drafts[i].content) ? drafts[i].content.match(regex).filter((v, i, a) => a.indexOf(v) === i).join(", ") + ", " : "" myInfo = "**" + timeDifference(drafts[i][mocProp]) + "** " + inlineTags + drafts[i].tags.join(", ") // + separator var j=0 mlHits = hits[n].match(searchReg) while(mlHits[j]){ instances.push({ title: mlHits[j].replace("@(","").replace(")",""), description: descr.replace(/\t/g,""), info: myInfo, metadata: hits[n], uuid: drafts[i].uuid, forSort: drafts[i].createdAt.toISOString().substring(0,10) }); j++ } n++; } i++; } var newArray = []; let uniqueObject = {}; for (let i in instances) { // Loop for the array elements objTitle = instances[i]['title']; // Extract the title uniqueObject[objTitle] = instances[i] // Use the title as the index } for (i in uniqueObject) { // Loop to push unique object into array newArray.push(uniqueObject[i]); } newArray.sort(compare); // Create an MGCheckListPrompt. var prompt = new MGCheckListPrompt(); prompt.message = "Query: " + searchStr; prompt.addItems(newArray) prompt.allowsTypeToFilter = true prompt.singleSelectionMode = true prompt.selectsImmediately = true prompt.processMarkdown = true prompt.includedContent = ` <style> .item-description { font-size: 90%; display: inline; } .item-info { font-size: 70%; display: inline; } </style> ` // Show the prompt. var selectedItems = prompt.show(); // Report the result. if (prompt.didShow) { if (selectedItems != null) { source = Draft.find(newArray[selectedItems[0]].uuid); editor.load(source) fullText = editor.getText() anchor = newArray[selectedItems[0]].metadata pos = fullText.indexOf(anchor) // find position of selected line // pos = fullText.search("/"+ escapeRegex(anchor) +"/i") pos = fullText.indexOf(newArray[selectedItems[0]].title, pos) // this to select the search term editor.setSelectedRange(pos,newArray[selectedItems[0]].title.length) // anchor.length or searchStr.length, to select search term editor.activate(); } else { } } else { app.displayErrorMessage("Looks like your query returned no results."); context.cancel() }
Options
-
After Success Nothing Notification None Log Level None
Items available in the Drafts Directory are uploaded by community members. Use appropriate caution reviewing downloaded items before use.