Skip to content

Commit

Permalink
Add new Stimulus controllers and improve script environment handling (#…
Browse files Browse the repository at this point in the history
…234)

Introduced multiple new Stimulus controllers for handling various browser features such as battery, device orientation, geolocation, and more. Converted environment handling in `castor.php` to use context-based approach, ensuring better isolation and maintainability.
  • Loading branch information
Spomky authored Oct 2, 2024
1 parent 98757a3 commit 6a3aa6a
Show file tree
Hide file tree
Showing 51 changed files with 547 additions and 85 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/integrate.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ jobs:

- name: "Check file permissions"
run: |
test "$(find . -type f -not -path './.git/*' -executable)" == ""
test "$(find . -type f -not -path './.git/*' -not -wholename './link' -executable)" == ""
- name: "Find non-printable ASCII characters"
run: |
Expand Down
82 changes: 76 additions & 6 deletions assets/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,23 +5,58 @@
"version": "1.0.0",
"symfony": {
"controllers": {
"backgroundsync-form": {
"main": "src/backgroundsync-form_controller.js",
"name": "pwa/backgroundsync-form",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"badge": {
"main": "src/badge_controller.js",
"name": "pwa/badge",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"battery": {
"main": "src/battery_controller.js",
"name": "pwa/battery",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"connection-status": {
"main": "src/connection-status_controller.js",
"name": "pwa/connection-status",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"backgroundsync-form": {
"main": "src/backgroundsync-form_controller.js",
"name": "pwa/backgroundsync-form",
"device-orientation": {
"main": "src/device-orientation_controller.js",
"name": "pwa/device-orientation",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"sync-broadcast": {
"main": "src/sync-broadcast_controller.js",
"name": "pwa/sync-broadcast",
"fullscreen": {
"main": "src/fullscreen_controller.js",
"name": "pwa/fullscreen",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"geolocation": {
"main": "src/geolocation_controller.js",
"name": "pwa/geolocation",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"install": {
"main": "src/install_controller.js",
"name": "pwa/install",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
Expand All @@ -32,6 +67,41 @@
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"presentation": {
"main": "src/presentation_controller.js",
"name": "pwa/presentation",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"receiver": {
"main": "src/receiver_controller.js",
"name": "pwa/receiver",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"share": {
"main": "src/share_controller.js",
"name": "pwa/share",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"sync-broadcast": {
"main": "src/sync-broadcast_controller.js",
"name": "pwa/sync-broadcast",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
},
"vibration": {
"main": "src/vibration_controller.js",
"name": "pwa/vibration",
"webpackMode": "eager",
"fetch": "eager",
"enabled": true
}
},
"importmap": {
Expand Down
10 changes: 10 additions & 0 deletions assets/src/abstract_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

import { Controller } from '@hotwired/stimulus';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
dispatchEvent = (name, payload) => {
this.dispatch(name, { detail: payload });
}
}
21 changes: 12 additions & 9 deletions assets/src/backgroundsync-form_controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,16 @@ import { Controller } from '@hotwired/stimulus';
/* stimulusFetch: 'lazy' */
export default class extends Controller {
static values = {
params: { type: Object, default: {
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer'
}},
params: {
type: Object,
default: {
mode: 'cors',
cache: 'no-cache',
credentials: 'same-origin',
redirect: 'follow',
referrerPolicy: 'no-referrer'
}
},
headers: { type: Object, default: {} },
redirection: { type: String, default: null },
};
Expand All @@ -36,11 +39,11 @@ export default class extends Controller {
params.headers['Content-Type'] = 'application/x-www-form-urlencoded';
params.body = new URLSearchParams(new FormData(form));
} else {
console.error('Unsupported form enctype');
// Unsupported form enctype
return;
}
params.method = form.method.toUpperCase();
const response = await fetch(url, params);
console.log(new URLSearchParams(params.body).toString(), params, params.headers);
if (response.redirected) {
window.location.assign(response.url);
return;
Expand Down
16 changes: 16 additions & 0 deletions assets/src/badge_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
'use strict';

import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends AbstractController {
update = async ({counter}) => {
await navigator.setAppBadge(counter);
this.dispatchEvent('badge:updated', { counter });
}

clear = async () => {
await navigator.clearAppBadge();
this.dispatchEvent('badge:cleared');
}
}
36 changes: 36 additions & 0 deletions assets/src/battery_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
'use strict';

import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends AbstractController {
async connect() {
const battery = await navigator.getBattery();
battery.addEventListener('chargingchange', () => this.updateChargeInfo(battery));
battery.addEventListener('levelchange', () => this.updateLevelInfo(battery));
battery.addEventListener('chargingtimechange', () => this.updateChargingInfo(battery));
battery.addEventListener('dischargingtimechange', () => this.updateDischargingInfo(battery));

await this.updateChargeInfo(battery);
await this.updateLevelInfo(battery);
await this.updateChargingInfo(battery);
await this.updateDischargingInfo(battery);
}
update = async ({counter}) => {
await navigator.setAppBadge(counter);
this.dispatchEvent('badge:updated', { counter });
}

updateChargeInfo = async (battery) => {
this.dispatchEvent('battery:charge', { charging: battery.charging });
}
updateLevelInfo = async (battery) => {
this.dispatchEvent('battery:level', { level: battery.level });
}
updateChargingInfo = async (battery) => {
this.dispatchEvent('battery:chargingtime', { chargingTime: battery.chargingTime });
}
updateDischargingInfo = async (battery) => {
this.dispatchEvent('battery:dischargingtime', { dischargingTime: battery.dischargingTime });
}
}
7 changes: 2 additions & 5 deletions assets/src/connection-status_controller.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
'use strict';

import { Controller } from '@hotwired/stimulus';
import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends Controller {
export default class extends AbstractController {
static targets = ['message', 'attribute'];
static values = {
onlineMessage: { type: String, default: 'You are online.' },
Expand Down Expand Up @@ -37,9 +37,6 @@ export default class extends Controller {
});
});
}
dispatchEvent = (name, payload) => {
this.dispatch(name, { detail: payload });
}

statusChanged = (data) => {
this.messageTargets.forEach((element) => {
Expand Down
21 changes: 21 additions & 0 deletions assets/src/device-orientation_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends AbstractController {
connect() {
window.addEventListener(
'deviceorientation',
(event) => {
this.dispatchEvent({
absolute: event.absolute,
alpha: event.alpha,
beta: event.beta,
gamma: event.gamma
})
},
true
);
}
}
39 changes: 39 additions & 0 deletions assets/src/fullscreen_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
'use strict';

import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends AbstractController {
connect () {
document.addEventListener("fullscreenchange", () => {
this.dispatchEvent('fullscreen:change', {
fullscreen: document.fullscreenElement !== null,
element: document.fullscreenElement
});
});
document.addEventListener("fullscreenerror", () => {
this.dispatchEvent('fullscreen:error', {
element: document.fullscreenElement
});
});
}

request = async (event) => {
const {params} = event;
const {target, ...rest} = params;
if (!target) {
await document.documentElement.requestFullscreen(rest);
return
}
const element = document.getElementById(target);
if (!element) {
console.error('Element not found:', target);
return;
}
await element.requestFullscreen(rest);
}

exit = async () => {
await document.exitFullscreen();
}
}
47 changes: 47 additions & 0 deletions assets/src/geolocation_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
'use strict';

import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends AbstractController {
watchId = null;

locate({params}) {
if (!navigator.geolocation) {
this.dispatchEvent('geolocation:unsupported');
return;
}

navigator.geolocation.getCurrentPosition(
(position) => {this.dispatchEvent('geolocation:position', {latitude: position.coords.latitude, longitude: position.coords.longitude});},
(error) => {this.dispatchEvent('geolocation:error', {error: error});},
params
);
}

watch({params}) {
if (!navigator.geolocation) {
this.dispatchEvent('geolocation:unsupported');
return;
}
if (this.watchId) {
return;
}

this.watchId = navigator.geolocation.watchPosition(
(position) => {this.dispatchEvent('geolocation:position', {latitude: position.coords.latitude, longitude: position.coords.longitude});},
(error) => {this.dispatchEvent('geolocation:error', {error: error});},
params
);
}

clearWatch() {
if (!this.watchId) {
return;
}

navigator.geolocation.clearWatch(this.watchId);
this.watchId = null;
this.dispatchEvent('geolocation:watch:cleared');
}
}
42 changes: 42 additions & 0 deletions assets/src/install_controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
'use strict';

import AbstractController from './abstract_controller.js';

/* stimulusFetch: 'lazy' */
export default class extends AbstractController {
static targets = ['install'];
installPrompt = null;

async connect() {
this.disableInstallTargets();
window.addEventListener("beforeinstallprompt", async (event) => {
event.preventDefault();
this.installPrompt = event;
this.enableInstallTargets();
});
}

async install() {
if (!this.installPrompt) {
return;
}
const result = await this.installPrompt.prompt();
if (result.outcome === 'accepted') {
this.disableInstallTargets();
} else {
this.dispatchEvent('install:cancelled');
}
}

enableInstallTargets() {
this.installTargets.forEach((installElement) => {
installElement.removeAttribute("hidden");
});
}

disableInstallTargets() {
this.installTargets.forEach((installElement) => {
installElement.setAttribute("hidden", "");
});
}
}
Loading

0 comments on commit 6a3aa6a

Please sign in to comment.