aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorRoger Braun <roger@rogerbraun.net>2016-11-07 11:56:14 +0100
committerRoger Braun <roger@rogerbraun.net>2016-11-07 11:56:14 +0100
commitcf972e968cd1e059c4a7a05a9a3d42f3da05414b (patch)
tree2d7d9ee5408397f1ac5d36fa98943158d5a105c4 /src
parentacc439f26684d3d188542e904190532ac781c936 (diff)
parent83e7add2c7cd3d7b878c82ffb86e09479bff3500 (diff)
Merge branch 'master' of ssh.gitgud.io:lambadalambda/pleroma-fe
Diffstat (limited to 'src')
-rw-r--r--src/App.js4
-rw-r--r--src/App.scss29
-rw-r--r--src/components/attachment/attachment.js4
-rw-r--r--src/components/attachment/attachment.vue2
-rw-r--r--src/components/media_upload/media_upload.js22
-rw-r--r--src/components/media_upload/media_upload.vue17
-rw-r--r--src/components/nav_panel/nav_panel.js4
-rw-r--r--src/components/nav_panel/nav_panel.vue54
-rw-r--r--src/components/post_status_form/post_status_form.js17
-rw-r--r--src/components/post_status_form/post_status_form.vue2
-rw-r--r--src/components/public_and_external_timeline/public_and_external_timeline.js11
-rw-r--r--src/components/public_and_external_timeline/public_and_external_timeline.vue10
-rw-r--r--src/components/status/status.js3
-rw-r--r--src/components/status/status.vue2
-rw-r--r--src/components/timeline/timeline.js24
-rw-r--r--src/components/timeline/timeline.vue7
-rw-r--r--src/main.js15
-rw-r--r--src/modules/statuses.js20
-rw-r--r--src/services/api/api.service.js25
-rw-r--r--src/services/status_poster/status_poster.service.js15
l---------src/services/timeline_fetcher/.#timeline_fetcher.service.js1
-rw-r--r--src/services/timeline_fetcher/timeline_fetcher.service.js6
22 files changed, 238 insertions, 56 deletions
diff --git a/src/App.js b/src/App.js
index 3c677566..c3e5164a 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,9 +1,11 @@
import UserPanel from './components/user_panel/user_panel.vue'
+import NavPanel from './components/nav_panel/nav_panel.vue'
export default {
name: 'app',
components: {
- UserPanel
+ UserPanel,
+ NavPanel
},
computed: {
user () { return this.$store.state.users.currentUser || {} },
diff --git a/src/App.scss b/src/App.scss
index 4856f990..2850867d 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -2,12 +2,13 @@ $main-color: #f58d2c;
$main-background: white;
$darkened-background: whitesmoke;
-body {
+#app {
background-color: $main-color;
background-size: cover;
background-attachment: fixed;
background-repeat: no-repeat;
background-position: 0 50px;
+ min-height: 100vh;
}
h4 {
@@ -197,27 +198,6 @@ status.ng-enter.ng-enter-active {
cursor: pointer;
}
-nav-panel ul {
- list-style: none;
- margin: 0;
- padding: 0;
-}
-
-nav-panel li {
- border-bottom: 1px solid silver;
- padding: 0.5em;
- padding-left: 1em;
-}
-
-nav-panel li:last-child {
- border: none;
-}
-
-nav-panel a {
- display: block;
- width: 100%;
-}
-
.status-el p {
margin: 0;
margin-top: 0.2em;
@@ -279,11 +259,6 @@ attention {
display: flex;
padding: 0.5em;
- media-upload {
- font-size: 26px;
- flex: 1;
- }
-
button {
flex: 2;
}
diff --git a/src/components/attachment/attachment.js b/src/components/attachment/attachment.js
index 161c6b2b..85d924d0 100644
--- a/src/components/attachment/attachment.js
+++ b/src/components/attachment/attachment.js
@@ -19,8 +19,8 @@ const Attachment = {
type = 'image';
}
- if(this.attachment.mimetype.match(/video\/webm/)) {
- type = 'webm';
+ if(this.attachment.mimetype.match(/video\/(webm|mp4)/)) {
+ type = 'video';
};
return type
diff --git a/src/components/attachment/attachment.vue b/src/components/attachment/attachment.vue
index b8c55a1a..8c088cf1 100644
--- a/src/components/attachment/attachment.vue
+++ b/src/components/attachment/attachment.vue
@@ -6,7 +6,7 @@
<a class="image-attachment" v-if="type === 'image' && !nsfw" :href="attachment.url" target="_blank"><img :src="attachment.url"></img></a>
- <video v-if="type === 'webm' && !nsfw" :src="attachment.url" controls></video>
+ <video v-if="type === 'video' && !nsfw" :src="attachment.url" controls></video>
<span v-if="type === 'unknown'">Don't know how to display this...</span>
diff --git a/src/components/media_upload/media_upload.js b/src/components/media_upload/media_upload.js
new file mode 100644
index 00000000..c24c71e9
--- /dev/null
+++ b/src/components/media_upload/media_upload.js
@@ -0,0 +1,22 @@
+/* eslint-env browser */
+import statusPosterService from '../../services/status_poster/status_poster.service.js'
+
+const mediaUpload = {
+ mounted () {
+ const store = this.$store
+ const input = this.$el.querySelector('input')
+ const self = this
+
+ input.addEventListener('change', ({target}) => {
+ const file = target.files[0];
+ const formData = new FormData();
+ formData.append('media', file);
+ statusPosterService.uploadMedia({ store, formData })
+ .then((fileData) => {
+ self.$emit('uploaded', fileData)
+ })
+ })
+ }
+}
+
+export default mediaUpload
diff --git a/src/components/media_upload/media_upload.vue b/src/components/media_upload/media_upload.vue
new file mode 100644
index 00000000..a62d8316
--- /dev/null
+++ b/src/components/media_upload/media_upload.vue
@@ -0,0 +1,17 @@
+<template>
+ <div class="media-upload">
+ <label class="btn btn-default">
+ <i class="fa icon-upload"></i>
+ <input type=file style="position: fixed; top: -100em"></input>
+ </label>
+ </div>
+</template>
+
+<script src="./media_upload.js" ></script>
+
+<style>
+ .media-upload {
+ font-size: 26px;
+ flex: 1;
+ }
+</style>
diff --git a/src/components/nav_panel/nav_panel.js b/src/components/nav_panel/nav_panel.js
new file mode 100644
index 00000000..318d30cc
--- /dev/null
+++ b/src/components/nav_panel/nav_panel.js
@@ -0,0 +1,4 @@
+const NavPanel = {
+}
+
+export default NavPanel
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
new file mode 100644
index 00000000..d493fad3
--- /dev/null
+++ b/src/components/nav_panel/nav_panel.vue
@@ -0,0 +1,54 @@
+<template>
+ <div class="nav-panel">
+ <div class="panel panel-default">
+ <ul>
+ <li ng-if='currentUser'>
+ <router-link to='/main/friends'>
+ Timeline
+ </router-link>
+ </li>
+ <li>
+ <router-link to='/main/public'>
+ Public Timeline
+ </router-link>
+ </li>
+ <li>
+ <router-link to='/main/all'>
+ The Whole Known Network
+ </router-link>
+ </li>
+ </ul>
+ </div>
+ </div>
+</template>
+
+<script src="./nav_panel.js" ></script>
+
+<style lang="scss">
+
+ .nav-panel ul {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ .nav-panel li {
+ border-bottom: 1px solid silver;
+ padding: 0.5em;
+ padding-left: 1em;
+ }
+
+ .nav-panel li:last-child {
+ border: none;
+ }
+
+ .nav-panel a {
+ display: block;
+ width: 100%;
+
+ &.router-link-active {
+ font-weight: bold
+ }
+ }
+
+</style>
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 2c015154..30a7cd40 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -1,4 +1,6 @@
import statusPoster from '../../services/status_poster/status_poster.service.js'
+import MediaUpload from '../media_upload/media_upload.vue'
+
import { reject, map, uniqBy } from 'lodash';
const buildMentionsString = ({user, attentions}, currentUser) => {
@@ -23,6 +25,9 @@ const PostStatusForm = {
'repliedUser',
'attentions'
],
+ components: {
+ MediaUpload
+ },
data () {
let statusText = ''
@@ -33,7 +38,8 @@ const PostStatusForm = {
return {
newStatus: {
- status: statusText
+ status: statusText,
+ files: []
}
}
},
@@ -41,11 +47,18 @@ const PostStatusForm = {
postStatus (newStatus) {
statusPoster.postStatus({
status: newStatus.status,
+ media: newStatus.files,
store: this.$store,
inReplyToStatusId: this.replyTo
})
- this.newStatus = { }
+ this.newStatus = {
+ status: '',
+ files: []
+ }
this.$emit('posted')
+ },
+ addMediaFile (fileInfo) {
+ this.newStatus.files.push(fileInfo)
}
}
}
diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue
index d2106d5a..943bf422 100644
--- a/src/components/post_status_form/post_status_form.vue
+++ b/src/components/post_status_form/post_status_form.vue
@@ -10,7 +10,7 @@
</div>
</div>
<div class='form-bottom'>
- <media-upload files="newStatus.files"></media-upload>
+ <media-upload v-on:uploaded="addMediaFile"></media-upload>
<button type="submit" class="btn btn-default" >Submit</button>
</div>
</form>
diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.js b/src/components/public_and_external_timeline/public_and_external_timeline.js
new file mode 100644
index 00000000..138118ad
--- /dev/null
+++ b/src/components/public_and_external_timeline/public_and_external_timeline.js
@@ -0,0 +1,11 @@
+import Timeline from '../timeline/timeline.vue'
+const PublicAndExternalTimeline = {
+ components: {
+ Timeline
+ },
+ computed: {
+ timeline () { return this.$store.state.statuses.timelines.publicAndExternal }
+ }
+}
+
+export default PublicAndExternalTimeline
diff --git a/src/components/public_and_external_timeline/public_and_external_timeline.vue b/src/components/public_and_external_timeline/public_and_external_timeline.vue
new file mode 100644
index 00000000..94cdaf17
--- /dev/null
+++ b/src/components/public_and_external_timeline/public_and_external_timeline.vue
@@ -0,0 +1,10 @@
+<template>
+ <div class="timeline panel panel-default">
+ <div class="panel-heading">THE WHOLE KNOWN NETWORK</div>
+ <div class="panel-body">
+ <Timeline v-bind:timeline="timeline" v-bind:timeline-name="'publicAndExternal'"/>
+ </div>
+ </div>
+</template>
+
+<script src="./public_and_external_timeline.js"></script>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 2e6565e8..6253d334 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -16,6 +16,9 @@ const Status = {
} else {
return this.statusoid
}
+ },
+ loggedIn () {
+ return !!this.$store.state.users.currentUser
}
},
components: {
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 8361aa52..1c5dc458 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -32,7 +32,7 @@
</attachment>
</div>
- <div>
+ <div v-if="loggedIn">
<div class='status-actions'>
<div>
<a href="#" v-on:click.prevent="toggleReplying">
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 433bca11..e0c75d76 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -1,4 +1,5 @@
import Status from '../status/status.vue'
+import timelineFetcher from '../../services/timeline_fetcher/timeline_fetcher.service.js'
const Timeline = {
props: [
@@ -8,9 +9,32 @@ const Timeline = {
components: {
Status
},
+ created () {
+ const store = this.$store
+ const credentials = store.state.users.currentUser.credentials
+
+ timelineFetcher.fetchAndUpdate({
+ store,
+ credentials,
+ timeline: this.timelineName,
+ showImmediately: true
+ })
+ },
methods: {
showNewStatuses () {
this.$store.commit('showNewStatuses', { timeline: this.timelineName })
+ },
+ fetchOlderStatuses () {
+ const store = this.$store
+ const credentials = store.state.users.currentUser.credentials
+ store.commit('setLoading', { timeline: this.timelineName, value: true });
+ timelineFetcher.fetchAndUpdate({
+ store,
+ credentials,
+ timeline: this.timelineName,
+ older: true,
+ showImmediately: true
+ }).then(() => store.commit('setLoading', { timeline: this.timelineName, value: false }))
}
}
}
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 1e779638..2f1b8c28 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -8,6 +8,13 @@
</div>
</a>
<status v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status"></status>
+ <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading">
+ <div class="new-status-notification">
+ <p class="text-center" >
+ Load older statuses.
+ </p>
+ </div>
+ </a>
</div>
</template>
<script src="./timeline.js"></script>
diff --git a/src/main.js b/src/main.js
index 6ce2ca1b..de3b2af1 100644
--- a/src/main.js
+++ b/src/main.js
@@ -3,6 +3,7 @@ import VueRouter from 'vue-router'
import Vuex from 'vuex'
import App from './App.vue'
import PublicTimeline from './components/public_timeline/public_timeline.vue'
+import PublicAndExternalTimeline from './components/public_and_external_timeline/public_and_external_timeline.vue'
import FriendsTimeline from './components/friends_timeline/friends_timeline.vue'
import statusesModule from './modules/statuses.js'
@@ -19,12 +20,16 @@ const store = new Vuex.Store({
})
const routes = [
- { path: '/', redirect: '/main/public' },
+ { path: '/', redirect: '/main/all' },
+ { path: '/main/all', component: PublicAndExternalTimeline },
{ path: '/main/public', component: PublicTimeline },
{ path: '/main/friends', component: FriendsTimeline }
]
-const router = new VueRouter({routes})
+const router = new VueRouter({
+ mode: 'history',
+ routes
+})
/* eslint-disable no-new */
new Vue({
@@ -34,9 +39,3 @@ new Vue({
template: '<App/>',
components: { App }
})
-
-const statusesEx = require('../test/fixtures/statuses.json')
-
-setTimeout(() => {
- store.commit('addNewStatuses', { statuses: statusesEx, timeline: 'public', showImmediately: false })
-}, 3000)
diff --git a/src/modules/statuses.js b/src/modules/statuses.js
index eee368a3..5fb57a4f 100644
--- a/src/modules/statuses.js
+++ b/src/modules/statuses.js
@@ -12,7 +12,8 @@ const defaultState = {
visibleStatuses: [],
newStatusCount: 0,
maxId: 0,
- minVisibleId: 0
+ minVisibleId: 0,
+ loading: false
},
publicAndExternal: {
statuses: [],
@@ -20,7 +21,8 @@ const defaultState = {
visibleStatuses: [],
newStatusCount: 0,
maxId: 0,
- minVisibleId: 0
+ minVisibleId: 0,
+ loading: false
},
friends: {
statuses: [],
@@ -28,7 +30,8 @@ const defaultState = {
visibleStatuses: [],
newStatusCount: 0,
maxId: 0,
- minVisibleId: 0
+ minVisibleId: 0,
+ loading: false
}
}
}
@@ -37,7 +40,7 @@ const statusType = (status) => {
return !status.is_post_verb && status.uri.match(/fave/) ? 'fave' : 'status'
}
-const addStatusesToTimeline = (addedStatuses, showImmediately, { statuses, visibleStatuses, newStatusCount, faves }) => {
+const addStatusesToTimeline = (addedStatuses, showImmediately, { statuses, visibleStatuses, newStatusCount, faves, loading }) => {
const statusesAndFaves = groupBy(addedStatuses, statusType)
const addedFaves = statusesAndFaves['fave'] || []
const unseenFaves = differenceBy(addedFaves, faves, 'id')
@@ -55,6 +58,9 @@ const addStatusesToTimeline = (addedStatuses, showImmediately, { statuses, visib
// Add some html and nsfw to the statuses.
each(addedStatuses, (status) => {
const statusoid = status.retweeted_status || status
+
+ statusoid.created_at_parsed = statusoid.created_at
+
if (statusoid.parsedText === undefined) {
// statusoid.parsedText = statusParserService.parse(statusoid)
statusoid.parsedText = statusoid.text
@@ -89,7 +95,8 @@ const addStatusesToTimeline = (addedStatuses, showImmediately, { statuses, visib
newStatusCount: newNewStatusCount,
maxId: newStatuses[0].id,
minVisibleId: (last(newVisibleStatuses) || { id: undefined }).id,
- faves: unionBy(faves, addedFaves, 'id')
+ faves: unionBy(faves, addedFaves, 'id'),
+ loading
}
}
@@ -135,6 +142,9 @@ const statuses = {
const newStatus = find(state.allStatuses, status)
newStatus.favorited = value
},
+ setLoading (state, { timeline, value }) {
+ state.timelines[timeline].loading = value
+ },
setNsfw (state, { id, nsfw }) {
// For now, walk through all the statuses because the stuff might be in the replied_to_status
// TODO: Save the replied_tos as references.
diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js
index df7b4190..06585ac7 100644
--- a/src/services/api/api.service.js
+++ b/src/services/api/api.service.js
@@ -6,21 +6,27 @@ const PUBLIC_AND_EXTERNAL_TIMELINE_URL = '/api/statuses/public_and_external_time
const FAVORITE_URL = '/api/favorites/create'
const UNFAVORITE_URL = '/api/favorites/destroy'
const STATUS_UPDATE_URL = '/api/statuses/update.json'
+const MEDIA_UPLOAD_URL = '/api/statusnet/media/upload'
// const CONVERSATION_URL = '/api/statusnet/conversation/';
-// const MEDIA_UPLOAD_URL = '/api/statusnet/media/upload';
// const FORM_CONTENT_TYPE = {'Content-Type': 'application/x-www-form-urlencoded'};
// import { param, ajax } from 'jquery';
// import { merge } from 'lodash';
-const authHeaders = (user) => ({ 'Authorization': `Basic ${btoa(`${user.username}:${user.password}`)}` })
+const authHeaders = (user) => {
+ if (user) {
+ return { 'Authorization': `Basic ${btoa(`${user.username}:${user.password}`)}` }
+ } else {
+ return { }
+ }
+}
const fetchTimeline = ({timeline, credentials, since = false, until = false}) => {
const timelineUrls = {
public: PUBLIC_TIMELINE_URL,
friends: FRIENDS_TIMELINE_URL,
- 'public-and-external': PUBLIC_AND_EXTERNAL_TIMELINE_URL
+ 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL
}
let url = timelineUrls[timeline]
@@ -75,12 +81,23 @@ const postStatus = ({credentials, status, mediaIds, inReplyToStatusId}) => {
})
}
+const uploadMedia = ({formData, credentials}) => {
+ return fetch(MEDIA_UPLOAD_URL, {
+ body: formData,
+ method: 'POST',
+ headers: authHeaders(credentials)
+ })
+ .then((response) => response.text())
+ .then((text) => (new DOMParser()).parseFromString(text, 'application/xml'))
+}
+
const apiService = {
verifyCredentials,
fetchTimeline,
favorite,
unfavorite,
- postStatus
+ postStatus,
+ uploadMedia
}
export default apiService
diff --git a/src/services/status_poster/status_poster.service.js b/src/services/status_poster/status_poster.service.js
index 1a96b5f6..2a324541 100644
--- a/src/services/status_poster/status_poster.service.js
+++ b/src/services/status_poster/status_poster.service.js
@@ -12,8 +12,21 @@ const postStatus = ({ store, status, media = [], inReplyToStatusId = undefined }
})
}
+const uploadMedia = ({ store, formData }) => {
+ const credentials = store.state.users.currentUser.credentials
+
+ return apiService.uploadMedia({ credentials, formData }).then((xml) => {
+ return {
+ id: xml.getElementsByTagName('media_id')[0].textContent,
+ url: xml.getElementsByTagName('media_url')[0].textContent,
+ image: xml.getElementsByTagName('atom:link')[0].getAttribute('href')
+ }
+ })
+}
+
const statusPosterService = {
- postStatus
+ postStatus,
+ uploadMedia
}
export default statusPosterService
diff --git a/src/services/timeline_fetcher/.#timeline_fetcher.service.js b/src/services/timeline_fetcher/.#timeline_fetcher.service.js
deleted file mode 120000
index 8315cdae..00000000
--- a/src/services/timeline_fetcher/.#timeline_fetcher.service.js
+++ /dev/null
@@ -1 +0,0 @@
-roger@yuuyuu.18961 \ No newline at end of file
diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js
index a3d9b9d1..8a39eeb5 100644
--- a/src/services/timeline_fetcher/timeline_fetcher.service.js
+++ b/src/services/timeline_fetcher/timeline_fetcher.service.js
@@ -16,7 +16,8 @@ const update = ({store, statuses, timeline, showImmediately}) => {
const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false, showImmediately = false}) => {
const args = { timeline, credentials }
- const timelineData = store.rootState.statuses.timelines[camelCase(timeline)]
+ const rootState = store.rootState || store.state
+ const timelineData = rootState.statuses.timelines[camelCase(timeline)]
if (older) {
args['until'] = timelineData.minVisibleId
@@ -24,7 +25,7 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false
args['since'] = timelineData.maxId
}
- apiService.fetchTimeline(args)
+ return apiService.fetchTimeline(args)
.then((statuses) => update({store, statuses, timeline, showImmediately}))
}
@@ -35,6 +36,7 @@ const startFetching = ({ timeline = 'friends', credentials, store }) => {
setInterval(boundFetchAndUpdate, 10000)
}
const timelineFetcher = {
+ fetchAndUpdate,
startFetching
}