The button itself is working fine, but I have a problem with the associated popover (when using the “right part” of the button).
I understand that I’m doing something wrong, I just can’t figure out what: I define the <f7-popover>
element in a template, so that it ends up somewhere down in the hierarchy in the DOM, with display: none
. But, when it’s opened, a new element is inserted under the framework7-root
DIV, which is displayed. However, when this is closed, the created element isn’t removed, it’s opacity is merely set to 0. That means that it’s still there, and blocks clicks to the elements which it covered while it was “open”.
Even worse, a new such element is created each time the popover is opened. I realize that there must be something wrong with the way I close the popover, I just can’t figure out how to do it properly. I have made the popover close when an option is selected, and it’s this “closing” that doesn’t clean up properly. If I click the “backdrop” instead, the element is removed and everything is fine.
There are two vue templates involved in this. Please not that this is a work in progress, so don’t look at the stuff that’s not related to opening/closing, as some things are just there because of testing and some things aren’t made yet.
<template>
<div class="addon-install-button">
<f7-segmented v-if="versioned" class="split-button" round :bgColor="buttonColor">
<f7-button class="install-button" :text="buttonText" small @click="clicked()" />
<f7-button class="install-menu-button" popover-open=".addon-version-select" icon-f7="chevron_down" small />
</f7-segmented>
<f7-button v-else class="install-button" :text="buttonText" :color="buttonColor" round small fill @click="clicked()" />
<addon-version-select @version-selected="(v) => versionSelected(v)" :addon="addon" />
</div>
</template>
<style lang="stylus">
.addon-install-button
.split-button
.install-button
--f7-button-text-color var(--f7-page-bg-color)
--f7-button-text-transform uppercase
padding-left 15px
padding-right 10px
font-size 16px
text-overflow: clip
.install-menu-button
--f7-button-text-color var(--f7-page-bg-color)
padding-left 7px
padding-right 16px
text-overflow: clip
border-left-width: thin
border-left-color: var(--f7-page-bg-color)
width 40px
.install-button
--f7-button-text-transform uppercase
padding-left 15px
padding-right 15px
font-size 16px
text-overflow: clip
</style>
<script>
import AddonVersionSelect from '@/components/addons/addon-version-select.vue'
export default {
props: ['addon'],
components: {
AddonVersionSelect
},
emits: ['clicked', 'install', 'uninstall', 'upgrade', 'downgrade'], // TODO: (Nad) Figure out emits
computed: {
versioned () {
return this.addon && this.addon.versions && Object.keys(this.addon.versions).length > 1
},
installable () {
return (this.addon && (this.addon.contentType === 'application/vnd.openhab.bundle' || this.addon.contentType.indexOf('application/vnd.openhab.feature') === 0))
},
buttonColor () {
if (!this.addon) {
return 'gray'
}
if (this.addon.installed) {
// TODO: (Nad) Upgrade/downgrade
return 'red'
}
return 'blue'
},
buttonText () {
if (!this.addon) {
return ''
}
if (this.addon.installed) {
// TODO: (Nad) Upgrade/downgrade
return 'Remove'
}
return this.installable ? 'Install' : 'Add'
} // TODO: (Nad) Clean up not needed
},
methods: {
clicked () {
this.$emit('clicked') // TODO: (Nad) Emit actual event
},
versionSelected (version) {
this.$emit('version-selected', version)
}
}
}
</script>
<template>
<f7-popover ref="versionPopover" class="addon-version-select" closeByBackdropClick closeByOutsideClick closeOnEscape>
<div class="block-title">
Select version
</div>
<div class="list">
<ul>
<li v-for="version in versions" :key="version.name">
<label class="item-radio item-content" @click="versionSelected(version)">
<input type="radio" name="version-select" :value="version.name" :checked="version.selected">
<i class="icon icon-radio" />
<div class="item-inner" :title="versionTooltip(version)">
<div class="item-title" :class="versionClasses(version)">{{ version.name }}</div>
</div>
</label>
</li>
</ul>
</div>
</f7-popover>
</template>
<style lang="stylus">
.addon-version-select
border-radius: 20px;
padding: 0px 10px 10px 10px;
.block-title
font-weight: 700;
.item-title.incompatible:before
content: 'exclamationmark_triangle_fill'
font-family: 'Framework7 Icons'
font-style: normal
font-weight: 400
color: red
margin-inline-end: 0.3em
.item-title.latest:after
content: 'checkmark_shield_fill'
font-family: 'Framework7 Icons'
font-style: normal
font-weight: 400
margin-inline-start: 0.3em
color: green
</style>
<script>
export default {
props: ['addon'],
emits: ['versionSelected'],
computed: {
versions () {
if (!this.addon || !this.addon.versions) {
return []
}
let result = Object.keys(this.addon.versions).flatMap((k) => {
let result = {
name: this.addon.versions[k].version,
compatible: this.addon.versions[k].compatible,
stable: this.addon.versions[k].stable
}
if (!this.addon.installedVersion && this.addon.versions[k].version === this.addon.version) {
result.selected = true
}
if ((this.addon.installedVersion && this.addon.versions[k].version === this.addon.installedVersion)) {
result.installed = true
}
if (this.addon.versions[k].version === this.addon.defaultVersion) {
result.latest = true
}
return result
})
if (result.length > 0 && !result.some(v => v.selected)) {
let ver = result.find((v) => v.version === this.addon.defaultVersion)
if (ver) {
ver.selected = true
} else {
result[0].selected = true
}
}
return result
}
},
methods: {
versionClasses (version) {
let result = []
if (!version.compatible) {
result.push('incompatible')
}
if (version.stable) {
result.push('stable')
}
if (version.latest) {
result.push('latest')
}
return result.join(' ')
},
versionTooltip (version) {
return version.latest ? 'Latest stable' : (version.compatible ? undefined : 'Incompatible')
},
versionSelected (version) {
this.$refs.versionPopover.close()
this.$emit('version-selected', version)
}
}
}
</script>