+
+
+
+
+
diff --git a/boilerplate_templates/chrome_extension/main.js b/boilerplate_templates/chrome_extension/main.js
new file mode 100644
index 0000000..a3ac706
--- /dev/null
+++ b/boilerplate_templates/chrome_extension/main.js
@@ -0,0 +1,25 @@
+// This is the main content script module that will get injected into the page with access to it's DOM etc.
+import { CommandChannel } from 'path_to_library/kiss/kiss_chrome_extension/message_utils.js'
+
+import { COMMANDS } from './commands.js'
+
+// Commands
+async function testCommand (inputData) {
+ // This code will execute in the webpages sandbox, allowing to access it's contents, issue fetch requests etc.
+ console.log(`TEST COMMAND REQUEST RECEIVED, Got ${inputData}`)
+ const results = document.getElementsByTagName('h3')[0]?.textContent
+ return new Promise(resolve => resolve(results))
+}
+
+// The chrome extension script can trigger commands to execute in the webpages sandbox by sending a
+// message along the commandMessageChannel, as demonstrated in `popup_script.js`.
+// Results of a command will be sent back to the caller along the channel.
+// Event listeners and messages
+const commandsMap = {
+ [COMMANDS.TEST]: testCommand
+}
+const commandMessageChannel = new CommandChannel(commandsMap)
+commandMessageChannel.listenForCommands()
+
+// Init finished
+console.log('Content script injected into web page.')
diff --git a/boilerplate_templates/chrome_extension/manifest.json b/boilerplate_templates/chrome_extension/manifest.json
new file mode 100644
index 0000000..086c647
--- /dev/null
+++ b/boilerplate_templates/chrome_extension/manifest.json
@@ -0,0 +1,24 @@
+{
+ "manifest_version": 3,
+ "name": "Example Plug-In",
+ "description": "Example plug-in using kiss-chrome-extension",
+ "version": "1.0",
+ "action": {
+ "default_popup": "main.html"
+ },
+ "content_scripts": [{
+ "matches": ["*://*.desired.domain.here/*"],
+ "js": [
+ "path_to_library/kiss/kiss_chrome_extension/content_script_utils.js"
+ ]
+ }],
+ "web_accessible_resources": [
+ {
+ "matches": ["*://*.desired.domain.here/*"],
+ "resources": [
+ "main.js",
+ "path_to_library/kiss/kiss_chrome_extension/message_utils.js"
+ ]
+ }
+ ]
+ }
diff --git a/boilerplate_templates/chrome_extension/popup_script.js b/boilerplate_templates/chrome_extension/popup_script.js
new file mode 100644
index 0000000..c78fb52
--- /dev/null
+++ b/boilerplate_templates/chrome_extension/popup_script.js
@@ -0,0 +1,14 @@
+import { CommandChannel } from 'path_to_library/kiss/kiss_chrome_extension/message_utils.js'
+import { COMMANDS } from './commands.js'
+
+// Chrome extension specific
+const commandMessageChannel = new CommandChannel()
+
+// State management
+function executeTestCommandInContentScript () {
+ const payloadToSendTestCommand = {someData: 'Test data'}
+ commandMessageChannel.sendCommandToActiveTab(COMMANDS.TEST, (results) => {
+ // Here we can execute any callback once the Test command has executed and its results are returned
+ console.log('Returning fresh results!')
+ }, payloadToSendTestCommand)
+}
diff --git a/boilerplate_templates/web_ui/app_config.js b/boilerplate_templates/web_ui/app_config.js
new file mode 100644
index 0000000..69e0a75
--- /dev/null
+++ b/boilerplate_templates/web_ui/app_config.js
@@ -0,0 +1,20 @@
+import { ExampleComponent } from './component_template.js'
+import { UiApp, ExamplePublicEvent } from 'ui_app_template.js'
+
+export const APPNAMEPREFIX = 'ap' // This will be appended to the front of the HTML tag ex. `ap-ui-app`
+
+export const GLOBALSTYLESHEETS = [
+ ''
+]
+
+export const PUBLICEVENTS = [
+ ExamplePublicEvent
+]
+
+// Order matters here. All child components used by parent components need to be registered before the
+// parent component can be registered. Aka order should be leafs to root, it should be already clear but
+// let us restate that cyclical dependency will break the component registration functionality
+export const APPCOMPONENTS = [
+ ExampleComponent,
+ UiApp
+]
diff --git a/boilerplate_templates/component_template.js b/boilerplate_templates/web_ui/component_template.js
similarity index 65%
rename from boilerplate_templates/component_template.js
rename to boilerplate_templates/web_ui/component_template.js
index fb3e0e8..b2f802d 100644
--- a/boilerplate_templates/component_template.js
+++ b/boilerplate_templates/web_ui/component_template.js
@@ -2,6 +2,7 @@ import { BaseElement } from 'path_to_library/kiss/kiss_web_ui/base.js'
export class ExampleComponent extends BaseElement {
template = TEMPLATESTRING
+ #RESULTSID = 'data'
exampleProp = null
exampleAttrib = null
@@ -9,6 +10,9 @@ export class ExampleComponent extends BaseElement {
buildComponent () {
const templateInstance = this.defaultTemplate
templateInstance.utils.updateTextById('example-id', this.exampleProp)
+ const span = document.createElement('span')
+ span.id = this.#RESULTSID
+ templateInstance.utils.appendById('main-example-id', span)
return templateInstance
}
@@ -17,10 +21,15 @@ export class ExampleComponent extends BaseElement {
// component will be on real DOM and redrawn
return ['example-attrib']
}
+
+ replaceResults (resultsData) {
+ this.domUtils.updateTextbyId(this.#RESULTSID, resultsData)
+ }
}
const TEMPLATESTRING = `
-
- Text that will be set to exampleProp.
+
+
+
`
diff --git a/boilerplate_templates/web_ui/main.html b/boilerplate_templates/web_ui/main.html
new file mode 100644
index 0000000..1bc94a3
--- /dev/null
+++ b/boilerplate_templates/web_ui/main.html
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/boilerplate_templates/web_ui/main.js b/boilerplate_templates/web_ui/main.js
new file mode 100644
index 0000000..143b74d
--- /dev/null
+++ b/boilerplate_templates/web_ui/main.js
@@ -0,0 +1,25 @@
+import { initSimpleWebCApp } from 'path_to_library/kiss/kiss_web_ui/utils.js'
+
+// Initialize
+const { appUi, publicUiEvents } = await initSimpleWebCApp('/path_to_app_components_code', 'example-extension-app-id')
+
+async function refreshResults (eventDetails, callback) {
+ console.log('Do some required processing, I/O etc. and call the appropriate UI app command')
+ // Pass the callback to some async function/s that is doing the processing
+ // Pretend async block
+ const pretendData = 'DATA'
+ callback(pretendData)
+}
+
+// Register UI event handlers
+document.addEventListener(
+ publicUiEvents.ExamplePublicEvent.EVENTNAME, (event) => {
+ console.log('Example event, details:', event.detail)
+ if (event.detail.someEventProp != null) {
+ refreshResults(
+ event.detail,
+ appUi.commands.updateResults
+ )
+ }
+ }
+)
diff --git a/boilerplate_templates/web_ui/ui_app_template.js b/boilerplate_templates/web_ui/ui_app_template.js
new file mode 100644
index 0000000..a6ff247
--- /dev/null
+++ b/boilerplate_templates/web_ui/ui_app_template.js
@@ -0,0 +1,73 @@
+import { BaseElement, PublicUiEvent } from 'path_to_library/kiss/kiss_web_ui/base.js'
+import { ExampleComponent } from './component_template.js'
+
+export class ExamplePublicEvent extends PublicUiEvent {
+ static EVENTNAME = 'exampleEvent'
+ static DataClass = class {
+ constructor (eventDetailsPropInput) {
+ this.someEventProp = eventDetailsPropInput
+ }
+ }
+
+ constructor (eventDetails) {
+ const eventData = { detail: eventDetails }
+ super(ExamplePublicEvent.EVENTNAME, eventData)
+ }
+}
+
+export class UiApp extends BaseElement {
+ template = TEMPLATESTRING
+ #PROPNAME = 'some-prop'
+ #EXAMPLECOMPONENTID = 'example-component'
+
+ buildComponent () {
+ const templateInstance = this.defaultTemplate
+ const exampleChildComponent = new ExampleComponent()
+ exampleChildComponent.id = this.#EXAMPLECOMPONENTID
+ templateInstance.utils.appendById('components-container', exampleChildComponent)
+
+ return templateInstance
+ }
+
+ static get observedAttributes () {
+ return []
+ }
+
+ onMount () {
+ console.log('APP Mounted!')
+
+ // Register event handlers here
+ this.domUtils.addListenerById('refresh-button', 'click', this.eventHandlers.refreshClick)
+ }
+
+ // Organize event handler methods under .eventHandlers
+ eventHandlers = {
+ refreshClick: (_) => {
+ const someEventProp = this.domUtils.byId(
+ 'main-element'
+ ).getAttribute(this.#PROPNAME)
+
+ this.commands.requestResults(someEventProp)
+ }
+ }
+
+ // Publicly available commands are under .commands only on the root app component
+ // the root component is responsible for managing the rest of the child components
+ commands = {
+ requestResults: (someEventProp) => {
+ this.dispatchEvent(new ExamplePublicEvent(new ExamplePublicEvent.DataClass(someEventProp)))
+ },
+
+ updateResults: (resultsData) => {
+ this.domUtils.byId(this.#EXAMPLECOMPONENTID).replaceResults(resultsData)
+ }
+ }
+}
+
+const TEMPLATESTRING = `
+