Builds a content embed widget

This commit is contained in:
Alicia Sykes 2021-12-14 13:48:50 +00:00
parent 642cfc655b
commit f61366ca48
3 changed files with 121 additions and 6 deletions

View File

@ -14,10 +14,11 @@ Dashy has support for displaying dynamic content in the form of widgets. There a
- [Exchange Rates](#exchange-rates)
- [Stock Price History](#stock-price-history)
- [Joke of the Day](#joke)
- [Flight Data](#flight-data)
- [Self-Hosted Services Widgets](#dynamic-widgets)
- [Dynamic Widgets](#dynamic-widgets)
- [Iframe Widget](#iframe-widget)
- [HTML Widget](#html-widget)
- [HTML Embed Widget](#html-embedded-widget)
- [Build your own Widget](#build-your-own-widget)
## General Widgets
@ -330,12 +331,31 @@ Embed any webpage into your dashboard as a widget.
--- | --- | --- | ---
**`url`** | `string` | Required | The URL to the webpage to embed
### HTML Embedded Widget
Many websites and apps provide their own embeddable widgets. These can be used with Dashy using the Embed widget, which lets you dynamically embed and HTML, CSS or JavaScript contents.
⚠️ **NOTE:** Use with extreme caution. Embedding a script from an untrustworthy source may have serious unintended consequences.
<p align="center"><img width="400" src="https://i.ibb.co/yn0SGtL/embed-widget.png" /></p>
##### Options
**Field** | **Type** | **Required** | **Description**
--- | --- | --- | ---
**`html`** | `string` | _Optional_ | HTML contents to render in the widget
**`script`** | `string` | _Optional_ | Raw JavaScript code to execute (caution)
**`scriptSrc`** | `string` | _Optional_ | A URL to JavaScript content (caution)
**`css`** | `string` | _Optional_ | Any stylings for widget contents
##### Example
```yaml
- type: iframe
options:
url: https://fiatleak.com/
- type: embed
options:
css: '.coinmarketcap-currency-widget { color: var(--widget-text-color); }'
html: '<div class="coinmarketcap-currency-widget" data-currencyid="1" data-base="USD" data-secondary="" data-ticker="true" data-rank="true" data-marketcap="true" data-volume="true" data-statsticker="true" data-stats="USD"></div>'
scriptSrc: 'https://files.coinmarketcap.com/static/widget/currency.js'
```
---

View File

@ -0,0 +1,86 @@
<template>
<div class="html-widget">
<div :id="elementId" />
</div>
</template>
<script>
import WidgetMixin from '@/mixins/WidgetMixin';
export default {
mixins: [WidgetMixin],
computed: {
html() {
return this.options.html || '';
},
css() {
return this.options.css || '';
},
script() {
return this.options.script || '';
},
scriptSrc() {
return this.options.scriptSrc || '';
},
elementId() {
return `elem-${Math.round(Math.random() * 10000)}`;
},
},
mounted() {
this.initiate();
},
beforeDestroy() {
if (this.eventListener) {
document.removeEventListener(this.eventListener);
}
},
data: () => ({
eventListener: null,
}),
methods: {
/* Injects users content */
injectHtml() {
if (this.html) {
const element = document.getElementById(this.elementId);
element.innerHTML = this.html;
}
if (this.css) {
const styleElem = document.createElement('style');
styleElem.textContent = this.css;
document.head.append(styleElem);
}
if (this.script) {
const scriptElem = document.createElement('script');
scriptElem.text = this.script;
document.head.append(scriptElem);
}
if (this.scriptSrc) {
const scriptElem = document.createElement('script');
scriptElem.src = this.scriptSrc;
document.head.append(scriptElem);
}
},
/* What for the DOM to finish loading, before proceeding */
initiate() {
if (document.readyState === 'complete' || document.readyState === 'loaded') {
this.injectHtml();
} else {
this.eventListener = document.addEventListener('DOMContentLoaded', () => {
this.injectHtml();
});
}
},
update() {
this.injectHtml();
},
},
};
</script>
<style scoped lang="scss">
.html-widget {
width: 100%;
min-height: 240px;
}
</style>

View File

@ -102,6 +102,13 @@
@error="handleError"
:ref="widgetRef"
/>
<EmbedWidget
v-else-if="widgetType === 'embed'"
:options="widgetOptions"
@loading="setLoaderState"
@error="handleError"
:ref="widgetRef"
/>
<!-- No widget type specified -->
<div v-else>{{ handleError('No widget type was specified') }}</div>
</div>
@ -127,8 +134,9 @@ import XkcdComic from '@/components/Widgets/XkcdComic.vue';
import ExchangeRates from '@/components/Widgets/ExchangeRates.vue';
import StockPriceChart from '@/components/Widgets/StockPriceChart.vue';
import Jokes from '@/components/Widgets/Jokes.vue';
import IframeWidget from '@/components/Widgets/IframeWidget.vue';
import Flights from '@/components/Widgets/Flights.vue';
import IframeWidget from '@/components/Widgets/IframeWidget.vue';
import EmbedWidget from '@/components/Widgets/EmbedWidget.vue';
export default {
name: 'Widget',
@ -147,8 +155,9 @@ export default {
ExchangeRates,
StockPriceChart,
Jokes,
IframeWidget,
Flights,
IframeWidget,
EmbedWidget,
},
props: {
widget: Object,