Commit e9e2f805 authored by greg@1m's avatar greg@1m
Browse files

adding spreadsheet ctag + updating rss + wip in tsdoc

parent 99dfdd9b
......@@ -114,7 +114,8 @@
"npm-run-all": "^4.1.5",
"raf": "^3.4.1",
"ts-jest": "^28.0.2",
"typedoc": "^0.22.15"
"typedoc": "^0.22.15",
"typedoc-plugin-missing-exports": "^0.22.6"
}
},
"node_modules/@babel/code-frame": {
......@@ -26964,6 +26965,15 @@
"typescript": "4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x || 4.6.x"
}
},
"node_modules/typedoc-plugin-missing-exports": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.22.6.tgz",
"integrity": "sha512-1uguGQqa+c5f33nWS3v1mm0uAx4Ii1lw4Kx2zQksmYFKNEWTmrmMXbMNBoBg4wu0p4dFCNC7JIWPoRzpNS6pFA==",
"dev": true,
"peerDependencies": {
"typedoc": "0.22.x"
}
},
"node_modules/typedoc/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
......@@ -49920,6 +49930,13 @@
}
}
},
"typedoc-plugin-missing-exports": {
"version": "0.22.6",
"resolved": "https://registry.npmjs.org/typedoc-plugin-missing-exports/-/typedoc-plugin-missing-exports-0.22.6.tgz",
"integrity": "sha512-1uguGQqa+c5f33nWS3v1mm0uAx4Ii1lw4Kx2zQksmYFKNEWTmrmMXbMNBoBg4wu0p4dFCNC7JIWPoRzpNS6pFA==",
"dev": true,
"requires": {}
},
"typescript": {
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.3.5.tgz",
......@@ -150,6 +150,7 @@
"npm-run-all": "^4.1.5",
"raf": "^3.4.1",
"ts-jest": "^28.0.2",
"typedoc": "^0.22.15"
"typedoc": "^0.22.15",
"typedoc-plugin-missing-exports": "^0.22.6"
}
}
type ApiCalls =
'file.getContent' |
'files.getContent' |
'woop.geti' |
'woop.iiwo' |
'ifldsakl.fdsla'
/**
* Returns the average of two numbers.
*
* @remarks
* This method is part of the {@link core-library#Statistics | Statistics subsystem}.
*
* @param nameApi- The first input woop
* - file.getContent
* - file.getContent
* - file.getContent
* - file.getContent
* - file.getContent
* - file.getContent
* @param x - The first input number
* @param x - The first input number
* @param x - The first input number
* @param x - The first input number
* @param x - The first input number
* @param x - The first input number
* @param x - The first input number
* @param y - The second input number
* @returns The arithmetic mean of `x` and `y`
*
* @beta
*/
export function call(nameApi: ApiCalls, y: number): void { //
return
}
/**
* Returns the average of two numbers.
*
* @remarks
* This method is part of the {@link core-library#Statistics | Statistics subsystem}.
*
* @param x - The first input number
* @param y - The second input number
* @returns The arithmetic mean of `x` and `y`
*
* @beta
*/
export function getAverage(x: number, y: number): number {
return (x + y) / 2.0;
}
// The TypeScript function is included for illustrative purposes.
// It is not processed by the TSDoc parser.
// export const api = {
// version: "1.0",
// utils: {
// call,
// getAverage
// }
// }
import { each } from "lodash";
import { iFile } from "../../../shared/types.shared";
import { replaceCustomMdTags } from "./markdown.manager";
type iIframeActions = 'init' | 'api' | 'resize'
export interface iIframeData {
init: {
file: iFile | null
innerTag: string
tagName: string
tagContent: string
frameId: string
}
resize: {
height: number
}
}
interface iIframeMessage {
frameId: string
action: iIframeActions
data: any
}
const h = `[IFRAME PARENT] 00563`
//
// LISTENING
//
const initIframeListening = () => {
console.log(h, `INIT IFRAME LISTENING`);
window.addEventListener('message', m => {
notify(m.data as iIframeMessage)
});
}
initIframeListening()
//
// EVENT BUS
//
const subscribers: { [id: string]: Function } = {}
const notify = (message: iIframeMessage) => {
each(subscribers, (sCb, sId) => {
if (sId === message.frameId) {
try {
console.log(`${h} parent <== iframe`, message);
sCb(message);
}
catch (e) { console.log(`${h} error with function`, e); }
}
});
}
const subscribe = (id: string, cb: (message: iIframeMessage) => void) => {
subscribers[id] = cb
}
const unsubscribe = (id: string) => {
if (subscribers[id]) delete subscribers[id]
}
const sendToIframe = (el: HTMLIFrameElement | null, message: iIframeMessage) => {
if (!el || !el.contentWindow) return;
console.log(h, `parent ==> iframe`, message);
el.contentWindow.postMessage(message, "*")
}
//
// IFRAME CODE
//
const generateIframeHtml = (tagContent: string) => {
const html = `
<html>
<div id="content-wrapper">
${tagContent}
</div>
<script>
const IMPORTED_replaceCustomMdTags = ${replaceCustomMdTags.toString()}
const main = ${iframeMainCode.toString()};
main({
replaceCustomMdTags: IMPORTED_replaceCustomMdTags
})
</script>
</html>
`
return html
}
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
// JAVASCRIPT CODE EXECUTED IN IFRAME
// Doesnt have access to any library of the project
//
const iframeMainCode = (p: {
replaceCustomMdTags
}) => {
const h = '[IFRAME child] 00564'
//
// STORAGE
//
const d: iIframeData['init'] = {
file: null,
frameId: '',
innerTag: '',
tagName: '',
tagContent: '',
}
//
// SUPPORT FUNCTIONS
//
const send = (message: iIframeMessage) => {
if (d.frameId === '') return console.warn(h, 'NO FRAME ID, CANNOT SEND TO PARENT')
//@ts-ignore
// console.log(h, 'sending message to parent', message);
window.parent.postMessage(message, '*');
}
const on = (events: { [event in iIframeActions]: Function }) => {
window.onmessage = (e) => {
const msg = e.data as iIframeMessage
if (!msg || !msg.frameId) return
for (const event in events) {
if (event === msg.action) events[event](e.data.data)
}
}
}
const executeScriptTags = (bodyRaw: string): string => {
let res = p.replaceCustomMdTags(
bodyRaw,
'[[script]]',
(UNSAFE_user_script: string) => {
console.log(h, UNSAFE_user_script);
const scriptTxt = `${UNSAFE_user_script}`
try {
// using Function instead of eval to isolate the execution scope
return new Function(scriptTxt)()
} catch (e: any) {
console.warn(h, `[SCRIPT] error: ${e}`, scriptTxt)
}
});
return res;
};
const getIframeHeight = () => {
}
//
// EXECUTION LOGIC
//
on({
init: (m: iIframeData['init']) => {
// BOOTING
// When iframe receive infos from parent
console.log(h, 'init inside iframe!');
d.frameId = m.frameId
d.innerTag = m.innerTag
d.tagContent = m.tagContent
d.tagName = m.tagName
d.file = m.file
// get content and replace script tags
const el = document.getElementById('content-wrapper')
if (el) {
const newHtml = executeScriptTags(el.innerHTML)
// console.log(h, 'transformMarkdownScript', { old: el.innerHTML, new: newHtml });
el.innerHTML = newHtml
//
// sending height back for resizing sthg
setTimeout(() => {
const data: iIframeData['resize'] = {
height: el.clientHeight + 20
}
send({ frameId: d.frameId, action: 'resize', data })
}, 100)
}
},
api: m => {
},
resize: () => {
}
})
}
// END OF RESTRICTED JS IFRAME ENVIRONMENT
/////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////
//
// EXPORTS
//
export const iframeManager = {
subscribe,
unsubscribe,
send: sendToIframe,
generateIframeHtml
}
import { each } from "lodash";
import { generateUUID } from "../../../shared/helpers/id.helper";
import { bindToElClass } from "./renderNote.manager";
import { iFile } from "../../../shared/types.shared";
import { iFile, iFileNature } from "../../../shared/types.shared";
import { createEventBus, iEventBusMessage } from "./eventBus.manager";
import { replaceCustomMdTags } from "./markdown.manager";
import { unescapeHtml } from "./textProcessor.manager";
import { iFileApi } from "../hooks/api/file.api.hook";
import { iFilesApi } from "../hooks/api/files.api.hook";
import { iPopupApi } from "../hooks/app/usePromptPopup.hook";
import { getClientApi2, iClientApi } from "../hooks/api/api.hook";
type iIframeActions = 'init' | 'apiCall' | 'apiAnswer' | 'resize' | 'iframeError'
......@@ -131,7 +135,7 @@ export const generateIframeHtml = (tagContent: string) => {
}
const iframeMainCode = (p: {
export const iframeMainCode = (p: {
replaceCustomMdTags,
unescapeHtml,
createEventBus,
......@@ -267,7 +271,6 @@ const iframeMainCode = (p: {
const loadScripts = (scripts: string[], cb: Function) => {
console.log(h, 'loadScripts', scripts);
let scriptsLoaded = 0;
// each(scripts, scriptToLoad => {
for (let i = 0; i < scripts.length; i++) {
const scriptToLoad = scripts[i];
......@@ -288,12 +291,10 @@ const iframeMainCode = (p: {
const el = document.getElementById('external-scripts-wrapper')
if (el) el.appendChild(s)
}
// })
}
// LOAD CUSTOM TAG
const loadCustomTag = (url: string, innerTag: string, opts:any) => {
const loadCustomTag = (url: string, innerTag: string, opts: any) => {
const { div, updateContent } = api.utils.createDiv();
api.utils.loadScripts([url],
......@@ -319,15 +320,11 @@ const iframeMainCode = (p: {
!apiArguments || !apiName ||
apiArguments.constructor !== Array || typeof apiName !== 'string'
) return sendError(`Call Api : ${apiName} => wrong arguments type / number(${JSON.stringify({ apiName, apiArguments, cb })})`)
const reqId = `iframe - api - call - ${p.generateUUID()} `
const reqId = `iframe-api-call-${p.generateUUID()} `
// listen for answer
subscribeOnce(reqId, res => {
if (cb) cb(res)
})
// send request
const apiData: iIframeData['apiCall'] = { reqId, apiName, apiArguments }
sendToParent({ action: 'apiCall', data: apiData })
......@@ -372,6 +369,7 @@ const iframeMainCode = (p: {
},
})
return api
}
// END OF RESTRICTED JS IFRAME ENVIRONMENT
......@@ -382,9 +380,3 @@ const iframeMainCode = (p: {
......@@ -2,6 +2,7 @@ const rssApp = (innerTagStr, opts) => {
if (!opts) opts = {}
if (!opts.size) opts.size = "95%"
if (!opts.rssToJsonUrl) opts.rssToJsonUrl = "https://api.rss2json.com/v1/api.json?rss_url="
const h = `[CTAG RSS] 0431 v1.1`
const api = window.api;
......@@ -26,7 +27,7 @@ const rssApp = (innerTagStr, opts) => {
const getJsons = (cb) => {
const feedsArr = getFeeds(feedsStr)
const urlApi = "https://api.rss2json.com/v1/api.json?rss_url="
const urlApi = opts.rssToJsonUrl
let resItems = []
for(let i = 0; i < feedsArr.length; i++) {
fetch(`${urlApi}${feedsArr[i].url}`)
......@@ -161,6 +162,7 @@ const rssApp = (innerTagStr, opts) => {
background: white;
height: calc(100% - 110px);
overflow-y: scroll;
height: 100%;
right: 0px;
top: 0px;
box-shadow: 0px 0px 17px rgb(0 0 0 / 25%);
......@@ -198,6 +200,8 @@ const rssApp = (innerTagStr, opts) => {
.article-link {
font-size: 12px;
padding-bottom: 30px;
margin-bottom: 30px;
display: block;
}
.bg-image {
width: 30%;
......
const spreadSheetApp = (innerTagStr, opts) => {
if (!opts) opts = {}
const h = `[CTAG SPREADSHEET] 04111 v1.0`
const api = window.api;
const { div, updateContent } = api.utils.createDiv();
const classId = `spreadsheet-${api.utils.uuid()}`;
console.log(h, "========= INIT with opts:", opts)
//
// CHUNK INNERTAG ARRAY
//
const innertag = innerTagStr
// const innertag = `
// hello|world|woop|wooop
// -|-|-|-
// 11|12|13|=SUM(A1:C1)
// 21|22|23|=SUM(A2:C2)
// 31|32|33|=SUM(A1:C3)
// `;
const tableMdToArray = (str) => {
const arr1 = str.split("\n");
const arr3 = [];
for (let i = 0; i < arr1.length; i++) {
const arr2 = arr1[i].split("|");
if (arr2.length === 1 && arr2[0] === "") continue;
for (let y = 0; y < arr2.length; y++) {
arr2[y] = arr2[y].trim();
}
arr3.push(arr2);
}
const headArr = arr3[0];
const bodyArr = arr3.slice(2);
console.log(1044, "woop", { arr3, headArr, bodyArr });
return { headArr, bodyArr };
};
//
// CALC & RENDER ARRAY HTML
//
const renderTable = (bodyArr, headArr) => {
const hf = window.HyperFormula.buildEmpty({
precisionRounding: 10,
licenseKey: "gpl-v3"
});
// Add a new sheet and get its id.
const sheetName = hf.addSheet("main");
const sheetId = hf.getSheetId(sheetName);
// Fill the HyperFormula sheet with data.
hf.setCellContents(
{
row: 0,
col: 0,
sheet: sheetId
},
bodyArr
);
const { height, width } = hf.getSheetDimensions(sheetId);
let newTheadHTML = "";
let newTbodyHTML = "";
for (let row = -1; row < height; row++) {
for (let col = 0; col < width; col++) {
if (row === -1) {
newTheadHTML += `<th><span>${headArr[col]}</span></th>`;
continue;
}
const cellAddress = { sheet: sheetId, col, row };
const cellHasFormula = hf.doesCellHaveFormula(cellAddress);
let cellValue = "";
if (!hf.isCellEmpty(cellAddress) && !cellHasFormula) {
cellValue = hf.getCellValue(cellAddress);
} else {
cellValue = hf.getCellValue(cellAddress);
}
newTbodyHTML += `<td><span>
${cellValue}
</span></td>`;
}
newTbodyHTML += "</tr>";
}
const head = newTheadHTML;
const body = newTbodyHTML;
const htmlRes = `
<table>
<thead>${head}</thead>
<tbody>${body}</tbody>
</table>
`;
return htmlRes;
};
api.utils.loadScripts(
["https://cdn.jsdelivr.net/npm/hyperformula/dist/hyperformula.full.min.js"],
() => {
const { headArr, bodyArr } = tableMdToArray(innertag);
const renderedRes = `${renderTable(bodyArr, headArr)}`;
updateContent(`
<div class="${classId}">
${renderedRes}
</div>
<style>
${styleTable}
</style>
`);
setTimeout(() => {
api.utils.resizeIframe();
}, 100);
}
);
const styleTable = `
body {
font-family: sans-serif;
counter-reset: row-counter col-counter;
}2
.example button.run {
background-color: #1c49e4;
border-color: #1c49e4;
margin-bottom: 20px;
}
.example button.run:hover {
background-color: #2350ea;
}
table tbody tr td:first-child {
text-align: left;
padding: 0;
}
table {
table-layout: fixed;
}
table tbody tr td,
table tbody tr th {
text-align: left;
overflow: hidden;
text-overflow: ellipsis;
}
table thead tr th:first-child {
padding-left: 40px;
}
table tbody tr td:first-child span {
width: 100%;
display: inline-block;
text-align: left;
padding-left: 15px;
margin-left: 0;
}
table tbody tr td:first-child span::before {
counter-increment: row-counter;
content: "("counter(row-counter)")";
display: inline-block;
width: 20px;