Skip to content

Commit

Permalink
Merge pull request #190 from r74tech/feature/include
Browse files Browse the repository at this point in the history
Feature/include
  • Loading branch information
r74tech committed Nov 1, 2023
2 parents 4e3742e + 0c33c92 commit 9eea999
Show file tree
Hide file tree
Showing 3 changed files with 200 additions and 3 deletions.
2 changes: 1 addition & 1 deletion src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,4 @@ document.querySelector("head > style#innercss")!.innerHTML = css;
document.querySelector("head > style#collapsible")!.innerHTML = collapsible;
document.querySelector("head > style#init")!.innerHTML = init;
// Event listeners...
document.addEventListener('DOMContentLoaded', handleDOMContentLoaded);
document.addEventListener('DOMContentLoaded', handleDOMContentLoaded);
40 changes: 38 additions & 2 deletions src/script/eventHandlers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
generateShortId, getOrCreateUserShortId, getCurrentPageShortId, encryptSha256, setCookie, getCookie
} from './utils';

import { TextWikiParseInclude } from "./include";


import {
Expand Down Expand Up @@ -159,7 +160,42 @@ const handleEditpageInput = debounce((event) => {
const storageKey = shortid ? `FtmlStorage[${shortid}]` : 'FtmlStorage';
localStorage.setItem(storageKey, JSON.stringify(FtmlStorageItem));

ftml.postMessage({ value, type });
// const WPInc = {
// source: value,
// vars: {}
// };
// const parser = new TextWikiParseInclude(WPInc);
// parser.parse().then(() => {
// console.log("Source after parsing: \n", WPInc.source);
// ftml.postMessage({ value: WPInc.source, type });
// }).catch(error => {
// console.error("Parsing failed with error: ", error);
// });

// [WIP] includeの処理を行う
// include元のソースを保持する。(GASの実行制限を考慮して、include元のソースを保持する必要がある)
// include元のページを配列で持っておいて、その中身に変更があった場合は、include元のソースを増えたものだけ取得しに行く


const wiki = {
source: editpageField.value,
vars: {}
};

// console.log("Source before parsing: \n", wiki.source);
const parser = new TextWikiParseInclude(wiki);

// onEditでthis.wiki.sourceを更新する。editpageFieldが更新されたらonEditにeventを渡す。
// editpageField.addEventListener('input', parser.onEdit.bind(parser));
parser.onEdit(event).then(() => {
// console.log("Source after parsing: \n", wiki.source);
ftml.postMessage({ value: wiki.source, type });
}
).catch(error => {
console.error("Parsing failed with error: ", error);
});

// ftml.postMessage({ value, type });

}, 1000);

Expand Down Expand Up @@ -281,7 +317,7 @@ const handleShareButtonClick = async () => {
}




console.debug('Sending data to GAS:', dataToSend);

Expand Down
161 changes: 161 additions & 0 deletions src/script/include.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
import { getDataFromGAS } from "./helper";

interface Wiki {
source: string;
vars: Record<string, any>;
}

class Page {
constructor(private pageId: string, private source: string) { }

getPageId(): string {
return this.pageId;
}

getSource(): string {
return this.source;
}
}

export class TextWikiParseInclude {
private conf = { base: '/path/to/scripts/' };
private regex = /^\[\[include ([a-zA-Z0-9\s\-:]+?)(\s+.*?)?(?:\]\])$/ims;
private includedPages: string[] = [];

constructor(private wiki: Wiki) {
this.updateIncludedPages();
}

async parse(): Promise<void> {
let level = 0;
let oldSource;
do {
oldSource = this.wiki.source;
const matches = this.regex.exec(this.wiki.source);
if (matches) {
const output = await this.process(matches.slice(1));
this.wiki.source = this.wiki.source.replace(this.regex, output);
}
level++;
} while (oldSource !== this.wiki.source && level <= 10);
this.saveIncludedPagesToLocalStorage();
}

private async process(matches: string[]): Promise<string> {
const [pageName, subs] = matches;
const cleanedPageName = this.toUnixName(pageName.trim());

// const page = await this.getPageFromDb(cleanedPageName);
const cachedPages = this.getCachedPages();
// console.log('cachedPages:', cachedPages);
// cachedPagesにpageNameがあれば、pageIdとsourceを取得
// なければ、GASから取得
const cachedPage = cachedPages[pageName];
const page = cachedPage ? new Page(cachedPage.pageId, cachedPage.source) : await this.getPageFromDb(cleanedPageName);

if (!page) {
const output = `\n\n[[div class="error-block"]]\nPage to be included ${cleanedPageName} cannot be found!\n[[/div]]\n\n`;
this.wiki.vars.inclusionsNotExist = { ...this.wiki.vars.inclusionsNotExist, [cleanedPageName]: cleanedPageName };
return output;
}

let output = page.getSource();
if (subs && output) {
const subsArray = subs.split('|');
for (const sub of subsArray) {
const [varName, value] = sub.split('=').map(s => s.trim());
if (value && varName && /^[a-z0-9\-_]+$/i.test(varName)) {
output = output.replace(new RegExp(`\{\\$${varName}\}`, 'g'), value);
}
}
}

this.wiki.vars.inclusions = { ...this.wiki.vars.inclusions, [page.getPageId()]: page.getPageId() };
return `${output}`;
}

private toUnixName(name: string): string {
return name.replace(/\s+/g, '_');
}

private async getPageFromDb(pageName: string): Promise<Page | null> {
try {
const data = await getDataFromGAS(pageName);
return new Page(data.data.shortId, data.data.source);
} catch (error) {
console.error('Failed to get page from DB:', error);
return null;
}
}

private updateIncludedPages() {
const regex = /\[\[include ([a-zA-Z0-9\s\-:]+?)(\s+.*?)?\]\]/g;
let match;
while ((match = regex.exec(this.wiki.source)) !== null) {
// this.includedPages.push(match[1].trim()); //重複を削除したい
const pageName = match[1].trim();
if (!this.includedPages.includes(pageName)) {
this.includedPages.push(pageName);
}
}
}

private saveIncludedPagesToLocalStorage() {
localStorage.setItem('includedPages', JSON.stringify(this.includedPages));
}

static loadIncludedPagesFromLocalStorage(): string[] {
const savedData = localStorage.getItem('includedPages');
if (savedData) {
const savedPages = JSON.parse(savedData);
if (Array.isArray(savedPages)) {
return savedPages;
}
}
return [];
}

async onEdit(event: Event) {
const source = (event.target as HTMLTextAreaElement).value;
// console.log('Source changed:', source);
this.wiki.source = source; // クラス内のwiki.sourceを更新
this.updateIncludedPages(); // 引数なしで呼び出し
await this.checkForNewIncludes();
this.saveIncludedPagesToLocalStorage();

// paese()を呼び出し、wiki.sourceを更新
await this.parse();
}

private async checkForNewIncludes() {
const cachedPages = this.getCachedPages();
const newIncludes = this.includedPages.filter(page => !cachedPages[page]);
if (newIncludes.length > 0) {
await this.fetchPagesFromGAS(newIncludes);
}
}

private async fetchPagesFromGAS(pages: string[]) {
for (const page of pages) {
try {
const data = await getDataFromGAS(page);
this.cachePage(page, data);
} catch (error) {
console.error('Failed to fetch page:', page, error);
}
}
}

private cachePage(pageName: string, data: any) {
const cachedPages = this.getCachedPages();
cachedPages[pageName] = { pageId: data.data.shortId, source: data.data.source }; // オブジェクトをそのまま保存
localStorage.setItem('cachedPages', JSON.stringify(cachedPages)); // オブジェクトを文字列に変換して保存
}

private getCachedPages(): Record<string, { pageId: string; source: string }> {
const savedData = localStorage.getItem('cachedPages');
return savedData ? JSON.parse(savedData) : {};
}

}

0 comments on commit 9eea999

Please sign in to comment.