mirror of
https://github.com/canna71/obsidian-sheets.git
synced 2026-07-22 08:30:27 +00:00
auto saving
This commit is contained in:
parent
243e2b1cd3
commit
f519f3a3b1
4 changed files with 161 additions and 115 deletions
|
|
@ -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();
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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[];
|
||||
|
|
|
|||
Loading…
Reference in a new issue