diff --git a/routes/_actions/media.js b/routes/_actions/media.js index 0c5ba9e4..4cdb84aa 100644 --- a/routes/_actions/media.js +++ b/routes/_actions/media.js @@ -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}) +} diff --git a/routes/_components/IconButton.html b/routes/_components/IconButton.html index 3d961ebe..5c854cca 100644 --- a/routes/_components/IconButton.html +++ b/routes/_components/IconButton.html @@ -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(' ') } } diff --git a/routes/_components/LoadingSpinner.html b/routes/_components/LoadingSpinner.html index db495ab7..5b78ff6f 100644 --- a/routes/_components/LoadingSpinner.html +++ b/routes/_components/LoadingSpinner.html @@ -1,4 +1,4 @@ - @@ -7,22 +7,9 @@ \ No newline at end of file diff --git a/routes/_components/compose/ComposeMedia.html b/routes/_components/compose/ComposeMedia.html index 5de77fde..885ef252 100644 --- a/routes/_components/compose/ComposeMedia.html +++ b/routes/_components/compose/ComposeMedia.html @@ -1,10 +1,13 @@ -{{#if $mediaToUpload && $mediaToUpload.length}} -
- {{#each $mediaToUpload as media}} +{{#if $uploadedMedia && $uploadedMedia.length}} +
+ {{#each $uploadedMedia as media, i}}
{{media.file.name}}
-
@@ -87,8 +90,14 @@ \ No newline at end of file diff --git a/routes/_components/compose/ComposeToolbar.html b/routes/_components/compose/ComposeToolbar.html index 62a426f6..ef6181f5 100644 --- a/routes/_components/compose/ComposeToolbar.html +++ b/routes/_components/compose/ComposeToolbar.html @@ -4,9 +4,11 @@ href="#fa-smile" on:click="onEmojiClick()" /> - diff --git a/scss/global.scss b/scss/global.scss index 2b364e0b..70990393 100644 --- a/scss/global.scss +++ b/scss/global.scss @@ -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; } \ No newline at end of file diff --git a/templates/2xx.html b/templates/2xx.html index f288e27e..16ee342e 100644 --- a/templates/2xx.html +++ b/templates/2xx.html @@ -11,7 +11,7 @@ diff --git a/tests/images.js b/tests/images.js index 4fb25735..67f7f086 100644 --- a/tests/images.js +++ b/tests/images.js @@ -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' +} diff --git a/tests/images/kitten1.jpg b/tests/images/kitten1.jpg new file mode 100644 index 00000000..ee230487 Binary files /dev/null and b/tests/images/kitten1.jpg differ diff --git a/tests/images/kitten2.jpg b/tests/images/kitten2.jpg new file mode 100644 index 00000000..50d67701 Binary files /dev/null and b/tests/images/kitten2.jpg differ diff --git a/tests/images/kitten3.jpg b/tests/images/kitten3.jpg new file mode 100644 index 00000000..6740d7c3 Binary files /dev/null and b/tests/images/kitten3.jpg differ diff --git a/tests/images/kitten4.jpg b/tests/images/kitten4.jpg new file mode 100644 index 00000000..e4f6b36f Binary files /dev/null and b/tests/images/kitten4.jpg differ diff --git a/tests/spec/12-compose.js b/tests/spec/12-compose.js index f07d2ec4..61eb3dc8 100644 --- a/tests/spec/12-compose.js +++ b/tests/spec/12-compose.js @@ -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') -}) diff --git a/tests/spec/13-compose-media.js b/tests/spec/13-compose-media.js new file mode 100644 index 00000000..ad564e66 --- /dev/null +++ b/tests/spec/13-compose-media.js @@ -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() +}) diff --git a/tests/utils.js b/tests/utils.js index f21707e4..5490dfab 100644 --- a/tests/utils.js +++ b/tests/utils.js @@ -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}"]`)