mirror of
https://github.com/gosticks/flashcards-obsidian.git
synced 2025-10-16 12:05:33 +00:00
Add eslint and apply quick fixes
This commit is contained in:
parent
1940e78eda
commit
81a15ade41
20
.eslintrc.json
Normal file
20
.eslintrc.json
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"env": {
|
||||||
|
"browser": true,
|
||||||
|
"es2021": true
|
||||||
|
},
|
||||||
|
"extends": [
|
||||||
|
"eslint:recommended",
|
||||||
|
"plugin:@typescript-eslint/recommended"
|
||||||
|
],
|
||||||
|
"parser": "@typescript-eslint/parser",
|
||||||
|
"parserOptions": {
|
||||||
|
"ecmaVersion": 13,
|
||||||
|
"sourceType": "module"
|
||||||
|
},
|
||||||
|
"plugins": [
|
||||||
|
"@typescript-eslint"
|
||||||
|
],
|
||||||
|
"rules": {
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,6 +15,9 @@
|
|||||||
"@rollup/plugin-node-resolve": "^9.0.0",
|
"@rollup/plugin-node-resolve": "^9.0.0",
|
||||||
"@rollup/plugin-typescript": "^6.0.0",
|
"@rollup/plugin-typescript": "^6.0.0",
|
||||||
"@types/node": "^14.17.4",
|
"@types/node": "^14.17.4",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.7.0",
|
||||||
|
"@typescript-eslint/parser": "^5.7.0",
|
||||||
|
"eslint": "^8.4.1",
|
||||||
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
|
"obsidian": "https://github.com/obsidianmd/obsidian-api/tarball/master",
|
||||||
"rollup": "^2.52.2",
|
"rollup": "^2.52.2",
|
||||||
"ts-node": "^9.1.0",
|
"ts-node": "^9.1.0",
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -16,7 +16,7 @@ export abstract class Card {
|
|||||||
containsCode: boolean
|
containsCode: boolean
|
||||||
modelName: string
|
modelName: string
|
||||||
|
|
||||||
constructor(id: number, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[], inserted: boolean, mediaNames: string[], containsCode: boolean = false) {
|
constructor(id: number, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[], inserted: boolean, mediaNames: string[], containsCode = false) {
|
||||||
this.id = id
|
this.id = id
|
||||||
this.deckName = deckName
|
this.deckName = deckName
|
||||||
this.initialContent = initialContent
|
this.initialContent = initialContent
|
||||||
@ -43,14 +43,14 @@ export abstract class Card {
|
|||||||
// return false
|
// return false
|
||||||
// }
|
// }
|
||||||
|
|
||||||
let fields = Object.entries(card.fields)
|
const fields = Object.entries(card.fields)
|
||||||
// This is the case of a switch from a model to another one. It cannot be handeled
|
// This is the case of a switch from a model to another one. It cannot be handeled
|
||||||
if (fields.length !== Object.entries(this.fields).length) {
|
if (fields.length !== Object.entries(this.fields).length) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let field of fields) {
|
for (const field of fields) {
|
||||||
let fieldName = field[0]
|
const fieldName = field[0]
|
||||||
if (field[1].value !== this.fields[fieldName]) {
|
if (field[1].value !== this.fields[fieldName]) {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { codeDeckExtension, sourceDeckExtension } from 'src/constants';
|
|||||||
import { Card } from "src/entities/card";
|
import { Card } from "src/entities/card";
|
||||||
|
|
||||||
export class Flashcard extends Card {
|
export class Flashcard extends Card {
|
||||||
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
|
constructor(id = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted = false, mediaNames: string[], containsCode: boolean) {
|
||||||
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
|
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
|
||||||
this.modelName = this.reversed ? `Obsidian-basic-reversed` : `Obsidian-basic`
|
this.modelName = this.reversed ? `Obsidian-basic-reversed` : `Obsidian-basic`
|
||||||
if (fields["Source"]) {
|
if (fields["Source"]) {
|
||||||
@ -13,8 +13,8 @@ export class Flashcard extends Card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCard(update: boolean = false): object {
|
public getCard(update = false): object {
|
||||||
let card: any = {
|
const card: any = {
|
||||||
"deckName": this.deckName,
|
"deckName": this.deckName,
|
||||||
"modelName": this.modelName,
|
"modelName": this.modelName,
|
||||||
"fields": this.fields,
|
"fields": this.fields,
|
||||||
@ -29,7 +29,7 @@ export class Flashcard extends Card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getMedias(): object[] {
|
public getMedias(): object[] {
|
||||||
let medias: object[] = []
|
const medias: object[] = []
|
||||||
this.mediaBase64Encoded.forEach((data, index) => {
|
this.mediaBase64Encoded.forEach((data, index) => {
|
||||||
medias.push({
|
medias.push({
|
||||||
"filename": this.mediaNames[index],
|
"filename": this.mediaNames[index],
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { codeDeckExtension, sourceDeckExtension } from 'src/constants';
|
|||||||
import { Card } from "src/entities/card";
|
import { Card } from "src/entities/card";
|
||||||
|
|
||||||
export class Inlinecard extends Card {
|
export class Inlinecard extends Card {
|
||||||
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
|
constructor(id = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted = false, mediaNames: string[], containsCode: boolean) {
|
||||||
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode) // ! CHANGE []
|
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode) // ! CHANGE []
|
||||||
|
|
||||||
this.modelName = this.reversed ? `Obsidian-basic-reversed` : `Obsidian-basic`
|
this.modelName = this.reversed ? `Obsidian-basic-reversed` : `Obsidian-basic`
|
||||||
@ -14,8 +14,8 @@ export class Inlinecard extends Card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCard(update: boolean = false): object {
|
public getCard(update = false): object {
|
||||||
let card: any = {
|
const card: any = {
|
||||||
"deckName": this.deckName,
|
"deckName": this.deckName,
|
||||||
"modelName": this.modelName,
|
"modelName": this.modelName,
|
||||||
"fields": this.fields,
|
"fields": this.fields,
|
||||||
@ -30,7 +30,7 @@ export class Inlinecard extends Card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getMedias(): object[] {
|
public getMedias(): object[] {
|
||||||
let medias: object[] = []
|
const medias: object[] = []
|
||||||
this.mediaBase64Encoded.forEach((data, index) => {
|
this.mediaBase64Encoded.forEach((data, index) => {
|
||||||
medias.push({
|
medias.push({
|
||||||
"filename": this.mediaNames[index],
|
"filename": this.mediaNames[index],
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { codeDeckExtension, sourceDeckExtension } from 'src/constants';
|
|||||||
import { Card } from "src/entities/card";
|
import { Card } from "src/entities/card";
|
||||||
|
|
||||||
export class Spacedcard extends Card {
|
export class Spacedcard extends Card {
|
||||||
constructor(id: number = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted: boolean = false, mediaNames: string[], containsCode: boolean) {
|
constructor(id = -1, deckName: string, initialContent: string, fields: Record<string, string>, reversed: boolean, endOffset: number, tags: string[] = [], inserted = false, mediaNames: string[], containsCode: boolean) {
|
||||||
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
|
super(id, deckName, initialContent, fields, reversed, endOffset, tags, inserted, mediaNames, containsCode)
|
||||||
this.modelName = `Obsidian-spaced`
|
this.modelName = `Obsidian-spaced`
|
||||||
if (fields["Source"]) {
|
if (fields["Source"]) {
|
||||||
@ -13,9 +13,9 @@ export class Spacedcard extends Card {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public getCard(update: boolean = false): object {
|
public getCard(update = false): object {
|
||||||
|
|
||||||
let card: any = {
|
const card: any = {
|
||||||
"deckName": this.deckName,
|
"deckName": this.deckName,
|
||||||
"modelName": this.modelName,
|
"modelName": this.modelName,
|
||||||
"fields": this.fields,
|
"fields": this.fields,
|
||||||
@ -30,7 +30,7 @@ export class Spacedcard extends Card {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getMedias(): object[] {
|
public getMedias(): object[] {
|
||||||
let medias: object[] = []
|
const medias: object[] = []
|
||||||
this.mediaBase64Encoded.forEach((data, index) => {
|
this.mediaBase64Encoded.forEach((data, index) => {
|
||||||
medias.push({
|
medias.push({
|
||||||
"filename": this.mediaNames[index],
|
"filename": this.mediaNames[index],
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { Anki } from 'src/services/anki'
|
|||||||
|
|
||||||
export class SettingsTab extends PluginSettingTab {
|
export class SettingsTab extends PluginSettingTab {
|
||||||
display(): void {
|
display(): void {
|
||||||
let { containerEl } = this
|
const { containerEl } = this
|
||||||
const plugin = (this as any).plugin
|
const plugin = (this as any).plugin
|
||||||
|
|
||||||
containerEl.empty()
|
containerEl.empty()
|
||||||
|
|||||||
@ -34,13 +34,13 @@ export class Regex {
|
|||||||
this.cardsToDelete = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm
|
this.cardsToDelete = /^\s*(?:\n)(?:\^(\d{13}))(?:\n\s*?)?/gm
|
||||||
|
|
||||||
// https://regex101.com/r/WxuFI2/1
|
// https://regex101.com/r/WxuFI2/1
|
||||||
this.globalTagsSplitter = /\[\[(.*?)\]\]|#([\p{L}:\-_\/]+)|([\p{L}:\-_\/]+)/gmiu
|
this.globalTagsSplitter = /\[\[(.*?)\]\]|#([\p{L}:\-_/]+)|([\p{L}:\-_/]+)/gmiu
|
||||||
this.tagHierarchy = /\//gm
|
this.tagHierarchy = /\//gm
|
||||||
|
|
||||||
// Cards
|
// Cards
|
||||||
let flags = "gimu"
|
const flags = "gimu"
|
||||||
// https://regex101.com/r/p3yQwY/2
|
// https://regex101.com/r/p3yQwY/2
|
||||||
let str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "(?:[\/-]reverse)?)((?: *#[\\p{Letter}\\-\\/_]+)*) *?\\n+((?:[^\\n]\\n?)*?(?=\\^\\d{13}|$))(?:\\^(\\d{13}))?"
|
let str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "(?:[/-]reverse)?)((?: *#[\\p{Letter}\\-\\/_]+)*) *?\\n+((?:[^\\n]\\n?)*?(?=\\^\\d{13}|$))(?:\\^(\\d{13}))?"
|
||||||
this.flashscardsWithTag = new RegExp(str, flags)
|
this.flashscardsWithTag = new RegExp(str, flags)
|
||||||
|
|
||||||
// https://regex101.com/r/Ixtzlv/1
|
// https://regex101.com/r/Ixtzlv/1
|
||||||
@ -52,7 +52,7 @@ export class Regex {
|
|||||||
this.cardsInlineStyle = new RegExp(str, flags)
|
this.cardsInlineStyle = new RegExp(str, flags)
|
||||||
|
|
||||||
// https://regex101.com/r/HOXF5E/1
|
// https://regex101.com/r/HOXF5E/1
|
||||||
str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "[\/-]spaced)((?: *#[\\p{Letter}-]+)*) *\\n?(?:\\^(\\d{13}))?"
|
str = "( {0,3}[#]*)((?:[^\\n]\\n?)+?)(#" + settings.flashcardsTag + "[/-]spaced)((?: *#[\\p{Letter}-]+)*) *\\n?(?:\\^(\\d{13}))?"
|
||||||
this.cardsSpacedStyle = new RegExp(str, flags)
|
this.cardsSpacedStyle = new RegExp(str, flags)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,10 +16,10 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async storeMediaFiles(cards: Card[]) {
|
public async storeMediaFiles(cards: Card[]) {
|
||||||
let actions: any[] = []
|
const actions: any[] = []
|
||||||
|
|
||||||
for (let card of cards) {
|
for (const card of cards) {
|
||||||
for (let media of card.getMedias()) {
|
for (const media of card.getMedias()) {
|
||||||
actions.push({
|
actions.push({
|
||||||
"action": "storeMediaFile",
|
"action": "storeMediaFile",
|
||||||
"params": media
|
"params": media
|
||||||
@ -35,7 +35,7 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async storeCodeHighlightMedias() {
|
public async storeCodeHighlightMedias() {
|
||||||
let fileExists = await this.invoke(
|
const fileExists = await this.invoke(
|
||||||
"retrieveMediaFile",
|
"retrieveMediaFile",
|
||||||
6,
|
6,
|
||||||
{
|
{
|
||||||
@ -43,19 +43,19 @@ export class Anki {
|
|||||||
})
|
})
|
||||||
|
|
||||||
if (!fileExists) {
|
if (!fileExists) {
|
||||||
let highlightjs = {
|
const highlightjs = {
|
||||||
"action": "storeMediaFile", "params": {
|
"action": "storeMediaFile", "params": {
|
||||||
"filename": "_highlight.js",
|
"filename": "_highlight.js",
|
||||||
"data": highlightjsBase64
|
"data": highlightjsBase64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let highlightjsInit = {
|
const highlightjsInit = {
|
||||||
"action": "storeMediaFile", "params": {
|
"action": "storeMediaFile", "params": {
|
||||||
"filename": "_highlightInit.js",
|
"filename": "_highlightInit.js",
|
||||||
"data": hihglightjsInitBase64
|
"data": hihglightjsInitBase64
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let highlightjcss = {
|
const highlightjcss = {
|
||||||
"action": "storeMediaFile", "params": {
|
"action": "storeMediaFile", "params": {
|
||||||
"filename": "_highlight.css",
|
"filename": "_highlight.css",
|
||||||
"data": highlightCssBase64
|
"data": highlightCssBase64
|
||||||
@ -66,7 +66,7 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async addCards(cards: Card[]): Promise<number[]> {
|
public async addCards(cards: Card[]): Promise<number[]> {
|
||||||
let notes: any = []
|
const notes: any = []
|
||||||
|
|
||||||
cards.forEach(card => notes.push(card.getCard(false)))
|
cards.forEach(card => notes.push(card.getCard(false)))
|
||||||
|
|
||||||
@ -92,9 +92,9 @@ export class Anki {
|
|||||||
// This means that the delta from the current tags on Anki and the generated one should be added/removed
|
// This means that the delta from the current tags on Anki and the generated one should be added/removed
|
||||||
// That's what the current approach does, but in the future if the API it is made more consistent
|
// That's what the current approach does, but in the future if the API it is made more consistent
|
||||||
// then mergeTags(...) is not needed anymore
|
// then mergeTags(...) is not needed anymore
|
||||||
let ids: number[] = []
|
const ids: number[] = []
|
||||||
|
|
||||||
for (let card of cards) {
|
for (const card of cards) {
|
||||||
updateActions.push({
|
updateActions.push({
|
||||||
"action": "updateNoteFields",
|
"action": "updateNoteFields",
|
||||||
"params": {
|
"params": {
|
||||||
@ -139,11 +139,11 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private mergeTags(oldTags: string[], newTags: string[], cardId: number) {
|
private mergeTags(oldTags: string[], newTags: string[], cardId: number) {
|
||||||
let actions = []
|
const actions = []
|
||||||
|
|
||||||
// Find tags to Add
|
// Find tags to Add
|
||||||
for (let tag of newTags) {
|
for (const tag of newTags) {
|
||||||
let index = oldTags.indexOf(tag)
|
const index = oldTags.indexOf(tag)
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
oldTags.splice(index, 1)
|
oldTags.splice(index, 1)
|
||||||
} else {
|
} else {
|
||||||
@ -158,7 +158,7 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// All Tags to delete
|
// All Tags to delete
|
||||||
for (let tag of oldTags) {
|
for (const tag of oldTags) {
|
||||||
actions.push({
|
actions.push({
|
||||||
"action": "removeTags",
|
"action": "removeTags",
|
||||||
"params": {
|
"params": {
|
||||||
@ -171,7 +171,7 @@ export class Anki {
|
|||||||
return actions
|
return actions
|
||||||
}
|
}
|
||||||
|
|
||||||
private invoke(action: string, version: number = 6, params = {}): any {
|
private invoke(action: string, version = 6, params = {}): any {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const xhr = new XMLHttpRequest();
|
const xhr = new XMLHttpRequest();
|
||||||
xhr.addEventListener('error', () => reject('failed to issue request'));
|
xhr.addEventListener('error', () => reject('failed to issue request'));
|
||||||
@ -181,10 +181,10 @@ export class Anki {
|
|||||||
if (Object.getOwnPropertyNames(response).length != 2) {
|
if (Object.getOwnPropertyNames(response).length != 2) {
|
||||||
throw 'response has an unexpected number of fields';
|
throw 'response has an unexpected number of fields';
|
||||||
}
|
}
|
||||||
if (!response.hasOwnProperty('error')) {
|
if (!Object.prototype.hasOwnProperty.call(response, "error")) {
|
||||||
throw 'response is missing required error field';
|
throw 'response is missing required error field';
|
||||||
}
|
}
|
||||||
if (!response.hasOwnProperty('result')) {
|
if (!Object.prototype.hasOwnProperty.call(response, "result")) {
|
||||||
throw 'response is missing required result field';
|
throw 'response is missing required result field';
|
||||||
}
|
}
|
||||||
if (response.error) {
|
if (response.error) {
|
||||||
@ -216,13 +216,13 @@ export class Anki {
|
|||||||
codeExtension = codeDeckExtension
|
codeExtension = codeDeckExtension
|
||||||
}
|
}
|
||||||
|
|
||||||
let css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n"
|
const css = ".card {\r\n font-family: arial;\r\n font-size: 20px;\r\n text-align: center;\r\n color: black;\r\n background-color: white;\r\n}\r\n\r\n.tag::before {\r\n\tcontent: \"#\";\r\n}\r\n\r\n.tag {\r\n color: white;\r\n background-color: #9F2BFF;\r\n border: none;\r\n font-size: 11px;\r\n font-weight: bold;\r\n padding: 1px 8px;\r\n margin: 0px 3px;\r\n text-align: center;\r\n text-decoration: none;\r\n cursor: pointer;\r\n border-radius: 14px;\r\n display: inline;\r\n vertical-align: middle;\r\n}\r\n"
|
||||||
let front = `{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
|
const front = `{{Front}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
|
||||||
let back = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}${sourceFieldContent}`
|
const back = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Back}}${sourceFieldContent}`
|
||||||
let frontReversed = `{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
|
const frontReversed = `{{Back}}\r\n<p class=\"tags\">{{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
|
||||||
let backReversed = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}${sourceFieldContent}`
|
const backReversed = `{{FrontSide}}\n\n<hr id=answer>\n\n{{Front}}${sourceFieldContent}`
|
||||||
let prompt = `{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
|
const prompt = `{{Prompt}}\r\n<p class=\"tags\">🧠spaced {{Tags}}<\/p>\r\n\r\n<script>\r\n var tagEl = document.querySelector(\'.tags\');\r\n var tags = tagEl.innerHTML.split(\' \');\r\n var html = \'\';\r\n tags.forEach(function(tag) {\r\n\tif (tag) {\r\n\t var newTag = \'<span class=\"tag\">\' + tag + \'<\/span>\';\r\n html += newTag;\r\n \t tagEl.innerHTML = html;\r\n\t}\r\n });\r\n \r\n<\/script>${codeScriptContent}`
|
||||||
let promptBack = `{{FrontSide}}\n\n<hr id=answer>🧠 Review done.${sourceFieldContent}`
|
const promptBack = `{{FrontSide}}\n\n<hr id=answer>🧠 Review done.${sourceFieldContent}`
|
||||||
|
|
||||||
let classicFields = ["Front", "Back"]
|
let classicFields = ["Front", "Back"]
|
||||||
let promptFields = ["Prompt"]
|
let promptFields = ["Prompt"]
|
||||||
@ -231,7 +231,7 @@ export class Anki {
|
|||||||
promptFields = promptFields.concat("Source")
|
promptFields = promptFields.concat("Source")
|
||||||
}
|
}
|
||||||
|
|
||||||
let obsidianBasic = {
|
const obsidianBasic = {
|
||||||
"action": "createModel",
|
"action": "createModel",
|
||||||
"params": {
|
"params": {
|
||||||
"modelName": `Obsidian-basic${sourceExtension}${codeExtension}`,
|
"modelName": `Obsidian-basic${sourceExtension}${codeExtension}`,
|
||||||
@ -247,7 +247,7 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let obsidianBasicReversed = {
|
const obsidianBasicReversed = {
|
||||||
"action": "createModel",
|
"action": "createModel",
|
||||||
"params": {
|
"params": {
|
||||||
"modelName": `Obsidian-basic-reversed${sourceExtension}${codeExtension}`,
|
"modelName": `Obsidian-basic-reversed${sourceExtension}${codeExtension}`,
|
||||||
@ -268,7 +268,7 @@ export class Anki {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let obsidianSpaced = {
|
const obsidianSpaced = {
|
||||||
"action": "createModel",
|
"action": "createModel",
|
||||||
"params": {
|
"params": {
|
||||||
"modelName": `Obsidian-spaced${sourceExtension}${codeExtension}`,
|
"modelName": `Obsidian-spaced${sourceExtension}${codeExtension}`,
|
||||||
|
|||||||
@ -43,14 +43,14 @@ export class CardsService {
|
|||||||
this.updateFile = false
|
this.updateFile = false
|
||||||
this.totalOffset = 0
|
this.totalOffset = 0
|
||||||
this.notifications = []
|
this.notifications = []
|
||||||
let filePath = activeFile.basename
|
const filePath = activeFile.basename
|
||||||
let sourcePath = activeFile.path
|
const sourcePath = activeFile.path
|
||||||
let fileCachedMetadata = this.app.metadataCache.getFileCache(activeFile)
|
const fileCachedMetadata = this.app.metadataCache.getFileCache(activeFile)
|
||||||
let vaultName = this.app.vault.getName()
|
const vaultName = this.app.vault.getName()
|
||||||
let globalTags: string[] = undefined
|
let globalTags: string[] = undefined
|
||||||
|
|
||||||
// Parse frontmatter
|
// Parse frontmatter
|
||||||
let frontmatter = fileCachedMetadata.frontmatter
|
const frontmatter = fileCachedMetadata.frontmatter
|
||||||
let deckName = this.settings.deck
|
let deckName = this.settings.deck
|
||||||
if (frontmatter) {
|
if (frontmatter) {
|
||||||
deckName = parseFrontMatterEntry(frontmatter, "cards-deck") || this.settings.deck
|
deckName = parseFrontMatterEntry(frontmatter, "cards-deck") || this.settings.deck
|
||||||
@ -66,13 +66,13 @@ export class CardsService {
|
|||||||
}
|
}
|
||||||
globalTags = this.parseGlobalTags(this.file)
|
globalTags = this.parseGlobalTags(this.file)
|
||||||
// TODO with empty check that does not call ankiCards line
|
// TODO with empty check that does not call ankiCards line
|
||||||
let ankiBlocks = this.parser.getAnkiIDsBlocks(this.file)
|
const ankiBlocks = this.parser.getAnkiIDsBlocks(this.file)
|
||||||
let ankiCards = ankiBlocks ? await this.anki.getCards(this.getAnkiIDs(ankiBlocks)) : undefined
|
const ankiCards = ankiBlocks ? await this.anki.getCards(this.getAnkiIDs(ankiBlocks)) : undefined
|
||||||
|
|
||||||
let cards: Card[] = this.parser.generateFlashcards(this.file, deckName, vaultName, filePath, globalTags)
|
const cards: Card[] = this.parser.generateFlashcards(this.file, deckName, vaultName, filePath, globalTags)
|
||||||
let [cardsToCreate, cardsToUpdate, cardsNotInAnki] = this.filterByUpdate(ankiCards, cards)
|
const [cardsToCreate, cardsToUpdate, cardsNotInAnki] = this.filterByUpdate(ankiCards, cards)
|
||||||
let cardIds: number[] = this.getCardsIds(ankiCards, cards)
|
const cardIds: number[] = this.getCardsIds(ankiCards, cards)
|
||||||
let cardsToDelete: number[] = this.parser.getCardsToDelete(this.file)
|
const cardsToDelete: number[] = this.parser.getCardsToDelete(this.file)
|
||||||
|
|
||||||
console.info("Flashcards: Cards to create")
|
console.info("Flashcards: Cards to create")
|
||||||
console.info(cardsToCreate)
|
console.info(cardsToCreate)
|
||||||
@ -82,7 +82,7 @@ export class CardsService {
|
|||||||
console.info(cardsToDelete)
|
console.info(cardsToDelete)
|
||||||
if (cardsNotInAnki) {
|
if (cardsNotInAnki) {
|
||||||
console.info("Flashcards: Cards not in Anki (maybe deleted)")
|
console.info("Flashcards: Cards not in Anki (maybe deleted)")
|
||||||
for (let card of cardsNotInAnki) {
|
for (const card of cardsNotInAnki) {
|
||||||
this.notifications.push(`Error: Card with ID ${card.id} is not in Anki!`)
|
this.notifications.push(`Error: Card with ID ${card.id} is not in Anki!`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -94,7 +94,7 @@ export class CardsService {
|
|||||||
await this.insertCardsOnAnki(cardsToCreate, frontmatter, deckName)
|
await this.insertCardsOnAnki(cardsToCreate, frontmatter, deckName)
|
||||||
|
|
||||||
// Update decks if needed
|
// Update decks if needed
|
||||||
let deckNeedToBeChanged = await this.deckNeedToBeChanged(cardIds, deckName)
|
const deckNeedToBeChanged = await this.deckNeedToBeChanged(cardIds, deckName)
|
||||||
if (deckNeedToBeChanged) {
|
if (deckNeedToBeChanged) {
|
||||||
try {
|
try {
|
||||||
this.anki.changeDeck(cardIds, deckName)
|
this.anki.changeDeck(cardIds, deckName)
|
||||||
@ -141,17 +141,17 @@ export class CardsService {
|
|||||||
if (this.app.vault.adapter instanceof FileSystemAdapter) {
|
if (this.app.vault.adapter instanceof FileSystemAdapter) {
|
||||||
// @ts-ignore: Unreachable code error
|
// @ts-ignore: Unreachable code error
|
||||||
|
|
||||||
for (let card of cards) {
|
for (const card of cards) {
|
||||||
for (let media of card.mediaNames) {
|
for (const media of card.mediaNames) {
|
||||||
let image = this.app.metadataCache.getFirstLinkpathDest(decodeURIComponent(media), sourcePath);
|
const image = this.app.metadataCache.getFirstLinkpathDest(decodeURIComponent(media), sourcePath);
|
||||||
try {
|
try {
|
||||||
let binaryMedia = await this.app.vault.readBinary(image)
|
const binaryMedia = await this.app.vault.readBinary(image)
|
||||||
card.mediaBase64Encoded.push(arrayBufferToBase64(binaryMedia))
|
card.mediaBase64Encoded.push(arrayBufferToBase64(binaryMedia))
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
Error("Error: Could not read media")
|
Error("Error: Could not read media")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -159,7 +159,7 @@ export class CardsService {
|
|||||||
if (cardsToCreate.length) {
|
if (cardsToCreate.length) {
|
||||||
let insertedCards = 0
|
let insertedCards = 0
|
||||||
try {
|
try {
|
||||||
let ids = await this.anki.addCards(cardsToCreate)
|
const ids = await this.anki.addCards(cardsToCreate)
|
||||||
// Add IDs from response to Flashcard[]
|
// Add IDs from response to Flashcard[]
|
||||||
ids.map((id: number, index: number) => {
|
ids.map((id: number, index: number) => {
|
||||||
cardsToCreate[index].id = id
|
cardsToCreate[index].id = id
|
||||||
@ -188,10 +188,10 @@ export class CardsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private updateFrontmatter(frontmatter: FrontMatterCache, deckName: string) {
|
private updateFrontmatter(frontmatter: FrontMatterCache, deckName: string) {
|
||||||
let newFrontmatter: string = ""
|
let newFrontmatter = ""
|
||||||
let cardsDeckLine: string = `cards-deck: ${deckName}\n`
|
const cardsDeckLine = `cards-deck: ${deckName}\n`
|
||||||
if (frontmatter) {
|
if (frontmatter) {
|
||||||
let oldFrontmatter: string = this.file.substring(frontmatter.position.start.offset, frontmatter.position.end.offset)
|
const oldFrontmatter: string = this.file.substring(frontmatter.position.start.offset, frontmatter.position.end.offset)
|
||||||
if (!oldFrontmatter.match(this.regex.cardsDeckLine)) {
|
if (!oldFrontmatter.match(this.regex.cardsDeckLine)) {
|
||||||
newFrontmatter = oldFrontmatter.substring(0, oldFrontmatter.length - 3) + cardsDeckLine + "---"
|
newFrontmatter = oldFrontmatter.substring(0, oldFrontmatter.length - 3) + cardsDeckLine + "---"
|
||||||
this.totalOffset += cardsDeckLine.length
|
this.totalOffset += cardsDeckLine.length
|
||||||
@ -205,7 +205,7 @@ export class CardsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private writeAnkiBlocks(cardsToCreate: Card[]) {
|
private writeAnkiBlocks(cardsToCreate: Card[]) {
|
||||||
for (let card of cardsToCreate) {
|
for (const card of cardsToCreate) {
|
||||||
// Card.id cannot be null, because if written already previously it has an ID,
|
// Card.id cannot be null, because if written already previously it has an ID,
|
||||||
// if it has been inserted it has an ID too
|
// if it has been inserted it has an ID too
|
||||||
if (card.id !== null && !card.inserted) {
|
if (card.id !== null && !card.inserted) {
|
||||||
@ -218,7 +218,7 @@ export class CardsService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
card.endOffset += this.totalOffset
|
card.endOffset += this.totalOffset
|
||||||
let offset = card.endOffset
|
const offset = card.endOffset
|
||||||
|
|
||||||
this.updateFile = true
|
this.updateFile = true
|
||||||
this.file = this.file.substring(0, offset) + id + this.file.substring(offset, this.file.length + 1)
|
this.file = this.file.substring(0, offset) + id + this.file.substring(offset, this.file.length + 1)
|
||||||
@ -245,7 +245,7 @@ export class CardsService {
|
|||||||
if (cards.length) {
|
if (cards.length) {
|
||||||
let deletedCards = 0
|
let deletedCards = 0
|
||||||
for (const block of ankiBlocks) {
|
for (const block of ankiBlocks) {
|
||||||
let id = Number(block[1])
|
const id = Number(block[1])
|
||||||
|
|
||||||
// Deletion of cards that need to be deleted (i.e. blocks ID that don't have content)
|
// Deletion of cards that need to be deleted (i.e. blocks ID that don't have content)
|
||||||
if (cards.includes(id)) {
|
if (cards.includes(id)) {
|
||||||
@ -269,8 +269,8 @@ export class CardsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getAnkiIDs(blocks: RegExpMatchArray[]): number[] {
|
private getAnkiIDs(blocks: RegExpMatchArray[]): number[] {
|
||||||
let IDs: number[] = []
|
const IDs: number[] = []
|
||||||
for (let b of blocks) {
|
for (const b of blocks) {
|
||||||
IDs.push(Number(b[1]))
|
IDs.push(Number(b[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -280,11 +280,11 @@ export class CardsService {
|
|||||||
|
|
||||||
public filterByUpdate(ankiCards: any, generatedCards: Card[]) {
|
public filterByUpdate(ankiCards: any, generatedCards: Card[]) {
|
||||||
let cardsToCreate: Card[] = []
|
let cardsToCreate: Card[] = []
|
||||||
let cardsToUpdate: Card[] = []
|
const cardsToUpdate: Card[] = []
|
||||||
let cardsNotInAnki: Card[] = []
|
const cardsNotInAnki: Card[] = []
|
||||||
|
|
||||||
if (ankiCards) {
|
if (ankiCards) {
|
||||||
for (let flashcard of generatedCards) {
|
for (const flashcard of generatedCards) {
|
||||||
// Inserted means that anki blocks are available, that means that the card should
|
// Inserted means that anki blocks are available, that means that the card should
|
||||||
// (the user can always delete it) be in Anki
|
// (the user can always delete it) be in Anki
|
||||||
let ankiCard = undefined
|
let ankiCard = undefined
|
||||||
@ -308,7 +308,7 @@ export class CardsService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public async deckNeedToBeChanged(cardsIds: number[], deckName: string) {
|
public async deckNeedToBeChanged(cardsIds: number[], deckName: string) {
|
||||||
let cardsInfo = await this.anki.cardsInfo(cardsIds)
|
const cardsInfo = await this.anki.cardsInfo(cardsIds)
|
||||||
console.log("Flashcards: Cards info")
|
console.log("Flashcards: Cards info")
|
||||||
console.log(cardsInfo)
|
console.log(cardsInfo)
|
||||||
if (cardsInfo.length !== 0) {
|
if (cardsInfo.length !== 0) {
|
||||||
@ -322,7 +322,7 @@ export class CardsService {
|
|||||||
let ids: number[] = []
|
let ids: number[] = []
|
||||||
|
|
||||||
if (ankiCards) {
|
if (ankiCards) {
|
||||||
for (let flashcard of generatedCards) {
|
for (const flashcard of generatedCards) {
|
||||||
let ankiCard = undefined
|
let ankiCard = undefined
|
||||||
if (flashcard.inserted) {
|
if (flashcard.inserted) {
|
||||||
ankiCard = ankiCards.filter((card: any) => Number(card.noteId) === flashcard.id)[0]
|
ankiCard = ankiCards.filter((card: any) => Number(card.noteId) === flashcard.id)[0]
|
||||||
@ -336,10 +336,10 @@ export class CardsService {
|
|||||||
return ids
|
return ids
|
||||||
}
|
}
|
||||||
|
|
||||||
public parseGlobalTags(file: String): string[] {
|
public parseGlobalTags(file: string): string[] {
|
||||||
let globalTags: string[] = []
|
let globalTags: string[] = []
|
||||||
|
|
||||||
let tags = file.match(/(?:cards-)?tags: ?(.*)/im)
|
const tags = file.match(/(?:cards-)?tags: ?(.*)/im)
|
||||||
globalTags = tags ? tags[1].match(this.regex.globalTagsSplitter) : []
|
globalTags = tags ? tags[1].match(this.regex.globalTagsSplitter) : []
|
||||||
|
|
||||||
if (globalTags) {
|
if (globalTags) {
|
||||||
|
|||||||
@ -24,7 +24,7 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public generateFlashcards(file: string, deck: string, vault: string, note: string, globalTags: string[] = []): Flashcard[] {
|
public generateFlashcards(file: string, deck: string, vault: string, note: string, globalTags: string[] = []): Flashcard[] {
|
||||||
let contextAware = this.settings.contextAwareMode
|
const contextAware = this.settings.contextAwareMode
|
||||||
let cards: Flashcard[] = []
|
let cards: Flashcard[] = []
|
||||||
let headings: any = []
|
let headings: any = []
|
||||||
|
|
||||||
@ -39,7 +39,7 @@ export class Parser {
|
|||||||
cards = cards.concat(this.generateSpacedCards(file, headings, deck, vault, note, globalTags))
|
cards = cards.concat(this.generateSpacedCards(file, headings, deck, vault, note, globalTags))
|
||||||
cards.sort((a, b) => a.endOffset - b.endOffset)
|
cards.sort((a, b) => a.endOffset - b.endOffset)
|
||||||
|
|
||||||
let defaultAnkiTag = this.settings.defaultAnkiTag
|
const defaultAnkiTag = this.settings.defaultAnkiTag
|
||||||
if (defaultAnkiTag) {
|
if (defaultAnkiTag) {
|
||||||
for (const card of cards) {
|
for (const card of cards) {
|
||||||
card.tags.push(defaultAnkiTag)
|
card.tags.push(defaultAnkiTag)
|
||||||
@ -57,9 +57,9 @@ export class Parser {
|
|||||||
* @param headingLevel The level of the first ancestor heading, i.e. the number of #.
|
* @param headingLevel The level of the first ancestor heading, i.e. the number of #.
|
||||||
*/
|
*/
|
||||||
private getContext(headings: any, index: number, headingLevel: number): string[] {
|
private getContext(headings: any, index: number, headingLevel: number): string[] {
|
||||||
let context: string[] = []
|
const context: string[] = []
|
||||||
let currentIndex: number = index
|
let currentIndex: number = index
|
||||||
let goalLevel: number = 6
|
let goalLevel = 6
|
||||||
|
|
||||||
let i = headings.length - 1
|
let i = headings.length - 1
|
||||||
// Get the level of the first heading before the index (i.e. above the current line)
|
// Get the level of the first heading before the index (i.e. above the current line)
|
||||||
@ -82,7 +82,7 @@ export class Parser {
|
|||||||
|
|
||||||
// Search for the other headings
|
// Search for the other headings
|
||||||
for (i; i >= 0; i--) {
|
for (i; i >= 0; i--) {
|
||||||
let currentLevel = headings[i][1].length
|
const currentLevel = headings[i][1].length
|
||||||
if (currentLevel == goalLevel && headings[i].index < currentIndex) {
|
if (currentLevel == goalLevel && headings[i].index < currentIndex) {
|
||||||
currentIndex = headings[i].index
|
currentIndex = headings[i].index
|
||||||
goalLevel = currentLevel - 1
|
goalLevel = currentLevel - 1
|
||||||
@ -95,36 +95,36 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private generateSpacedCards(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
|
private generateSpacedCards(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
|
||||||
let contextAware = this.settings.contextAwareMode
|
const contextAware = this.settings.contextAwareMode
|
||||||
let cards: Spacedcard[] = []
|
const cards: Spacedcard[] = []
|
||||||
let matches = [...file.matchAll(this.regex.cardsSpacedStyle)]
|
const matches = [...file.matchAll(this.regex.cardsSpacedStyle)]
|
||||||
|
|
||||||
for (let match of matches) {
|
for (const match of matches) {
|
||||||
let reversed: boolean = false
|
const reversed = false
|
||||||
let headingLevel = -1
|
let headingLevel = -1
|
||||||
if (match[1]) {
|
if (match[1]) {
|
||||||
headingLevel = match[1].trim().length !== 0 ? match[1].trim().length : -1
|
headingLevel = match[1].trim().length !== 0 ? match[1].trim().length : -1
|
||||||
}
|
}
|
||||||
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
||||||
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
const context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
||||||
|
|
||||||
let originalPrompt = match[2].trim()
|
const originalPrompt = match[2].trim()
|
||||||
let prompt = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
let prompt = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
||||||
let medias: string[] = this.getImageLinks(prompt)
|
let medias: string[] = this.getImageLinks(prompt)
|
||||||
medias = medias.concat(this.getAudioLinks(prompt))
|
medias = medias.concat(this.getAudioLinks(prompt))
|
||||||
prompt = this.parseLine(prompt, vault)
|
prompt = this.parseLine(prompt, vault)
|
||||||
|
|
||||||
let endingLine = match.index + match[0].length
|
const endingLine = match.index + match[0].length
|
||||||
let tags: string[] = this.parseTags(match[4], globalTags)
|
const tags: string[] = this.parseTags(match[4], globalTags)
|
||||||
let id: number = match[5] ? Number(match[5]) : -1
|
const id: number = match[5] ? Number(match[5]) : -1
|
||||||
let inserted: boolean = match[5] ? true : false
|
const inserted: boolean = match[5] ? true : false
|
||||||
let fields: any = { "Prompt": prompt }
|
const fields: any = { "Prompt": prompt }
|
||||||
if (this.settings.sourceSupport) {
|
if (this.settings.sourceSupport) {
|
||||||
fields["Source"] = note
|
fields["Source"] = note
|
||||||
}
|
}
|
||||||
let containsCode = this.containsCode([prompt])
|
const containsCode = this.containsCode([prompt])
|
||||||
|
|
||||||
let card = new Spacedcard(id, deck, originalPrompt, fields, reversed, endingLine, tags, inserted, medias, containsCode)
|
const card = new Spacedcard(id, deck, originalPrompt, fields, reversed, endingLine, tags, inserted, medias, containsCode)
|
||||||
cards.push(card)
|
cards.push(card)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,24 +132,24 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private generateInlineCards(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
|
private generateInlineCards(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
|
||||||
let contextAware = this.settings.contextAwareMode
|
const contextAware = this.settings.contextAwareMode
|
||||||
let cards: Inlinecard[] = []
|
const cards: Inlinecard[] = []
|
||||||
let matches = [...file.matchAll(this.regex.cardsInlineStyle)]
|
const matches = [...file.matchAll(this.regex.cardsInlineStyle)]
|
||||||
|
|
||||||
for (let match of matches) {
|
for (const match of matches) {
|
||||||
if (match[2].toLowerCase().startsWith("cards-deck") || match[2].toLowerCase().startsWith("tags")) {
|
if (match[2].toLowerCase().startsWith("cards-deck") || match[2].toLowerCase().startsWith("tags")) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
let reversed: boolean = match[3].trim().toLowerCase() === ':::'
|
const reversed: boolean = match[3].trim().toLowerCase() === ':::'
|
||||||
let headingLevel = -1
|
let headingLevel = -1
|
||||||
if (match[1]) {
|
if (match[1]) {
|
||||||
headingLevel = match[1].trim().length !== 0 ? match[1].trim().length : -1
|
headingLevel = match[1].trim().length !== 0 ? match[1].trim().length : -1
|
||||||
}
|
}
|
||||||
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
||||||
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
const context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
||||||
|
|
||||||
let originalQuestion = match[2].trim()
|
const originalQuestion = match[2].trim()
|
||||||
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
||||||
let answer = match[4].trim()
|
let answer = match[4].trim()
|
||||||
let medias: string[] = this.getImageLinks(question)
|
let medias: string[] = this.getImageLinks(question)
|
||||||
@ -158,17 +158,17 @@ export class Parser {
|
|||||||
question = this.parseLine(question, vault)
|
question = this.parseLine(question, vault)
|
||||||
answer = this.parseLine(answer, vault)
|
answer = this.parseLine(answer, vault)
|
||||||
|
|
||||||
let endingLine = match.index + match[0].length
|
const endingLine = match.index + match[0].length
|
||||||
let tags: string[] = this.parseTags(match[5], globalTags)
|
const tags: string[] = this.parseTags(match[5], globalTags)
|
||||||
let id: number = match[6] ? Number(match[6]) : -1
|
const id: number = match[6] ? Number(match[6]) : -1
|
||||||
let inserted: boolean = match[6] ? true : false
|
const inserted: boolean = match[6] ? true : false
|
||||||
let fields: any = { "Front": question, "Back": answer }
|
const fields: any = { "Front": question, "Back": answer }
|
||||||
if (this.settings.sourceSupport) {
|
if (this.settings.sourceSupport) {
|
||||||
fields["Source"] = note
|
fields["Source"] = note
|
||||||
}
|
}
|
||||||
let containsCode = this.containsCode([question, answer])
|
const containsCode = this.containsCode([question, answer])
|
||||||
|
|
||||||
let card = new Inlinecard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
|
const card = new Inlinecard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
|
||||||
cards.push(card)
|
cards.push(card)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,17 +176,17 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private generateCardsWithTag(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
|
private generateCardsWithTag(file: string, headings: any, deck: string, vault: string, note: string, globalTags: string[] = []) {
|
||||||
let contextAware = this.settings.contextAwareMode
|
const contextAware = this.settings.contextAwareMode
|
||||||
let cards: Flashcard[] = []
|
const cards: Flashcard[] = []
|
||||||
let matches = [...file.matchAll(this.regex.flashscardsWithTag)]
|
const matches = [...file.matchAll(this.regex.flashscardsWithTag)]
|
||||||
|
|
||||||
for (let match of matches) {
|
for (const match of matches) {
|
||||||
let reversed: boolean = match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}-reverse` || match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}/reverse`
|
const reversed: boolean = match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}-reverse` || match[3].trim().toLowerCase() === `#${this.settings.flashcardsTag}/reverse`
|
||||||
let headingLevel = match[1].trim().length !== 0 ? match[1].length : -1
|
const headingLevel = match[1].trim().length !== 0 ? match[1].length : -1
|
||||||
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
// Match.index - 1 because otherwise in the context there will be even match[1], i.e. the question itself
|
||||||
let context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
const context = contextAware ? this.getContext(headings, match.index - 1, headingLevel) : ""
|
||||||
|
|
||||||
let originalQuestion = match[2].trim()
|
const originalQuestion = match[2].trim()
|
||||||
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
let question = contextAware ? [...context, match[2].trim()].join(`${this.settings.contextSeparator}`) : match[2].trim()
|
||||||
let answer = match[5].trim()
|
let answer = match[5].trim()
|
||||||
let medias: string[] = this.getImageLinks(question)
|
let medias: string[] = this.getImageLinks(question)
|
||||||
@ -195,17 +195,17 @@ export class Parser {
|
|||||||
question = this.parseLine(question, vault)
|
question = this.parseLine(question, vault)
|
||||||
answer = this.parseLine(answer, vault)
|
answer = this.parseLine(answer, vault)
|
||||||
|
|
||||||
let endingLine = match.index + match[0].length
|
const endingLine = match.index + match[0].length
|
||||||
let tags: string[] = this.parseTags(match[4], globalTags)
|
const tags: string[] = this.parseTags(match[4], globalTags)
|
||||||
let id: number = match[6] ? Number(match[6]) : -1
|
const id: number = match[6] ? Number(match[6]) : -1
|
||||||
let inserted: boolean = match[6] ? true : false
|
const inserted: boolean = match[6] ? true : false
|
||||||
let fields: any = { "Front": question, "Back": answer }
|
const fields: any = { "Front": question, "Back": answer }
|
||||||
if (this.settings.sourceSupport) {
|
if (this.settings.sourceSupport) {
|
||||||
fields["Source"] = note
|
fields["Source"] = note
|
||||||
}
|
}
|
||||||
let containsCode = this.containsCode([question, answer])
|
const containsCode = this.containsCode([question, answer])
|
||||||
|
|
||||||
let card = new Flashcard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
|
const card = new Flashcard(id, deck, originalQuestion, fields, reversed, endingLine, tags, inserted, medias, containsCode)
|
||||||
cards.push(card)
|
cards.push(card)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -213,7 +213,7 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public containsCode(str: string[]): boolean {
|
public containsCode(str: string[]): boolean {
|
||||||
for (let s of str) {
|
for (const s of str) {
|
||||||
if (s.match(this.regex.codeBlock)) {
|
if (s.match(this.regex.codeBlock)) {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@ -231,15 +231,15 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getImageLinks(str: string) {
|
private getImageLinks(str: string) {
|
||||||
let wikiMatches = str.matchAll(this.regex.wikiImageLinks)
|
const wikiMatches = str.matchAll(this.regex.wikiImageLinks)
|
||||||
let markdownMatches = str.matchAll(this.regex.markdownImageLinks)
|
const markdownMatches = str.matchAll(this.regex.markdownImageLinks)
|
||||||
let links: string[] = []
|
const links: string[] = []
|
||||||
|
|
||||||
for (let wikiMatch of wikiMatches) {
|
for (const wikiMatch of wikiMatches) {
|
||||||
links.push(wikiMatch[1])
|
links.push(wikiMatch[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let markdownMatch of markdownMatches) {
|
for (const markdownMatch of markdownMatches) {
|
||||||
links.push(decodeURIComponent(markdownMatch[1]))
|
links.push(decodeURIComponent(markdownMatch[1]))
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -247,10 +247,10 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private getAudioLinks(str: string) {
|
private getAudioLinks(str: string) {
|
||||||
let wikiMatches = str.matchAll(this.regex.wikiAudioLinks)
|
const wikiMatches = str.matchAll(this.regex.wikiAudioLinks)
|
||||||
let links: string[] = []
|
const links: string[] = []
|
||||||
|
|
||||||
for (let wikiMatch of wikiMatches) {
|
for (const wikiMatch of wikiMatches) {
|
||||||
links.push(wikiMatch[1])
|
links.push(wikiMatch[1])
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -258,13 +258,13 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private substituteObsidianLinks(str: string, vaultName: string) {
|
private substituteObsidianLinks(str: string, vaultName: string) {
|
||||||
let linkRegex = /\[\[(.+?)(?:\|(.+))?\]\]/gmi
|
const linkRegex = /\[\[(.+?)(?:\|(.+))?\]\]/gmi
|
||||||
vaultName = encodeURIComponent(vaultName)
|
vaultName = encodeURIComponent(vaultName)
|
||||||
|
|
||||||
return str.replace(linkRegex, (match, filename, rename) => {
|
return str.replace(linkRegex, (match, filename, rename) => {
|
||||||
let href = `obsidian://open?vault=${vaultName}&file=${encodeURIComponent(filename)}.md`
|
const href = `obsidian://open?vault=${vaultName}&file=${encodeURIComponent(filename)}.md`
|
||||||
let fileRename = rename ? rename : filename
|
const fileRename = rename ? rename : filename
|
||||||
let link = `<a href="${href}">[[${fileRename}]]</a>`
|
const link = `<a href="${href}">[[${fileRename}]]</a>`
|
||||||
return link
|
return link
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -281,12 +281,12 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private mathToAnki(str: string) {
|
private mathToAnki(str: string) {
|
||||||
let mathBlockRegex = /(\$\$)(.*?)(\$\$)/gis
|
const mathBlockRegex = /(\$\$)(.*?)(\$\$)/gis
|
||||||
str = str.replace(mathBlockRegex, function (match, p1, p2) {
|
str = str.replace(mathBlockRegex, function (match, p1, p2) {
|
||||||
return '\\\\[' + escapeMarkdown(p2) + ' \\\\]'
|
return '\\\\[' + escapeMarkdown(p2) + ' \\\\]'
|
||||||
})
|
})
|
||||||
|
|
||||||
let mathInlineRegex = /(\$)(.*?)(\$)/gi
|
const mathInlineRegex = /(\$)(.*?)(\$)/gi
|
||||||
str = str.replace(mathInlineRegex, function (match, p1, p2) {
|
str = str.replace(mathInlineRegex, function (match, p1, p2) {
|
||||||
return '\\\\(' + escapeMarkdown(p2) + '\\\\)'
|
return '\\\\(' + escapeMarkdown(p2) + '\\\\)'
|
||||||
})
|
})
|
||||||
@ -295,10 +295,10 @@ export class Parser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private parseTags(str: string, globalTags: string[]): string[] {
|
private parseTags(str: string, globalTags: string[]): string[] {
|
||||||
let tags: string[] = [...globalTags]
|
const tags: string[] = [...globalTags]
|
||||||
|
|
||||||
if (str) {
|
if (str) {
|
||||||
for (let tag of str.split("#")) {
|
for (const tag of str.split("#")) {
|
||||||
let newTag = tag.trim()
|
let newTag = tag.trim()
|
||||||
if (newTag) {
|
if (newTag) {
|
||||||
// Replace obsidian hierarchy tags delimeter \ with anki delimeter ::
|
// Replace obsidian hierarchy tags delimeter \ with anki delimeter ::
|
||||||
|
|||||||
22
src/utils.ts
22
src/utils.ts
@ -1,10 +1,8 @@
|
|||||||
import { Vault, TFile} from 'obsidian';
|
|
||||||
|
|
||||||
export function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
export function arrayBufferToBase64(buffer: ArrayBuffer): string {
|
||||||
var binary = "";
|
let binary = "";
|
||||||
var bytes = new Uint8Array(buffer);
|
const bytes = new Uint8Array(buffer);
|
||||||
var len = bytes.byteLength;
|
const len = bytes.byteLength;
|
||||||
for (var i = 0; i < len; i++) {
|
for (let i = 0; i < len; i++) {
|
||||||
binary += String.fromCharCode(bytes[i]);
|
binary += String.fromCharCode(bytes[i]);
|
||||||
}
|
}
|
||||||
return window.btoa(binary);
|
return window.btoa(binary);
|
||||||
@ -18,14 +16,14 @@ export function arraysEqual(a: string[], b: string[]) {
|
|||||||
a.sort();
|
a.sort();
|
||||||
b.sort();
|
b.sort();
|
||||||
|
|
||||||
for (var i = 0; i < a.length; ++i) {
|
for (let i = 0; i < a.length; ++i) {
|
||||||
if (a[i] !== b[i]) return false;
|
if (a[i] !== b[i]) return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function escapeMarkdown(string: string, skips: string[] = []) {
|
export function escapeMarkdown(string: string, skips: string[] = []) {
|
||||||
let replacements: any = [
|
const replacements: any = [
|
||||||
[/\*/g, "\\*", "asterisks"],
|
[/\*/g, "\\*", "asterisks"],
|
||||||
[/#/g, "\\#", "number signs"],
|
[/#/g, "\\#", "number signs"],
|
||||||
[/\//g, "\\/", "slashes"],
|
[/\//g, "\\/", "slashes"],
|
||||||
@ -39,10 +37,10 @@ export function escapeMarkdown(string: string, skips: string[] = []) {
|
|||||||
[/_/g, "\\_", "underscores"],
|
[/_/g, "\\_", "underscores"],
|
||||||
];
|
];
|
||||||
|
|
||||||
return replacements.reduce(function (string: string, replacement: any) {
|
return replacements.reduce(function (s: string, replacement: any) {
|
||||||
let name = replacement[2];
|
const name = replacement[2];
|
||||||
return name && skips.indexOf(name) !== -1
|
return name && skips.indexOf(name) !== -1
|
||||||
? string
|
? s
|
||||||
: string.replace(replacement[0], replacement[1]);
|
: s.replace(replacement[0], replacement[1]);
|
||||||
}, string);
|
}, string);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user