summaryrefslogtreecommitdiffstats
path: root/ui
diff options
context:
space:
mode:
authorDessalines <tyhou13@gmx.com>2020-02-17 11:18:01 -0500
committerDessalines <tyhou13@gmx.com>2020-02-17 11:18:01 -0500
commit55f91ac5dc1816463fb99d6974f89acd46de3444 (patch)
tree8c06996dfefb3dba27856c4efa36b669530c09d2 /ui
parentb6ce26023efc75ca2b871d12c4f1c2c7b9696083 (diff)
First pass at adding oembeds / iframely.
Diffstat (limited to 'ui')
-rw-r--r--ui/src/components/iframely-card.tsx100
-rw-r--r--ui/src/components/post-listing.tsx53
-rw-r--r--ui/src/interfaces.ts15
3 files changed, 164 insertions, 4 deletions
diff --git a/ui/src/components/iframely-card.tsx b/ui/src/components/iframely-card.tsx
new file mode 100644
index 00000000..73f3cef7
--- /dev/null
+++ b/ui/src/components/iframely-card.tsx
@@ -0,0 +1,100 @@
+import { Component, linkEvent } from 'inferno';
+import { FramelyData } from '../interfaces';
+import { mdToHtml } from '../utils';
+
+interface FramelyCardProps {
+ iframely: FramelyData;
+}
+
+interface FramelyCardState {
+ expanded: boolean;
+}
+
+export class IFramelyCard extends Component<
+ FramelyCardProps,
+ FramelyCardState
+> {
+ private emptyState: FramelyCardState = {
+ expanded: false,
+ };
+
+ constructor(props: any, context: any) {
+ super(props, context);
+ this.state = this.emptyState;
+ }
+
+ render() {
+ let iframely = this.props.iframely;
+ return (
+ <>
+ <div class="card my-2">
+ <div class="row no-gutters">
+ {iframely.thumbnail_url && (
+ <div class="col-sm-3">
+ {iframely.html ? (
+ <span
+ class="pointer"
+ onClick={linkEvent(this, this.handleIframeExpand)}
+ >
+ <img class="card-img" src={iframely.thumbnail_url} />
+ </span>
+ ) : (
+ <img
+ class="img-fluid card-img"
+ src={iframely.thumbnail_url}
+ />
+ )}
+ </div>
+ )}
+ <div class="col-sm-9">
+ <div class="card-body">
+ <h5 class="card-title d-inline">
+ <span>
+ <a class="text-body" target="_blank" href={iframely.url}>
+ {iframely.title}
+ </a>
+ </span>
+ </h5>
+ <span class="d-inline-block ml-2 mb-2 small text-muted">
+ <a class="text-muted" target="_blank" href={iframely.url}>
+ {new URL(iframely.url).hostname}
+ <svg class="ml-1 icon">
+ <use xlinkHref="#icon-external-link"></use>
+ </svg>
+ </a>
+ {iframely.html && (
+ <span
+ class="ml-2 pointer"
+ onClick={linkEvent(this, this.handleIframeExpand)}
+ >
+ {this.state.expanded ? '[-]' : '[+]'}
+ </span>
+ )}
+ </span>
+ {iframely.description && (
+ <div
+ className="card-text small text-muted md-div"
+ dangerouslySetInnerHTML={mdToHtml(iframely.description)}
+ />
+ )}
+ </div>
+ </div>
+ </div>
+ </div>
+ {this.state.expanded && (
+ <div class="my-2 embed-responsive embed-responsive-16by9">
+ <div
+ class="embed-responsive-item"
+ dangerouslySetInnerHTML={{ __html: iframely.html }}
+ />
+ </div>
+ )}
+ </>
+ );
+ }
+
+ handleIframeExpand(i: IFramelyCard) {
+ i.state.expanded = !i.state.expanded;
+ i.setState(i.state);
+ }
+}
diff --git a/ui/src/components/post-listing.tsx b/ui/src/components/post-listing.tsx
index d3772544..5cc63251 100644
--- a/ui/src/components/post-listing.tsx
+++ b/ui/src/components/post-listing.tsx
@@ -15,9 +15,11 @@ import {
AddAdminForm,
TransferSiteForm,
TransferCommunityForm,
+ FramelyData,
} from '../interfaces';
import { MomentTime } from './moment-time';
import { PostForm } from './post-form';
+import { IFramelyCard } from './iframely-card';
import {
mdToHtml,
canMod,
@@ -47,6 +49,7 @@ interface PostListingState {
score: number;
upvotes: number;
downvotes: number;
+ iframely: FramelyData;
}
interface PostListingProps {
@@ -74,6 +77,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
score: this.props.post.score,
upvotes: this.props.post.upvotes,
downvotes: this.props.post.downvotes,
+ iframely: null,
};
constructor(props: any, context: any) {
@@ -84,6 +88,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
this.handlePostDisLike = this.handlePostDisLike.bind(this);
this.handleEditPost = this.handleEditPost.bind(this);
this.handleEditCancel = this.handleEditCancel.bind(this);
+
+ if (this.props.post.url) {
+ this.fetchIframely();
+ }
}
componentWillReceiveProps(nextProps: PostListingProps) {
@@ -141,7 +149,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</button>
)}
</div>
- {post.url && isImage(post.url) && !this.state.imageExpanded && (
+ {this.hasImage() && !this.state.imageExpanded && (
<span
title={i18n.t('expand_here')}
class="pointer"
@@ -151,7 +159,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
className={`mx-2 mt-1 float-left img-fluid thumbnail rounded ${(post.nsfw ||
post.community_nsfw) &&
'img-blur'}`}
- src={imageThumbnailer(post.url)}
+ src={imageThumbnailer(this.getImage())}
/>
</span>
)}
@@ -205,7 +213,7 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</a>
</small>
)}
- {post.url && isImage(post.url) && (
+ {this.hasImage() && (
<>
{!this.state.imageExpanded ? (
<span
@@ -228,7 +236,10 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
class="pointer"
onClick={linkEvent(this, this.handleImageExpandClick)}
>
- <img class="img-fluid img-expanded" src={post.url} />
+ <img
+ class="img-fluid img-expanded"
+ src={this.getImage()}
+ />
</span>
</div>
</span>
@@ -587,6 +598,9 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
</li>
)}
</ul>
+ {post.url && this.props.showBody && this.state.iframely && (
+ <IFramelyCard iframely={this.state.iframely} />
+ )}
{this.state.showRemoveDialog && (
<form
class="form-inline"
@@ -737,6 +751,37 @@ export class PostListing extends Component<PostListingProps, PostListingState> {
);
}
+ fetchIframely() {
+ fetch(`/iframely/oembed?url=${this.props.post.url}`)
+ .then(res => res.json())
+ .then(res => {
+ this.state.iframely = res;
+ this.setState(this.state);
+ })
+ .catch(error => {
+ console.error(`Iframely service not set up properly. ${error}`);
+ });
+ }
+
+ hasImage(): boolean {
+ return (
+ (this.props.post.url && isImage(this.props.post.url)) ||
+ (this.state.iframely && this.state.iframely.thumbnail_url !== undefined)
+ );
+ }
+
+ getImage(): string {
+ let simpleImg = isImage(this.props.post.url);
+ if (simpleImg) {
+ return this.props.post.url;
+ } else if (this.state.iframely) {
+ let iframelyThumbnail = this.state.iframely.thumbnail_url;
+ if (iframelyThumbnail) {
+ return iframelyThumbnail;
+ }
+ }
+ }
+
handlePostLike(i: PostListing) {
let new_vote = i.state.my_vote == 1 ? 0 : 1;
diff --git a/ui/src/interfaces.ts b/ui/src/interfaces.ts
index 5846b548..5baadb17 100644
--- a/ui/src/interfaces.ts
+++ b/ui/src/interfaces.ts
@@ -876,3 +876,18 @@ export interface WebSocketJsonResponse {
error?: string;
reconnect?: boolean;
}
+
+export interface FramelyData {
+ url: string;
+ type: string;
+ version?: string;
+ title: string;
+ author?: string;
+ author_url?: string;
+ provider_name?: string;
+ thumbnail_url?: string;
+ thumbnail_width?: number;
+ thumbnail_height?: number;
+ description?: string;
+ html?: string;
+}