already existing character sheets can now be updated. Furthermore aliases are now conducted when trying to link feats/spells/actions
parent
e327c53390
commit
73ef5ef3fc
159
main.ts
159
main.ts
|
|
@ -1,5 +1,5 @@
|
||||||
import * as Handlebars from 'handlebars';
|
import * as Handlebars from 'handlebars';
|
||||||
import { App, Vault, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TAbstractFile } from 'obsidian';
|
import { App, Vault, Editor, MarkdownView, Modal, Notice, Plugin, PluginSettingTab, Setting, TAbstractFile, TFile } from 'obsidian';
|
||||||
|
|
||||||
// Remember to rename these classes and interfaces!
|
// Remember to rename these classes and interfaces!
|
||||||
|
|
||||||
|
|
@ -12,7 +12,7 @@ interface P2HLOSettings {
|
||||||
const DEFAULT_SETTINGS: P2HLOSettings = {
|
const DEFAULT_SETTINGS: P2HLOSettings = {
|
||||||
userToken: '',
|
userToken: '',
|
||||||
campaignToken: '',
|
campaignToken: '',
|
||||||
notesFolder: '/'
|
notesFolder: '/',
|
||||||
}
|
}
|
||||||
|
|
||||||
const toolName = "p2hlo-bridge"
|
const toolName = "p2hlo-bridge"
|
||||||
|
|
@ -38,38 +38,58 @@ interface convertReturn {
|
||||||
|
|
||||||
export default class P2HLO extends Plugin {
|
export default class P2HLO extends Plugin {
|
||||||
settings: P2HLOSettings;
|
settings: P2HLOSettings;
|
||||||
|
notes: { // mapping of a note by full filepath including file extension to its aliases
|
||||||
|
[filePath: string]: string[],
|
||||||
|
}
|
||||||
|
|
||||||
private byPrefixCode(obj: object, prefix: string) {
|
private byPrefixCode(obj: object, prefix: string) {
|
||||||
return obj[Object.keys(obj).find( predicate => predicate.startsWith(prefix))]
|
return obj[Object.keys(obj).find( predicate => predicate.startsWith(prefix))]
|
||||||
|
}
|
||||||
|
|
||||||
|
private filterKeysByPrefixCode(obj: object, prefix: string) {
|
||||||
|
const keys = [...Object.keys(obj).filter( predicate => predicate.startsWith(prefix))]
|
||||||
|
return keys.map (key => {
|
||||||
|
return {
|
||||||
|
...obj[key]
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private prefixNumber(n: number) {
|
||||||
|
if (n < 0) {
|
||||||
|
return `-${n}`
|
||||||
|
} else if (n > 0) {
|
||||||
|
return `+${n}`
|
||||||
|
} else {
|
||||||
|
return "+0"
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private filterKeysByPrefixCode(obj: object, prefix: string) {
|
private hloTextToMarkdown(str: string) {
|
||||||
const keys = [...Object.keys(obj).filter( predicate => predicate.startsWith(prefix))]
|
return str.replace(/\{b\}/gi, "**").replace(/\{\/b\}/gi, "**").replace(/\{br\}\{br\}/gi, "{br}").replace(/\{br\}/gi, "\\n")
|
||||||
return keys.map (key => {
|
}
|
||||||
return {
|
|
||||||
...obj[key]
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
|
private makeLink(linkName: string, category: string = ""): string|undefined {
|
||||||
private prefixNumber(n: number) {
|
const sanitizedLinkName = linkName.replace("'", "'").toLowerCase().replace(/\ /g, "-")
|
||||||
if (n < 0) {
|
console.log("finding link to ", sanitizedLinkName)
|
||||||
return `-${n}`
|
let found = undefined
|
||||||
} else if (n > 0) {
|
const reName = new RegExp(`^${sanitizedLinkName}(?:-.{1,4})?\.md$`, "gi")
|
||||||
return `+${n}`
|
console.log("try to match", reName, category)
|
||||||
} else {
|
let fileName = ""
|
||||||
return "+0"
|
for (fileName in this.notes) {
|
||||||
|
if ((this.notes[fileName]??"").contains(linkName)) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (fileName !== "") {
|
||||||
private hloTextToMarkdown(str: string) {
|
return fileName.split(".md")[0]
|
||||||
return str.replace(/\{b\}/gi, "**").replace(/\{\/b\}/gi, "**").replace(/\{br\}\{br\}/gi, "{br}").replace(/\{br\}/gi, "\\n")
|
} else {
|
||||||
|
return undefined
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private convert(json: Object): convertReturn|null {
|
||||||
convert(json: Object): convertReturn|null {
|
|
||||||
|
|
||||||
const actor = this.byPrefixCode(json, "actor");
|
const actor = this.byPrefixCode(json, "actor");
|
||||||
|
|
||||||
|
|
@ -131,13 +151,13 @@ size: {{size}}
|
||||||
level: {{classes}}
|
level: {{classes}}
|
||||||
trait_03: "Player"
|
trait_03: "Player"
|
||||||
trait_04: "{{ancestry}}"
|
trait_04: "{{ancestry}}"
|
||||||
languages: "{{#languages}}{{this}}, {{/languages}}; "
|
languages: "{{#languages}} {{this}}, {{/languages}}; "
|
||||||
perception:
|
perception:
|
||||||
- name: "Perception"
|
- name: "Perception"
|
||||||
- desc: "Perception {{perception}}"
|
desc: "Perception {{perception}}"
|
||||||
skills:
|
skills:
|
||||||
- name: "Skills"
|
- name: "Skills"
|
||||||
- desc: "{{#skills}}__{{name}}__: {{mod}} (1d20{{mod}}); {{/skills}}"
|
desc: "{{#skills}}__{{name}}__: {{mod}} (1d20{{mod}}); {{/skills}}"
|
||||||
abilitiyMods: [{{str}}, {{con}}, {{dex}}, {{int}}, {{cha}}, {{wis}}]
|
abilitiyMods: [{{str}}, {{con}}, {{dex}}, {{int}}, {{cha}}, {{wis}}]
|
||||||
|
|
||||||
abilities_top:
|
abilities_top:
|
||||||
|
|
@ -155,6 +175,7 @@ abilities_bot:
|
||||||
armorclass:
|
armorclass:
|
||||||
- name: AC
|
- name: AC
|
||||||
desc: "{{ac}}; __Fort__: {{fortitude}} (1d20{{fortitude}}); __Ref__: {{reflex}} (1d20{{reflex}}); __Will__: {{will}} (1d20{{will}})"
|
desc: "{{ac}}; __Fort__: {{fortitude}} (1d20{{fortitude}}); __Ref__: {{reflex}} (1d20{{reflex}}); __Will__: {{will}} (1d20{{will}})"
|
||||||
|
|
||||||
speed: "{{speeds}}"
|
speed: "{{speeds}}"
|
||||||
|
|
||||||
attacks:
|
attacks:
|
||||||
|
|
@ -175,7 +196,7 @@ attacks:
|
||||||
{{#items}}
|
{{#items}}
|
||||||
- {{name}}
|
- {{name}}
|
||||||
{{/items}}
|
{{/items}}
|
||||||
`
|
`
|
||||||
|
|
||||||
const template = Handlebars.compile(src)
|
const template = Handlebars.compile(src)
|
||||||
|
|
||||||
|
|
@ -221,7 +242,7 @@ attacks:
|
||||||
desc = predicate.name.split("(")[1].split(")")[0]
|
desc = predicate.name.split("(")[1].split(")")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
link = `compendium/feats/${name.trim().replace(/\ /g, "-")}`
|
link = this.makeLink(name.trim(), "feats") ?? ""
|
||||||
|
|
||||||
if (predicate.actions) {
|
if (predicate.actions) {
|
||||||
actionpoints = predicate.actions
|
actionpoints = predicate.actions
|
||||||
|
|
@ -255,7 +276,7 @@ attacks:
|
||||||
desc = predicate.name.split("(")[1].split(")")[0]
|
desc = predicate.name.split("(")[1].split(")")[0]
|
||||||
}
|
}
|
||||||
|
|
||||||
link = `rules/actions/${name.trim().replace(/\ /g, "-")}`
|
link = this.makeLink(name.trim(), "actions") ?? ""
|
||||||
|
|
||||||
if (predicate.actions) {
|
if (predicate.actions) {
|
||||||
actionpoints = predicate.actions
|
actionpoints = predicate.actions
|
||||||
|
|
@ -283,9 +304,7 @@ attacks:
|
||||||
}),
|
}),
|
||||||
items: [...alchemicalItems, ...gear].map(predicate => {
|
items: [...alchemicalItems, ...gear].map(predicate => {
|
||||||
let itemName = predicate.name
|
let itemName = predicate.name
|
||||||
console.log(predicate.items)
|
|
||||||
if (predicate.items) {
|
if (predicate.items) {
|
||||||
console.log(predicate.items, Object.values(predicate.items))
|
|
||||||
itemName += "("
|
itemName += "("
|
||||||
itemName += Object.values(predicate.items).map(predicate2 => "*" + predicate2.name + "*").join(", ")
|
itemName += Object.values(predicate.items).map(predicate2 => "*" + predicate2.name + "*").join(", ")
|
||||||
itemName += ")"
|
itemName += ")"
|
||||||
|
|
@ -311,8 +330,8 @@ attacks:
|
||||||
if (predicate.useInPlay) {
|
if (predicate.useInPlay) {
|
||||||
desc = this.hloTextToMarkdown(predicate.useInPlay)
|
desc = this.hloTextToMarkdown(predicate.useInPlay)
|
||||||
}
|
}
|
||||||
|
console.log(name.trim())
|
||||||
let link = `compendium/spells/${predicate.name.trim()}`
|
let link = this.makeLink(predicate.name.trim(), "spells") ?? ""
|
||||||
|
|
||||||
link = link.split(" (")[0]
|
link = link.split(" (")[0]
|
||||||
link = link.replace(/\ /g, "-")
|
link = link.replace(/\ /g, "-")
|
||||||
|
|
@ -420,21 +439,21 @@ attacks:
|
||||||
}
|
}
|
||||||
|
|
||||||
async performTask() {
|
async performTask() {
|
||||||
|
await this.precacheNotes()
|
||||||
|
console.log(this.notes)
|
||||||
if (await this.preflightTest()) {
|
if (await this.preflightTest()) {
|
||||||
const accessToken = await this.fetchAccessToken()
|
const accessToken = await this.fetchAccessToken()
|
||||||
const castMember = await this.fetchStage(accessToken)
|
const castMember = await this.fetchStage(accessToken)
|
||||||
console.log(castMember)
|
|
||||||
if (castMember.length == 0) {
|
if (castMember.length == 0) {
|
||||||
new Notice("No Castmember found on Stage. Did you forgot to start a session?")
|
new Notice("No Castmember found on Stage. Did you forgot to start a session?")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
const characters = await this.fetchCharacters(accessToken, castMember)
|
const characters = await this.fetchCharacters(accessToken, castMember)
|
||||||
console.log(characters)
|
|
||||||
try {
|
try {
|
||||||
const folder = this.app.vault.getFolderByPath(this.settings.notesFolder)
|
const folder = this.app.vault.getFolderByPath(this.settings.notesFolder)
|
||||||
await this.app.vault.trash(folder as TAbstractFile, true)
|
await this.app.fileManager.trashFile(folder as TAbstractFile)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log(e)
|
console.error(e)
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
await this.app.vault.createFolder(this.settings.notesFolder)
|
await this.app.vault.createFolder(this.settings.notesFolder)
|
||||||
|
|
@ -448,12 +467,17 @@ attacks:
|
||||||
try {
|
try {
|
||||||
await this.app.vault.create(`${this.settings.notesFolder}/${result.name}.md`, result.output)
|
await this.app.vault.create(`${this.settings.notesFolder}/${result.name}.md`, result.output)
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
const file = this.app.vault.getFileByPath(`/${this.settings.notesFolder}/${result.name}.md`)
|
const directoryWithoutRoot = this.settings.notesFolder.substring(1)
|
||||||
|
const file = this.app.vault.getFileByPath(`${directoryWithoutRoot}/${result.name}.md`)
|
||||||
|
try {
|
||||||
if (file) {
|
if (file) {
|
||||||
await this.app.vault.modify(file, result.output)
|
await this.app.vault.modify(file, result.output)
|
||||||
} else {
|
} else {
|
||||||
console.error(file)
|
console.error(file)
|
||||||
}
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.error(e)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -461,21 +485,42 @@ attacks:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
async getAliasesOfTFile(fileObject: TFile): Promise<string[]> {
|
||||||
|
|
||||||
|
return new Promise( (resolve, reject) => {
|
||||||
|
this.app.fileManager.processFrontMatter(
|
||||||
|
fileObject,
|
||||||
|
(frontMatter) => {
|
||||||
|
resolve(frontMatter.aliases)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private async precacheNotes() {
|
||||||
|
|
||||||
|
this.notes = {}
|
||||||
|
|
||||||
|
this.app.vault
|
||||||
|
.getMarkdownFiles()
|
||||||
|
.forEach(
|
||||||
|
async (fileObject: TFile) => {
|
||||||
|
this.notes[fileObject.path] = await this.getAliasesOfTFile(fileObject)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
async onload() {
|
async onload() {
|
||||||
await this.loadSettings();
|
await this.loadSettings()
|
||||||
|
|
||||||
// This creates an icon in the left ribbon.
|
// This creates an icon in the left ribbon.
|
||||||
const ribbonIconEl = this.addRibbonIcon('dice', 'Sync Stage', async (evt: MouseEvent) => {
|
const ribbonIconEl = this.addRibbonIcon('dot-network', 'Sync Stage', async (evt: MouseEvent) => {
|
||||||
// Called when the user clicks the icon.
|
// Called when the user clicks the icon.
|
||||||
await this.performTask()
|
await this.performTask()
|
||||||
|
|
||||||
});
|
})
|
||||||
// Perform additional things with the ribbon
|
|
||||||
ribbonIconEl.addClass('my-plugin-ribbon-class');
|
|
||||||
|
|
||||||
// This adds a status bar item to the bottom of the app. Does not work on mobile apps.
|
|
||||||
const statusBarItemEl = this.addStatusBarItem();
|
|
||||||
statusBarItemEl.setText('Status Bar Text');
|
|
||||||
|
|
||||||
// This adds a simple command that can be triggered anywhere
|
// This adds a simple command that can be triggered anywhere
|
||||||
this.addCommand({
|
this.addCommand({
|
||||||
|
|
@ -484,19 +529,9 @@ attacks:
|
||||||
callback: () => {
|
callback: () => {
|
||||||
this.preflightTest()
|
this.preflightTest()
|
||||||
}
|
}
|
||||||
});
|
})
|
||||||
|
|
||||||
// This adds a settings tab so the user can configure various aspects of the plugin
|
this.addSettingTab(new P2HLOSettingTab(this.app, this))
|
||||||
this.addSettingTab(new SampleSettingTab(this.app, this));
|
|
||||||
|
|
||||||
// If the plugin hooks up any global DOM events (on parts of the app that doesn't belong to this plugin)
|
|
||||||
// Using this function will automatically remove the event listener when this plugin is disabled.
|
|
||||||
this.registerDomEvent(document, 'click', (evt: MouseEvent) => {
|
|
||||||
console.log('click', evt);
|
|
||||||
});
|
|
||||||
|
|
||||||
// When registering intervals, this function will automatically clear the interval when the plugin is disabled.
|
|
||||||
this.registerInterval(window.setInterval(() => console.log('setInterval'), 5 * 60 * 1000));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
onunload() {
|
onunload() {
|
||||||
|
|
@ -512,7 +547,7 @@ attacks:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class SampleSettingTab extends PluginSettingTab {
|
class P2HLOSettingTab extends PluginSettingTab {
|
||||||
plugin: P2HLO;
|
plugin: P2HLO;
|
||||||
|
|
||||||
constructor(app: App, plugin: P2HLO) {
|
constructor(app: App, plugin: P2HLO) {
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue