main.js
1 "use strict"; 2 var __create = Object.create; 3 var __defProp = Object.defineProperty; 4 var __getOwnPropDesc = Object.getOwnPropertyDescriptor; 5 var __getOwnPropNames = Object.getOwnPropertyNames; 6 var __getProtoOf = Object.getPrototypeOf; 7 var __hasOwnProp = Object.prototype.hasOwnProperty; 8 var __commonJS = (cb, mod) => function __require() { 9 return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports; 10 }; 11 var __export = (target, all) => { 12 for (var name in all) 13 __defProp(target, name, { get: all[name], enumerable: true }); 14 }; 15 var __copyProps = (to, from, except, desc) => { 16 if (from && typeof from === "object" || typeof from === "function") { 17 for (let key of __getOwnPropNames(from)) 18 if (!__hasOwnProp.call(to, key) && key !== except) 19 __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); 20 } 21 return to; 22 }; 23 var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( 24 // If the importer is in node compatibility mode or this is not an ESM 25 // file that has been converted to a CommonJS file using a Babel- 26 // compatible transform (i.e. "__esModule" has not been set), then set 27 // "default" to the CommonJS "module.exports" for node compatibility. 28 isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, 29 mod 30 )); 31 var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); 32 33 // node_modules/obsidian-daily-notes-interface/dist/main.js 34 var require_main = __commonJS({ 35 "node_modules/obsidian-daily-notes-interface/dist/main.js"(exports) { 36 "use strict"; 37 Object.defineProperty(exports, "__esModule", { value: true }); 38 var obsidian = require("obsidian"); 39 var DEFAULT_DAILY_NOTE_FORMAT = "YYYY-MM-DD"; 40 var DEFAULT_WEEKLY_NOTE_FORMAT = "gggg-[W]ww"; 41 var DEFAULT_MONTHLY_NOTE_FORMAT = "YYYY-MM"; 42 var DEFAULT_QUARTERLY_NOTE_FORMAT = "YYYY-[Q]Q"; 43 var DEFAULT_YEARLY_NOTE_FORMAT = "YYYY"; 44 function shouldUsePeriodicNotesSettings(periodicity) { 45 var _a, _b; 46 const periodicNotes = window.app.plugins.getPlugin("periodic-notes"); 47 return periodicNotes && ((_b = (_a = periodicNotes.settings) == null ? void 0 : _a[periodicity]) == null ? void 0 : _b.enabled); 48 } 49 function getDailyNoteSettings2() { 50 var _a, _b, _c, _d; 51 try { 52 const { internalPlugins, plugins } = window.app; 53 if (shouldUsePeriodicNotesSettings("daily")) { 54 const { format: format2, folder: folder2, template: template2 } = ((_b = (_a = plugins.getPlugin("periodic-notes")) == null ? void 0 : _a.settings) == null ? void 0 : _b.daily) || {}; 55 return { 56 format: format2 || DEFAULT_DAILY_NOTE_FORMAT, 57 folder: (folder2 == null ? void 0 : folder2.trim()) || "", 58 template: (template2 == null ? void 0 : template2.trim()) || "" 59 }; 60 } 61 const { folder, format, template } = ((_d = (_c = internalPlugins.getPluginById("daily-notes")) == null ? void 0 : _c.instance) == null ? void 0 : _d.options) || {}; 62 return { 63 format: format || DEFAULT_DAILY_NOTE_FORMAT, 64 folder: (folder == null ? void 0 : folder.trim()) || "", 65 template: (template == null ? void 0 : template.trim()) || "" 66 }; 67 } catch (err) { 68 console.info("No custom daily note settings found!", err); 69 } 70 } 71 function getWeeklyNoteSettings() { 72 var _a, _b, _c, _d, _e, _f, _g; 73 try { 74 const pluginManager = window.app.plugins; 75 const calendarSettings = (_a = pluginManager.getPlugin("calendar")) == null ? void 0 : _a.options; 76 const periodicNotesSettings = (_c = (_b = pluginManager.getPlugin("periodic-notes")) == null ? void 0 : _b.settings) == null ? void 0 : _c.weekly; 77 if (shouldUsePeriodicNotesSettings("weekly")) { 78 return { 79 format: periodicNotesSettings.format || DEFAULT_WEEKLY_NOTE_FORMAT, 80 folder: ((_d = periodicNotesSettings.folder) == null ? void 0 : _d.trim()) || "", 81 template: ((_e = periodicNotesSettings.template) == null ? void 0 : _e.trim()) || "" 82 }; 83 } 84 const settings = calendarSettings || {}; 85 return { 86 format: settings.weeklyNoteFormat || DEFAULT_WEEKLY_NOTE_FORMAT, 87 folder: ((_f = settings.weeklyNoteFolder) == null ? void 0 : _f.trim()) || "", 88 template: ((_g = settings.weeklyNoteTemplate) == null ? void 0 : _g.trim()) || "" 89 }; 90 } catch (err) { 91 console.info("No custom weekly note settings found!", err); 92 } 93 } 94 function getMonthlyNoteSettings() { 95 var _a, _b, _c, _d; 96 const pluginManager = window.app.plugins; 97 try { 98 const settings = shouldUsePeriodicNotesSettings("monthly") && ((_b = (_a = pluginManager.getPlugin("periodic-notes")) == null ? void 0 : _a.settings) == null ? void 0 : _b.monthly) || {}; 99 return { 100 format: settings.format || DEFAULT_MONTHLY_NOTE_FORMAT, 101 folder: ((_c = settings.folder) == null ? void 0 : _c.trim()) || "", 102 template: ((_d = settings.template) == null ? void 0 : _d.trim()) || "" 103 }; 104 } catch (err) { 105 console.info("No custom monthly note settings found!", err); 106 } 107 } 108 function getQuarterlyNoteSettings() { 109 var _a, _b, _c, _d; 110 const pluginManager = window.app.plugins; 111 try { 112 const settings = shouldUsePeriodicNotesSettings("quarterly") && ((_b = (_a = pluginManager.getPlugin("periodic-notes")) == null ? void 0 : _a.settings) == null ? void 0 : _b.quarterly) || {}; 113 return { 114 format: settings.format || DEFAULT_QUARTERLY_NOTE_FORMAT, 115 folder: ((_c = settings.folder) == null ? void 0 : _c.trim()) || "", 116 template: ((_d = settings.template) == null ? void 0 : _d.trim()) || "" 117 }; 118 } catch (err) { 119 console.info("No custom quarterly note settings found!", err); 120 } 121 } 122 function getYearlyNoteSettings() { 123 var _a, _b, _c, _d; 124 const pluginManager = window.app.plugins; 125 try { 126 const settings = shouldUsePeriodicNotesSettings("yearly") && ((_b = (_a = pluginManager.getPlugin("periodic-notes")) == null ? void 0 : _a.settings) == null ? void 0 : _b.yearly) || {}; 127 return { 128 format: settings.format || DEFAULT_YEARLY_NOTE_FORMAT, 129 folder: ((_c = settings.folder) == null ? void 0 : _c.trim()) || "", 130 template: ((_d = settings.template) == null ? void 0 : _d.trim()) || "" 131 }; 132 } catch (err) { 133 console.info("No custom yearly note settings found!", err); 134 } 135 } 136 function join(...partSegments) { 137 let parts = []; 138 for (let i = 0, l = partSegments.length; i < l; i++) { 139 parts = parts.concat(partSegments[i].split("/")); 140 } 141 const newParts = []; 142 for (let i = 0, l = parts.length; i < l; i++) { 143 const part = parts[i]; 144 if (!part || part === ".") 145 continue; 146 else 147 newParts.push(part); 148 } 149 if (parts[0] === "") 150 newParts.unshift(""); 151 return newParts.join("/"); 152 } 153 function basename(fullPath) { 154 let base = fullPath.substring(fullPath.lastIndexOf("/") + 1); 155 if (base.lastIndexOf(".") != -1) 156 base = base.substring(0, base.lastIndexOf(".")); 157 return base; 158 } 159 async function ensureFolderExists(path) { 160 const dirs = path.replace(/\\/g, "/").split("/"); 161 dirs.pop(); 162 if (dirs.length) { 163 const dir = join(...dirs); 164 if (!window.app.vault.getAbstractFileByPath(dir)) { 165 await window.app.vault.createFolder(dir); 166 } 167 } 168 } 169 async function getNotePath(directory, filename) { 170 if (!filename.endsWith(".md")) { 171 filename += ".md"; 172 } 173 const path = obsidian.normalizePath(join(directory, filename)); 174 await ensureFolderExists(path); 175 return path; 176 } 177 async function getTemplateInfo(template) { 178 const { metadataCache, vault } = window.app; 179 const templatePath = obsidian.normalizePath(template); 180 if (templatePath === "/") { 181 return Promise.resolve(["", null]); 182 } 183 try { 184 const templateFile = metadataCache.getFirstLinkpathDest(templatePath, ""); 185 const contents = await vault.cachedRead(templateFile); 186 const IFoldInfo = window.app.foldManager.load(templateFile); 187 return [contents, IFoldInfo]; 188 } catch (err) { 189 console.error(`Failed to read the daily note template '${templatePath}'`, err); 190 new obsidian.Notice("Failed to read the daily note template"); 191 return ["", null]; 192 } 193 } 194 function getDateUID(date, granularity = "day") { 195 const ts = date.clone().startOf(granularity).format(); 196 return `${granularity}-${ts}`; 197 } 198 function removeEscapedCharacters(format) { 199 return format.replace(/\[[^\]]*\]/g, ""); 200 } 201 function isFormatAmbiguous(format, granularity) { 202 if (granularity === "week") { 203 const cleanFormat = removeEscapedCharacters(format); 204 return /w{1,2}/i.test(cleanFormat) && (/M{1,4}/.test(cleanFormat) || /D{1,4}/.test(cleanFormat)); 205 } 206 return false; 207 } 208 function getDateFromFile(file, granularity) { 209 return getDateFromFilename(file.basename, granularity); 210 } 211 function getDateFromPath(path, granularity) { 212 return getDateFromFilename(basename(path), granularity); 213 } 214 function getDateFromFilename(filename, granularity) { 215 const getSettings = { 216 day: getDailyNoteSettings2, 217 week: getWeeklyNoteSettings, 218 month: getMonthlyNoteSettings, 219 quarter: getQuarterlyNoteSettings, 220 year: getYearlyNoteSettings 221 }; 222 const format = getSettings[granularity]().format.split("/").pop(); 223 const noteDate = window.moment(filename, format, true); 224 if (!noteDate.isValid()) { 225 return null; 226 } 227 if (isFormatAmbiguous(format, granularity)) { 228 if (granularity === "week") { 229 const cleanFormat = removeEscapedCharacters(format); 230 if (/w{1,2}/i.test(cleanFormat)) { 231 return window.moment( 232 filename, 233 // If format contains week, remove day & month formatting 234 format.replace(/M{1,4}/g, "").replace(/D{1,4}/g, ""), 235 false 236 ); 237 } 238 } 239 } 240 return noteDate; 241 } 242 var DailyNotesFolderMissingError = class extends Error { 243 }; 244 async function createDailyNote(date) { 245 const app = window.app; 246 const { vault } = app; 247 const moment2 = window.moment; 248 const { template, format, folder } = getDailyNoteSettings2(); 249 const [templateContents, IFoldInfo] = await getTemplateInfo(template); 250 const filename = date.format(format); 251 const normalizedPath = await getNotePath(folder, filename); 252 try { 253 const createdFile = await vault.create(normalizedPath, templateContents.replace(/{{\s*date\s*}}/gi, filename).replace(/{{\s*time\s*}}/gi, moment2().format("HH:mm")).replace(/{{\s*title\s*}}/gi, filename).replace(/{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => { 254 const now = moment2(); 255 const currentDate = date.clone().set({ 256 hour: now.get("hour"), 257 minute: now.get("minute"), 258 second: now.get("second") 259 }); 260 if (calc) { 261 currentDate.add(parseInt(timeDelta, 10), unit); 262 } 263 if (momentFormat) { 264 return currentDate.format(momentFormat.substring(1).trim()); 265 } 266 return currentDate.format(format); 267 }).replace(/{{\s*yesterday\s*}}/gi, date.clone().subtract(1, "day").format(format)).replace(/{{\s*tomorrow\s*}}/gi, date.clone().add(1, "d").format(format))); 268 app.foldManager.save(createdFile, IFoldInfo); 269 return createdFile; 270 } catch (err) { 271 console.error(`Failed to create file: '${normalizedPath}'`, err); 272 new obsidian.Notice("Unable to create new file."); 273 } 274 } 275 function getDailyNote(date, dailyNotes) { 276 var _a; 277 return (_a = dailyNotes[getDateUID(date, "day")]) != null ? _a : null; 278 } 279 function getAllDailyNotes() { 280 const { vault } = window.app; 281 const { folder } = getDailyNoteSettings2(); 282 const dailyNotesFolder = vault.getAbstractFileByPath(obsidian.normalizePath(folder)); 283 if (!dailyNotesFolder) { 284 throw new DailyNotesFolderMissingError("Failed to find daily notes folder"); 285 } 286 const dailyNotes = {}; 287 obsidian.Vault.recurseChildren(dailyNotesFolder, (note) => { 288 if (note instanceof obsidian.TFile) { 289 const date = getDateFromFile(note, "day"); 290 if (date) { 291 const dateString = getDateUID(date, "day"); 292 dailyNotes[dateString] = note; 293 } 294 } 295 }); 296 return dailyNotes; 297 } 298 var WeeklyNotesFolderMissingError = class extends Error { 299 }; 300 function getDaysOfWeek() { 301 const { moment: moment2 } = window; 302 let weekStart = moment2.localeData()._week.dow; 303 const daysOfWeek = [ 304 "sunday", 305 "monday", 306 "tuesday", 307 "wednesday", 308 "thursday", 309 "friday", 310 "saturday" 311 ]; 312 while (weekStart) { 313 daysOfWeek.push(daysOfWeek.shift()); 314 weekStart--; 315 } 316 return daysOfWeek; 317 } 318 function getDayOfWeekNumericalValue(dayOfWeekName) { 319 return getDaysOfWeek().indexOf(dayOfWeekName.toLowerCase()); 320 } 321 async function createWeeklyNote(date) { 322 const { vault } = window.app; 323 const { template, format, folder } = getWeeklyNoteSettings(); 324 const [templateContents, IFoldInfo] = await getTemplateInfo(template); 325 const filename = date.format(format); 326 const normalizedPath = await getNotePath(folder, filename); 327 try { 328 const createdFile = await vault.create(normalizedPath, templateContents.replace(/{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => { 329 const now = window.moment(); 330 const currentDate = date.clone().set({ 331 hour: now.get("hour"), 332 minute: now.get("minute"), 333 second: now.get("second") 334 }); 335 if (calc) { 336 currentDate.add(parseInt(timeDelta, 10), unit); 337 } 338 if (momentFormat) { 339 return currentDate.format(momentFormat.substring(1).trim()); 340 } 341 return currentDate.format(format); 342 }).replace(/{{\s*title\s*}}/gi, filename).replace(/{{\s*time\s*}}/gi, window.moment().format("HH:mm")).replace(/{{\s*(sunday|monday|tuesday|wednesday|thursday|friday|saturday)\s*:(.*?)}}/gi, (_, dayOfWeek, momentFormat) => { 343 const day = getDayOfWeekNumericalValue(dayOfWeek); 344 return date.weekday(day).format(momentFormat.trim()); 345 })); 346 window.app.foldManager.save(createdFile, IFoldInfo); 347 return createdFile; 348 } catch (err) { 349 console.error(`Failed to create file: '${normalizedPath}'`, err); 350 new obsidian.Notice("Unable to create new file."); 351 } 352 } 353 function getWeeklyNote(date, weeklyNotes) { 354 var _a; 355 return (_a = weeklyNotes[getDateUID(date, "week")]) != null ? _a : null; 356 } 357 function getAllWeeklyNotes() { 358 const weeklyNotes = {}; 359 if (!appHasWeeklyNotesPluginLoaded()) { 360 return weeklyNotes; 361 } 362 const { vault } = window.app; 363 const { folder } = getWeeklyNoteSettings(); 364 const weeklyNotesFolder = vault.getAbstractFileByPath(obsidian.normalizePath(folder)); 365 if (!weeklyNotesFolder) { 366 throw new WeeklyNotesFolderMissingError("Failed to find weekly notes folder"); 367 } 368 obsidian.Vault.recurseChildren(weeklyNotesFolder, (note) => { 369 if (note instanceof obsidian.TFile) { 370 const date = getDateFromFile(note, "week"); 371 if (date) { 372 const dateString = getDateUID(date, "week"); 373 weeklyNotes[dateString] = note; 374 } 375 } 376 }); 377 return weeklyNotes; 378 } 379 var MonthlyNotesFolderMissingError = class extends Error { 380 }; 381 async function createMonthlyNote(date) { 382 const { vault } = window.app; 383 const { template, format, folder } = getMonthlyNoteSettings(); 384 const [templateContents, IFoldInfo] = await getTemplateInfo(template); 385 const filename = date.format(format); 386 const normalizedPath = await getNotePath(folder, filename); 387 try { 388 const createdFile = await vault.create(normalizedPath, templateContents.replace(/{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => { 389 const now = window.moment(); 390 const currentDate = date.clone().set({ 391 hour: now.get("hour"), 392 minute: now.get("minute"), 393 second: now.get("second") 394 }); 395 if (calc) { 396 currentDate.add(parseInt(timeDelta, 10), unit); 397 } 398 if (momentFormat) { 399 return currentDate.format(momentFormat.substring(1).trim()); 400 } 401 return currentDate.format(format); 402 }).replace(/{{\s*date\s*}}/gi, filename).replace(/{{\s*time\s*}}/gi, window.moment().format("HH:mm")).replace(/{{\s*title\s*}}/gi, filename)); 403 window.app.foldManager.save(createdFile, IFoldInfo); 404 return createdFile; 405 } catch (err) { 406 console.error(`Failed to create file: '${normalizedPath}'`, err); 407 new obsidian.Notice("Unable to create new file."); 408 } 409 } 410 function getMonthlyNote(date, monthlyNotes) { 411 var _a; 412 return (_a = monthlyNotes[getDateUID(date, "month")]) != null ? _a : null; 413 } 414 function getAllMonthlyNotes() { 415 const monthlyNotes = {}; 416 if (!appHasMonthlyNotesPluginLoaded()) { 417 return monthlyNotes; 418 } 419 const { vault } = window.app; 420 const { folder } = getMonthlyNoteSettings(); 421 const monthlyNotesFolder = vault.getAbstractFileByPath(obsidian.normalizePath(folder)); 422 if (!monthlyNotesFolder) { 423 throw new MonthlyNotesFolderMissingError("Failed to find monthly notes folder"); 424 } 425 obsidian.Vault.recurseChildren(monthlyNotesFolder, (note) => { 426 if (note instanceof obsidian.TFile) { 427 const date = getDateFromFile(note, "month"); 428 if (date) { 429 const dateString = getDateUID(date, "month"); 430 monthlyNotes[dateString] = note; 431 } 432 } 433 }); 434 return monthlyNotes; 435 } 436 var QuarterlyNotesFolderMissingError = class extends Error { 437 }; 438 async function createQuarterlyNote(date) { 439 const { vault } = window.app; 440 const { template, format, folder } = getQuarterlyNoteSettings(); 441 const [templateContents, IFoldInfo] = await getTemplateInfo(template); 442 const filename = date.format(format); 443 const normalizedPath = await getNotePath(folder, filename); 444 try { 445 const createdFile = await vault.create(normalizedPath, templateContents.replace(/{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => { 446 const now = window.moment(); 447 const currentDate = date.clone().set({ 448 hour: now.get("hour"), 449 minute: now.get("minute"), 450 second: now.get("second") 451 }); 452 if (calc) { 453 currentDate.add(parseInt(timeDelta, 10), unit); 454 } 455 if (momentFormat) { 456 return currentDate.format(momentFormat.substring(1).trim()); 457 } 458 return currentDate.format(format); 459 }).replace(/{{\s*date\s*}}/gi, filename).replace(/{{\s*time\s*}}/gi, window.moment().format("HH:mm")).replace(/{{\s*title\s*}}/gi, filename)); 460 window.app.foldManager.save(createdFile, IFoldInfo); 461 return createdFile; 462 } catch (err) { 463 console.error(`Failed to create file: '${normalizedPath}'`, err); 464 new obsidian.Notice("Unable to create new file."); 465 } 466 } 467 function getQuarterlyNote(date, quarterly) { 468 var _a; 469 return (_a = quarterly[getDateUID(date, "quarter")]) != null ? _a : null; 470 } 471 function getAllQuarterlyNotes() { 472 const quarterly = {}; 473 if (!appHasQuarterlyNotesPluginLoaded()) { 474 return quarterly; 475 } 476 const { vault } = window.app; 477 const { folder } = getQuarterlyNoteSettings(); 478 const quarterlyFolder = vault.getAbstractFileByPath(obsidian.normalizePath(folder)); 479 if (!quarterlyFolder) { 480 throw new QuarterlyNotesFolderMissingError("Failed to find quarterly notes folder"); 481 } 482 obsidian.Vault.recurseChildren(quarterlyFolder, (note) => { 483 if (note instanceof obsidian.TFile) { 484 const date = getDateFromFile(note, "quarter"); 485 if (date) { 486 const dateString = getDateUID(date, "quarter"); 487 quarterly[dateString] = note; 488 } 489 } 490 }); 491 return quarterly; 492 } 493 var YearlyNotesFolderMissingError = class extends Error { 494 }; 495 async function createYearlyNote(date) { 496 const { vault } = window.app; 497 const { template, format, folder } = getYearlyNoteSettings(); 498 const [templateContents, IFoldInfo] = await getTemplateInfo(template); 499 const filename = date.format(format); 500 const normalizedPath = await getNotePath(folder, filename); 501 try { 502 const createdFile = await vault.create(normalizedPath, templateContents.replace(/{{\s*(date|time)\s*(([+-]\d+)([yqmwdhs]))?\s*(:.+?)?}}/gi, (_, _timeOrDate, calc, timeDelta, unit, momentFormat) => { 503 const now = window.moment(); 504 const currentDate = date.clone().set({ 505 hour: now.get("hour"), 506 minute: now.get("minute"), 507 second: now.get("second") 508 }); 509 if (calc) { 510 currentDate.add(parseInt(timeDelta, 10), unit); 511 } 512 if (momentFormat) { 513 return currentDate.format(momentFormat.substring(1).trim()); 514 } 515 return currentDate.format(format); 516 }).replace(/{{\s*date\s*}}/gi, filename).replace(/{{\s*time\s*}}/gi, window.moment().format("HH:mm")).replace(/{{\s*title\s*}}/gi, filename)); 517 window.app.foldManager.save(createdFile, IFoldInfo); 518 return createdFile; 519 } catch (err) { 520 console.error(`Failed to create file: '${normalizedPath}'`, err); 521 new obsidian.Notice("Unable to create new file."); 522 } 523 } 524 function getYearlyNote(date, yearlyNotes) { 525 var _a; 526 return (_a = yearlyNotes[getDateUID(date, "year")]) != null ? _a : null; 527 } 528 function getAllYearlyNotes() { 529 const yearlyNotes = {}; 530 if (!appHasYearlyNotesPluginLoaded()) { 531 return yearlyNotes; 532 } 533 const { vault } = window.app; 534 const { folder } = getYearlyNoteSettings(); 535 const yearlyNotesFolder = vault.getAbstractFileByPath(obsidian.normalizePath(folder)); 536 if (!yearlyNotesFolder) { 537 throw new YearlyNotesFolderMissingError("Failed to find yearly notes folder"); 538 } 539 obsidian.Vault.recurseChildren(yearlyNotesFolder, (note) => { 540 if (note instanceof obsidian.TFile) { 541 const date = getDateFromFile(note, "year"); 542 if (date) { 543 const dateString = getDateUID(date, "year"); 544 yearlyNotes[dateString] = note; 545 } 546 } 547 }); 548 return yearlyNotes; 549 } 550 function appHasDailyNotesPluginLoaded() { 551 var _a, _b; 552 const { app } = window; 553 const dailyNotesPlugin = app.internalPlugins.plugins["daily-notes"]; 554 if (dailyNotesPlugin && dailyNotesPlugin.enabled) { 555 return true; 556 } 557 const periodicNotes = app.plugins.getPlugin("periodic-notes"); 558 return periodicNotes && ((_b = (_a = periodicNotes.settings) == null ? void 0 : _a.daily) == null ? void 0 : _b.enabled); 559 } 560 function appHasWeeklyNotesPluginLoaded() { 561 var _a, _b; 562 const { app } = window; 563 if (app.plugins.getPlugin("calendar")) { 564 return true; 565 } 566 const periodicNotes = app.plugins.getPlugin("periodic-notes"); 567 return periodicNotes && ((_b = (_a = periodicNotes.settings) == null ? void 0 : _a.weekly) == null ? void 0 : _b.enabled); 568 } 569 function appHasMonthlyNotesPluginLoaded() { 570 var _a, _b; 571 const { app } = window; 572 const periodicNotes = app.plugins.getPlugin("periodic-notes"); 573 return periodicNotes && ((_b = (_a = periodicNotes.settings) == null ? void 0 : _a.monthly) == null ? void 0 : _b.enabled); 574 } 575 function appHasQuarterlyNotesPluginLoaded() { 576 var _a, _b; 577 const { app } = window; 578 const periodicNotes = app.plugins.getPlugin("periodic-notes"); 579 return periodicNotes && ((_b = (_a = periodicNotes.settings) == null ? void 0 : _a.quarterly) == null ? void 0 : _b.enabled); 580 } 581 function appHasYearlyNotesPluginLoaded() { 582 var _a, _b; 583 const { app } = window; 584 const periodicNotes = app.plugins.getPlugin("periodic-notes"); 585 return periodicNotes && ((_b = (_a = periodicNotes.settings) == null ? void 0 : _a.yearly) == null ? void 0 : _b.enabled); 586 } 587 function getPeriodicNoteSettings(granularity) { 588 const getSettings = { 589 day: getDailyNoteSettings2, 590 week: getWeeklyNoteSettings, 591 month: getMonthlyNoteSettings, 592 quarter: getQuarterlyNoteSettings, 593 year: getYearlyNoteSettings 594 }[granularity]; 595 return getSettings(); 596 } 597 function createPeriodicNote(granularity, date) { 598 const createFn = { 599 day: createDailyNote, 600 month: createMonthlyNote, 601 week: createWeeklyNote 602 }; 603 return createFn[granularity](date); 604 } 605 exports.DEFAULT_DAILY_NOTE_FORMAT = DEFAULT_DAILY_NOTE_FORMAT; 606 exports.DEFAULT_MONTHLY_NOTE_FORMAT = DEFAULT_MONTHLY_NOTE_FORMAT; 607 exports.DEFAULT_QUARTERLY_NOTE_FORMAT = DEFAULT_QUARTERLY_NOTE_FORMAT; 608 exports.DEFAULT_WEEKLY_NOTE_FORMAT = DEFAULT_WEEKLY_NOTE_FORMAT; 609 exports.DEFAULT_YEARLY_NOTE_FORMAT = DEFAULT_YEARLY_NOTE_FORMAT; 610 exports.appHasDailyNotesPluginLoaded = appHasDailyNotesPluginLoaded; 611 exports.appHasMonthlyNotesPluginLoaded = appHasMonthlyNotesPluginLoaded; 612 exports.appHasQuarterlyNotesPluginLoaded = appHasQuarterlyNotesPluginLoaded; 613 exports.appHasWeeklyNotesPluginLoaded = appHasWeeklyNotesPluginLoaded; 614 exports.appHasYearlyNotesPluginLoaded = appHasYearlyNotesPluginLoaded; 615 exports.createDailyNote = createDailyNote; 616 exports.createMonthlyNote = createMonthlyNote; 617 exports.createPeriodicNote = createPeriodicNote; 618 exports.createQuarterlyNote = createQuarterlyNote; 619 exports.createWeeklyNote = createWeeklyNote; 620 exports.createYearlyNote = createYearlyNote; 621 exports.getAllDailyNotes = getAllDailyNotes; 622 exports.getAllMonthlyNotes = getAllMonthlyNotes; 623 exports.getAllQuarterlyNotes = getAllQuarterlyNotes; 624 exports.getAllWeeklyNotes = getAllWeeklyNotes; 625 exports.getAllYearlyNotes = getAllYearlyNotes; 626 exports.getDailyNote = getDailyNote; 627 exports.getDailyNoteSettings = getDailyNoteSettings2; 628 exports.getDateFromFile = getDateFromFile; 629 exports.getDateFromPath = getDateFromPath; 630 exports.getDateUID = getDateUID; 631 exports.getMonthlyNote = getMonthlyNote; 632 exports.getMonthlyNoteSettings = getMonthlyNoteSettings; 633 exports.getPeriodicNoteSettings = getPeriodicNoteSettings; 634 exports.getQuarterlyNote = getQuarterlyNote; 635 exports.getQuarterlyNoteSettings = getQuarterlyNoteSettings; 636 exports.getTemplateInfo = getTemplateInfo; 637 exports.getWeeklyNote = getWeeklyNote; 638 exports.getWeeklyNoteSettings = getWeeklyNoteSettings; 639 exports.getYearlyNote = getYearlyNote; 640 exports.getYearlyNoteSettings = getYearlyNoteSettings; 641 } 642 }); 643 644 // src/main.ts 645 var main_exports = {}; 646 __export(main_exports, { 647 default: () => ThePlugin 648 }); 649 module.exports = __toCommonJS(main_exports); 650 var import_obsidian11 = require("obsidian"); 651 652 // src/ui/SettingsTab.ts 653 var import_obsidian5 = require("obsidian"); 654 655 // src/features/themes.ts 656 var import_obsidian3 = require("obsidian"); 657 658 // src/features/githubUtils.ts 659 var import_obsidian = require("obsidian"); 660 var GITHUB_RAW_USERCONTENT_PATH = "https://raw.githubusercontent.com/"; 661 var isPrivateRepo = async (repository, debugLogging = true, personalAccessToken = "") => { 662 const URL2 = `https://api.github.com/repos/${repository}`; 663 try { 664 const response = await (0, import_obsidian.request)({ 665 url: URL2, 666 headers: personalAccessToken ? { 667 Authorization: `Token ${personalAccessToken}` 668 } : {} 669 }); 670 const data = await JSON.parse(response); 671 return data.private; 672 } catch (e) { 673 if (debugLogging) 674 console.log("error in isPrivateRepo", URL2, e); 675 return false; 676 } 677 }; 678 var grabReleaseFileFromRepository = async (repository, version, fileName, debugLogging = true, personalAccessToken = "") => { 679 try { 680 const isPrivate = await isPrivateRepo(repository, debugLogging, personalAccessToken); 681 if (isPrivate) { 682 const URL2 = `https://api.github.com/repos/${repository}/releases`; 683 const response = await (0, import_obsidian.request)({ 684 url: URL2, 685 headers: { 686 Authorization: `Token ${personalAccessToken}` 687 } 688 }); 689 const data = await JSON.parse(response); 690 const release = data.find((release2) => release2.tag_name === version); 691 if (!release) { 692 return null; 693 } 694 const asset = release.assets.find( 695 (asset2) => asset2.name === fileName 696 ); 697 if (!asset) { 698 return null; 699 } 700 const download = await (0, import_obsidian.request)({ 701 url: asset.url, 702 headers: { 703 Authorization: `Token ${personalAccessToken}`, 704 Accept: "application/octet-stream" 705 } 706 }); 707 return download === "Not Found" || download === `{"error":"Not Found"}` ? null : download; 708 } else { 709 const URL2 = `https://github.com/${repository}/releases/download/${version}/${fileName}`; 710 const download = await (0, import_obsidian.request)({ 711 url: URL2, 712 headers: personalAccessToken ? { 713 Authorization: `Token ${personalAccessToken}` 714 } : {} 715 }); 716 return download === "Not Found" || download === `{"error":"Not Found"}` ? null : download; 717 } 718 } catch (error) { 719 if (debugLogging) 720 console.log("error in grabReleaseFileFromRepository", URL, error); 721 return null; 722 } 723 }; 724 var grabManifestJsonFromRepository = async (repositoryPath, rootManifest = true, debugLogging = true, personalAccessToken = "") => { 725 const manifestJsonPath = GITHUB_RAW_USERCONTENT_PATH + repositoryPath + (rootManifest ? "/HEAD/manifest.json" : "/HEAD/manifest-beta.json"); 726 if (debugLogging) 727 console.log("grabManifestJsonFromRepository manifestJsonPath", manifestJsonPath); 728 try { 729 const response = await (0, import_obsidian.request)({ 730 url: manifestJsonPath, 731 headers: personalAccessToken ? { 732 Authorization: `Token ${personalAccessToken}` 733 } : {} 734 }); 735 if (debugLogging) 736 console.log("grabManifestJsonFromRepository response", response); 737 return response === "404: Not Found" ? null : await JSON.parse(response); 738 } catch (error) { 739 if (error !== "Error: Request failed, status 404" && debugLogging) { 740 console.log( 741 `error in grabManifestJsonFromRepository for ${manifestJsonPath}`, 742 error 743 ); 744 } 745 return null; 746 } 747 }; 748 var grabCommmunityPluginList = async (debugLogging = true) => { 749 const pluginListUrl = `https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-plugins.json`; 750 try { 751 const response = await (0, import_obsidian.request)({ url: pluginListUrl }); 752 return response === "404: Not Found" ? null : await JSON.parse(response); 753 } catch (error) { 754 if (debugLogging) 755 console.log("error in grabCommmunityPluginList", error); 756 return null; 757 } 758 }; 759 var grabCommmunityThemesList = async (debugLogging = true) => { 760 const themesUrl = `https://raw.githubusercontent.com/obsidianmd/obsidian-releases/HEAD/community-css-themes.json`; 761 try { 762 const response = await (0, import_obsidian.request)({ url: themesUrl }); 763 return response === "404: Not Found" ? null : await JSON.parse(response); 764 } catch (error) { 765 if (debugLogging) 766 console.log("error in grabCommmunityThemesList", error); 767 return null; 768 } 769 }; 770 var grabCommmunityThemeCssFile = async (repositoryPath, betaVersion = false, debugLogging) => { 771 const themesUrl = `https://raw.githubusercontent.com/${repositoryPath}/HEAD/theme${betaVersion ? "-beta" : ""}.css`; 772 try { 773 const response = await (0, import_obsidian.request)({ url: themesUrl }); 774 return response === "404: Not Found" ? null : response; 775 } catch (error) { 776 if (debugLogging) 777 console.log("error in grabCommmunityThemeCssFile", error); 778 return null; 779 } 780 }; 781 var grabCommmunityThemeManifestFile = async (repositoryPath, debugLogging = true) => { 782 const themesUrl = `https://raw.githubusercontent.com/${repositoryPath}/HEAD/manifest.json`; 783 try { 784 const response = await (0, import_obsidian.request)({ url: themesUrl }); 785 return response === "404: Not Found" ? null : response; 786 } catch (error) { 787 if (debugLogging) 788 console.log("error in grabCommmunityThemeManifestFile", error); 789 return null; 790 } 791 }; 792 var checksum = (str) => { 793 let sum = 0; 794 for (let i = 0; i < str.length; i++) { 795 sum += str.charCodeAt(i); 796 } 797 return sum; 798 }; 799 var checksumForString = (str) => { 800 return checksum(str).toString(); 801 }; 802 var grabChecksumOfThemeCssFile = async (repositoryPath, betaVersion, debugLogging) => { 803 const themeCss = await grabCommmunityThemeCssFile( 804 repositoryPath, 805 betaVersion, 806 debugLogging 807 ); 808 return themeCss ? checksumForString(themeCss) : "0"; 809 }; 810 var grabLastCommitInfoForFile = async (repositoryPath, path, debugLogging = true) => { 811 const url = `https://api.github.com/repos/${repositoryPath}/commits?path=${path}&page=1&per_page=1`; 812 try { 813 const response = await (0, import_obsidian.request)({ url }); 814 return response === "404: Not Found" ? null : JSON.parse(response); 815 } catch (error) { 816 if (debugLogging) 817 console.log("error in grabLastCommitInfoForAFile", error); 818 return null; 819 } 820 }; 821 var grabLastCommitDateForFile = async (repositoryPath, path) => { 822 var _a; 823 const test = await grabLastCommitInfoForFile(repositoryPath, path); 824 if (test && test.length > 0 && ((_a = test[0].commit.committer) == null ? void 0 : _a.date)) { 825 return test[0].commit.committer.date; 826 } else { 827 return ""; 828 } 829 }; 830 831 // src/settings.ts 832 var DEFAULT_SETTINGS = { 833 pluginList: [], 834 pluginSubListFrozenVersion: [], 835 themesList: [], 836 updateAtStartup: true, 837 updateThemesAtStartup: true, 838 enableAfterInstall: true, 839 loggingEnabled: false, 840 loggingPath: "BRAT-log", 841 loggingVerboseEnabled: false, 842 debuggingMode: false, 843 notificationsEnabled: true, 844 personalAccessToken: "" 845 }; 846 function addBetaPluginToList(plugin, repositoryPath, specifyVersion = "") { 847 let save = false; 848 if (!plugin.settings.pluginList.contains(repositoryPath)) { 849 plugin.settings.pluginList.unshift(repositoryPath); 850 save = true; 851 } 852 if (specifyVersion !== "" && plugin.settings.pluginSubListFrozenVersion.filter((x) => x.repo === repositoryPath).length === 0) { 853 plugin.settings.pluginSubListFrozenVersion.unshift({ 854 repo: repositoryPath, 855 version: specifyVersion 856 }); 857 save = true; 858 } 859 if (save) { 860 void plugin.saveSettings(); 861 } 862 } 863 function existBetaPluginInList(plugin, repositoryPath) { 864 return plugin.settings.pluginList.contains(repositoryPath); 865 } 866 function addBetaThemeToList(plugin, repositoryPath, themeCss) { 867 const newTheme = { 868 repo: repositoryPath, 869 lastUpdate: checksumForString(themeCss) 870 }; 871 plugin.settings.themesList.unshift(newTheme); 872 void plugin.saveSettings(); 873 } 874 function existBetaThemeinInList(plugin, repositoryPath) { 875 const testIfThemExists = plugin.settings.themesList.find( 876 (t) => t.repo === repositoryPath 877 ); 878 return testIfThemExists ? true : false; 879 } 880 function updateBetaThemeLastUpdateChecksum(plugin, repositoryPath, checksum2) { 881 plugin.settings.themesList.forEach((t) => { 882 if (t.repo === repositoryPath) { 883 t.lastUpdate = checksum2; 884 void plugin.saveSettings(); 885 } 886 }); 887 } 888 889 // src/utils/notifications.ts 890 var import_obsidian2 = require("obsidian"); 891 function toastMessage(plugin, msg, timeoutInSeconds = 10, contextMenuCallback) { 892 if (!plugin.settings.notificationsEnabled) 893 return; 894 const additionalInfo = contextMenuCallback ? import_obsidian2.Platform.isDesktop ? "(click=dismiss, right-click=Info)" : "(click=dismiss)" : ""; 895 const newNotice = new import_obsidian2.Notice( 896 `BRAT 897 ${msg} 898 ${additionalInfo}`, 899 timeoutInSeconds * 1e3 900 ); 901 if (contextMenuCallback) 902 newNotice.noticeEl.oncontextmenu = () => { 903 contextMenuCallback(); 904 }; 905 } 906 907 // src/utils/internetconnection.ts 908 async function isConnectedToInternet() { 909 try { 910 const online = await fetch("https://obsidian.md/?" + Math.random()); 911 return online.status >= 200 && online.status < 300; 912 } catch (err) { 913 return false; 914 } 915 } 916 917 // src/features/themes.ts 918 var themeSave = async (plugin, cssGithubRepository, newInstall) => { 919 let themeCss = await grabCommmunityThemeCssFile( 920 cssGithubRepository, 921 true, 922 plugin.settings.debuggingMode 923 ); 924 if (!themeCss) 925 themeCss = await grabCommmunityThemeCssFile( 926 cssGithubRepository, 927 false, 928 plugin.settings.debuggingMode 929 ); 930 if (!themeCss) { 931 toastMessage( 932 plugin, 933 "There is no theme.css or theme-beta.css file in the root path of this repository, so there is no theme to install." 934 ); 935 return false; 936 } 937 const themeManifest = await grabCommmunityThemeManifestFile( 938 cssGithubRepository, 939 plugin.settings.debuggingMode 940 ); 941 if (!themeManifest) { 942 toastMessage( 943 plugin, 944 "There is no manifest.json file in the root path of this repository, so theme cannot be installed." 945 ); 946 return false; 947 } 948 const manifestInfo = await JSON.parse(themeManifest); 949 const themeTargetFolderPath = (0, import_obsidian3.normalizePath)(themesRootPath(plugin) + manifestInfo.name); 950 const { adapter } = plugin.app.vault; 951 if (!await adapter.exists(themeTargetFolderPath)) 952 await adapter.mkdir(themeTargetFolderPath); 953 await adapter.write((0, import_obsidian3.normalizePath)(themeTargetFolderPath + "/theme.css"), themeCss); 954 await adapter.write( 955 (0, import_obsidian3.normalizePath)(themeTargetFolderPath + "/manifest.json"), 956 themeManifest 957 ); 958 updateBetaThemeLastUpdateChecksum( 959 plugin, 960 cssGithubRepository, 961 checksumForString(themeCss) 962 ); 963 let msg = ``; 964 if (newInstall) { 965 addBetaThemeToList(plugin, cssGithubRepository, themeCss); 966 msg = `${manifestInfo.name} theme installed from ${cssGithubRepository}. `; 967 setTimeout(() => { 968 plugin.app.customCss.setTheme(manifestInfo.name); 969 }, 500); 970 } else { 971 msg = `${manifestInfo.name} theme updated from ${cssGithubRepository}.`; 972 } 973 void plugin.log(msg + `[Theme Info](https://github.com/${cssGithubRepository})`, false); 974 toastMessage(plugin, msg, 20, () => { 975 window.open(`https://github.com/${cssGithubRepository}`); 976 }); 977 return true; 978 }; 979 var themesCheckAndUpdates = async (plugin, showInfo) => { 980 if (!await isConnectedToInternet()) { 981 console.log("BRAT: No internet detected."); 982 return; 983 } 984 let newNotice; 985 const msg1 = `Checking for beta theme updates STARTED`; 986 await plugin.log(msg1, true); 987 if (showInfo && plugin.settings.notificationsEnabled) 988 newNotice = new import_obsidian3.Notice(`BRAT 989 ${msg1}`, 3e4); 990 for (const t of plugin.settings.themesList) { 991 let lastUpdateOnline = await grabChecksumOfThemeCssFile( 992 t.repo, 993 true, 994 plugin.settings.debuggingMode 995 ); 996 if (lastUpdateOnline === "0") 997 lastUpdateOnline = await grabChecksumOfThemeCssFile( 998 t.repo, 999 false, 1000 plugin.settings.debuggingMode 1001 ); 1002 console.log("BRAT: lastUpdateOnline", lastUpdateOnline); 1003 if (lastUpdateOnline !== t.lastUpdate) 1004 await themeSave(plugin, t.repo, false); 1005 } 1006 const msg2 = `Checking for beta theme updates COMPLETED`; 1007 (async () => { 1008 await plugin.log(msg2, true); 1009 })(); 1010 if (showInfo) { 1011 if (plugin.settings.notificationsEnabled && newNotice) 1012 newNotice.hide(); 1013 toastMessage(plugin, msg2); 1014 } 1015 }; 1016 var themeDelete = (plugin, cssGithubRepository) => { 1017 plugin.settings.themesList = plugin.settings.themesList.filter( 1018 (t) => t.repo !== cssGithubRepository 1019 ); 1020 void plugin.saveSettings(); 1021 const msg = `Removed ${cssGithubRepository} from BRAT themes list and will no longer be updated. However, the theme files still exist in the vault. To remove them, go into Settings > Appearance and remove the theme.`; 1022 void plugin.log(msg, true); 1023 toastMessage(plugin, msg); 1024 }; 1025 var themesRootPath = (plugin) => { 1026 return (0, import_obsidian3.normalizePath)(plugin.app.vault.configDir + "/themes") + "/"; 1027 }; 1028 1029 // src/ui/AddNewTheme.ts 1030 var import_obsidian4 = require("obsidian"); 1031 1032 // src/ui/Promotional.ts 1033 var promotionalLinks = (containerEl, settingsTab = true) => { 1034 const linksDiv = containerEl.createEl("div"); 1035 linksDiv.style.float = "right"; 1036 if (!settingsTab) { 1037 linksDiv.style.padding = "10px"; 1038 linksDiv.style.paddingLeft = "15px"; 1039 linksDiv.style.paddingRight = "15px"; 1040 } else { 1041 linksDiv.style.padding = "15px"; 1042 linksDiv.style.paddingLeft = "15px"; 1043 linksDiv.style.paddingRight = "15px"; 1044 linksDiv.style.marginLeft = "15px"; 1045 } 1046 const twitterSpan = linksDiv.createDiv("coffee"); 1047 twitterSpan.addClass("ex-twitter-span"); 1048 twitterSpan.style.paddingLeft = "10px"; 1049 const captionText = twitterSpan.createDiv(); 1050 captionText.innerText = "Learn more about my work at:"; 1051 twitterSpan.appendChild(captionText); 1052 const twitterLink = twitterSpan.createEl("a", { href: "https://tfthacker.com" }); 1053 twitterLink.innerText = "https://tfthacker.com"; 1054 return linksDiv; 1055 }; 1056 1057 // src/ui/AddNewTheme.ts 1058 var AddNewTheme = class extends import_obsidian4.Modal { 1059 constructor(plugin, openSettingsTabAfterwards = false) { 1060 super(plugin.app); 1061 this.plugin = plugin; 1062 this.address = ""; 1063 this.openSettingsTabAfterwards = openSettingsTabAfterwards; 1064 } 1065 async submitForm() { 1066 if (this.address === "") 1067 return; 1068 const scrubbedAddress = this.address.replace("https://github.com/", ""); 1069 if (existBetaThemeinInList(this.plugin, scrubbedAddress)) { 1070 toastMessage(this.plugin, `This theme is already in the list for beta testing`, 10); 1071 return; 1072 } 1073 if (await themeSave(this.plugin, scrubbedAddress, true)) { 1074 this.close(); 1075 } 1076 } 1077 onOpen() { 1078 this.contentEl.createEl("h4", { text: "Github repository for beta theme:" }); 1079 this.contentEl.createEl("form", {}, (formEl) => { 1080 formEl.addClass("brat-modal"); 1081 new import_obsidian4.Setting(formEl).addText((textEl) => { 1082 textEl.setPlaceholder( 1083 "Repository (example: https://github.com/GitubUserName/repository-name" 1084 ); 1085 textEl.setValue(this.address); 1086 textEl.onChange((value) => { 1087 this.address = value.trim(); 1088 }); 1089 textEl.inputEl.addEventListener("keydown", (e) => { 1090 if (e.key === "Enter" && this.address !== " ") { 1091 e.preventDefault(); 1092 void this.submitForm(); 1093 } 1094 }); 1095 textEl.inputEl.style.width = "100%"; 1096 window.setTimeout(() => { 1097 const title = document.querySelector(".setting-item-info"); 1098 if (title) 1099 title.remove(); 1100 textEl.inputEl.focus(); 1101 }, 10); 1102 }); 1103 formEl.createDiv("modal-button-container", (buttonContainerEl) => { 1104 buttonContainerEl.createEl("button", { attr: { type: "button" }, text: "Never mind" }).addEventListener("click", () => { 1105 this.close(); 1106 }); 1107 buttonContainerEl.createEl("button", { 1108 attr: { type: "submit" }, 1109 cls: "mod-cta", 1110 text: "Add Theme" 1111 }); 1112 }); 1113 const newDiv = formEl.createDiv(); 1114 newDiv.style.borderTop = "1px solid #ccc"; 1115 newDiv.style.marginTop = "30px"; 1116 const byTfThacker = newDiv.createSpan(); 1117 byTfThacker.innerHTML = "BRAT by <a href='https://bit.ly/o42-twitter'>TFTHacker</a>"; 1118 byTfThacker.style.fontStyle = "italic"; 1119 newDiv.appendChild(byTfThacker); 1120 promotionalLinks(newDiv, false); 1121 window.setTimeout(() => { 1122 const title = formEl.querySelectorAll(".brat-modal .setting-item-info"); 1123 title.forEach((titleEl) => { 1124 titleEl.remove(); 1125 }); 1126 }, 50); 1127 formEl.addEventListener("submit", (e) => { 1128 e.preventDefault(); 1129 if (this.address !== "") 1130 void this.submitForm(); 1131 }); 1132 }); 1133 } 1134 onClose() { 1135 if (this.openSettingsTabAfterwards) { 1136 this.plugin.app.setting.open(); 1137 this.plugin.app.setting.openTabById(this.plugin.APP_ID); 1138 } 1139 } 1140 }; 1141 1142 // src/ui/SettingsTab.ts 1143 var createLink = (githubResource, optionalText) => { 1144 const newLink = new DocumentFragment(); 1145 const linkElement = document.createElement("a"); 1146 linkElement.textContent = githubResource; 1147 linkElement.href = `https://github.com/${githubResource}`; 1148 newLink.appendChild(linkElement); 1149 if (optionalText) { 1150 const textNode = document.createTextNode(optionalText); 1151 newLink.appendChild(textNode); 1152 } 1153 return newLink; 1154 }; 1155 var BratSettingsTab = class extends import_obsidian5.PluginSettingTab { 1156 constructor(app, plugin) { 1157 super(app, plugin); 1158 this.plugin = plugin; 1159 } 1160 display() { 1161 const { containerEl } = this; 1162 containerEl.empty(); 1163 new import_obsidian5.Setting(containerEl).setName("Auto-enable plugins after installation").setDesc( 1164 'If enabled beta plugins will be automatically enabled after installtion by default. Note: you can toggle this on and off for each plugin in the "Add Plugin" form.' 1165 ).addToggle((cb) => { 1166 cb.setValue(this.plugin.settings.enableAfterInstall); 1167 cb.onChange(async (value) => { 1168 this.plugin.settings.enableAfterInstall = value; 1169 await this.plugin.saveSettings(); 1170 }); 1171 }); 1172 new import_obsidian5.Setting(containerEl).setName("Auto-update plugins at startup").setDesc( 1173 "If enabled all beta plugins will be checked for updates each time Obsidian starts. Note: this does not update frozen version plugins." 1174 ).addToggle((cb) => { 1175 cb.setValue(this.plugin.settings.updateAtStartup); 1176 cb.onChange(async (value) => { 1177 this.plugin.settings.updateAtStartup = value; 1178 await this.plugin.saveSettings(); 1179 }); 1180 }); 1181 new import_obsidian5.Setting(containerEl).setName("Auto-update themes at startup").setDesc( 1182 "If enabled all beta themes will be checked for updates each time Obsidian starts." 1183 ).addToggle((cb) => { 1184 cb.setValue(this.plugin.settings.updateThemesAtStartup); 1185 cb.onChange(async (value) => { 1186 this.plugin.settings.updateThemesAtStartup = value; 1187 await this.plugin.saveSettings(); 1188 }); 1189 }); 1190 promotionalLinks(containerEl, true); 1191 containerEl.createEl("hr"); 1192 containerEl.createEl("h2", { text: "Beta Plugin List" }); 1193 containerEl.createEl("div", { 1194 text: `The following is a list of beta plugins added via the command palette "Add a beta plugin for testing" or "Add a beta plugin with frozen version for testing". A frozen version is a specific release of a plugin based on its releease tag. ` 1195 }); 1196 containerEl.createEl("p"); 1197 containerEl.createEl("div", { 1198 text: `Click the x button next to a plugin to remove it from the list.` 1199 }); 1200 containerEl.createEl("p"); 1201 containerEl.createEl("span").createEl("b", { text: "Note: " }); 1202 containerEl.createSpan({ 1203 text: "This does not delete the plugin, this should be done from the Community Plugins tab in Settings." 1204 }); 1205 new import_obsidian5.Setting(containerEl).addButton((cb) => { 1206 cb.setButtonText("Add Beta plugin"); 1207 cb.onClick(() => { 1208 this.plugin.app.setting.close(); 1209 this.plugin.betaPlugins.displayAddNewPluginModal(true, false); 1210 }); 1211 }); 1212 const pluginSubListFrozenVersionNames = new Set( 1213 this.plugin.settings.pluginSubListFrozenVersion.map((x) => x.repo) 1214 ); 1215 for (const bp of this.plugin.settings.pluginList) { 1216 if (pluginSubListFrozenVersionNames.has(bp)) { 1217 continue; 1218 } 1219 new import_obsidian5.Setting(containerEl).setName(createLink(bp)).addButton((btn) => { 1220 btn.setIcon("cross"); 1221 btn.setTooltip("Delete this beta plugin"); 1222 btn.onClick(() => { 1223 if (btn.buttonEl.textContent === "") 1224 btn.setButtonText("Click once more to confirm removal"); 1225 else { 1226 const { buttonEl } = btn; 1227 const { parentElement } = buttonEl; 1228 if (parentElement == null ? void 0 : parentElement.parentElement) { 1229 parentElement.parentElement.remove(); 1230 this.plugin.betaPlugins.deletePlugin(bp); 1231 } 1232 } 1233 }); 1234 }); 1235 } 1236 new import_obsidian5.Setting(containerEl).addButton((cb) => { 1237 cb.setButtonText("Add Beta plugin with frozen version"); 1238 cb.onClick(() => { 1239 this.plugin.app.setting.close(); 1240 this.plugin.betaPlugins.displayAddNewPluginModal(true, true); 1241 }); 1242 }); 1243 for (const bp of this.plugin.settings.pluginSubListFrozenVersion) { 1244 new import_obsidian5.Setting(containerEl).setName(createLink(bp.repo, ` (version ${bp.version})`)).addButton((btn) => { 1245 btn.setIcon("cross"); 1246 btn.setTooltip("Delete this beta plugin"); 1247 btn.onClick(() => { 1248 if (btn.buttonEl.textContent === "") 1249 btn.setButtonText("Click once more to confirm removal"); 1250 else { 1251 const { buttonEl } = btn; 1252 const { parentElement } = buttonEl; 1253 if (parentElement == null ? void 0 : parentElement.parentElement) { 1254 parentElement.parentElement.remove(); 1255 this.plugin.betaPlugins.deletePlugin(bp.repo); 1256 } 1257 } 1258 }); 1259 }); 1260 } 1261 containerEl.createEl("h2", { text: "Beta Themes List" }); 1262 new import_obsidian5.Setting(containerEl).addButton((cb) => { 1263 cb.setButtonText("Add Beta Theme"); 1264 cb.onClick(() => { 1265 this.plugin.app.setting.close(); 1266 new AddNewTheme(this.plugin).open(); 1267 }); 1268 }); 1269 for (const bp of this.plugin.settings.themesList) { 1270 new import_obsidian5.Setting(containerEl).setName(createLink(bp.repo)).addButton((btn) => { 1271 btn.setIcon("cross"); 1272 btn.setTooltip("Delete this beta theme"); 1273 btn.onClick(() => { 1274 if (btn.buttonEl.textContent === "") 1275 btn.setButtonText("Click once more to confirm removal"); 1276 else { 1277 const { buttonEl } = btn; 1278 const { parentElement } = buttonEl; 1279 if (parentElement == null ? void 0 : parentElement.parentElement) { 1280 parentElement.parentElement.remove(); 1281 themeDelete(this.plugin, bp.repo); 1282 } 1283 } 1284 }); 1285 }); 1286 } 1287 containerEl.createEl("h2", { text: "Monitoring" }); 1288 new import_obsidian5.Setting(containerEl).setName("Enable Notifications").setDesc( 1289 "BRAT will provide popup notifications for its various activities. Turn this off means no notifications from BRAT." 1290 ).addToggle((cb) => { 1291 cb.setValue(this.plugin.settings.notificationsEnabled); 1292 cb.onChange(async (value) => { 1293 this.plugin.settings.notificationsEnabled = value; 1294 await this.plugin.saveSettings(); 1295 }); 1296 }); 1297 new import_obsidian5.Setting(containerEl).setName("Enable Logging").setDesc("Plugin updates will be logged to a file in the log file.").addToggle((cb) => { 1298 cb.setValue(this.plugin.settings.loggingEnabled); 1299 cb.onChange(async (value) => { 1300 this.plugin.settings.loggingEnabled = value; 1301 await this.plugin.saveSettings(); 1302 }); 1303 }); 1304 new import_obsidian5.Setting(this.containerEl).setName("BRAT Log File Location").setDesc("Logs will be saved to this file. Don't add .md to the file name.").addSearch((cb) => { 1305 cb.setPlaceholder("Example: BRAT-log").setValue(this.plugin.settings.loggingPath).onChange(async (newFolder) => { 1306 this.plugin.settings.loggingPath = newFolder; 1307 await this.plugin.saveSettings(); 1308 }); 1309 }); 1310 new import_obsidian5.Setting(containerEl).setName("Enable Verbose Logging").setDesc("Get a lot more information in the log.").addToggle((cb) => { 1311 cb.setValue(this.plugin.settings.loggingVerboseEnabled); 1312 cb.onChange(async (value) => { 1313 this.plugin.settings.loggingVerboseEnabled = value; 1314 await this.plugin.saveSettings(); 1315 }); 1316 }); 1317 new import_obsidian5.Setting(containerEl).setName("Debugging Mode").setDesc( 1318 "Atomic Bomb level console logging. Can be used for troubleshoting and development." 1319 ).addToggle((cb) => { 1320 cb.setValue(this.plugin.settings.debuggingMode); 1321 cb.onChange(async (value) => { 1322 this.plugin.settings.debuggingMode = value; 1323 await this.plugin.saveSettings(); 1324 }); 1325 }); 1326 new import_obsidian5.Setting(containerEl).setName("Personal Access Token").setDesc( 1327 "If you need to access private repositories, enter the personal access token here." 1328 ).addText((text) => { 1329 var _a; 1330 text.setPlaceholder("Enter your personal access token").setValue((_a = this.plugin.settings.personalAccessToken) != null ? _a : "").onChange(async (value) => { 1331 this.plugin.settings.personalAccessToken = value; 1332 await this.plugin.saveSettings(); 1333 }); 1334 }); 1335 } 1336 }; 1337 1338 // src/ui/AddNewPluginModal.ts 1339 var import_obsidian6 = require("obsidian"); 1340 var AddNewPluginModal = class extends import_obsidian6.Modal { 1341 constructor(plugin, betaPlugins, openSettingsTabAfterwards = false, useFrozenVersion = false) { 1342 super(plugin.app); 1343 this.plugin = plugin; 1344 this.betaPlugins = betaPlugins; 1345 this.address = ""; 1346 this.openSettingsTabAfterwards = openSettingsTabAfterwards; 1347 this.useFrozenVersion = useFrozenVersion; 1348 this.enableAfterInstall = plugin.settings.enableAfterInstall; 1349 this.version = ""; 1350 } 1351 async submitForm() { 1352 if (this.address === "") 1353 return; 1354 let scrubbedAddress = this.address.replace("https://github.com/", ""); 1355 if (scrubbedAddress.endsWith(".git")) 1356 scrubbedAddress = scrubbedAddress.slice(0, -4); 1357 if (existBetaPluginInList(this.plugin, scrubbedAddress)) { 1358 toastMessage( 1359 this.plugin, 1360 `This plugin is already in the list for beta testing`, 1361 10 1362 ); 1363 return; 1364 } 1365 const result = await this.betaPlugins.addPlugin( 1366 scrubbedAddress, 1367 false, 1368 false, 1369 false, 1370 this.version, 1371 false, 1372 this.enableAfterInstall 1373 ); 1374 if (result) { 1375 this.close(); 1376 } 1377 } 1378 onOpen() { 1379 this.contentEl.createEl("h4", { text: "Github repository for beta plugin:" }); 1380 this.contentEl.createEl("form", {}, (formEl) => { 1381 formEl.addClass("brat-modal"); 1382 new import_obsidian6.Setting(formEl).addText((textEl) => { 1383 textEl.setPlaceholder( 1384 "Repository (example: https://github.com/GitubUserName/repository-name)" 1385 ); 1386 textEl.setValue(this.address); 1387 textEl.onChange((value) => { 1388 this.address = value.trim(); 1389 }); 1390 textEl.inputEl.addEventListener("keydown", (e) => { 1391 if (e.key === "Enter" && this.address !== " ") { 1392 if (this.useFrozenVersion && this.version !== "" || !this.useFrozenVersion) { 1393 e.preventDefault(); 1394 void this.submitForm(); 1395 } 1396 } 1397 }); 1398 textEl.inputEl.style.width = "100%"; 1399 }); 1400 if (this.useFrozenVersion) { 1401 new import_obsidian6.Setting(formEl).addText((textEl) => { 1402 textEl.setPlaceholder("Specify the release version tag (example: 1.0.0)"); 1403 textEl.onChange((value) => { 1404 this.version = value.trim(); 1405 }); 1406 textEl.inputEl.style.width = "100%"; 1407 }); 1408 } 1409 formEl.createDiv("modal-button-container", (buttonContainerEl) => { 1410 buttonContainerEl.createEl( 1411 "label", 1412 { 1413 cls: "mod-checkbox" 1414 }, 1415 (labelEl) => { 1416 const checkboxEl = labelEl.createEl("input", { 1417 attr: { tabindex: -1 }, 1418 type: "checkbox" 1419 }); 1420 checkboxEl.checked = this.enableAfterInstall; 1421 checkboxEl.addEventListener("click", () => { 1422 this.enableAfterInstall = checkboxEl.checked; 1423 }); 1424 labelEl.appendText("Enable after installing the plugin"); 1425 } 1426 ); 1427 buttonContainerEl.createEl("button", { attr: { type: "button" }, text: "Never mind" }).addEventListener("click", () => { 1428 this.close(); 1429 }); 1430 buttonContainerEl.createEl("button", { 1431 attr: { type: "submit" }, 1432 cls: "mod-cta", 1433 text: "Add Plugin" 1434 }); 1435 }); 1436 const newDiv = formEl.createDiv(); 1437 newDiv.style.borderTop = "1px solid #ccc"; 1438 newDiv.style.marginTop = "30px"; 1439 const byTfThacker = newDiv.createSpan(); 1440 byTfThacker.innerHTML = "BRAT by <a href='https://bit.ly/o42-twitter'>TFTHacker</a>"; 1441 byTfThacker.style.fontStyle = "italic"; 1442 newDiv.appendChild(byTfThacker); 1443 promotionalLinks(newDiv, false); 1444 window.setTimeout(() => { 1445 const title = formEl.querySelectorAll(".brat-modal .setting-item-info"); 1446 title.forEach((titleEl) => { 1447 titleEl.remove(); 1448 }); 1449 }, 50); 1450 formEl.addEventListener("submit", (e) => { 1451 e.preventDefault(); 1452 if (this.address !== "") { 1453 if (this.useFrozenVersion && this.version !== "" || !this.useFrozenVersion) { 1454 void this.submitForm(); 1455 } 1456 } 1457 }); 1458 }); 1459 } 1460 onClose() { 1461 if (this.openSettingsTabAfterwards) { 1462 this.plugin.app.setting.open(); 1463 this.plugin.app.setting.openTabById(this.plugin.APP_ID); 1464 } 1465 } 1466 }; 1467 1468 // src/features/BetaPlugins.ts 1469 var import_obsidian7 = require("obsidian"); 1470 var BetaPlugins = class { 1471 constructor(plugin) { 1472 this.plugin = plugin; 1473 } 1474 /** 1475 * opens the AddNewPluginModal to get info for a new beta plugin 1476 * @param openSettingsTabAfterwards - will open settings screen afterwards. Used when this command is called from settings tab 1477 * @param useFrozenVersion - install the plugin using frozen version. 1478 */ 1479 displayAddNewPluginModal(openSettingsTabAfterwards = false, useFrozenVersion = false) { 1480 const newPlugin = new AddNewPluginModal( 1481 this.plugin, 1482 this, 1483 openSettingsTabAfterwards, 1484 useFrozenVersion 1485 ); 1486 newPlugin.open(); 1487 } 1488 /** 1489 * Validates that a GitHub repository is plugin 1490 * 1491 * @param repositoryPath - GithubUser/RepositoryName (example: TfThacker/obsidian42-brat) 1492 * @param getBetaManifest - test the beta version of the manifest, not at the root 1493 * @param false - [false description] 1494 * @param reportIssues - will display notices as it finds issues 1495 * 1496 * @returns the manifest file if found, or null if its incomplete 1497 */ 1498 async validateRepository(repositoryPath, getBetaManifest = false, reportIssues = false) { 1499 const noticeTimeout = 15; 1500 const manifestJson = await grabManifestJsonFromRepository( 1501 repositoryPath, 1502 !getBetaManifest, 1503 this.plugin.settings.debuggingMode, 1504 this.plugin.settings.personalAccessToken 1505 ); 1506 if (!manifestJson) { 1507 if (reportIssues) { 1508 toastMessage( 1509 this.plugin, 1510 `${repositoryPath} 1511 This does not seem to be an obsidian plugin, as there is no manifest.json file.`, 1512 noticeTimeout 1513 ); 1514 console.error( 1515 "BRAT: validateRepository", 1516 repositoryPath, 1517 getBetaManifest, 1518 reportIssues 1519 ); 1520 } 1521 return null; 1522 } 1523 if (!("id" in manifestJson)) { 1524 if (reportIssues) 1525 toastMessage( 1526 this.plugin, 1527 `${repositoryPath} 1528 The plugin id attribute for the release is missing from the manifest file`, 1529 noticeTimeout 1530 ); 1531 return null; 1532 } 1533 if (!("version" in manifestJson)) { 1534 if (reportIssues) 1535 toastMessage( 1536 this.plugin, 1537 `${repositoryPath} 1538 The version attribute for the release is missing from the manifest file`, 1539 noticeTimeout 1540 ); 1541 return null; 1542 } 1543 return manifestJson; 1544 } 1545 /** 1546 * Gets all the release files based on the version number in the manifest 1547 * 1548 * @param repositoryPath - path to the GitHub repository 1549 * @param manifest - manifest file 1550 * @param getManifest - grab the remote manifest file 1551 * @param specifyVersion - grab the specified version if set 1552 * 1553 * @returns all relase files as strings based on the ReleaseFiles interaface 1554 */ 1555 async getAllReleaseFiles(repositoryPath, manifest, getManifest, specifyVersion = "") { 1556 const version = specifyVersion === "" ? manifest.version : specifyVersion; 1557 const reallyGetManifestOrNot = getManifest || specifyVersion !== ""; 1558 console.log({ reallyGetManifestOrNot, version }); 1559 return { 1560 mainJs: await grabReleaseFileFromRepository( 1561 repositoryPath, 1562 version, 1563 "main.js", 1564 this.plugin.settings.debuggingMode, 1565 this.plugin.settings.personalAccessToken 1566 ), 1567 manifest: reallyGetManifestOrNot ? await grabReleaseFileFromRepository( 1568 repositoryPath, 1569 version, 1570 "manifest.json", 1571 this.plugin.settings.debuggingMode, 1572 this.plugin.settings.personalAccessToken 1573 ) : "", 1574 styles: await grabReleaseFileFromRepository( 1575 repositoryPath, 1576 version, 1577 "styles.css", 1578 this.plugin.settings.debuggingMode, 1579 this.plugin.settings.personalAccessToken 1580 ) 1581 }; 1582 } 1583 /** 1584 * Writes the plugin release files to the local obsidian .plugins folder 1585 * 1586 * @param betaPluginId - the id of the plugin (not the repository path) 1587 * @param relFiles - release file as strings, based on the ReleaseFiles interface 1588 * 1589 */ 1590 async writeReleaseFilesToPluginFolder(betaPluginId, relFiles) { 1591 var _a, _b; 1592 const pluginTargetFolderPath = (0, import_obsidian7.normalizePath)(this.plugin.app.vault.configDir + "/plugins/" + betaPluginId) + "/"; 1593 const { adapter } = this.plugin.app.vault; 1594 if (!await adapter.exists(pluginTargetFolderPath) || !await adapter.exists(pluginTargetFolderPath + "manifest.json")) { 1595 await adapter.mkdir(pluginTargetFolderPath); 1596 } 1597 await adapter.write(pluginTargetFolderPath + "main.js", (_a = relFiles.mainJs) != null ? _a : ""); 1598 await adapter.write( 1599 pluginTargetFolderPath + "manifest.json", 1600 (_b = relFiles.manifest) != null ? _b : "" 1601 ); 1602 if (relFiles.styles) 1603 await adapter.write(pluginTargetFolderPath + "styles.css", relFiles.styles); 1604 } 1605 /** 1606 * Primary function for adding a new beta plugin to Obsidian. 1607 * Also this function is used for updating existing plugins. 1608 * 1609 * @param repositoryPath - path to GitHub repository formated as USERNAME/repository 1610 * @param updatePluginFiles - true if this is just an update not an install 1611 * @param seeIfUpdatedOnly - if true, and updatePluginFiles true, will just check for updates, but not do the update. will report to user that there is a new plugin 1612 * @param reportIfNotUpdted - if true, report if an update has not succed 1613 * @param specifyVersion - if not empty, need to install a specified version instead of the value in manifest-beta.json 1614 * @param forceReinstall - if true, will force a reinstall of the plugin, even if it is already installed 1615 * 1616 * @returns true if succeeds 1617 */ 1618 async addPlugin(repositoryPath, updatePluginFiles = false, seeIfUpdatedOnly = false, reportIfNotUpdted = false, specifyVersion = "", forceReinstall = false, enableAfterInstall = this.plugin.settings.enableAfterInstall) { 1619 if (this.plugin.settings.debuggingMode) 1620 console.log( 1621 "BRAT: addPlugin", 1622 repositoryPath, 1623 updatePluginFiles, 1624 seeIfUpdatedOnly, 1625 reportIfNotUpdted, 1626 specifyVersion, 1627 forceReinstall, 1628 enableAfterInstall 1629 ); 1630 const noticeTimeout = 10; 1631 let primaryManifest = await this.validateRepository(repositoryPath, true, false); 1632 const usingBetaManifest = primaryManifest ? true : false; 1633 if (!usingBetaManifest) 1634 primaryManifest = await this.validateRepository(repositoryPath, false, true); 1635 if (primaryManifest === null) { 1636 const msg = `${repositoryPath} 1637 A manifest.json or manifest-beta.json file does not exist in the root directory of the repository. This plugin cannot be installed.`; 1638 await this.plugin.log(msg, true); 1639 toastMessage(this.plugin, msg, noticeTimeout); 1640 return false; 1641 } 1642 if (!Object.hasOwn(primaryManifest, "version")) { 1643 const msg = `${repositoryPath} 1644 The manifest${usingBetaManifest ? "-beta" : ""}.json file in the root directory of the repository does not have a version number in the file. This plugin cannot be installed.`; 1645 await this.plugin.log(msg, true); 1646 toastMessage(this.plugin, msg, noticeTimeout); 1647 return false; 1648 } 1649 if (!Object.hasOwn(primaryManifest, "minAppVersion")) { 1650 if (!(0, import_obsidian7.requireApiVersion)(primaryManifest.minAppVersion)) { 1651 const msg = `Plugin: ${repositoryPath} 1652 1653 The manifest${usingBetaManifest ? "-beta" : ""}.json for this plugin indicates that the Obsidian version of the app needs to be ${primaryManifest.minAppVersion}, but this installation of Obsidian is ${import_obsidian7.apiVersion}. 1654 1655 You will need to update your Obsidian to use this plugin or contact the plugin developer for more information.`; 1656 await this.plugin.log(msg, true); 1657 toastMessage(this.plugin, msg, 30); 1658 return false; 1659 } 1660 } 1661 const getRelease = async () => { 1662 const rFiles = await this.getAllReleaseFiles( 1663 repositoryPath, 1664 // @ts-expect-error typescript will complain that this can be null, but in this case it won't be 1665 primaryManifest, 1666 usingBetaManifest, 1667 specifyVersion 1668 ); 1669 console.log("rFiles", rFiles); 1670 if (usingBetaManifest || rFiles.manifest === "") 1671 rFiles.manifest = JSON.stringify(primaryManifest); 1672 if (this.plugin.settings.debuggingMode) 1673 console.log("BRAT: rFiles.manifest", usingBetaManifest, rFiles); 1674 if (rFiles.mainJs === null) { 1675 const msg = `${repositoryPath} 1676 The release is not complete and cannot be download. main.js is missing from the Release`; 1677 await this.plugin.log(msg, true); 1678 toastMessage(this.plugin, msg, noticeTimeout); 1679 return null; 1680 } 1681 return rFiles; 1682 }; 1683 if (!updatePluginFiles || forceReinstall) { 1684 const releaseFiles = await getRelease(); 1685 if (releaseFiles === null) 1686 return false; 1687 await this.writeReleaseFilesToPluginFolder(primaryManifest.id, releaseFiles); 1688 if (!forceReinstall) 1689 addBetaPluginToList(this.plugin, repositoryPath, specifyVersion); 1690 if (enableAfterInstall) { 1691 const { plugins } = this.plugin.app; 1692 const pluginTargetFolderPath = (0, import_obsidian7.normalizePath)( 1693 plugins.getPluginFolder() + "/" + primaryManifest.id 1694 ); 1695 await plugins.loadManifest(pluginTargetFolderPath); 1696 await plugins.enablePluginAndSave(primaryManifest.id); 1697 } 1698 await this.plugin.app.plugins.loadManifests(); 1699 if (forceReinstall) { 1700 await this.reloadPlugin(primaryManifest.id); 1701 await this.plugin.log(`${repositoryPath} reinstalled`, true); 1702 toastMessage( 1703 this.plugin, 1704 `${repositoryPath} 1705 Plugin has been reinstalled and reloaded.`, 1706 noticeTimeout 1707 ); 1708 } else { 1709 const versionText = specifyVersion === "" ? "" : ` (version: ${specifyVersion})`; 1710 let msg = `${repositoryPath}${versionText} 1711 The plugin has been registered with BRAT.`; 1712 if (!enableAfterInstall) { 1713 msg += " You may still need to enable it the Community Plugin List."; 1714 } 1715 await this.plugin.log(msg, true); 1716 toastMessage(this.plugin, msg, noticeTimeout); 1717 } 1718 } else { 1719 const pluginTargetFolderPath = this.plugin.app.vault.configDir + "/plugins/" + primaryManifest.id + "/"; 1720 let localManifestContents = ""; 1721 try { 1722 localManifestContents = await this.plugin.app.vault.adapter.read( 1723 pluginTargetFolderPath + "manifest.json" 1724 ); 1725 } catch (e) { 1726 if (e.errno === -4058 || e.errno === -2) { 1727 await this.addPlugin( 1728 repositoryPath, 1729 false, 1730 usingBetaManifest, 1731 false, 1732 specifyVersion 1733 ); 1734 return true; 1735 } else 1736 console.log( 1737 "BRAT - Local Manifest Load", 1738 primaryManifest.id, 1739 JSON.stringify(e, null, 2) 1740 ); 1741 } 1742 if (specifyVersion !== "" || this.plugin.settings.pluginSubListFrozenVersion.map((x) => x.repo).includes(repositoryPath)) { 1743 toastMessage( 1744 this.plugin, 1745 `The version of ${repositoryPath} is frozen, not updating.`, 1746 3 1747 ); 1748 return false; 1749 } 1750 const localManifestJson = await JSON.parse( 1751 localManifestContents 1752 ); 1753 if (localManifestJson.version !== primaryManifest.version) { 1754 const releaseFiles = await getRelease(); 1755 if (releaseFiles === null) 1756 return false; 1757 if (seeIfUpdatedOnly) { 1758 const msg = `There is an update available for ${primaryManifest.id} from version ${localManifestJson.version} to ${primaryManifest.version}. `; 1759 await this.plugin.log( 1760 msg + `[Release Info](https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version})`, 1761 true 1762 ); 1763 toastMessage(this.plugin, msg, 30, () => { 1764 if (primaryManifest) { 1765 window.open( 1766 `https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version}` 1767 ); 1768 } 1769 }); 1770 } else { 1771 await this.writeReleaseFilesToPluginFolder(primaryManifest.id, releaseFiles); 1772 await this.plugin.app.plugins.loadManifests(); 1773 await this.reloadPlugin(primaryManifest.id); 1774 const msg = `${primaryManifest.id} 1775 Plugin has been updated from version ${localManifestJson.version} to ${primaryManifest.version}. `; 1776 await this.plugin.log( 1777 msg + `[Release Info](https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version})`, 1778 true 1779 ); 1780 toastMessage(this.plugin, msg, 30, () => { 1781 if (primaryManifest) { 1782 window.open( 1783 `https://github.com/${repositoryPath}/releases/tag/${primaryManifest.version}` 1784 ); 1785 } 1786 }); 1787 } 1788 } else if (reportIfNotUpdted) 1789 toastMessage(this.plugin, `No update available for ${repositoryPath}`, 3); 1790 } 1791 return true; 1792 } 1793 /** 1794 * reloads a plugin (assuming it has been enabled by user) 1795 * pjeby, Thanks Bro https://github.com/pjeby/hot-reload/blob/master/main.js 1796 * 1797 * @param pluginName - name of plugin 1798 * 1799 */ 1800 async reloadPlugin(pluginName) { 1801 const { plugins } = this.plugin.app; 1802 try { 1803 await plugins.disablePlugin(pluginName); 1804 await plugins.enablePlugin(pluginName); 1805 } catch (e) { 1806 if (this.plugin.settings.debuggingMode) 1807 console.log("reload plugin", e); 1808 } 1809 } 1810 /** 1811 * updates a beta plugin 1812 * 1813 * @param repositoryPath - repository path on GitHub 1814 * @param onlyCheckDontUpdate - only looks for update 1815 * 1816 */ 1817 async updatePlugin(repositoryPath, onlyCheckDontUpdate = false, reportIfNotUpdted = false, forceReinstall = false) { 1818 const result = await this.addPlugin( 1819 repositoryPath, 1820 true, 1821 onlyCheckDontUpdate, 1822 reportIfNotUpdted, 1823 "", 1824 forceReinstall 1825 ); 1826 if (!result && !onlyCheckDontUpdate) 1827 toastMessage(this.plugin, `${repositoryPath} 1828 Update of plugin failed.`); 1829 return result; 1830 } 1831 /** 1832 * walks through the list of plugins without frozen version and performs an update 1833 * 1834 * @param showInfo - should this with a started/completed message - useful when ran from CP 1835 * 1836 */ 1837 async checkForPluginUpdatesAndInstallUpdates(showInfo = false, onlyCheckDontUpdate = false) { 1838 if (!await isConnectedToInternet()) { 1839 console.log("BRAT: No internet detected."); 1840 return; 1841 } 1842 let newNotice; 1843 const msg1 = `Checking for plugin updates STARTED`; 1844 await this.plugin.log(msg1, true); 1845 if (showInfo && this.plugin.settings.notificationsEnabled) 1846 newNotice = new import_obsidian7.Notice(`BRAT 1847 ${msg1}`, 3e4); 1848 const pluginSubListFrozenVersionNames = new Set( 1849 this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo) 1850 ); 1851 for (const bp of this.plugin.settings.pluginList) { 1852 if (pluginSubListFrozenVersionNames.has(bp)) { 1853 continue; 1854 } 1855 await this.updatePlugin(bp, onlyCheckDontUpdate); 1856 } 1857 const msg2 = `Checking for plugin updates COMPLETED`; 1858 await this.plugin.log(msg2, true); 1859 if (showInfo) { 1860 if (newNotice) { 1861 newNotice.hide(); 1862 } 1863 toastMessage(this.plugin, msg2, 10); 1864 } 1865 } 1866 /** 1867 * Removes the beta plugin from the list of beta plugins (does not delete them from disk) 1868 * 1869 * @param betaPluginID - repository path 1870 * 1871 */ 1872 deletePlugin(repositoryPath) { 1873 const msg = `Removed ${repositoryPath} from BRAT plugin list`; 1874 void this.plugin.log(msg, true); 1875 this.plugin.settings.pluginList = this.plugin.settings.pluginList.filter( 1876 (b) => b !== repositoryPath 1877 ); 1878 this.plugin.settings.pluginSubListFrozenVersion = this.plugin.settings.pluginSubListFrozenVersion.filter( 1879 (b) => b.repo !== repositoryPath 1880 ); 1881 void this.plugin.saveSettings(); 1882 } 1883 /** 1884 * Returns a list of plugins that are currently enabled or currently disabled 1885 * 1886 * @param enabled - true for enabled plugins, false for disabled plutings 1887 * 1888 * @returns manifests of plugins 1889 */ 1890 getEnabledDisabledPlugins(enabled) { 1891 const pl = this.plugin.app.plugins; 1892 const manifests = Object.values(pl.manifests); 1893 const enabledPlugins = Object.values(pl.plugins).map( 1894 (p) => p.manifest 1895 ); 1896 return enabled ? manifests.filter( 1897 (manifest) => enabledPlugins.find((pluginName) => manifest.id === pluginName.id) 1898 ) : manifests.filter( 1899 (manifest) => !enabledPlugins.find((pluginName) => manifest.id === pluginName.id) 1900 ); 1901 } 1902 }; 1903 1904 // src/ui/icons.ts 1905 var import_obsidian8 = require("obsidian"); 1906 function addIcons() { 1907 (0, import_obsidian8.addIcon)( 1908 "BratIcon", 1909 `<path fill="currentColor" stroke="currentColor" d="M 41.667969 41.667969 C 41.667969 39.367188 39.800781 37.5 37.5 37.5 C 35.199219 37.5 33.332031 39.367188 33.332031 41.667969 C 33.332031 43.96875 35.199219 45.832031 37.5 45.832031 C 39.800781 45.832031 41.667969 43.96875 41.667969 41.667969 Z M 60.417969 58.582031 C 59.460938 58.023438 58.320312 57.867188 57.25 58.148438 C 56.179688 58.429688 55.265625 59.125 54.707031 60.082031 C 53.746094 61.777344 51.949219 62.820312 50 62.820312 C 48.050781 62.820312 46.253906 61.777344 45.292969 60.082031 C 44.734375 59.125 43.820312 58.429688 42.75 58.148438 C 41.679688 57.867188 40.539062 58.023438 39.582031 58.582031 C 37.597656 59.726562 36.910156 62.257812 38.042969 64.25 C 40.5 68.53125 45.0625 71.171875 50 71.171875 C 54.9375 71.171875 59.5 68.53125 61.957031 64.25 C 63.089844 62.257812 62.402344 59.726562 60.417969 58.582031 Z M 62.5 37.5 C 60.199219 37.5 58.332031 39.367188 58.332031 41.667969 C 58.332031 43.96875 60.199219 45.832031 62.5 45.832031 C 64.800781 45.832031 66.667969 43.96875 66.667969 41.667969 C 66.667969 39.367188 64.800781 37.5 62.5 37.5 Z M 50 8.332031 C 26.988281 8.332031 8.332031 26.988281 8.332031 50 C 8.332031 73.011719 26.988281 91.667969 50 91.667969 C 73.011719 91.667969 91.667969 73.011719 91.667969 50 C 91.667969 26.988281 73.011719 8.332031 50 8.332031 Z M 50 83.332031 C 33.988281 83.402344 20.191406 72.078125 17.136719 56.363281 C 14.078125 40.644531 22.628906 24.976562 37.5 19.042969 C 37.457031 19.636719 37.457031 20.238281 37.5 20.832031 C 37.5 27.738281 43.097656 33.332031 50 33.332031 C 52.300781 33.332031 54.167969 31.46875 54.167969 29.167969 C 54.167969 26.867188 52.300781 25 50 25 C 47.699219 25 45.832031 23.132812 45.832031 20.832031 C 45.832031 18.53125 47.699219 16.667969 50 16.667969 C 68.410156 16.667969 83.332031 31.589844 83.332031 50 C 83.332031 68.410156 68.410156 83.332031 50 83.332031 Z M 50 83.332031 " />` 1910 ); 1911 } 1912 1913 // src/utils/logging.ts 1914 var import_obsidian9 = require("obsidian"); 1915 var import_obsidian_daily_notes_interface = __toESM(require_main()); 1916 async function logger(plugin, textToLog, verboseLoggingOn = false) { 1917 if (plugin.settings.debuggingMode) 1918 console.log("BRAT: " + textToLog); 1919 if (plugin.settings.loggingEnabled) { 1920 if (!plugin.settings.loggingVerboseEnabled && verboseLoggingOn) { 1921 return; 1922 } else { 1923 const fileName = plugin.settings.loggingPath + ".md"; 1924 const dateOutput = "[[" + (0, import_obsidian9.moment)().format((0, import_obsidian_daily_notes_interface.getDailyNoteSettings)().format).toString() + "]] " + (0, import_obsidian9.moment)().format("HH:mm"); 1925 const os = window.require("os"); 1926 const machineName = import_obsidian9.Platform.isDesktop ? os.hostname() : "MOBILE"; 1927 let output = dateOutput + " " + machineName + " " + textToLog.replace("\n", " ") + "\n\n"; 1928 if (await plugin.app.vault.adapter.exists(fileName)) { 1929 const fileContents = await plugin.app.vault.adapter.read(fileName); 1930 output = output + fileContents; 1931 const file = plugin.app.vault.getAbstractFileByPath(fileName); 1932 await plugin.app.vault.modify(file, output); 1933 } else 1934 await plugin.app.vault.create(fileName, output); 1935 } 1936 } 1937 } 1938 1939 // src/ui/GenericFuzzySuggester.ts 1940 var import_obsidian10 = require("obsidian"); 1941 var GenericFuzzySuggester = class extends import_obsidian10.FuzzySuggestModal { 1942 constructor(plugin) { 1943 super(plugin.app); 1944 this.data = []; 1945 this.scope.register(["Shift"], "Enter", (evt) => { 1946 this.enterTrigger(evt); 1947 }); 1948 this.scope.register(["Ctrl"], "Enter", (evt) => { 1949 this.enterTrigger(evt); 1950 }); 1951 } 1952 setSuggesterData(suggesterData) { 1953 this.data = suggesterData; 1954 } 1955 display(callBack) { 1956 this.callbackFunction = callBack; 1957 this.open(); 1958 } 1959 getItems() { 1960 return this.data; 1961 } 1962 getItemText(item) { 1963 return item.display; 1964 } 1965 onChooseItem() { 1966 return; 1967 } 1968 renderSuggestion(item, el) { 1969 el.createEl("div", { text: item.item.display }); 1970 } 1971 enterTrigger(evt) { 1972 var _a; 1973 const selectedText = (_a = document.querySelector(".suggestion-item.is-selected div")) == null ? void 0 : _a.textContent; 1974 const item = this.data.find((i) => i.display === selectedText); 1975 if (item) { 1976 this.invokeCallback(item, evt); 1977 this.close(); 1978 } 1979 } 1980 onChooseSuggestion(item, evt) { 1981 this.invokeCallback(item.item, evt); 1982 } 1983 invokeCallback(item, evt) { 1984 if (typeof this.callbackFunction === "function") { 1985 this.callbackFunction(item, evt); 1986 } 1987 } 1988 }; 1989 1990 // src/ui/PluginCommands.ts 1991 var PluginCommands = class { 1992 constructor(plugin) { 1993 this.bratCommands = [ 1994 { 1995 id: "BRAT-AddBetaPlugin", 1996 icon: "BratIcon", 1997 name: "Plugins: Add a beta plugin for testing", 1998 showInRibbon: true, 1999 callback: () => { 2000 this.plugin.betaPlugins.displayAddNewPluginModal(false, false); 2001 } 2002 }, 2003 { 2004 id: "BRAT-AddBetaPluginWithFrozenVersion", 2005 icon: "BratIcon", 2006 name: "Plugins: Add a beta plugin with frozen version based on a release tag", 2007 showInRibbon: true, 2008 callback: () => { 2009 this.plugin.betaPlugins.displayAddNewPluginModal(false, true); 2010 } 2011 }, 2012 { 2013 id: "BRAT-checkForUpdatesAndUpdate", 2014 icon: "BratIcon", 2015 name: "Plugins: Check for updates to all beta plugins and UPDATE", 2016 showInRibbon: true, 2017 callback: async () => { 2018 await this.plugin.betaPlugins.checkForPluginUpdatesAndInstallUpdates(true, false); 2019 } 2020 }, 2021 { 2022 id: "BRAT-checkForUpdatesAndDontUpdate", 2023 icon: "BratIcon", 2024 name: "Plugins: Only check for updates to beta plugins, but don't Update", 2025 showInRibbon: true, 2026 callback: async () => { 2027 await this.plugin.betaPlugins.checkForPluginUpdatesAndInstallUpdates(true, true); 2028 } 2029 }, 2030 { 2031 id: "BRAT-updateOnePlugin", 2032 icon: "BratIcon", 2033 name: "Plugins: Choose a single plugin version to update", 2034 showInRibbon: true, 2035 callback: () => { 2036 const pluginSubListFrozenVersionNames = new Set( 2037 this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo) 2038 ); 2039 const pluginList = Object.values(this.plugin.settings.pluginList).filter((f) => !pluginSubListFrozenVersionNames.has(f)).map((m) => { 2040 return { display: m, info: m }; 2041 }); 2042 const gfs = new GenericFuzzySuggester(this.plugin); 2043 gfs.setSuggesterData(pluginList); 2044 gfs.display((results) => { 2045 const msg = `Checking for updates for ${results.info}`; 2046 void this.plugin.log(msg, true); 2047 toastMessage(this.plugin, ` 2048 ${msg}`, 3); 2049 void this.plugin.betaPlugins.updatePlugin(results.info, false, true); 2050 }); 2051 } 2052 }, 2053 { 2054 id: "BRAT-reinstallOnePlugin", 2055 icon: "BratIcon", 2056 name: "Plugins: Choose a single plugin to reinstall", 2057 showInRibbon: true, 2058 callback: () => { 2059 const pluginSubListFrozenVersionNames = new Set( 2060 this.plugin.settings.pluginSubListFrozenVersion.map((f) => f.repo) 2061 ); 2062 const pluginList = Object.values(this.plugin.settings.pluginList).filter((f) => !pluginSubListFrozenVersionNames.has(f)).map((m) => { 2063 return { display: m, info: m }; 2064 }); 2065 const gfs = new GenericFuzzySuggester(this.plugin); 2066 gfs.setSuggesterData(pluginList); 2067 gfs.display((results) => { 2068 const msg = `Reinstalling ${results.info}`; 2069 toastMessage(this.plugin, ` 2070 ${msg}`, 3); 2071 void this.plugin.log(msg, true); 2072 void this.plugin.betaPlugins.updatePlugin( 2073 results.info, 2074 false, 2075 false, 2076 true 2077 ); 2078 }); 2079 } 2080 }, 2081 { 2082 id: "BRAT-restartPlugin", 2083 icon: "BratIcon", 2084 name: "Plugins: Restart a plugin that is already installed", 2085 showInRibbon: true, 2086 callback: () => { 2087 const pluginList = Object.values( 2088 this.plugin.app.plugins.manifests 2089 ).map((m) => { 2090 return { display: m.id, info: m.id }; 2091 }); 2092 const gfs = new GenericFuzzySuggester(this.plugin); 2093 gfs.setSuggesterData(pluginList); 2094 gfs.display((results) => { 2095 toastMessage( 2096 this.plugin, 2097 `${results.info} 2098 Plugin reloading .....`, 2099 5 2100 ); 2101 void this.plugin.betaPlugins.reloadPlugin(results.info); 2102 }); 2103 } 2104 }, 2105 { 2106 id: "BRAT-disablePlugin", 2107 icon: "BratIcon", 2108 name: "Plugins: Disable a plugin - toggle it off", 2109 showInRibbon: true, 2110 callback: () => { 2111 const pluginList = this.plugin.betaPlugins.getEnabledDisabledPlugins(true).map((manifest) => { 2112 return { display: `${manifest.name} (${manifest.id})`, info: manifest.id }; 2113 }); 2114 const gfs = new GenericFuzzySuggester(this.plugin); 2115 gfs.setSuggesterData(pluginList); 2116 gfs.display((results) => { 2117 void this.plugin.log(`${results.display} plugin disabled`, false); 2118 if (this.plugin.settings.debuggingMode) 2119 console.log(results.info); 2120 void this.plugin.app.plugins.disablePluginAndSave(results.info); 2121 }); 2122 } 2123 }, 2124 { 2125 id: "BRAT-enablePlugin", 2126 icon: "BratIcon", 2127 name: "Plugins: Enable a plugin - toggle it on", 2128 showInRibbon: true, 2129 callback: () => { 2130 const pluginList = this.plugin.betaPlugins.getEnabledDisabledPlugins(false).map((manifest) => { 2131 return { display: `${manifest.name} (${manifest.id})`, info: manifest.id }; 2132 }); 2133 const gfs = new GenericFuzzySuggester(this.plugin); 2134 gfs.setSuggesterData(pluginList); 2135 gfs.display((results) => { 2136 void this.plugin.log(`${results.display} plugin enabled`, false); 2137 void this.plugin.app.plugins.enablePluginAndSave(results.info); 2138 }); 2139 } 2140 }, 2141 { 2142 id: "BRAT-openGitHubZRepository", 2143 icon: "BratIcon", 2144 name: "Plugins: Open the GitHub repository for a plugin", 2145 showInRibbon: true, 2146 callback: async () => { 2147 const communityPlugins = await grabCommmunityPluginList( 2148 this.plugin.settings.debuggingMode 2149 ); 2150 if (communityPlugins) { 2151 const communityPluginList = Object.values( 2152 communityPlugins 2153 ).map((p) => { 2154 return { display: `Plugin: ${p.name} (${p.repo})`, info: p.repo }; 2155 }); 2156 const bratList = Object.values( 2157 this.plugin.settings.pluginList 2158 ).map((p) => { 2159 return { display: "BRAT: " + p, info: p }; 2160 }); 2161 communityPluginList.forEach((si) => bratList.push(si)); 2162 const gfs = new GenericFuzzySuggester(this.plugin); 2163 gfs.setSuggesterData(bratList); 2164 gfs.display((results) => { 2165 if (results.info) 2166 window.open(`https://github.com/${results.info}`); 2167 }); 2168 } 2169 } 2170 }, 2171 { 2172 id: "BRAT-openGitHubRepoTheme", 2173 icon: "BratIcon", 2174 name: "Themes: Open the GitHub repository for a theme (appearance)", 2175 showInRibbon: true, 2176 callback: async () => { 2177 const communityTheme = await grabCommmunityThemesList( 2178 this.plugin.settings.debuggingMode 2179 ); 2180 if (communityTheme) { 2181 const communityThemeList = Object.values(communityTheme).map( 2182 (p) => { 2183 return { display: `Theme: ${p.name} (${p.repo})`, info: p.repo }; 2184 } 2185 ); 2186 const gfs = new GenericFuzzySuggester(this.plugin); 2187 gfs.setSuggesterData(communityThemeList); 2188 gfs.display((results) => { 2189 if (results.info) 2190 window.open(`https://github.com/${results.info}`); 2191 }); 2192 } 2193 } 2194 }, 2195 { 2196 id: "BRAT-opentPluginSettings", 2197 icon: "BratIcon", 2198 name: "Plugins: Open Plugin Settings Tab", 2199 showInRibbon: true, 2200 callback: () => { 2201 const settings = this.plugin.app.setting; 2202 const listOfPluginSettingsTabs = Object.values( 2203 settings.pluginTabs 2204 ).map((t) => { 2205 return { display: "Plugin: " + t.name, info: t.id }; 2206 }); 2207 const gfs = new GenericFuzzySuggester(this.plugin); 2208 const listOfCoreSettingsTabs = Object.values( 2209 settings.settingTabs 2210 ).map((t) => { 2211 return { display: "Core: " + t.name, info: t.id }; 2212 }); 2213 listOfPluginSettingsTabs.forEach((si) => listOfCoreSettingsTabs.push(si)); 2214 gfs.setSuggesterData(listOfCoreSettingsTabs); 2215 gfs.display((results) => { 2216 settings.open(); 2217 settings.openTabById(results.info); 2218 }); 2219 } 2220 }, 2221 { 2222 id: "BRAT-GrabBetaTheme", 2223 icon: "BratIcon", 2224 name: "Themes: Grab a beta theme for testing from a Github repository", 2225 showInRibbon: true, 2226 callback: () => { 2227 new AddNewTheme(this.plugin).open(); 2228 } 2229 }, 2230 { 2231 id: "BRAT-updateBetaThemes", 2232 icon: "BratIcon", 2233 name: "Themes: Update beta themes", 2234 showInRibbon: true, 2235 callback: async () => { 2236 await themesCheckAndUpdates(this.plugin, true); 2237 } 2238 }, 2239 { 2240 id: "BRAT-allCommands", 2241 icon: "BratIcon", 2242 name: "All Commands list", 2243 showInRibbon: false, 2244 callback: () => { 2245 this.ribbonDisplayCommands(); 2246 } 2247 } 2248 ]; 2249 this.plugin = plugin; 2250 this.bratCommands.forEach((item) => { 2251 this.plugin.addCommand({ 2252 id: item.id, 2253 name: item.name, 2254 icon: item.icon, 2255 callback: () => { 2256 item.callback(); 2257 } 2258 }); 2259 }); 2260 } 2261 ribbonDisplayCommands() { 2262 const bratCommandList = []; 2263 this.bratCommands.forEach((cmd) => { 2264 if (cmd.showInRibbon) 2265 bratCommandList.push({ display: cmd.name, info: cmd.callback }); 2266 }); 2267 const gfs = new GenericFuzzySuggester(this.plugin); 2268 const settings = this.plugin.app.setting; 2269 const listOfCoreSettingsTabs = Object.values( 2270 settings.settingTabs 2271 ).map((t) => { 2272 return { 2273 display: "Core: " + t.name, 2274 info: () => { 2275 settings.open(); 2276 settings.openTabById(t.id); 2277 } 2278 }; 2279 }); 2280 const listOfPluginSettingsTabs = Object.values( 2281 settings.pluginTabs 2282 ).map((t) => { 2283 return { 2284 display: "Plugin: " + t.name, 2285 info: () => { 2286 settings.open(); 2287 settings.openTabById(t.id); 2288 } 2289 }; 2290 }); 2291 bratCommandList.push({ 2292 display: "---- Core Plugin Settings ----", 2293 info: () => { 2294 this.ribbonDisplayCommands(); 2295 } 2296 }); 2297 listOfCoreSettingsTabs.forEach((si) => bratCommandList.push(si)); 2298 bratCommandList.push({ 2299 display: "---- Plugin Settings ----", 2300 info: () => { 2301 this.ribbonDisplayCommands(); 2302 } 2303 }); 2304 listOfPluginSettingsTabs.forEach((si) => bratCommandList.push(si)); 2305 gfs.setSuggesterData(bratCommandList); 2306 gfs.display((results) => { 2307 if (typeof results.info === "function") { 2308 results.info(); 2309 } 2310 }); 2311 } 2312 }; 2313 2314 // src/utils/BratAPI.ts 2315 var BratAPI = class { 2316 constructor(plugin) { 2317 this.console = (logDescription, ...outputs) => { 2318 console.log("BRAT: " + logDescription, ...outputs); 2319 }; 2320 this.themes = { 2321 themeseCheckAndUpates: async (showInfo) => { 2322 await themesCheckAndUpdates(this.plugin, showInfo); 2323 }, 2324 themeInstallTheme: async (cssGithubRepository) => { 2325 const scrubbedAddress = cssGithubRepository.replace("https://github.com/", ""); 2326 await themeSave(this.plugin, scrubbedAddress, true); 2327 }, 2328 themesDelete: (cssGithubRepository) => { 2329 const scrubbedAddress = cssGithubRepository.replace("https://github.com/", ""); 2330 themeDelete(this.plugin, scrubbedAddress); 2331 }, 2332 grabCommmunityThemeCssFile: async (repositoryPath, betaVersion = false) => { 2333 return await grabCommmunityThemeCssFile( 2334 repositoryPath, 2335 betaVersion, 2336 this.plugin.settings.debuggingMode 2337 ); 2338 }, 2339 grabChecksumOfThemeCssFile: async (repositoryPath, betaVersion = false) => { 2340 return await grabChecksumOfThemeCssFile( 2341 repositoryPath, 2342 betaVersion, 2343 this.plugin.settings.debuggingMode 2344 ); 2345 }, 2346 grabLastCommitDateForFile: async (repositoryPath, path) => { 2347 return await grabLastCommitDateForFile(repositoryPath, path); 2348 } 2349 }; 2350 this.plugin = plugin; 2351 } 2352 }; 2353 2354 // src/main.ts 2355 var ThePlugin = class extends import_obsidian11.Plugin { 2356 constructor() { 2357 super(...arguments); 2358 this.APP_NAME = "BRAT"; 2359 this.APP_ID = "obsidian42-brat"; 2360 this.settings = DEFAULT_SETTINGS; 2361 this.betaPlugins = new BetaPlugins(this); 2362 this.commands = new PluginCommands(this); 2363 this.bratApi = new BratAPI(this); 2364 this.obsidianProtocolHandler = (params) => { 2365 if (!params.plugin && !params.theme) { 2366 toastMessage(this, `Could not locate the repository from the URL.`, 10); 2367 return; 2368 } 2369 for (const which of ["plugin", "theme"]) { 2370 if (params[which]) { 2371 const modal = which === "plugin" ? new AddNewPluginModal(this, this.betaPlugins) : new AddNewTheme(this); 2372 modal.address = params[which]; 2373 modal.open(); 2374 return; 2375 } 2376 } 2377 }; 2378 } 2379 async onload() { 2380 console.log("loading " + this.APP_NAME); 2381 await this.loadSettings(); 2382 this.addSettingTab(new BratSettingsTab(this.app, this)); 2383 addIcons(); 2384 this.showRibbonButton(); 2385 this.registerObsidianProtocolHandler("brat", this.obsidianProtocolHandler); 2386 this.app.workspace.onLayoutReady(() => { 2387 if (this.settings.updateAtStartup) { 2388 setTimeout(() => { 2389 void this.betaPlugins.checkForPluginUpdatesAndInstallUpdates(false); 2390 }, 6e4); 2391 } 2392 if (this.settings.updateThemesAtStartup) { 2393 setTimeout(() => { 2394 void themesCheckAndUpdates(this, false); 2395 }, 12e4); 2396 } 2397 setTimeout(() => { 2398 window.bratAPI = this.bratApi; 2399 }, 500); 2400 }); 2401 } 2402 showRibbonButton() { 2403 this.addRibbonIcon("BratIcon", "BRAT", () => { 2404 this.commands.ribbonDisplayCommands(); 2405 }); 2406 } 2407 async log(textToLog, verbose = false) { 2408 await logger(this, textToLog, verbose); 2409 } 2410 onunload() { 2411 console.log("unloading " + this.APP_NAME); 2412 } 2413 async loadSettings() { 2414 this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData()); 2415 } 2416 async saveSettings() { 2417 await this.saveData(this.settings); 2418 } 2419 };