Import existing attempt to port to vue
Signed-off-by: Carl Schwan <carl@carlschwan.eu>
This commit is contained in:
parent
753e88793e
commit
47cc783b63
|
@ -0,0 +1,25 @@
|
|||
<template>
|
||||
<Content app-name="news">
|
||||
<Sidebar />
|
||||
<AppContent>
|
||||
<router-view />
|
||||
</AppContent>
|
||||
</Content>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Content from '@nextcloud/vue/dist/Components/Content'
|
||||
import AppContent from '@nextcloud/vue/dist/Components/AppContent'
|
||||
import Sidebar from './components/Sidebar.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
Content,
|
||||
Sidebar,
|
||||
AppContent,
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('loadFolder')
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,171 @@
|
|||
<template>
|
||||
<NcModal @close="$emit('close')">
|
||||
<div id="new-feed" news-add-feed="Navigation.feed">
|
||||
<form ng-submit="Navigation.createFeed(Navigation.feed)"
|
||||
ng-init="Navigation.feed.autoDiscover=true"
|
||||
name="feedform">
|
||||
<fieldset ng-disabled="Navigation.addingFeed" style="padding: 16px">
|
||||
<input type="text"
|
||||
:value="feed"
|
||||
ng-model="Navigation.feed.url"
|
||||
ng-class="{'ng-invalid':
|
||||
!Navigation.addingFeed &&
|
||||
Navigation.feedUrlExists(Navigation.feed.url)
|
||||
}"
|
||||
:placeholder="t('news', 'Web address')"
|
||||
name="address"
|
||||
pattern="[^\s]+"
|
||||
required
|
||||
autofocus>
|
||||
|
||||
<p class="error"
|
||||
ng-show="!Navigation.addingFeed &&
|
||||
Navigation.feedUrlExists(Navigation.feed.url)">
|
||||
{{ t("news", "Feed exists already!") }}
|
||||
</p>
|
||||
|
||||
<!-- select a folder -->
|
||||
<CheckboxRadioSwitch :checked.sync="createNewFolder" type="switch">
|
||||
{{ t("news", "New folder") }}?
|
||||
</CheckboxRadioSwitch>
|
||||
|
||||
<NcMultiselect v-if="!createNewFolder"
|
||||
v-model="folder"
|
||||
:options="folders"
|
||||
track-by="id"
|
||||
label="name" />
|
||||
|
||||
<!-- add a folder -->
|
||||
<input v-if="createNewFolder"
|
||||
type="text"
|
||||
ng-model="Navigation.feed.newFolder"
|
||||
ng-class="{'ng-invalid':
|
||||
!Navigation.addingFeed &&
|
||||
!Navigation.addingFeed &&
|
||||
Navigation.showNewFolder &&
|
||||
Navigation.folderNameExists(
|
||||
Navigation.feed.newFolder
|
||||
)
|
||||
}"
|
||||
:placeholder="t('news', 'Folder name')"
|
||||
name="folderName"
|
||||
style="width: 90%"
|
||||
required>
|
||||
|
||||
<p class="error"
|
||||
ng-show="!Navigation.addingFeed &&
|
||||
Navigation.folderNameExists(Navigation.feed.newFolder)">
|
||||
{{ t("news", "Folder exists already!") }}
|
||||
</p>
|
||||
|
||||
<!-- basic auth -->
|
||||
|
||||
<CheckboxRadioSwitch :checked.sync="withBasicAuth" type="switch">
|
||||
{{ t("news", "Credentials") }}?
|
||||
</CheckboxRadioSwitch>
|
||||
|
||||
<div v-if="withBasicAuth" class="add-feed-basicauth">
|
||||
<p class="warning">
|
||||
{{
|
||||
t(
|
||||
"news",
|
||||
"HTTP Basic Auth credentials must be stored unencrypted! Everyone with access to the server or database will be able to access them!"
|
||||
)
|
||||
}}>
|
||||
</p>
|
||||
<input type="text"
|
||||
ng-model="Navigation.feed.user"
|
||||
:placeholder="t('news', 'Username')"
|
||||
name="user"
|
||||
autofocus>
|
||||
|
||||
<input type="password"
|
||||
ng-model="Navigation.feed.password"
|
||||
:placeholder="t('news', 'Password')"
|
||||
name="password"
|
||||
autocomplete="new-password">
|
||||
</div>
|
||||
|
||||
<NcCheckboxRadioSwitch :checked.sync="autoDiscover" type="switch">
|
||||
{{ t("news", "Auto discover Feed") }}?
|
||||
</NcCheckboxRadioSwitch>
|
||||
|
||||
<NcButton :wide="true"
|
||||
type="primary"
|
||||
ng-disabled="
|
||||
Navigation.feedUrlExists(Navigation.feed.url) ||
|
||||
(
|
||||
Navigation.showNewFolder &&
|
||||
Navigation.folderNameExists(folder.name)
|
||||
)"
|
||||
@click="addFeed()">
|
||||
{{ t("news", "Subscribe") }}
|
||||
</NcButton>
|
||||
</fieldset>
|
||||
</form>
|
||||
</div>
|
||||
</NcModal>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
/* eslint-disable vue/require-prop-type-constructor */
|
||||
|
||||
import NcModal from '@nextcloud/vue/dist/Components/NcModal.js'
|
||||
import NcCheckboxRadioSwitch from '@nextcloud/vue/dist/Components/NcCheckboxRadioSwitch.js'
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
|
||||
import NcMultiselect from '@nextcloud/vue/dist/Components/NcMultiselect.js'
|
||||
|
||||
export default {
|
||||
name: 'AddFeed',
|
||||
components: {
|
||||
NcModal,
|
||||
NcCheckboxRadioSwitch,
|
||||
NcButton,
|
||||
NcMultiselect,
|
||||
},
|
||||
props: {
|
||||
feed: '',
|
||||
},
|
||||
emits: ['close'],
|
||||
data() {
|
||||
return {
|
||||
folder: {},
|
||||
autoDiscover: true,
|
||||
createNewFolder: false,
|
||||
withBasicAuth: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
folders() {
|
||||
return this.$store.state.folders
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
newFolder() {
|
||||
this.createNewFolder = true
|
||||
},
|
||||
abortNewFolder() {
|
||||
this.createNewFolder = false
|
||||
},
|
||||
addFeed() {
|
||||
this.$store.dispatch('addFeed', {
|
||||
feedReq: {
|
||||
url: this.feed,
|
||||
folder: this.folder,
|
||||
autoDiscover: true,
|
||||
},
|
||||
})
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
input {
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.multiselect {
|
||||
width: 100%
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,78 @@
|
|||
<template>
|
||||
<div id="explore">
|
||||
<AddFeed v-if="showAddFeed" :feed="feed" @close="closeShowAddFeed()" />
|
||||
<div class="grid-container">
|
||||
<div v-for="entry in exploreSites"
|
||||
:key="entry.title"
|
||||
class="explore-feed grid-item">
|
||||
<h2 v-if="entry.favicon"
|
||||
class="explore-title"
|
||||
:style="{ backgroundImage: 'url(' + entry.favicon + ')' }">
|
||||
<a target="_blank" rel="noreferrer" :href="entry.url">
|
||||
{{ entry.title }}
|
||||
</a>
|
||||
</h2>
|
||||
<h2 v-if="!entry.favicon" class="icon-rss explore-title">
|
||||
{{ entry.title }}
|
||||
</h2>
|
||||
<div class="explore-content">
|
||||
<p>{{ entry.description }}</p>
|
||||
|
||||
<div class="explore-logo">
|
||||
<img :src="entry.image">
|
||||
</div>
|
||||
</div>
|
||||
<Button @click="subscribe(entry.feed)">
|
||||
{{ t("news", "Subscribe to") }} {{ entry.title }}
|
||||
</Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import NcButton from '@nextcloud/vue/dist/Components/NcButton.js'
|
||||
import axios from '@nextcloud/axios'
|
||||
import AddFeed from './AddFeed.vue'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
|
||||
export default {
|
||||
name: 'ExploreComponent',
|
||||
components: {
|
||||
NcButton,
|
||||
AddFeed,
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
exploreSites: [],
|
||||
feed: {},
|
||||
showAddFeed: false,
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.sites()
|
||||
},
|
||||
|
||||
methods: {
|
||||
async sites() {
|
||||
const settings = await axios.get(generateUrl('/apps/news/settings'))
|
||||
|
||||
const exploreUrl = settings.data.settings.exploreUrl + 'feeds.en.json'
|
||||
const explore = await axios.get(exploreUrl)
|
||||
|
||||
Object.keys(explore.data).forEach((key) =>
|
||||
explore.data[key].forEach((value) =>
|
||||
this.exploreSites.push(value),
|
||||
),
|
||||
)
|
||||
},
|
||||
async subscribe(feed) {
|
||||
this.feed = feed
|
||||
this.showAddFeed = true
|
||||
},
|
||||
closeShowAddFeed() {
|
||||
this.showAddFeed = false
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
|
@ -0,0 +1,211 @@
|
|||
<template>
|
||||
<NcAppNavigation>
|
||||
<AddFeed v-if="showAddFeed" @close="closeShowAddFeed()" />
|
||||
<NcAppNavigationNew :text="t('news', 'Subscribe')"
|
||||
button-id="new-feed-button"
|
||||
button-class="icon-add"
|
||||
@click="showShowAddFeed()" />
|
||||
|
||||
<div class="news-navigation">
|
||||
<NcAppNavigationNewItem :title="t('news', 'New folder')" @new-item="newFolder">
|
||||
<template #icon>
|
||||
<PlusCircle :size="16" />
|
||||
</template>
|
||||
</NcAppNavigationNewItem>
|
||||
|
||||
<NcAppNavigationItem :title="t('news', 'Unread articles')" icon="icon-rss">
|
||||
<template #actions>
|
||||
<ActionButton icon="icon-checkmark" @click="alert('Edit')">
|
||||
t('news','Mark read')
|
||||
</ActionButton>
|
||||
</template>
|
||||
<template #counter>
|
||||
<NcCounterBubble>5</NcCounterBubble>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem :title="t('news', 'All articles')" icon="icon-rss">
|
||||
<template #actions>
|
||||
<NcActionButton icon="icon-checkmark" @click="alert('Edit')">
|
||||
t('news','Mark read')
|
||||
</NcActionButton>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
<NcAppNavigationItem :title="t('news', 'Starred')" icon="icon-starred">
|
||||
<template #counter>
|
||||
<NcCounterBubble>35</NcCounterBubble>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
|
||||
<NcAppNavigationItem v-for="folder in folders"
|
||||
:key="folder.name"
|
||||
:title="folder.name"
|
||||
icon="icon-folder"
|
||||
:allow-collapse="true">
|
||||
<template #default>
|
||||
<NcAppNavigationItem v-for="feed in folder.feeds"
|
||||
:key="feed.name"
|
||||
:title="feed.title">
|
||||
<template #icon>
|
||||
<img v-if="feed.faviconLink"
|
||||
:src="feed.faviconLink"
|
||||
alt="feedIcon">
|
||||
<div v-if="!feed.faviconLink" class="icon-rss" />
|
||||
</template>
|
||||
<template #actions>
|
||||
<NcActionButton icon="icon-checkmark" @click="alert('Mark read')">
|
||||
{{ t("news", "Mark read") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-pinned" @click="alert('Rename')">
|
||||
{{ t("news", "Unpin from top") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-caret-dark"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Newest first") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-caret-dark"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Oldest first") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-caret-dark"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Default order") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-full-text-disabled"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Enable full text") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-full-text-enabled"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Disable full text") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-updatemode-default"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Unread updated") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-updatemode-unread"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Ignore updated") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-icon-rss" @click="deleteFolder(folder)">
|
||||
{{ t("news", "Open feed URL") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-icon-rename"
|
||||
@click="deleteFolder(folder)">
|
||||
{{ t("news", "Rename") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-delete" @click="deleteFolder(folder)">
|
||||
{{ t("news", "Delete") }}
|
||||
</NcActionButton>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
</template>
|
||||
<template v-if="folder.feedCount > 0" #counter>
|
||||
<NcCounterBubble>{{ folder.feedCount }}</NcCounterBubble>
|
||||
</template>
|
||||
<template #actions>
|
||||
<NcActionButton icon="icon-checkmark" @click="alert('Mark read')">
|
||||
{{ t("news", "Mark read") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-rename" @click="alert('Rename')">
|
||||
{{ t("news", "Rename") }}
|
||||
</NcActionButton>
|
||||
<NcActionButton icon="icon-delete" @click="deleteFolder(folder)">
|
||||
{{ t("news", "Delete") }}
|
||||
</NcActionButton>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
|
||||
<NcAppNavigationItem :title="t('news', 'Explore')"
|
||||
icon="icon-link"
|
||||
:to="{ name: 'explore' }">
|
||||
<template #counter>
|
||||
<NcCounterBubble>35</NcCounterBubble>
|
||||
</template>
|
||||
</NcAppNavigationItem>
|
||||
</div>
|
||||
</NcAppNavigation>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
||||
import NcAppNavigation from '@nextcloud/vue/dist/Components/NcAppNavigation.js'
|
||||
import NcAppNavigationNew from '@nextcloud/vue/dist/Components/NcAppNavigationNew.js'
|
||||
import NcAppNavigationItem from '@nextcloud/vue/dist/Components/NcAppNavigationItem.js'
|
||||
import NcAppNavigationNewItem from '@nextcloud/vue/dist/Components/NcAppNavigationNewItem.js'
|
||||
// import AppNavigationCounter from '@nextcloud/vue/dist/Components/AppNavigationCounter'
|
||||
import NcCounterBubble from '@nextcloud/vue/dist/Components/NcCounterBubble.js'
|
||||
import NcActionButton from '@nextcloud/vue/dist/Components/NcActionButton.js'
|
||||
import AddFeed from './AddFeed.vue'
|
||||
import PlusCircle from 'vue-material-design-icons/PlusCircle.vue'
|
||||
|
||||
export default {
|
||||
components: {
|
||||
NcAppNavigation,
|
||||
NcAppNavigationNew,
|
||||
NcAppNavigationItem,
|
||||
NcAppNavigationNewItem,
|
||||
// AppNavigationCounter,
|
||||
NcCounterBubble,
|
||||
NcActionButton,
|
||||
AddFeed,
|
||||
PlusCircle,
|
||||
},
|
||||
data: () => {
|
||||
return {
|
||||
showAddFeed: false,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
folders() {
|
||||
return this.$store.state.folders
|
||||
},
|
||||
},
|
||||
created() {
|
||||
// TODO?
|
||||
},
|
||||
methods: {
|
||||
newFolder(value) {
|
||||
const folderName = value.trim()
|
||||
const folder = { name: folderName }
|
||||
this.$store.dispatch('addFolder', { folder })
|
||||
},
|
||||
deleteFolder(folder) {
|
||||
this.$store.dispatch('deleteFolder', { folder })
|
||||
window.location.reload(true)
|
||||
},
|
||||
showShowAddFeed() {
|
||||
this.showAddFeed = true
|
||||
},
|
||||
closeShowAddFeed() {
|
||||
this.showAddFeed = false
|
||||
},
|
||||
alert(msg) {
|
||||
window.alert(msg)
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.news-navigation {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
padding-left: 10px;
|
||||
padding-right: 10px;
|
||||
gap: 10px;
|
||||
|
||||
& ::v-deep .app-navigation-input-confirm {
|
||||
form {
|
||||
gap: 4px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
button.button-vue--icon-only {
|
||||
min-height: 36px !important;
|
||||
width: 36px !important;
|
||||
height: 36px !important;
|
||||
min-width: 36px !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -0,0 +1,132 @@
|
|||
|
||||
import Vue from 'vue'
|
||||
import App from './App.vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import Explore from './components/Explore.vue'
|
||||
import { generateUrl } from '@nextcloud/router'
|
||||
import Vuex, { Store } from 'vuex'
|
||||
import axios from '@nextcloud/axios'
|
||||
|
||||
import { Tooltip } from '@nextcloud/vue'
|
||||
|
||||
Vue.prototype.t = t
|
||||
Vue.prototype.n = n
|
||||
Vue.prototype.OC = OC
|
||||
Vue.prototype.OCA = OCA
|
||||
|
||||
Vue.use(Vuex)
|
||||
Vue.use(VueRouter)
|
||||
|
||||
Vue.directive('tooltip', Tooltip)
|
||||
|
||||
const feedUrl = generateUrl('/apps/news/feeds')
|
||||
const folderUrl = generateUrl('/apps/news/folders')
|
||||
|
||||
const routes = [
|
||||
{
|
||||
name: 'explore',
|
||||
path: '#explore',
|
||||
component: Explore,
|
||||
},
|
||||
]
|
||||
|
||||
const router = new VueRouter({
|
||||
mode: 'history',
|
||||
base: generateUrl('apps/news'),
|
||||
routes,
|
||||
})
|
||||
|
||||
const store = new Store({
|
||||
state: {
|
||||
folders: [],
|
||||
feeds: [],
|
||||
},
|
||||
mutations: {
|
||||
addFolders(state, folders) {
|
||||
folders.forEach((it) => {
|
||||
it.feedCount = 0
|
||||
state.folders.push(it)
|
||||
})
|
||||
},
|
||||
addFeeds(state, feeds) {
|
||||
feeds.forEach((it) => {
|
||||
state.feeds.push(it)
|
||||
const folder = state.folders.find(
|
||||
(folder) => folder.id === it.folderId,
|
||||
)
|
||||
if (folder) {
|
||||
folder.feeds.push(it)
|
||||
folder.feedCount += it.unreadCount
|
||||
}
|
||||
})
|
||||
},
|
||||
},
|
||||
actions: {
|
||||
addFolder({ commit }, { folder }) {
|
||||
axios
|
||||
.post(folderUrl, { folderName: folder.name })
|
||||
.then((response) =>
|
||||
commit('addFolders', response.data.folders),
|
||||
)
|
||||
},
|
||||
deleteFolder({ commit }, { folder }) {
|
||||
/**
|
||||
this.getByFolderId(folderId).forEach(function (feed) {
|
||||
promises.push(self.reversiblyDelete(feed.id, false, true));
|
||||
});
|
||||
this.updateUnreadCache();
|
||||
*/
|
||||
axios.delete(folderUrl + '/' + folder.id).then()
|
||||
},
|
||||
loadFolder({ commit }) {
|
||||
axios.get(folderUrl).then((response) => {
|
||||
commit('addFolders', response.data.folders)
|
||||
axios
|
||||
.get(feedUrl)
|
||||
.then((response) =>
|
||||
commit('addFeeds', response.data.feeds),
|
||||
)
|
||||
})
|
||||
},
|
||||
addFeed({ commit }, { feedReq }) {
|
||||
let url = feedReq.url.trim()
|
||||
if (!url.startsWith('http')) {
|
||||
url = 'https://' + url
|
||||
}
|
||||
|
||||
/**
|
||||
if (title !== undefined) {
|
||||
title = title.trim();
|
||||
}
|
||||
*/
|
||||
|
||||
const feed = {
|
||||
url,
|
||||
folderId: feedReq.folder.id || 0,
|
||||
title: null,
|
||||
unreadCount: 0,
|
||||
}
|
||||
|
||||
// this.add(feed);
|
||||
// this.updateFolderCache();
|
||||
|
||||
axios
|
||||
.post(feedUrl, {
|
||||
url: feed.url,
|
||||
parentFolderId: feed.folderId,
|
||||
title: null,
|
||||
user: null,
|
||||
password: null,
|
||||
fullDiscover: feed.autoDiscover,
|
||||
})
|
||||
.then()
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
export default new Vue({
|
||||
router,
|
||||
store,
|
||||
el: '#content',
|
||||
render: (h) => h(App),
|
||||
})
|
|
@ -1,4 +1,8 @@
|
|||
<?php
|
||||
|
||||
\OCP\Util::addScript('news', 'build/news-main');
|
||||
|
||||
/*
|
||||
use OCA\News\Plugin\Client\Plugin;
|
||||
|
||||
script('news', [
|
||||
|
@ -97,3 +101,4 @@ foreach (Plugin::getScripts() as $appName => $fileName) {
|
|||
news-scroll-enabled-mark-read="Content.markReadEnabled()"
|
||||
news-scroll-auto-page="Content.autoPage()"
|
||||
news-scroll-mark-read="Content.scrollRead(itemIds)"></div>
|
||||
*/
|
||||
|
|
|
@ -6,6 +6,7 @@ const webpackConfig = require('@nextcloud/webpack-vue-config')
|
|||
|
||||
webpackConfig.entry = {
|
||||
'admin-settings': path.join(__dirname, 'src', 'main-admin.js'),
|
||||
'main': path.join(__dirname, 'src', 'main.js'),
|
||||
}
|
||||
webpackConfig.output.path = path.resolve('./js/build/')
|
||||
webpackConfig.output.publicPath = path.join('/apps/', process.env.npm_package_name, '/js/build/')
|
||||
|
|
Loading…
Reference in New Issue