From f519f3a3b1a6616b2a077ef43daa2eaee4bc9e92 Mon Sep 17 00:00:00 2001 From: Gabriele Cannata Date: Tue, 15 Aug 2023 15:14:13 +0200 Subject: [PATCH] auto saving --- src/SettingTab.ts | 73 ++++++++++++---------- src/Settings.ts | 6 +- src/Views/SheetView.ts | 105 ++++++++++++-------------------- src/Views/spreadSheetWrapper.ts | 92 +++++++++++++++++++++++----- 4 files changed, 161 insertions(+), 115 deletions(-) diff --git a/src/SettingTab.ts b/src/SettingTab.ts index 4e38b58..20b4cc8 100644 --- a/src/SettingTab.ts +++ b/src/SettingTab.ts @@ -1,46 +1,53 @@ import SheetjsPlugin from "src/main"; import { App, PluginSettingTab, Setting } from "obsidian"; - export class SheetjsSettingsTab extends PluginSettingTab { - plugin: SheetjsPlugin; + plugin: SheetjsPlugin; - constructor(app: App, plugin: SheetjsPlugin) { - super(app, plugin); - this.plugin = plugin; - } + constructor(app: App, plugin: SheetjsPlugin) { + super(app, plugin); + this.plugin = plugin; + } - display(): void { - const {containerEl} = this; + display(): void { + const { containerEl } = this; - containerEl.empty(); + containerEl.empty(); - containerEl.createEl('h2', {text: 'Sheetjs Settings'}); + containerEl.createEl("h2", { text: "Sheetjs Settings" }); - this.createToggle(containerEl, "Add Ribbon Icon", - "Adds an icon to the ribbon to launch scan", - "addRibbonIcon" + this.createToggle( + containerEl, + "Enable Saving To File", + "Enabling saving to external files (.xlsx, .xls, ,.csv)", + "enableSaveToFile" ); - this.createToggle(containerEl, "Show Sheetjs Sidebar", - "Opens Sheetjs sidebar at startup", - "showAtStartUp" - ); + this.createToggle( + containerEl, + "Auto Save", + "Saves automatically", + "autoSave" + ); + } - - } - - private createToggle(containerEl: HTMLElement, name: string, desc: string, prop: string) { - new Setting(containerEl) - .setName(name) - .setDesc(desc) - .addToggle(bool => bool - .setValue((this.plugin.settings as any)[prop] as boolean) - .onChange(async (value) => { - (this.plugin.settings as any)[prop] = value; - await this.plugin.saveSettings(); - this.display(); - }) - ); - } + private createToggle( + containerEl: HTMLElement, + name: string, + desc: string, + prop: string + ) { + new Setting(containerEl) + .setName(name) + .setDesc(desc) + .addToggle((bool) => + bool + .setValue((this.plugin.settings as any)[prop] as boolean) + .onChange(async (value) => { + (this.plugin.settings as any)[prop] = value; + await this.plugin.saveSettings(); + this.display(); + }) + ); + } } diff --git a/src/Settings.ts b/src/Settings.ts index dc57432..a1a8e7f 100644 --- a/src/Settings.ts +++ b/src/Settings.ts @@ -1,11 +1,13 @@ export interface SheetsSettings { addRibbonIcon: boolean; - enableSaveToFile: boolean + enableSaveToFile: boolean; + autoSave: boolean; } export const DEFAULT_SETTINGS: SheetsSettings = { addRibbonIcon: false, - enableSaveToFile: true + enableSaveToFile: false, + autoSave: true } diff --git a/src/Views/SheetView.ts b/src/Views/SheetView.ts index 52f6e58..2a39665 100644 --- a/src/Views/SheetView.ts +++ b/src/Views/SheetView.ts @@ -18,8 +18,14 @@ import * as XLSX from "xlsx"; import * as ExcelJS from "exceljs"; import { stox } from "../utils/xlsxpread"; import { toSpreadsheet } from "src/utils/excelConverter"; -import { createSpreadSheet, prepareDataForSaving, saveToFile } from "./spreadSheetWrapper"; -import Spreadsheet from "x-data-spreadsheet"; +import { + createSpreadSheet, + prepareDataForSaving, + + saveDataIntoBlock, + + saveToFile, +} from "./spreadSheetWrapper"; const DEFAULT_OPTIONS = { height: 540, @@ -36,7 +42,6 @@ const MINHEIGHT = 400; const saveIcon = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBzdGFuZGFsb25lPSJubyI/PjwhRE9DVFlQRSBzdmcgUFVCTElDICItLy9XM0MvL0RURCBTVkcgMS4xLy9FTiIgImh0dHA6Ly93d3cudzMub3JnL0dyYXBoaWNzL1NWRy8xLjEvRFREL3N2ZzExLmR0ZCI+PHN2ZyB0PSIxNTc3MTc3MDkyOTg4IiBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgdmVyc2lvbj0iMS4xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHAtaWQ9IjI2NzgiIHdpZHRoPSIxOCIgaGVpZ2h0PSIxOCIgeG1sbnM6eGxpbms9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkveGxpbmsiPjxkZWZzPjxzdHlsZSB0eXBlPSJ0ZXh0L2NzcyI+PC9zdHlsZT48L2RlZnM+PHBhdGggZD0iTTIxMy4zMzMzMzMgMTI4aDU5Ny4zMzMzMzRhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMSA4NS4zMzMzMzMgODUuMzMzMzMzdjU5Ny4zMzMzMzRhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMS04NS4zMzMzMzMgODUuMzMzMzMzSDIxMy4zMzMzMzNhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMS04NS4zMzMzMzMtODUuMzMzMzMzVjIxMy4zMzMzMzNhODUuMzMzMzMzIDg1LjMzMzMzMyAwIDAgMSA4NS4zMzMzMzMtODUuMzMzMzMzeiBtMzY2LjkzMzMzNCAxMjhoMzQuMTMzMzMzYTI1LjYgMjUuNiAwIDAgMSAyNS42IDI1LjZ2MTE5LjQ2NjY2N2EyNS42IDI1LjYgMCAwIDEtMjUuNiAyNS42aC0zNC4xMzMzMzNhMjUuNiAyNS42IDAgMCAxLTI1LjYtMjUuNlYyODEuNmEyNS42IDI1LjYgMCAwIDEgMjUuNi0yNS42ek0yMTMuMzMzMzMzIDIxMy4zMzMzMzN2NTk3LjMzMzMzNGg1OTcuMzMzMzM0VjIxMy4zMzMzMzNIMjEzLjMzMzMzM3ogbTEyOCAwdjI1NmgzNDEuMzMzMzM0VjIxMy4zMzMzMzNoODUuMzMzMzMzdjI5OC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMS00Mi42NjY2NjcgNDIuNjY2NjY3SDI5OC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMS00Mi42NjY2NjctNDIuNjY2NjY3VjIxMy4zMzMzMzNoODUuMzMzMzMzek0yNTYgMjEzLjMzMzMzM2g4NS4zMzMzMzMtODUuMzMzMzMzeiBtNDI2LjY2NjY2NyAwaDg1LjMzMzMzMy04NS4zMzMzMzN6IG0wIDU5Ny4zMzMzMzR2LTEyOEgzNDEuMzMzMzMzdjEyOEgyNTZ2LTE3MC42NjY2NjdhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0Mi42NjY2NjctNDIuNjY2NjY3aDQyNi42NjY2NjZhNDIuNjY2NjY3IDQyLjY2NjY2NyAwIDAgMSA0Mi42NjY2NjcgNDIuNjY2NjY3djE3MC42NjY2NjdoLTg1LjMzMzMzM3ogbTg1LjMzMzMzMyAwaC04NS4zMzMzMzMgODUuMzMzMzMzek0zNDEuMzMzMzMzIDgxMC42NjY2NjdIMjU2aDg1LjMzMzMzM3oiIHAtaWQ9IjI2NzkiIGZpbGw9IiMyYzJjMmMiPjwvcGF0aD48L3N2Zz4="; - export function processCodeBlock( source: string, el: HTMLElement, @@ -59,7 +64,7 @@ export function processCodeBlock( if ((ctx as any).spreadsheet) return; const options = { ...DEFAULT_OPTIONS, ...parseYaml(source) }; - + options.height = Math.max(options.height, MINHEIGHT); const { @@ -133,9 +138,9 @@ export function processCodeBlock( icon: saveIcon, shortcut: "Ctrl+S", onClick: (s: any, d: any) => { - if(!filename) saveDataIntoBlock(s, d, ctx); + if (!filename) saveDataIntoBlock(s, d, ctx); else { - saveToFile((ctx as any).spreadsheet, filename) + saveToFile((ctx as any).spreadsheet, filename); } }, }, @@ -143,34 +148,37 @@ export function processCodeBlock( }; } - if (filename !== undefined) { - (async () => { - let data = undefined - try { - const fileContent = await app.vault.adapter.readBinary(filename); - - data = await parseFileContent(filename, fileContent); - } catch (e) { - console.warn(e) - } - - + // setTimeout(() => { + if (filename !== undefined) { + (async () => { + let data = undefined; + try { + const fileContent = await app.vault.adapter.readBinary( + filename + ); + + data = await parseFileContent(filename, fileContent); + } catch (e) { + console.warn(e); + } + + (ctx as any).spreadsheet = createSpreadSheet( + container, + spreadsheet_options, + { ...options, data: data }, + ctx + ); + // .loadData(); + })(); + } else { (ctx as any).spreadsheet = createSpreadSheet( container, spreadsheet_options, - { ...options, data: data }, + { ...options }, ctx ); - // .loadData(); - })(); - } else { - (ctx as any).spreadsheet = createSpreadSheet( - container, - spreadsheet_options, - { ...options }, - ctx - ); - } + } + // }, 0); // (ctx as any).spreadsheet = s; @@ -182,10 +190,9 @@ export function processCodeBlock( // https://github.com/wolf-table/table } -async function parseFileContent(filename:string, fileContent:ArrayBuffer){ - +async function parseFileContent(filename: string, fileContent: ArrayBuffer) { const ext = filename.slice(filename.lastIndexOf(".")).toLowerCase(); - if(ext === ".xlsx" || ext === ".csv") { + if (ext === ".xlsx" || ext === ".csv") { const workbook = new ExcelJS.Workbook(); const excelWorkbook = await workbook.xlsx.load(fileContent); const data2 = toSpreadsheet(excelWorkbook); @@ -199,38 +206,4 @@ async function parseFileContent(filename:string, fileContent:ArrayBuffer){ const data = stox(xlsx); return data; } - } - - - -function saveDataIntoBlock( - data: any, - sheet: any, - ctx: MarkdownPostProcessorContext -) { - const s = (ctx as any).spreadsheet as Spreadsheet; - const dts = prepareDataForSaving( s ); - - const view = app.workspace.getActiveViewOfType(MarkdownView); - if (!view) return; - if (view.getMode() === "source") { - const sec = ctx.getSectionInfo((ctx as any).el as HTMLElement); - if (sec) { - const obj = { data: dts }; - const yaml = stringifyYaml(obj) + "\n"; - view?.editor.replaceRange( - yaml, - { line: sec?.lineStart + 1, ch: 0 }, - { line: sec?.lineEnd, ch: 0 }, - "*" - ); - console.info("Data saved on code block"); - } - } else { - // preview - new Notice("Sheet not saved while in reading mode"); - } -} - - diff --git a/src/Views/spreadSheetWrapper.ts b/src/Views/spreadSheetWrapper.ts index 36c49f9..02c3696 100644 --- a/src/Views/spreadSheetWrapper.ts +++ b/src/Views/spreadSheetWrapper.ts @@ -1,12 +1,13 @@ // import { Spreadsheet } from 'x-data-spreadsheet'; /* eslint-disable @typescript-eslint/no-explicit-any */ -import { MarkdownPostProcessorContext, debounce } from "obsidian"; +import { MarkdownPostProcessorContext, MarkdownView, Notice, debounce, stringifyYaml } from "obsidian"; import * as XLSX from "xlsx"; import { xtos } from "../utils/xlsxpread"; import { toExcelJS } from "src/utils/excelConverter"; import { SheetData, SpreadsheetData } from "x-data-spreadsheet"; // HACK import Spreadsheet from "x-data-spreadsheet"; +import { getSheetjsSettings } from "src/main"; // import * as Spreadsheet from "x-data-spreadsheet"; // const { Spreadsheet } = require("x-data-spreadsheet"); @@ -74,26 +75,89 @@ export function createSpreadSheet( ) // .loadData(options.data || {}); + const settings = getSheetjsSettings() + prepareDataForLoading(spreadSheet, options.data as SpreadsheetData) - spreadSheet.change( - debounce((_data) => { - // save data - // console.log(data) - if (options.filename) { - saveToFile(spreadSheet, options.filename); - } else { - // at the moment we avoid since this would cause re-rendering - // saveDataIntoBlock(null,null,ctx) - } + let focused = true; - // XLSX.writeFile(xtos(s.getData(data)) as any, filename); - }, 1000) - ); + if(settings.autoSave) { + spreadSheet.change( + debounce((_data) => { + // save data + // console.log(data) + if (options.filename && settings.enableSaveToFile) { + saveToFile(spreadSheet, options.filename); + } else { + // at the moment we avoid since this would cause re-rendering + // saveDataIntoBlock(null,null,ctx) + } + + // XLSX.writeFile(xtos(s.getData(data)) as any, filename); + }, 1000) + ); + + if(!options.filename && settings.autoSave){ + const ae = container.closest("[tabindex]"); + console.log('ae',ae); + ae?.addEventListener('blur', debounce((e)=>{ + // console.log(`focus changed `,e); + const tmp = document.activeElement; + saveDataIntoBlock(null,null,ctx); + // let el = tmp; + // let f = false; + // while(el?.parentElement) { + // if(el === container) { + // f = true; + // break; + // } + // el = el.parentElement; + // } + // if(focused && !f){ + // // lost focus + // console.log(`lost focus`); + // } + // focused = f; + })) + } + + + } return spreadSheet; } + +export function saveDataIntoBlock( + data: any, + sheet: any, + ctx: MarkdownPostProcessorContext +) { + const s = (ctx as any).spreadsheet as Spreadsheet; + const dts = prepareDataForSaving( s ); + + const view = app.workspace.getActiveViewOfType(MarkdownView); + if (!view) return; + if (view.getMode() === "source") { + const sec = ctx.getSectionInfo((ctx as any).el as HTMLElement); + if (sec) { + const obj = { data: dts }; + const yaml = stringifyYaml(obj) + "\n"; + view?.editor.replaceRange( + yaml, + { line: sec?.lineStart + 1, ch: 0 }, + { line: sec?.lineEnd, ch: 0 }, + "*" + ); + console.info("Data saved on code block"); + } + } else { + // preview + new Notice("Sheet not saved while in reading mode"); + } +} + + export async function saveToFile(spreadSheet: Spreadsheet, filename: string) { const spreadsheetData = spreadSheet.getData() as any[];