Skip to content

Commit

Permalink
split container and content for better readibility - WIP - POC
Browse files Browse the repository at this point in the history
Add div that is the place the cached content are stored because content are never destroyed but only hidden
Add elementsCache  tool to handle communication between container and content
Adapt fullscreen button with new logic for extra content
  • Loading branch information
luc-github committed Jul 28, 2024
1 parent 8f7e11b commit c68cf0e
Show file tree
Hide file tree
Showing 8 changed files with 482 additions and 345 deletions.
140 changes: 140 additions & 0 deletions src/areas/elementsCache.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
/*
elementsCache.js - ESP3D WebUI MainPage file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
Original code inspiration : 2021 Alexandre Aussourd
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
import { h, render } from "preact"
import { ExtraContentItem } from "../components/ExtraContent"

const ElementsCache = () => {
return (<div style="position: fixed; top: 0; left: 0; width: 0; height: 0; overflow: visible;" id="elementsCache"></div>)
}

const elementsCache = {

has: (id) => {
const cacheHost = document.getElementById("elementsCache")
if (!cacheHost) return false
return cacheHost.querySelector('#' + id) !== null
},

create: (id, props) => {
if (!elementsCache.has(id)) {
const cacheHost = document.getElementById("elementsCache")
console.log("Creating element, because it doesn't exist: " + id)
console.log("Current host size is " + cacheHost.children.length)
try {
const container = document.getElementById("elementsCache")
const vnode = container.appendChild(document.createElement('div'))
vnode.id = "new_element" + id
const new_vnode = render(<ExtraContentItem {...props} id={id} />, container, vnode)
console.log("Element created: " + id + ", exists in cache: " + elementsCache.has(id))
console.log("Now Current host size is " + cacheHost.children.length)
console.log(cacheHost.innerHTML)
return true
} catch (error) {
console.error(`Error creating element ${id}:`, error)
return false
}
} else {
//console.log("Element already exists: " + id)
return true
}
},

get: (id) => {
const cacheHost = document.getElementById("elementsCache")
if (!cacheHost) return null
return cacheHost.querySelector('#' + id)
},

remove: (id) => {
const cacheItem = elementsCache.get(id)
if (cacheItem) {
try {
const cacheHost = document.getElementById("elementsCache")
if (!cacheHost) return false
removeCache = removeChild(cacheHost, cacheItem)
if (removeCache) {
removeCache.remove()
return true
} else {
return false
}
} catch (error) {
console.error(`Error removing element ${id}:`, error)
return false
}
}
return false
},

updateState: (id, newState) => {
const element = document.getElementById(id);
console.log("Updating state for element " + id)
console.log(newState)
if (element) {
if ('isVisible' in newState) {
element.style.display = newState.isVisible ? 'block' : 'none';
}
if ('isFullScreen' in newState) {
if (newState.isFullScreen) {
element.style.position = 'fixed';
element.style.top = '0';
element.style.left = '0';
element.style.width = '100%';
element.style.height = '100%';
element.style.zIndex = '9999';
} else {
// Rétablir les styles normaux
element.style.position = 'absolute';
element.style.top = '';
element.style.left = '';
element.style.width = '';
element.style.height = '';
element.style.zIndex = '';
}
}
return true;
}
return false;
},

updatePosition: (id, position) => {
const cacheItem = elementsCache.get(id)
//console.log("Updating position for element " + id + ", exists: " + elementsCache.has(id))
if (cacheItem) {
try {
//console.log("Updating positions to", position)
cacheItem.style.top = `${position.top}px`;
cacheItem.style.left = `${position.left}px`;
cacheItem.style.width = `${position.width}px`;
cacheItem.style.height = `${position.height}px`;
return true
} catch (error) {
console.error(`Error updating position for element ${id}:`, error)
return false
}
} else {
//console.log("Element " + id + " doesn't exist")
}
return false
}
}

export { ElementsCache, elementsCache }
2 changes: 2 additions & 0 deletions src/components/App/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,12 @@ import { TargetContextProvider } from "../../targets"
import { ToastsContainer } from "../Toast"
import { ModalContainer } from "../Modal"
import { ContentContainer } from "../../areas"
import { ElementsCache } from "../../areas/elementsCache"

const App = () => {
return (
<div id="app">
<ElementsCache />
<DatasContextProvider>
<TargetContextProvider>
<RouterContextProvider>
Expand Down
24 changes: 18 additions & 6 deletions src/components/Controls/FullScreenButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,12 +25,17 @@ const isFullScreen = (element) => {
return document.fullscreenElement === element
}

const FullScreenButton = ({ panelRef, hideOnFullScreen, asButton }) => {
const FullScreenButton = ({ panelRef,panelId, hideOnFullScreen, asButton, onclick }) => {
const [isFullScreenMode, setIsFullScreenMode] = useState(false)

const getPanelRef = () => {
if(panelRef) return panelRef.current
if (panelId)return document.getElementById(panelId)
return null
}
useEffect(() => {
const handleFullscreenChange = () => {
setIsFullScreenMode(isFullScreen(panelRef.current))
if(getPanelRef)
setIsFullScreenMode(isFullScreen(getPanelRef))
}

document.addEventListener("fullscreenchange", handleFullscreenChange)
Expand All @@ -41,11 +46,18 @@ const FullScreenButton = ({ panelRef, hideOnFullScreen, asButton }) => {
handleFullscreenChange
)
}
}, [panelRef])
}, [])

const toggleFullScreen = () => {
if (!isFullScreenMode) {
panelRef.current.requestFullscreen()
if (!isFullScreenMode) {//
if (onclick) {
onclick()
}
if (getPanelRef()){
getPanelRef().requestFullscreen()
}

console.log("Fullscreen activated pour " + panelId)
} else {
if (document.fullscreenElement) {
document.exitFullscreen()
Expand Down
185 changes: 185 additions & 0 deletions src/components/ExtraContent/extraContentItem.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/*
extraContentItem.js - ESP3D WebUI navigation page file
Copyright (c) 2020 Luc Lebosse. All rights reserved.
This code is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This code is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with This code; if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
import { Fragment, h } from "preact"
import { useState, useEffect, useCallback } from "preact/hooks"
import { espHttpURL } from "../Helpers"
import { useHttpFn } from "../../hooks"
import {
ButtonImg,
FullScreenButton,
CloseButton,
ContainerHelper,
} from "../Controls"
import { T } from "../Translations"
import { Play, Pause, Aperture, RefreshCcw } from "preact-feather"
import { elementsCache } from "../../areas/elementsCache"

const ExtraContentItem = ({ id, source, type, label, target, refreshtime, isVisible = true, isFullScreen = false, refreshPaused = false }) => {
const [contentUrl, setContentUrl] = useState("")
const { createNewRequest } = useHttpFn
console.log( id)
//console.log("ExtraContentItem rendering for " + id, "is in cache: " + elementsCache.has(id))
/*const loadContent = useCallback((forceReload = false) => {
if ( elementsCache.has(id) && !forceReload) {
console.log("Content already loaded for " + id)
return
}
if (source.startsWith("http") || forceReload) {
setContentUrl(source)
} else {
const idquery = type === "content" ? type + id : "download" + id
createNewRequest(
espHttpURL(source),
{ method: "GET", id: idquery, max: 2 },
{
onSuccess: handleContentSuccess,
onFail: handleContentError,
}
)
}
}, [id, source, type, createNewRequest])
const handleContentSuccess = useCallback((result) => {
let blob
switch (type) {
case "camera":
case "image":
blob = new Blob([result], { type: "image/jpeg" })
break
case "extension":
case "content":
blob = new Blob([result], { type: "text/html" })
break
default:
blob = new Blob([result], { type: "text/plain" })
}
const url = URL.createObjectURL(blob)
setContentUrl(url)
}, [type])
const handleContentError = useCallback((error) => {
console.error(`Error loading content for ${id}:`, error)
const errorContent = `<html><body><div style='display: flex; justify-content: center; align-items: center; height: 100%; font-family: Arial, sans-serif;'><p>Error loading content</p></div></body></html>`
const errorBlob = new Blob([errorContent], { type: "text/html" })
setContentUrl(URL.createObjectURL(errorBlob))
}, [id])
*/
useEffect(() => {
console.log("ExtraContentItem rendering for " + id, "is in cache: " + elementsCache.has(id))
}, [])
/*
const handleRefresh = () => loadContent(true)
const toggleFullScreen = () => elementsCache.updateState(id, { isFullScreen: !isFullScreen })
const toggleRefreshPause = () => elementsCache.updateState(id, { refreshPaused: !refreshPaused })
const renderControls = () => (
<div class="m-2 image-button-bar">
{parseInt(refreshtime) === 0 && target === "page" && (
<ButtonImg
m1
icon={<RefreshCcw size="0.8rem" />}
onclick={handleRefresh}
/>
)}
{parseInt(refreshtime) > 0 && type !== "extension" && (
<>
<ButtonImg
m1
tooltip
data-tooltip={refreshPaused ? T("S185") : T("S184")}
icon={refreshPaused ? <Play /> : <Pause />}
onclick={toggleRefreshPause}
/>
{type !== "content" && (
<ButtonImg
m1
tooltip
data-tooltip={T("S186")}
icon={<Aperture />}
onclick={() => {
// Handle screenshot functionality here
}}
/>
)}
</>
)}
{target === "panel" && (
<Fragment>
<CloseButton
panelRef={{ current: document.getElementById(`extra_content_${id}`) }}
panelId={id}
hideOnFullScreen={true}
callbackfn={() => elementsCache.updateState(id, { isVisible: false })}
/>
<FullScreenButton
panelRef={{ current: document.getElementById(`extra_content_${id}`) }}
hideOnFullScreen={true}
asButton={true}
onclick={toggleFullScreen}
/>
</Fragment>
)}
</div>
)
*/
const contentStyle = {
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: isFullScreen ? '9999' : 'auto',
display: isVisible ? 'block' : 'none',
}

let content
if (type === "camera" || type === "image") {
content = <img src={contentUrl} alt={label} style="width: 100%; height: 100%; object-fit: contain;" />
} else {
content = (
<iframe
src={contentUrl}
style={{
border: 'none',
width: '100%',
height: '100%',
visibility: contentUrl ? 'visible' : 'hidden'
}}
class={type === "extension" ? "extensionContainer" : "content-container"}
/>
)
}
console.log("ExtraContentItem rendering for " + id, "is in cache: " + elementsCache.has(id))
return (
<div id={id} class="extra-content-container" >
My {type} content is here
</div>
)
/* return (
<div id={id} style={contentStyle}>
{content}
{renderControls()}
{target === "panel" && <ContainerHelper id={id} />}
</div>
)*/
}

export { ExtraContentItem }
Loading

0 comments on commit c68cf0e

Please sign in to comment.