SimplyEdit is a Javascript library that makes it trivial to create webpages that can be edited by non-technical users.
In a similar fashion, SimplyCode is an environment to allow users to create web applications.
An application in SimplyCode consists of components. Currently, (2024) these components can only be built in SimplyCode directly.
This project demonstrates how components can be loaded from a different source.
It consists of two parts:
The component is loaded into the app and displayed.
The generated app can be visited at: https://blog.pother.ca/simplycode-dummy-app/generated.html
To make this work, changes were made in both the component and the app.
The component was created in SimplyCode and then exported as a JS module.
The component can be found at: https://blog.pother.ca/simplycode-dummy-component/index.js
The component was created as follows:
-
A component was created with a command and an action
- Action:
function (subject) { return new Promise(function (resolve, reject) { resolve(`Hello ${subject}`) }) }
- Command:
function (element) { simplyApp.actions.sayHello('World').then(message => alert) }
- Template:
<button data-simply-command="sayHello">Say Hello</button>
- Action:
-
A page was created with a route and HTML page
- The hello HTML contains a
<simply-render rel="hello"></simply-render>
- The route for
/
was set to "hello"
- The hello HTML contains a
-
The page-frame was changed to output a JS Module
This was all Simplycode compliant, thus a generated.html
file was created.
As the component is to be consumed as ESM, it was copied to index.js
.
The final result
export default {
'componentCss': `
`,
'pageCss': `
`,
'headHtml': `
`,
'bodyHtml': `
`,
'footHtml': `
`,
'componentTemplates': `
<template id="hello">
<button data-simply-command="sayHello">Say Hello</button>
</template>
`,
'pageTemplates': `
<template data-simply-template="hello">
<simply-render rel="hello"></simply-render>
</template>
`,
'simplyRawApi': {},
'simplyDataApi': {},
'simplyApp': {
'actions': {
'sayHello': function (subject) {
return new Promise(function (resolve, reject) {
resolve(`Hello ${subject}`)
})
},
},
'commands': {
'sayHello': function (element) {
simplyApp.actions.sayHello('World').then(message => alert)
},
},
'routes': {
'/': function (params) {
editor.pageData.page = 'hello'
},
},
},
'transformers': {},
'sorters': {},
'dataSources': undefined,
}
At this point, the repository looks like this:
.
├── components
│ └── hello
│ ├── actions
│ │ └── sayHello.js
│ ├── commands
│ │ └── sayHello.js
│ ├── componentTemplates
│ │ └── hello.html
│ └── meta.json
├── page-frame
│ ├── componentPreview.html
│ ├── fullApp.html <-- This was changed to output a JS module
│ └── pagePreview.html
├── pages
│ └── hello
│ ├── meta.json
│ ├── pageTemplates
│ │ └── hello.html
│ └── routes
│ ├── home.js
│ └── home.json
├── generated.html
├── index.js <-- This is the generated JS module
└── README.md
The app was created in SimplyCode.
The app can be found at: https://blog.pother.ca/simplycode-dummy-app/generated.html
The app was created as follows:
-
A page was created with a route and HTML page
- The hello HTML contains a
<h1>This is an App</h1>
- The route for
/
was set to "home"
- The hello HTML contains a
-
The page-frame was changed to allow us to prevent SimplyEdit from loading.
This was done by (ab)using the
data-simply-storage
attribute. An event listener was added for a customsimply-import-fired
event. This event is to be fired once the component is loaded.<script> window.waitForImport = { connect: () => true, disconnect: () => true, init: () => true, load: callback => window.addEventListener('simply-import-fired', () => callback('{}')), save: () => true, } </script> <script src="js/simply-edit.js" data-api-key="muze" data-simply-storage="waitForImport"></script>
-
Import logic was added to the foot HTML of the application.
It imports the component and adds the component's templates, actions, and commands to the app. It then fires the
simply-import-fired
event so SimplyEdit can continue loading.<script type="module"> import dc from 'https://blog.pother.ca/simplycode-dummy-component/index.js' document.body.insertAdjacentHTML('beforeend', dc.componentTemplates) document.body.querySelector("[data-simply-field=page]").insertAdjacentHTML('beforeend', dc.pageTemplates); window.addEventListener("simply-content-loaded", () => { Object.entries(dc.simplyApp.actions).forEach(([index,action]) => { simplyApp.actions[index] = action }) Object.entries(dc.simplyApp.commands).forEach(([index,command]) => { simplyApp.commands[index] = command }) }) // @CHECKME: Should we fire at the window or at the document? Why? editor.fireEvent('simply-import-fired', window) </script>
After this, the app route was changed from home
to hello
to load the component.
The final result
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<script>
var simplyDataApi = {};
var simplyApp = {};
window.addEventListener("simply-content-loaded", function() {
simply.bind = false;
var simplyRawApi = {};
simplyDataApi = {};
simplyApp = simply.app({
actions: {},
commands: {},
routes: {
"/" : function (params) {
editor.pageData.page = 'hello'
}
}
});
});
</script>
</head>
<body>
<div class="main" data-simply-field="page" data-simply-content="template">
<template data-simply-template="home">
<h1>This is an App</h1>
</template>
</div>
<script src="js/simply.everything.js"></script>
<script>
window.waitForImport = {
init : () => true,
save : () => true,
load : function(callback) {
window.addEventListener("simply-import-fired", () => {
callback("{}");
})
},
connect: () => true,
disconnect: () => true
}
</script>
<script src="js/simply-edit.js" data-api-key="muze" data-simply-storage="waitForImport"></script>
<script type="module">
import dc from 'https://blog.pother.ca/simplycode-dummy-component/index.js'
document.body.insertAdjacentHTML('beforeend', dc.componentTemplates)
document.body.querySelector("[data-simply-field=page]").insertAdjacentHTML('beforeend', dc.pageTemplates);
window.addEventListener("simply-content-loaded", () => {
Object.entries(dc.simplyApp.actions).forEach(([index,action]) => {
simplyApp.actions[index] = action
})
Object.entries(dc.simplyApp.commands).forEach(([index,command]) => {
simplyApp.commands[index] = command
})
})
editor.fireEvent('simply-import-fired', window)
</script>
</body>
</html>
At this point, the repository looks like this:
.
├── base-components
│ └── import
│ ├── footHtml
│ │ └── importFoot.html <-- This was changed to import the component
│ └── meta.json
├── generated.html
├── page-frame
│ ├── componentPreview.html <-- This was changed to prevent SimplyEdit from loading
│ ├── fullApp.html
│ └── pagePreview.html
├── pages
│ └── home
│ ├── meta.json
│ ├── pageTemplates
│ │ └── home.html
│ └── routes
│ ├── home.js
│ └── home.json
└── README.md