aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/components/attachment/attachment.js2
-rw-r--r--src/components/attachment/attachment.vue6
-rw-r--r--src/components/flash/flash.js52
-rw-r--r--src/components/flash/flash.vue88
-rw-r--r--src/i18n/en.json5
-rw-r--r--src/services/file_type/file_type.service.js4
-rw-r--r--src/services/ruffle_service/ruffle_service.js40
7 files changed, 196 insertions, 1 deletions
diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js
index 5f5779a0..8849f501 100644
--- a/src/components/attachment/attachment.js
+++ b/src/components/attachment/attachment.js
@@ -1,4 +1,5 @@
import StillImage from '../still-image/still-image.vue'
+import Flash from '../flash/flash.vue'
import VideoAttachment from '../video_attachment/video_attachment.vue'
import nsfwImage from '../../assets/nsfw.png'
import fileTypeService from '../../services/file_type/file_type.service.js'
@@ -43,6 +44,7 @@ const Attachment = {
}
},
components: {
+ Flash,
StillImage,
VideoAttachment
},
diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue
index 2c1c1682..f80badfd 100644
--- a/src/components/attachment/attachment.vue
+++ b/src/components/attachment/attachment.vue
@@ -117,6 +117,11 @@
<!-- eslint-enable vue/no-v-html -->
</div>
</div>
+
+ <Flash
+ v-if="type === 'flash'"
+ :src="attachment.large_thumb_url || attachment.url"
+ />
</div>
</template>
@@ -172,6 +177,7 @@
}
.non-gallery.attachment {
+ &.flash,
&.video {
flex: 1 0 40%;
}
diff --git a/src/components/flash/flash.js b/src/components/flash/flash.js
new file mode 100644
index 00000000..d03384c7
--- /dev/null
+++ b/src/components/flash/flash.js
@@ -0,0 +1,52 @@
+import RuffleService from '../../services/ruffle_service/ruffle_service.js'
+import { library } from '@fortawesome/fontawesome-svg-core'
+import {
+ faStop,
+ faExclamationTriangle
+} from '@fortawesome/free-solid-svg-icons'
+
+library.add(
+ faStop,
+ faExclamationTriangle
+)
+
+const Flash = {
+ props: [ 'src' ],
+ data () {
+ return {
+ player: false, // can be true, "hidden", false. hidden = element exists
+ loaded: false,
+ ruffleInstance: null
+ }
+ },
+ methods: {
+ openPlayer () {
+ if (this.player) return // prevent double-loading, or re-loading on failure
+ this.player = 'hidden'
+ RuffleService.getRuffle().then((ruffle) => {
+ const player = ruffle.newest().createPlayer()
+ player.config = {
+ letterbox: 'on'
+ }
+ const container = this.$refs.container
+ container.appendChild(player)
+ player.style.width = '100%'
+ player.style.height = '100%'
+ player.load(this.src).then(() => {
+ this.player = true
+ }).catch((e) => {
+ console.error('Error loading ruffle', e)
+ this.player = 'error'
+ })
+ this.ruffleInstance = player
+ })
+ },
+ closePlayer () {
+ console.log(this.ruffleInstance)
+ this.ruffleInstance.remove()
+ this.player = false
+ }
+ }
+}
+
+export default Flash
diff --git a/src/components/flash/flash.vue b/src/components/flash/flash.vue
new file mode 100644
index 00000000..d20d037b
--- /dev/null
+++ b/src/components/flash/flash.vue
@@ -0,0 +1,88 @@
+<template>
+ <div class="Flash">
+ <div
+ v-if="player === true || player === 'hidden'"
+ ref="container"
+ class="player"
+ :class="{ hidden: player === 'hidden' }"
+ />
+ <button
+ v-if="player !== true"
+ class="button-unstyled placeholder"
+ @click="openPlayer"
+ >
+ <span
+ v-if="player === 'hidden'"
+ class="label"
+ >
+ {{ $t('general.loading') }}
+ </span>
+ <span
+ v-if="player === 'error'"
+ class="label"
+ >
+ {{ $t('general.flash_fail') }}
+ </span>
+ <span
+ v-else
+ class="label"
+ >
+ <p>
+ {{ $t('general.flash_content') }}
+ </p>
+ <p>
+ <FAIcon icon="exclamation-triangle" />
+ {{ $t('general.flash_security') }}
+ </p>
+ </span>
+ </button>
+ <button
+ v-if="player"
+ class="button-unstyled hider"
+ @click="closePlayer"
+ >
+ <FAIcon icon="stop" />
+ </button>
+ </div>
+</template>
+
+<script src="./flash.js"></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+.Flash {
+ width: 100%;
+ height: 260px;
+ position: relative;
+
+ .player {
+ height: 100%;
+ width: 100%;
+ }
+
+ .hider {
+ top: 0;
+ }
+
+ .label {
+ text-align: center;
+ flex: 1 1 0;
+ line-height: 1.2;
+ white-space: normal;
+ word-wrap: normal;
+ }
+
+ .hidden {
+ display: none;
+ visibility: 'hidden';
+ }
+
+ .placeholder {
+ height: 100%;
+ flex: 1;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ }
+}
+</style>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 1b38e29a..aa440ac1 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -79,7 +79,10 @@
"role": {
"admin": "Admin",
"moderator": "Moderator"
- }
+ },
+ "flash_content": "Click to show Flash content using Ruffle (Experimental, may not work).",
+ "flash_security": "Note that this can be potentially dangerous since Flash content is still arbitrary code.",
+ "flash_fail": "Failed to load flash content, see console for details."
},
"image_cropper": {
"crop_picture": "Crop picture",
diff --git a/src/services/file_type/file_type.service.js b/src/services/file_type/file_type.service.js
index 2a046bec..5182ecd1 100644
--- a/src/services/file_type/file_type.service.js
+++ b/src/services/file_type/file_type.service.js
@@ -2,6 +2,10 @@
// or the entire service could be just mimetype service that only operates
// on mimetypes and not files. Currently the naming is confusing.
const fileType = mimetype => {
+ if (mimetype.match(/flash/)) {
+ return 'flash'
+ }
+
if (mimetype.match(/text\/html/)) {
return 'html'
}
diff --git a/src/services/ruffle_service/ruffle_service.js b/src/services/ruffle_service/ruffle_service.js
new file mode 100644
index 00000000..7411dd96
--- /dev/null
+++ b/src/services/ruffle_service/ruffle_service.js
@@ -0,0 +1,40 @@
+const createRuffleService = () => {
+ let ruffleInstance = null
+
+ const getRuffle = () => new Promise((resolve, reject) => {
+ if (ruffleInstance) {
+ resolve(ruffleInstance)
+ return
+ }
+ // Ruffle needs these to be set before it's loaded
+ // https://github.com/ruffle-rs/ruffle/issues/3952
+ window.RufflePlayer = {}
+ window.RufflePlayer.config = {
+ polyfills: false,
+ publicPath: '/static/ruffle'
+ }
+
+ // Currently it's seems like a better way of loading ruffle
+ // because it needs the wasm publically accessible, but it needs path to it
+ // and filename of wasm seems to be pseudo-randomly generated (is it a hash?)
+ const script = document.createElement('script')
+ // see webpack config, using CopyPlugin to copy it from node_modules
+ // provided via ruffle-mirror
+ script.src = '/static/ruffle/ruffle.js'
+ script.type = 'text/javascript'
+ script.onerror = (e) => { reject(e) }
+ script.onabort = (e) => { reject(e) }
+ script.oncancel = (e) => { reject(e) }
+ script.onload = () => {
+ ruffleInstance = window.RufflePlayer
+ resolve(ruffleInstance)
+ }
+ document.body.appendChild(script)
+ })
+
+ return { getRuffle }
+}
+
+const RuffleService = createRuffleService()
+
+export default RuffleService