11const path = require ( "path" ) ;
22const hardware = require ( "./hardware" ) ;
33const integration = require ( "./integration" ) ;
4- const { app, screen, nativeTheme, BaseWindow, WebContentsView } = require ( "electron" ) ;
4+ const { app, screen, nativeTheme, ipcMain , BaseWindow, WebContentsView } = require ( "electron" ) ;
55
66global . WEBVIEW = global . WEBVIEW || {
77 initialized : false ,
@@ -24,28 +24,58 @@ const init = async (args) => {
2424 console . error ( "Please provide the '--web-url' parameter" ) ;
2525 return app . quit ( ) ;
2626 }
27+ if ( ! / ^ h t t p s ? : \/ \/ / . test ( args . web_url ) ) {
28+ console . error ( "Please provide the '--web-url' parameter with http(s)" ) ;
29+ return app . quit ( ) ;
30+ }
2731 const url = new URL ( args . web_url ) ;
28- const theme = args . web_theme ? args . web_theme : "dark" ;
29- const zoom = args . web_zoom ? parseFloat ( args . web_zoom ) : 1.25 ;
32+ const theme = [ "light" , "dark" ] . includes ( args . web_theme ) ? args . web_theme : "dark" ;
33+ const zoom = ! isNaN ( parseFloat ( args . web_zoom ) ) ? parseFloat ( args . web_zoom ) : 1.25 ;
34+ const widget = args . web_widget ? args . web_widget === "true" : true ;
35+
36+ // Init global layout
37+ WEBVIEW . viewZoom = zoom ;
38+ WEBVIEW . viewTheme = theme ;
39+ WEBVIEW . widgetTheme = theme ;
40+ WEBVIEW . widgetEnabled = widget ;
41+ nativeTheme . themeSource = WEBVIEW . viewTheme ;
3042
3143 // Init global root window
32- nativeTheme . themeSource = theme ;
3344 WEBVIEW . window = new BaseWindow ( {
3445 title : `TouchKio - ${ url . host } ` ,
3546 icon : path . join ( __dirname , ".." , "img" , "icon.png" ) ,
3647 } ) ;
3748 WEBVIEW . window . setMenuBarVisibility ( false ) ;
3849 WEBVIEW . window . setFullScreen ( true ) ;
3950
40- // Init global main webview
41- WEBVIEW . view = new WebContentsView ( ) ;
51+ // Init global webview
52+ WEBVIEW . view = new WebContentsView ( {
53+ webPreferences : {
54+ nodeIntegration : false ,
55+ contextIsolation : true ,
56+ } ,
57+ } ) ;
4258 WEBVIEW . window . contentView . addChildView ( WEBVIEW . view ) ;
4359 WEBVIEW . view . webContents . loadURL ( url . toString ( ) ) ;
60+ WEBVIEW . view . setBackgroundColor ( "#FFFFFFFF" ) ;
61+
62+ // Init global widget
63+ WEBVIEW . widget = new WebContentsView ( {
64+ transparent : true ,
65+ webPreferences : {
66+ nodeIntegration : true ,
67+ contextIsolation : false ,
68+ } ,
69+ } ) ;
70+ WEBVIEW . window . contentView . addChildView ( WEBVIEW . widget ) ;
71+ WEBVIEW . widget . webContents . loadFile ( path . join ( __dirname , "widget.html" ) ) ;
72+ WEBVIEW . widget . setBackgroundColor ( "#00000000" ) ;
4473
4574 // Register events
46- windowEvents ( WEBVIEW . window , zoom ) ;
47- touchEvents ( WEBVIEW . window ) ;
48- viewEvents ( WEBVIEW . view ) ;
75+ windowEvents ( ) ;
76+ widgetEvents ( ) ;
77+ domEvents ( ) ;
78+ appEvents ( ) ;
4979
5080 return true ;
5181} ;
@@ -69,74 +99,74 @@ const update = () => {
6999 WEBVIEW . status = "Framed" ;
70100 }
71101
102+ // Update widget status
103+ if ( ! HARDWARE . support . keyboardVisibility ) {
104+ WEBVIEW . widget . webContents . send ( "button-hide" , { id : "keyboard" } ) ;
105+ }
106+
72107 // Update integration sensor
73108 console . log ( "Update Kiosk Status:" , WEBVIEW . status ) ;
74109 integration . update ( ) ;
75110} ;
76111
77112/**
78113 * Register window events and handler.
79- *
80- * @param {Object } window - The root window object.
81- * @param {number } zoom - Zoom level used for the webview.
82114 */
83- const windowEvents = ( window , zoom ) => {
84- // Handle window resize for webview bounds
115+ const windowEvents = ( ) => {
116+ // Handle window resize events
85117 const resize = ( ) => {
86- const { width, height } = window . getBounds ( ) ;
87- WEBVIEW . view . setBounds ( { x : 0 , y : 0 , width : width , height : height } ) ;
88- WEBVIEW . view . webContents . setZoomFactor ( zoom ) ;
89- } ;
90- window . on ( "ready-to-show" , resize ) ;
91- window . on ( "resize" , resize ) ;
92- resize ( ) ;
118+ const window = WEBVIEW . window . getBounds ( ) ;
119+ const widget = { width : 60 , height : 200 } ;
93120
94- // Handle window status updates
95- window . on ( "minimize" , update ) ;
96- window . on ( "restore" , update ) ;
97- window . on ( "maximize" , update ) ;
98- window . on ( "unmaximize" , update ) ;
99- window . on ( "enter-full-screen" , update ) ;
100- window . on ( "leave-full-screen" , update ) ;
121+ // Update view size
122+ WEBVIEW . view . setBounds ( {
123+ x : 0 ,
124+ y : 0 ,
125+ width : window . width ,
126+ height : window . height ,
127+ } ) ;
128+ WEBVIEW . view . webContents . setZoomFactor ( WEBVIEW . viewZoom ) ;
129+ WEBVIEW . view . webContents . focus ( ) ;
101130
102- // Handle signal and exit events
103- process . on ( "SIGINT" , app . quit ) ;
104- app . on ( "before-quit" , ( ) => {
105- WEBVIEW . status = "Terminated" ;
106- integration . update ( ) ;
107- } ) ;
108-
109- // Handle multiple instances
110- app . on ( "second-instance" , ( ) => {
111- if ( window . isMinimized ( ) ) {
112- window . restore ( ) ;
131+ // Update widget size
132+ if ( WEBVIEW . widgetEnabled ) {
133+ WEBVIEW . widget . setBounds ( {
134+ x : window . width - 15 ,
135+ y : parseInt ( window . height / 2 - widget . height / 2 ) ,
136+ width : widget . width ,
137+ height : widget . height ,
138+ } ) ;
139+ WEBVIEW . widget . webContents . send ( "data-theme" , { theme : "hidden" } ) ;
113140 }
114- window . focus ( ) ;
115- } ) ;
116- } ;
141+ } ;
142+ WEBVIEW . window . on ( "ready-to-show" , resize ) ;
143+ WEBVIEW . window . on ( "resize" , resize ) ;
144+ resize ( ) ;
117145
118- /**
119- * Register touch events and handler.
120- *
121- * @param {Object } window - The root window object.
122- */
123- const touchEvents = ( window ) => {
124- // Handle focus change for webview lock
125- window . on ( "focus" , ( ) => {
146+ // Handle window focus events
147+ WEBVIEW . window . on ( "focus" , ( ) => {
126148 if ( WEBVIEW . locked ) {
127149 hardware . setDisplayStatus ( "ON" ) ;
128- window . blur ( ) ;
150+ WEBVIEW . window . blur ( ) ;
129151 }
130152 WEBVIEW . locked = false ;
131153 } ) ;
132154 HARDWARE . display . notifiers . push ( ( ) => {
133155 WEBVIEW . locked = hardware . getDisplayStatus ( ) === "OFF" ;
134156 if ( WEBVIEW . locked ) {
135- window . blur ( ) ;
157+ WEBVIEW . window . blur ( ) ;
136158 }
137159 } ) ;
138160
139- // Handle touch events for activity tracking
161+ // Handle window status updates
162+ WEBVIEW . window . on ( "minimize" , update ) ;
163+ WEBVIEW . window . on ( "restore" , update ) ;
164+ WEBVIEW . window . on ( "maximize" , update ) ;
165+ WEBVIEW . window . on ( "unmaximize" , update ) ;
166+ WEBVIEW . window . on ( "enter-full-screen" , update ) ;
167+ WEBVIEW . window . on ( "leave-full-screen" , update ) ;
168+
169+ // Handle window touch events for activity tracking
140170 setInterval ( ( ) => {
141171 const posOld = WEBVIEW . pointer . position ;
142172 const posNew = screen . getCursorScreenPoint ( ) ;
@@ -156,35 +186,134 @@ const touchEvents = (window) => {
156186} ;
157187
158188/**
159- * Register webview events and handler.
160- *
161- * @param {Object } view - The main webview object.
189+ * Register widget events and handler.
162190 */
163- const viewEvents = ( view ) => {
191+ const widgetEvents = ( ) => {
192+ if ( ! WEBVIEW . widgetEnabled ) {
193+ return ;
194+ }
195+
196+ // Handle widget focus events
197+ WEBVIEW . widget . webContents . on ( "focus" , ( ) => {
198+ const window = WEBVIEW . window . getBounds ( ) ;
199+ const widget = WEBVIEW . widget . getBounds ( ) ;
200+
201+ // Show widget
202+ WEBVIEW . widget . setBounds ( {
203+ x : window . width - 60 ,
204+ y : widget . y ,
205+ width : widget . width ,
206+ height : widget . height ,
207+ } ) ;
208+ WEBVIEW . widget . webContents . send ( "data-theme" , { theme : WEBVIEW . widgetTheme } ) ;
209+ } ) ;
210+
211+ // Handle widget blur events
212+ WEBVIEW . widget . webContents . on ( "blur" , ( ) => {
213+ const window = WEBVIEW . window . getBounds ( ) ;
214+ const widget = WEBVIEW . widget . getBounds ( ) ;
215+
216+ // Hide widget
217+ WEBVIEW . widget . setBounds ( {
218+ x : window . width - 15 ,
219+ y : widget . y ,
220+ width : widget . width ,
221+ height : widget . height ,
222+ } ) ;
223+ WEBVIEW . widget . webContents . send ( "data-theme" , { theme : "hidden" } ) ;
224+ } ) ;
225+
226+ // Handle widget button click events
227+ ipcMain . on ( "button-click" , ( e , button ) => {
228+ switch ( button . id ) {
229+ case "refresh" :
230+ WEBVIEW . view . webContents . reloadIgnoringCache ( ) ;
231+ break ;
232+ case "fullscreen" :
233+ if ( WEBVIEW . window . isFullScreen ( ) ) {
234+ WEBVIEW . window . restore ( ) ;
235+ WEBVIEW . window . unmaximize ( ) ;
236+ WEBVIEW . window . setFullScreen ( false ) ;
237+ } else {
238+ WEBVIEW . window . restore ( ) ;
239+ WEBVIEW . window . unmaximize ( ) ;
240+ WEBVIEW . window . setFullScreen ( true ) ;
241+ }
242+ break ;
243+ case "minimize" :
244+ WEBVIEW . window . restore ( ) ;
245+ WEBVIEW . window . setFullScreen ( false ) ;
246+ WEBVIEW . window . minimize ( ) ;
247+ break ;
248+ case "keyboard" :
249+ const toggle = hardware . getKeyboardVisibility ( ) === "ON" ? "OFF" : "ON" ;
250+ hardware . setKeyboardVisibility ( toggle ) ;
251+ switch ( toggle ) {
252+ case "OFF" :
253+ WEBVIEW . window . restore ( ) ;
254+ WEBVIEW . window . unmaximize ( ) ;
255+ WEBVIEW . window . setFullScreen ( true ) ;
256+ break ;
257+ case "ON" :
258+ WEBVIEW . window . restore ( ) ;
259+ WEBVIEW . window . setFullScreen ( false ) ;
260+ WEBVIEW . window . maximize ( ) ;
261+ break ;
262+ }
263+ break ;
264+ }
265+ } ) ;
266+ } ;
267+
268+ /**
269+ * Register dom events and handler.
270+ */
271+ const domEvents = ( ) => {
164272 // Enable webview touch emulation
165- view . webContents . debugger . attach ( "1.1" ) ;
166- view . webContents . debugger . sendCommand ( "Emulation.setEmitTouchEventsForMouse" , {
273+ WEBVIEW . view . webContents . debugger . attach ( "1.1" ) ;
274+ WEBVIEW . view . webContents . debugger . sendCommand ( "Emulation.setEmitTouchEventsForMouse" , {
167275 configuration : "mobile" ,
168276 enabled : true ,
169277 } ) ;
170278
171279 // Disable webview hyperlinks
172- view . webContents . setWindowOpenHandler ( ( ) => {
280+ WEBVIEW . view . webContents . setWindowOpenHandler ( ( ) => {
173281 return { action : "deny" } ;
174282 } ) ;
175283
176284 // Remove webview scrollbar
177- view . webContents . on ( "dom-ready" , ( ) => {
178- view . webContents . insertCSS ( "::-webkit-scrollbar { display: none; }" ) ;
285+ WEBVIEW . view . webContents . on ( "dom-ready" , ( ) => {
286+ WEBVIEW . view . webContents . insertCSS ( "::-webkit-scrollbar { display: none; }" ) ;
179287 } ) ;
180288
181289 // Webview fully loaded
182- view . webContents . on ( "did-finish-load" , ( ) => {
290+ WEBVIEW . view . webContents . on ( "did-finish-load" , ( ) => {
291+ // view.webContents.openDevTools();
183292 WEBVIEW . initialized = true ;
184293 update ( ) ;
185294 } ) ;
186295} ;
187296
297+ /**
298+ * Register app events and handler.
299+ */
300+ const appEvents = ( ) => {
301+ // Handle signal and exit events
302+ process . on ( "SIGINT" , app . quit ) ;
303+ app . on ( "before-quit" , ( ) => {
304+ WEBVIEW . status = "Terminated" ;
305+ integration . update ( ) ;
306+ } ) ;
307+
308+ // Handle multiple instances
309+ app . on ( "second-instance" , ( ) => {
310+ if ( WEBVIEW . window . isMinimized ( ) ) {
311+ WEBVIEW . window . restore ( ) ;
312+ }
313+ WEBVIEW . window . focus ( ) ;
314+ } ) ;
315+ } ;
316+
188317module . exports = {
189318 init,
190319 update,
0 commit comments