Skip to content

Commit

Permalink
feat: implement dynamic CSS loading for p2p-media custom elements to …
Browse files Browse the repository at this point in the history
…ensure correct styling

feat: ensure class attributes are correctly synchronized for media elements

feat: optimize protocol support check with global caching

refactor: import module dependencies directly in respective scripts
  • Loading branch information
akhileshthite committed Jun 20, 2024
1 parent 58366b8 commit b5f6370
Show file tree
Hide file tree
Showing 14 changed files with 153 additions and 82 deletions.
8 changes: 0 additions & 8 deletions actor-mini-profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,6 @@
font: inherit;
}

.profile-mini-icon {
width: 28px;
height: 28px;
border-radius: 50%;
background-color: #000000;
margin-right: 6px;
}

.profile-mini-name {
color: var(--rdp-text-color);
}
Expand Down
1 change: 1 addition & 0 deletions actor-mini-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ class ActorMiniProfile extends HTMLElement {
// Actor icon
const p2pImage = document.createElement('p2p-image')
p2pImage.className = 'profile-mini-icon'
p2pImage.setAttribute('src', iconUrl)
p2pImage.alt = actorInfo.name ? actorInfo.name : 'Actor icon'
clickableContainer.appendChild(p2pImage)

Expand Down
9 changes: 0 additions & 9 deletions actor-profile.css
Original file line number Diff line number Diff line change
Expand Up @@ -13,15 +13,6 @@
margin-bottom: 16px;
}

.profile-icon {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #000000;
margin-right: 8px;
margin-bottom: 8px;
}

.profile-details {
display: flex;
flex-direction: column;
Expand Down
2 changes: 1 addition & 1 deletion actor-profile.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ class ActorProfile extends HTMLElement {
}

const p2pImage = document.createElement('p2p-image')
p2pImage.setAttribute('src', iconUrl)
p2pImage.classList.add('profile-icon')
p2pImage.setAttribute('src', iconUrl)
p2pImage.alt = actorInfo.name ? actorInfo.name : 'Actor icon'
actorContainer.appendChild(p2pImage) // Append to the actor container

Expand Down
30 changes: 24 additions & 6 deletions db.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,14 +42,32 @@ export function isP2P (url) {
return url.startsWith(HYPER_PREFIX) || url.startsWith(IPNS_PREFIX)
}

// Global cache to store protocol reachability
const protocolSupportMap = new Map()

export async function supportsP2P (url) {
try {
const response = await fetch(url)
return response.ok
} catch (error) {
console.log('P2P URL loading failed:', error)
return false
const urlObject = new URL(url)
const protocol = urlObject.protocol

if (protocolSupportMap.has(protocol)) {
return protocolSupportMap.get(protocol)
}

// Set a promise to avoid multiple simultaneous checks
const supportCheckPromise = fetch(url)
.then(response => {
const supported = response.ok
protocolSupportMap.set(protocol, supported)
return supported
})
.catch(error => {
console.error(`Error checking protocol support for ${protocol}:`, error)
protocolSupportMap.set(protocol, false)
return false
})

protocolSupportMap.set(protocol, supportCheckPromise)
return supportCheckPromise
}

export function resolveP2PUrl (url) {
Expand Down
3 changes: 2 additions & 1 deletion example/post.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
<!-- ipfs://bafybeifslnipwp5uanmhkckokwuse7h5gfrrjzqq4jg5oxewxbzrdcdawu -->
<distributed-post id="distributedPost"></distributed-post>
</div>

<!-- test P2P media -->
<p2p-image src="hyper://hypha.coop/assets/images/posts/2022-05-12-schneider-tweet.png"></p2p-image>
<script type="module" src="../post.js"></script>
<script>
const params = new URLSearchParams(window.location.search);
Expand Down
1 change: 0 additions & 1 deletion index.html
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@
<script type="module" src="./timeline.js"></script>
<script type="module" src="./outbox.js"></script>
<script type="module" src="./post.js"></script>
<script type="module" src="./p2p-media.js"></script>
<script type="module" src="./followed-accounts.js"></script>
<script type="module" src="./theme-selector.js"></script>
<script type="module" src="./error-message.js"></script>
1 change: 1 addition & 0 deletions outbox.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { db } from './dbInstance.js'
import './post.js'

class DistributedOutbox extends HTMLElement {
skip = 0
Expand Down
31 changes: 31 additions & 0 deletions p2p-media.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
p2p-image,
p2p-video {
max-width: 100%;
}

.profile-icon {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #000000;
margin-right: 8px;
margin-bottom: 8px;
}


.profile-mini-icon {
width: 28px;
height: 28px;
border-radius: 50%;
background-color: #000000;
margin-right: 6px;
}

.actor-icon {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #000000;
margin-right: 8px;
cursor: pointer;
}
78 changes: 64 additions & 14 deletions p2p-media.js
Original file line number Diff line number Diff line change
@@ -1,28 +1,43 @@
import { supportsP2P, resolveP2PUrl } from './db.js'
import { supportsP2P, resolveP2PUrl, isP2P } from './db.js'

class P2PImage extends HTMLElement {
constructor () {
super()
this.attachShadow({ mode: 'open' })

// Create an img element
this.img = document.createElement('img')
this.attachShadow({ mode: 'open' })
this.shadowRoot.appendChild(this.img)

// Load the CSS file
const style = document.createElement('style')
fetch('./p2p-media.css').then(response => response.text()).then(css => {
style.textContent = css
this.shadowRoot.append(style, this.img)
})

this.img.addEventListener('error', () => this.handleError())
}

static get observedAttributes () {
return ['src']
return ['src', 'class']
}

connectedCallback () {
if (this.hasAttribute('src')) {
this.loadImage(this.getAttribute('src'))
}
this.syncClass()
this.addEventListener('load-error', e => {
console.log(`Handled fallback for src: ${e.detail.fallbackSrc}`)
})
}

attributeChangedCallback (name, oldValue, newValue) {
if (name === 'src' && newValue !== oldValue) {
this.loadImage(newValue)
this.img.src = newValue // Ensure the inner image src is updated immediately
} else if (name === 'class' && newValue !== oldValue) {
this.syncClass()
}
}

Expand All @@ -39,10 +54,20 @@ class P2PImage extends HTMLElement {
}
}

async handleError () {
const fallbackSrc = resolveP2PUrl(this.getAttribute('src'))
console.log(`Failed to load image. Resolving to gateway URL: ${fallbackSrc}`)
this.img.src = fallbackSrc
syncClass () {
const classes = this.className.split(' ')
this.img.className = classes.join(' ')
}

handleError () {
const src = this.getAttribute('src')
if (isP2P(src)) {
const fallbackSrc = resolveP2PUrl(src)
console.log(`Failed to load, resolving to gateway URL: ${fallbackSrc}`)
this.img.src = fallbackSrc
this.setAttribute('src', fallbackSrc) // Update the attribute to the fallback source
this.dispatchEvent(new CustomEvent('load-error', { detail: { fallbackSrc } }))
}
}
}

Expand All @@ -51,25 +76,40 @@ customElements.define('p2p-image', P2PImage)
class P2PVideo extends HTMLElement {
constructor () {
super()
this.attachShadow({ mode: 'open' })

// Create a video element
this.video = document.createElement('video')
this.video.controls = true
this.attachShadow({ mode: 'open' })
this.shadowRoot.appendChild(this.video)

// Load the CSS file
const style = document.createElement('style')
fetch('./p2p-media.css').then(response => response.text()).then(css => {
style.textContent = css
this.shadowRoot.append(style, this.video)
})
}

static get observedAttributes () {
return ['src']
return ['src', 'class']
}

connectedCallback () {
if (this.hasAttribute('src')) {
this.loadVideo(this.getAttribute('src'))
}
this.syncClass()
this.addEventListener('load-error', e => {
console.log(`Handled fallback for src: ${e.detail.fallbackSrc}`)
})
}

attributeChangedCallback (name, oldValue, newValue) {
if (name === 'src' && newValue !== oldValue) {
this.loadVideo(newValue)
this.video.src = newValue // Ensure the inner video src is updated immediately
} else if (name === 'class' && newValue !== oldValue) {
this.syncClass()
}
}

Expand All @@ -92,10 +132,20 @@ class P2PVideo extends HTMLElement {
this.video.appendChild(source)
}

syncClass () {
const classes = this.className.split(' ')
this.video.className = classes.join(' ')
}

handleError (source) {
const fallbackSrc = resolveP2PUrl(source.src)
console.log(`Failed to load video source. Resolving to gateway URL: ${fallbackSrc}`)
source.src = fallbackSrc
const src = source.src
if (isP2P(src)) {
const fallbackSrc = resolveP2PUrl(src)
console.log(`Failed to load video source. Resolving to gateway URL: ${fallbackSrc}`)
source.src = fallbackSrc
this.setAttribute('src', fallbackSrc) // Update the attribute to the fallback source
this.dispatchEvent(new CustomEvent('load-error', { detail: { fallbackSrc } }))
}
}
}

Expand Down
9 changes: 0 additions & 9 deletions post.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,6 @@
align-items: center;
}

.actor-icon {
width: 50px;
height: 50px;
border-radius: 50%;
background-color: #000000;
margin-right: 8px;
cursor: pointer;
}

.actor-details {
display: flex;
flex-direction: column;
Expand Down
1 change: 0 additions & 1 deletion post.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,6 @@
<script type="module" src="./sidebar.js"></script>
<script type="module" src="./timeline.js"></script>
<script type="module" src="./post.js"></script>
<script type="module" src="./p2p-media.js"></script>
<script type="module" src="./followed-accounts.js"></script>
<script type="module" src="./theme-selector.js"></script>
<script type="module" src="./error-message.js"></script>
Loading

0 comments on commit b5f6370

Please sign in to comment.