add ability to remove media
This commit is contained in:
parent
9f8b4fa9d8
commit
5b94dd7829
|
@ -8,12 +8,12 @@ export async function doMediaUpload (file) {
|
|||
store.set({uploadingMedia: true})
|
||||
try {
|
||||
let response = await uploadMedia(instanceName, accessToken, file)
|
||||
let mediaToUpload = store.get('mediaToUpload') || []
|
||||
mediaToUpload.push({
|
||||
let uploadedMedia = store.get('uploadedMedia') || []
|
||||
uploadedMedia.push({
|
||||
data: response,
|
||||
file: file
|
||||
})
|
||||
store.set({ mediaToUpload })
|
||||
store.set({ uploadedMedia })
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
toast.say('Failed to upload media: ' + (e.message || ''))
|
||||
|
@ -21,3 +21,9 @@ export async function doMediaUpload (file) {
|
|||
store.set({uploadingMedia: false})
|
||||
}
|
||||
}
|
||||
|
||||
export function deleteMedia (i) {
|
||||
let uploadedMedia = store.get('uploadedMedia')
|
||||
uploadedMedia.splice(i, 1)
|
||||
store.set({uploadedMedia})
|
||||
}
|
||||
|
|
|
@ -64,12 +64,13 @@
|
|||
|
||||
export default {
|
||||
computed: {
|
||||
computedClass: (pressable, pressed, big) => {
|
||||
computedClass: (pressable, pressed, big, className) => {
|
||||
return [
|
||||
'icon-button',
|
||||
!pressable && 'not-pressable',
|
||||
pressed && 'pressed',
|
||||
big && 'big-icon',
|
||||
className
|
||||
].filter(identity).join(' ')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<svg class="loading-spinner-icon {{maskStyle ? 'mask-style' : ''}}"
|
||||
<svg class="loading-spinner-icon spin {{maskStyle ? 'mask-style' : ''}}"
|
||||
style="width: {{size || 64}}px; height: {{size || 64}}px;"
|
||||
aria-label="Loading"
|
||||
>
|
||||
|
@ -7,22 +7,9 @@
|
|||
<style>
|
||||
.loading-spinner-icon {
|
||||
fill: var(--svg-fill);
|
||||
animation: spin 2s infinite linear;
|
||||
}
|
||||
|
||||
.loading-spinner-icon.mask-style {
|
||||
fill: var(--mask-svg-fill);
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
</style>
|
Before Width: | Height: | Size: 559 B After Width: | Height: | Size: 354 B |
|
@ -1,10 +1,13 @@
|
|||
{{#if $mediaToUpload && $mediaToUpload.length}}
|
||||
<div class="compose-media-container" style="grid-template-columns: repeat({{$mediaToUpload.length}}, 1fr);">
|
||||
{{#each $mediaToUpload as media}}
|
||||
{{#if $uploadedMedia && $uploadedMedia.length}}
|
||||
<div class="compose-media-container" style="grid-template-columns: repeat({{$uploadedMedia.length}}, 1fr);">
|
||||
{{#each $uploadedMedia as media, i}}
|
||||
<div class="compose-media">
|
||||
<img src="{{media.data.preview_url}}" alt="{{media.file.name}}"/>
|
||||
<div class="compose-media-delete">
|
||||
<button class="compose-media-delete-button" data-a11y-dialog-hide aria-label="Delete {{media.file.name}}">
|
||||
<button class="compose-media-delete-button"
|
||||
data-a11y-dialog-hide aria-label="Delete {{media.file.name}}"
|
||||
on:click="onDeleteMedia(i)"
|
||||
>
|
||||
<span aria-hidden="true">×</span>
|
||||
</button>
|
||||
</div>
|
||||
|
@ -87,8 +90,14 @@
|
|||
</style>
|
||||
<script>
|
||||
import { store } from '../../_store/store'
|
||||
import { deleteMedia } from '../../_actions/media'
|
||||
|
||||
export default {
|
||||
store: () => store
|
||||
store: () => store,
|
||||
methods: {
|
||||
onDeleteMedia(i) {
|
||||
deleteMedia(i)
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
|
@ -4,9 +4,11 @@
|
|||
href="#fa-smile"
|
||||
on:click="onEmojiClick()"
|
||||
/>
|
||||
<IconButton label="Add media"
|
||||
href="#fa-camera"
|
||||
<IconButton className="{{$uploadingMedia ? 'spin' : ''}}"
|
||||
label="Add media"
|
||||
href="{{$uploadingMedia ? '#fa-spinner' : '#fa-camera'}}"
|
||||
on:click="onMediaClick()"
|
||||
disabled="{{$uploadingMedia || ($uploadedMedia && $uploadedMedia.length === 4)}}"
|
||||
/>
|
||||
<IconButton label="Adjust privacy" href="#fa-globe" />
|
||||
<IconButton label="Add content warning" href="#fa-exclamation-triangle" />
|
||||
|
|
|
@ -140,4 +140,20 @@ textarea {
|
|||
font-family: inherit;
|
||||
font-size: inherit;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
0% {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
50% {
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
100% {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
.spin {
|
||||
animation: spin 2s infinite linear;
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
<style>
|
||||
/* auto-generated w/ build-sass.js */
|
||||
body{--button-primary-bg:#6081e6;--button-primary-text:#fff;--button-primary-border:#132c76;--button-primary-bg-active:#456ce2;--button-primary-bg-hover:#6988e7;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#4169e1;--main-bg:#fff;--body-bg:#e8edfb;--body-text-color:#333;--main-border:#dadada;--svg-fill:#4169e1;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#4169e1;--nav-border:#214cce;--nav-a-border:#4169e1;--nav-a-selected-border:#fff;--nav-a-selected-bg:#6d8ce8;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#839deb;--nav-a-bg-hover:#577ae4;--nav-a-border-hover:#4169e1;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#90a8ee;--action-button-fill-color-hover:#a2b6f0;--action-button-fill-color-active:#577ae4;--action-button-fill-color-pressed:#2351dc;--action-button-fill-color-pressed-hover:#3862e0;--action-button-fill-color-pressed-active:#1d44b8;--settings-list-item-bg:#fff;--settings-list-item-text:#4169e1;--settings-list-item-text-hover:#4169e1;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#c5d1f6;--very-deemphasized-link-color:rgba(65,105,225,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#d2dcf8;--main-theme-color:#4169e1;--warning-color:#e01f19;--alt-input-bg:rgba(255,255,255,0.7)}
|
||||
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;will-change:transform;position:absolute;top:72px;left:0;right:0;bottom:0}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px}@media (max-width: 767px){main{margin:5px auto 15px}}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover{background:var(--button-bg-hover)}button:active{background:var(--button-bg-active)}button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}
|
||||
body{margin:0;font-family:system-ui, -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen, Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue;font-size:14px;line-height:1.4;color:var(--body-text-color);background:var(--body-bg);position:fixed;left:0;right:0;bottom:0;top:0}.container{overflow-y:auto;overflow-x:hidden;-webkit-overflow-scrolling:touch;will-change:transform;position:absolute;top:72px;left:0;right:0;bottom:0}@media (max-width: 767px){.container{top:62px}}main{position:relative;width:602px;max-width:100vw;padding:0;box-sizing:border-box;margin:30px auto 15px;background:var(--main-bg);border:1px solid var(--main-border);border-radius:1px}@media (max-width: 767px){main{margin:5px auto 15px}}h1,h2,h3,h4,h5,h6{margin:0 0 0.5em 0;font-weight:400;line-height:1.2}h1{font-size:2em}a{color:var(--anchor-text);text-decoration:none}a:visited{color:var(--anchor-text)}a:hover{text-decoration:underline}input{border:1px solid var(--input-border);padding:5px;box-sizing:border-box}button{font-size:1.2em;background:var(--button-bg);border-radius:2px;padding:10px 15px;border:1px solid var(--button-border);cursor:pointer;color:var(--button-text)}button:hover{background:var(--button-bg-hover)}button:active{background:var(--button-bg-active)}button[disabled]{opacity:0.35;pointer-events:none;cursor:not-allowed}button.primary{border:1px solid var(--button-primary-border);background:var(--button-primary-bg);color:var(--button-primary-text)}button.primary:hover{background:var(--button-primary-bg-hover)}button.primary:active{background:var(--button-primary-bg-active)}p,label,input{font-size:1.3em}ul,li,p{padding:0;margin:0}.hidden{opacity:0}*:focus{outline:2px solid var(--focus-outline)}button::-moz-focus-inner{border:0}input:required,input:invalid{box-shadow:none}textarea{font-family:inherit;font-size:inherit;box-sizing:border-box}@keyframes spin{0%{transform:rotate(0deg)}50%{transform:rotate(180deg)}100%{transform:rotate(360deg)}}.spin{animation:spin 2s infinite linear}
|
||||
body.offline,body.theme-hotpants.offline,body.theme-majesty.offline,body.theme-oaken.offline,body.theme-scarlet.offline,body.theme-seafoam.offline,body.theme-gecko.offline{--button-primary-bg:#ababab;--button-primary-text:#fff;--button-primary-border:#4d4d4d;--button-primary-bg-active:#9c9c9c;--button-primary-bg-hover:#b0b0b0;--button-bg:#e6e6e6;--button-text:#333;--button-border:#a7a7a7;--button-bg-active:#bfbfbf;--button-bg-hover:#f2f2f2;--input-border:#dadada;--anchor-text:#999;--main-bg:#fff;--body-bg:#fafafa;--body-text-color:#333;--main-border:#dadada;--svg-fill:#999;--form-bg:#f7f7f7;--form-border:#c1c1c1;--nav-bg:#999;--nav-border:gray;--nav-a-border:#999;--nav-a-selected-border:#fff;--nav-a-selected-bg:#b3b3b3;--nav-svg-fill:#fff;--nav-text-color:#fff;--nav-a-selected-border-hover:#fff;--nav-a-selected-bg-hover:#bfbfbf;--nav-a-bg-hover:#a6a6a6;--nav-a-border-hover:#999;--nav-svg-fill-hover:#fff;--nav-text-color-hover:#fff;--action-button-fill-color:#c7c7c7;--action-button-fill-color-hover:#d1d1d1;--action-button-fill-color-active:#a6a6a6;--action-button-fill-color-pressed:#878787;--action-button-fill-color-pressed-hover:#949494;--action-button-fill-color-pressed-active:#737373;--settings-list-item-bg:#fff;--settings-list-item-text:#999;--settings-list-item-text-hover:#999;--settings-list-item-border:#dadada;--settings-list-item-bg-active:#e6e6e6;--settings-list-item-bg-hover:#fafafa;--toast-bg:#333;--toast-border:#fafafa;--toast-text:#fff;--mask-bg:#333;--mask-svg-fill:#fff;--mask-opaque-bg:rgba(51,51,51,0.8);--loading-bg:#ededed;--deemphasized-text-color:#666;--focus-outline:#bfbfbf;--very-deemphasized-link-color:rgba(153,153,153,0.6);--very-deemphasized-text-color:rgba(102,102,102,0.6);--status-direct-background:#ededed;--main-theme-color:#999;--warning-color:#e01f19;--alt-input-bg:rgba(255,255,255,0.7)}
|
||||
|
||||
</style>
|
||||
|
|
|
@ -1 +1,22 @@
|
|||
export const image1 = 'iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mNk+M9QDwADhgGAWjR9awAAAABJRU5ErkJggg=='
|
||||
import fs from 'fs'
|
||||
import path from 'path'
|
||||
|
||||
export const kitten1 = {
|
||||
data: fs.readFileSync(path.join(__dirname, './images/kitten1.jpg')).toString('base64'),
|
||||
name: 'kitten1.jpg'
|
||||
}
|
||||
|
||||
export const kitten2 = {
|
||||
data: fs.readFileSync(path.join(__dirname, './images/kitten2.jpg')).toString('base64'),
|
||||
name: 'kitten2.jpg'
|
||||
}
|
||||
|
||||
export const kitten3 = {
|
||||
data: fs.readFileSync(path.join(__dirname, './images/kitten3.jpg')).toString('base64'),
|
||||
name: 'kitten3.jpg'
|
||||
}
|
||||
|
||||
export const kitten4 = {
|
||||
data: fs.readFileSync(path.join(__dirname, './images/kitten4.jpg')).toString('base64'),
|
||||
name: 'kitten4.jpg'
|
||||
}
|
||||
|
|
BIN
tests/images/kitten1.jpg
Normal file
BIN
tests/images/kitten1.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.5 KiB |
BIN
tests/images/kitten2.jpg
Normal file
BIN
tests/images/kitten2.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
tests/images/kitten3.jpg
Normal file
BIN
tests/images/kitten3.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.7 KiB |
BIN
tests/images/kitten4.jpg
Normal file
BIN
tests/images/kitten4.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.5 KiB |
|
@ -91,9 +91,3 @@ test('inserts emoji without typing anything', async t => {
|
|||
.click($('button img[title=":blobpeek:"]'))
|
||||
.expect(composeInput.value).eql(':blobpeek: :blobpats: ')
|
||||
})
|
||||
|
||||
test('inserts media', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
await uploadMedia()
|
||||
await t.expect($('.compose-media:nth-child(1) img').getAttribute('alt')).eql('foo.png')
|
||||
})
|
||||
|
|
39
tests/spec/13-compose-media.js
Normal file
39
tests/spec/13-compose-media.js
Normal file
|
@ -0,0 +1,39 @@
|
|||
import { Selector as $ } from 'testcafe'
|
||||
import { getNthMedia, mediaButton, uploadKittenImage } from '../utils'
|
||||
import { foobarRole } from '../roles'
|
||||
|
||||
fixture`13-compose-media.js`
|
||||
.page`http://localhost:4002`
|
||||
|
||||
test('inserts media', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
.expect(mediaButton.hasAttribute('disabled')).notOk()
|
||||
await (uploadKittenImage(1)())
|
||||
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||
await (uploadKittenImage(2)())
|
||||
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||
.expect(getNthMedia(2).getAttribute('alt')).eql('kitten2.jpg')
|
||||
.expect(mediaButton.hasAttribute('disabled')).notOk()
|
||||
await (uploadKittenImage(3)())
|
||||
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||
.expect(getNthMedia(2).getAttribute('alt')).eql('kitten2.jpg')
|
||||
.expect(getNthMedia(3).getAttribute('alt')).eql('kitten3.jpg')
|
||||
.expect(mediaButton.hasAttribute('disabled')).notOk()
|
||||
await (uploadKittenImage(4)())
|
||||
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||
.expect(getNthMedia(2).getAttribute('alt')).eql('kitten2.jpg')
|
||||
.expect(getNthMedia(3).getAttribute('alt')).eql('kitten3.jpg')
|
||||
.expect(getNthMedia(4).getAttribute('alt')).eql('kitten4.jpg')
|
||||
.expect(mediaButton.getAttribute('disabled')).eql('')
|
||||
})
|
||||
|
||||
test('removes media', async t => {
|
||||
await t.useRole(foobarRole)
|
||||
await (uploadKittenImage(1)())
|
||||
await (uploadKittenImage(2)())
|
||||
await t.expect(getNthMedia(1).getAttribute('alt')).eql('kitten1.jpg')
|
||||
.expect(getNthMedia(2).getAttribute('alt')).eql('kitten2.jpg')
|
||||
.click($('.compose-media:nth-child(2) .compose-media-delete-button'))
|
||||
.expect(getNthMedia(2).exists).notOk()
|
||||
.expect(getNthMedia(1).exists).ok()
|
||||
})
|
|
@ -15,6 +15,7 @@ export const composeInput = $('.compose-box-input')
|
|||
export const composeButton = $('.compose-box-button')
|
||||
export const composeLengthIndicator = $('.compose-box-length')
|
||||
export const emojiButton = $('.compose-box-toolbar button:first-child')
|
||||
export const mediaButton = $('.compose-box-toolbar button:nth-child(2)')
|
||||
export const emailInput = $('input#user_email')
|
||||
export const passwordInput = $('input#user_password')
|
||||
export const authorizeInput = $('button[type=submit]:not(.negative)')
|
||||
|
@ -39,16 +40,22 @@ export const getComposeSelectionStart = exec(() => composeInput().selectionStart
|
|||
dependencies: { composeInput }
|
||||
})
|
||||
|
||||
export const uploadMedia = exec(() => {
|
||||
let blob = blobUtils.base64StringToBlob(images.image1, 'image/png')
|
||||
blob.name = 'foo.png'
|
||||
export const uploadKittenImage = i => (exec(() => {
|
||||
let image = images[`kitten${i}`]
|
||||
let blob = blobUtils.base64StringToBlob(image.data, 'image/png')
|
||||
blob.name = image.name
|
||||
window.__fakeFileInput(blob)
|
||||
}, {
|
||||
dependencies: {
|
||||
images,
|
||||
blobUtils
|
||||
blobUtils,
|
||||
i
|
||||
}
|
||||
})
|
||||
}))
|
||||
|
||||
export function getNthMedia (n) {
|
||||
return $(`.compose-media:nth-child(${n}) img`)
|
||||
}
|
||||
|
||||
export function getNthStatus (n) {
|
||||
return $(`div[aria-hidden="false"] > article[aria-posinset="${n}"]`)
|
||||
|
|
Loading…
Reference in a new issue