Skip to content

Commit 632dbce

Browse files
authored
Merge pull request #3 from izo0x90/hristo/web-ui-templates
Add boilerplate templates
2 parents c3a980e + 76dfb3c commit 632dbce

10 files changed

Lines changed: 215 additions & 2 deletions

File tree

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export const COMMANDS = {
2+
TEST: 'test'
3+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<html>
2+
<body>
3+
4+
<div>
5+
Chrome extension content.
6+
</div>
7+
8+
<script src="path_to_library/kiss/kiss_chrome_extension/popup_script_utils.js"></script>
9+
<script src="popup_script.js" type="module"></script>
10+
</body>
11+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// This is the main content script module that will get injected into the page with access to it's DOM etc.
2+
import { CommandChannel } from 'path_to_library/kiss/kiss_chrome_extension/message_utils.js'
3+
4+
import { COMMANDS } from './commands.js'
5+
6+
// Commands
7+
async function testCommand (inputData) {
8+
// This code will execute in the webpages sandbox, allowing to access it's contents, issue fetch requests etc.
9+
console.log(`TEST COMMAND REQUEST RECEIVED, Got ${inputData}`)
10+
const results = document.getElementsByTagName('h3')[0]?.textContent
11+
return new Promise(resolve => resolve(results))
12+
}
13+
14+
// The chrome extension script can trigger commands to execute in the webpages sandbox by sending a
15+
// message along the commandMessageChannel, as demonstrated in `popup_script.js`.
16+
// Results of a command will be sent back to the caller along the channel.
17+
// Event listeners and messages
18+
const commandsMap = {
19+
[COMMANDS.TEST]: testCommand
20+
}
21+
const commandMessageChannel = new CommandChannel(commandsMap)
22+
commandMessageChannel.listenForCommands()
23+
24+
// Init finished
25+
console.log('Content script injected into web page.')
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
{
2+
"manifest_version": 3,
3+
"name": "Example Plug-In",
4+
"description": "Example plug-in using kiss-chrome-extension",
5+
"version": "1.0",
6+
"action": {
7+
"default_popup": "main.html"
8+
},
9+
"content_scripts": [{
10+
"matches": ["*://*.desired.domain.here/*"],
11+
"js": [
12+
"path_to_library/kiss/kiss_chrome_extension/content_script_utils.js"
13+
]
14+
}],
15+
"web_accessible_resources": [
16+
{
17+
"matches": ["*://*.desired.domain.here/*"],
18+
"resources": [
19+
"main.js",
20+
"path_to_library/kiss/kiss_chrome_extension/message_utils.js"
21+
]
22+
}
23+
]
24+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { CommandChannel } from 'path_to_library/kiss/kiss_chrome_extension/message_utils.js'
2+
import { COMMANDS } from './commands.js'
3+
4+
// Chrome extension specific
5+
const commandMessageChannel = new CommandChannel()
6+
7+
// State management
8+
function executeTestCommandInContentScript () {
9+
const payloadToSendTestCommand = {someData: 'Test data'}
10+
commandMessageChannel.sendCommandToActiveTab(COMMANDS.TEST, (results) => {
11+
// Here we can execute any callback once the Test command has executed and its results are returned
12+
console.log('Returning fresh results!')
13+
}, payloadToSendTestCommand)
14+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { ExampleComponent } from './component_template.js'
2+
import { UiApp, ExamplePublicEvent } from 'ui_app_template.js'
3+
4+
export const APPNAMEPREFIX = 'ap' // This will be appended to the front of the HTML tag ex. `ap-ui-app`
5+
6+
export const GLOBALSTYLESHEETS = [
7+
'<link rel="stylesheet" href="example_style_sheet.css">'
8+
]
9+
10+
export const PUBLICEVENTS = [
11+
ExamplePublicEvent
12+
]
13+
14+
// Order matters here. All child components used by parent components need to be registered before the
15+
// parent component can be registered. Aka order should be leafs to root, it should be already clear but
16+
// let us restate that cyclical dependency will break the component registration functionality
17+
export const APPCOMPONENTS = [
18+
ExampleComponent,
19+
UiApp
20+
]

boilerplate_templates/component_template.js renamed to boilerplate_templates/web_ui/component_template.js

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,17 @@ import { BaseElement } from 'path_to_library/kiss/kiss_web_ui/base.js'
22

33
export class ExampleComponent extends BaseElement {
44
template = TEMPLATESTRING
5+
#RESULTSID = 'data'
56

67
exampleProp = null
78
exampleAttrib = null
89

910
buildComponent () {
1011
const templateInstance = this.defaultTemplate
1112
templateInstance.utils.updateTextById('example-id', this.exampleProp)
13+
const span = document.createElement('span')
14+
span.id = this.#RESULTSID
15+
templateInstance.utils.appendById('main-example-id', span)
1216
return templateInstance
1317
}
1418

@@ -17,10 +21,15 @@ export class ExampleComponent extends BaseElement {
1721
// component will be on real DOM and redrawn
1822
return ['example-attrib']
1923
}
24+
25+
replaceResults (resultsData) {
26+
this.domUtils.updateTextbyId(this.#RESULTSID, resultsData)
27+
}
2028
}
2129

2230
const TEMPLATESTRING = `
23-
<div id="example-id">
24-
Text that will be set to exampleProp.
31+
<div id="main-example-id">
32+
<div id="example-id">
33+
</div>
2534
</div>
2635
`
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<html>
2+
<head>
3+
<link rel="stylesheet" href="example_style_sheet.css">
4+
</head>
5+
6+
<body>
7+
<ns-ui-app id="example-extension-app-id"></ns-ui-app>
8+
</body>
9+
</html>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { initSimpleWebCApp } from 'path_to_library/kiss/kiss_web_ui/utils.js'
2+
3+
// Initialize
4+
const { appUi, publicUiEvents } = await initSimpleWebCApp('/path_to_app_components_code', 'example-extension-app-id')
5+
6+
async function refreshResults (eventDetails, callback) {
7+
console.log('Do some required processing, I/O etc. and call the appropriate UI app command')
8+
// Pass the callback to some async function/s that is doing the processing
9+
// Pretend async block
10+
const pretendData = 'DATA'
11+
callback(pretendData)
12+
}
13+
14+
// Register UI event handlers
15+
document.addEventListener(
16+
publicUiEvents.ExamplePublicEvent.EVENTNAME, (event) => {
17+
console.log('Example event, details:', event.detail)
18+
if (event.detail.someEventProp != null) {
19+
refreshResults(
20+
event.detail,
21+
appUi.commands.updateResults
22+
)
23+
}
24+
}
25+
)
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import { BaseElement, PublicUiEvent } from 'path_to_library/kiss/kiss_web_ui/base.js'
2+
import { ExampleComponent } from './component_template.js'
3+
4+
export class ExamplePublicEvent extends PublicUiEvent {
5+
static EVENTNAME = 'exampleEvent'
6+
static DataClass = class {
7+
constructor (eventDetailsPropInput) {
8+
this.someEventProp = eventDetailsPropInput
9+
}
10+
}
11+
12+
constructor (eventDetails) {
13+
const eventData = { detail: eventDetails }
14+
super(ExamplePublicEvent.EVENTNAME, eventData)
15+
}
16+
}
17+
18+
export class UiApp extends BaseElement {
19+
template = TEMPLATESTRING
20+
#PROPNAME = 'some-prop'
21+
#EXAMPLECOMPONENTID = 'example-component'
22+
23+
buildComponent () {
24+
const templateInstance = this.defaultTemplate
25+
const exampleChildComponent = new ExampleComponent()
26+
exampleChildComponent.id = this.#EXAMPLECOMPONENTID
27+
templateInstance.utils.appendById('components-container', exampleChildComponent)
28+
29+
return templateInstance
30+
}
31+
32+
static get observedAttributes () {
33+
return []
34+
}
35+
36+
onMount () {
37+
console.log('APP Mounted!')
38+
39+
// Register event handlers here
40+
this.domUtils.addListenerById('refresh-button', 'click', this.eventHandlers.refreshClick)
41+
}
42+
43+
// Organize event handler methods under .eventHandlers
44+
eventHandlers = {
45+
refreshClick: (_) => {
46+
const someEventProp = this.domUtils.byId(
47+
'main-element'
48+
).getAttribute(this.#PROPNAME)
49+
50+
this.commands.requestResults(someEventProp)
51+
}
52+
}
53+
54+
// Publicly available commands are under .commands only on the root app component
55+
// the root component is responsible for managing the rest of the child components
56+
commands = {
57+
requestResults: (someEventProp) => {
58+
this.dispatchEvent(new ExamplePublicEvent(new ExamplePublicEvent.DataClass(someEventProp)))
59+
},
60+
61+
updateResults: (resultsData) => {
62+
this.domUtils.byId(this.#EXAMPLECOMPONENTID).replaceResults(resultsData)
63+
}
64+
}
65+
}
66+
67+
const TEMPLATESTRING = `
68+
<div id="main-element" some-prop="true">
69+
<button id="refresh-button">Click me!</button>
70+
<div id="components-container">
71+
</div>
72+
</div>
73+
`

0 commit comments

Comments
 (0)