UNPKG

san-cli-ui-addon-widgets

Version:

san cli ui addon widgets

161 lines (156 loc) 5.76 kB
/** * @file 新闻组件 * @author zttonly, Lohoyo */ import './news.less'; export default { template: /* html */` <div class="news"> <div s-if="loading" class="widget-loading"> <s-spin spinning="{=loading=}"> <s-icon slot="indicator" type="loading" style="font-size: 24px;" /> </s-spin> </div> <div s-elif="error" class="error"> <s-icon type="{{errIcons[error]}}"/> <div>{{$t('dashboard.widgets.news.errors.' + error)}}</div> </div> <fragment s-else> <nav> <article s-for="item in feed.items" class="news-item {{selectedItem === item ? 'news-item-selected' : ''}}" on-click="handleClick(item)"> <div> <div class="title" title={{item.title}}>{{item.title}}</div> <div class="snippet">{{item.contentSnippet}}</div> <span class="date">{{item.pubDate | dateFormat}}</span> <a href="{{item.link}}" target="_blank" rel="noopener noreferrer"> {{$t('dashboard.widgets.news.origin')}} </a> </div> </article> </nav> <main s-html="selectedItem['content:encoded'] || selectedItem.content"></main> <div s-if="selectedItem.enclosure" class="media"> <img s-if="isImg" src="{{selectedItem.enclosure.url}}"/> <audio s-if="isAudio" src="{{selectedItem.enclosure.url}}" controls></audio> <video s-if="isVideo" src="{{selectedItem.enclosure.url}}" controls></video> </div> </fragment> </div> `, computed: { isImg() { const selectedItem = this.data.get('selectedItem'); return selectedItem && selectedItem.enclosure && selectedItem.enclosure.type.indexOf('image/') === 0; }, isAudio() { const selectedItem = this.data.get('selectedItem'); return selectedItem && selectedItem.enclosure && selectedItem.enclosure.type.indexOf('audio/') === 0; }, isVideo() { const selectedItem = this.data.get('selectedItem'); return selectedItem && selectedItem.enclosure && selectedItem.enclosure.type.indexOf('video/') === 0; } }, filters: { dateFormat(d) { return new Date(d).toLocaleString(); } }, initData() { return { loading: false, feed: null, error: null, selectedItem: null, errIcons: { fetch: 'close', offline: 'disconnect', empty: 'frown' } }; }, created() { this.addAction(); }, attached() { const url = this.data.get('data.config.url'); if (url) { this.fetchFeed(); this.currentUrl = url; } this.watch('data.config.url', value => { const url = this.data.get('data.config.url'); // 有时data.config.url明明没有变化,却监听到了变化,所以这里做了下判断,判断到底有没有变化 if (url === this.currentUrl) { return; } value && this.fetchFeed(); this.currentUrl = url; }); this.watch('loading', value => { !value && this.addAction(); }); }, addAction() { this.dispatch('Widget:addHeaderAction', { id: 'reload', icon: 'reload', disabled: this.data.get('loading'), onCalled: () => this.fetchFeed(true), tooltip: this.$t('dashboard.widgets.news.actionTooltip.reload') }); }, async fetchFeed(force = false) { this.data.set('selectedItem', null); if (!navigator.onLine) { this.data.set('loading', false); this.data.set('error', 'offline'); return; } this.data.set('loading', true); this.data.set('error', false); this.dispatch('Widget:title', null); try { const {results, errors} = await this.$callPluginAction('san.widgets.actions.fetch-news', { url: this.data.get('data.config.url'), force }); if (errors.length && errors[0]) { throw new Error(errors[0]); } let feed = results[0]; if (feed && feed.items && feed.items.length) { feed.items.forEach(item => this.imgSrcReplace(item)); this.data.set('feed', feed); this.data.set('selectedItem', feed.items[0]); this.dispatch('Widget:title', feed.title); } else { this.data.set('error', 'empty'); } } catch (e) { this.data.set('error', 'fetch'); // eslint-disable-next-line no-console console.error(e); } this.data.set('loading', false); }, handleClick(value) { this.data.set('selectedItem', value); }, imgSrcReplace(item) { let match = item.link.match(/^http(s)?:\/\/(.*?)\//); let domain = match ? match[0] : ''; item.content = item.content.replace(/src=\"\/([^"]*\")/g, (m, s1) => 'src="' + domain + s1); } };