Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement MediaViewer Plugin #212

Merged
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
61 changes: 61 additions & 0 deletions geonode_mapstore_client/client/js/components/MediaViewer/Media.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
/*
* Copyright 2021, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import MediaComponent from '@mapstore/framework/components/geostory/media';
import HTML from '@mapstore/framework/components/I18N/HTML';
import PdfViewer from '@js/components/MediaViewer/PdfViewer';
import { determineResourceType } from '@js/utils/FileUtils';
import Loader from '@mapstore/framework/components/misc/Loader';


const mediaMap = {
image: MediaComponent,
video: MediaComponent,
pdf: PdfViewer,
unsupported: MediaComponent
};

const loaderComponent = () => <div className="pdf-loader"><Loader size={70}/></div>;

const mediaDefaultProps = {
video: {
mode: "view",
inView: true
},
image: {
fit: "contain",
enableFullscreen: true,
loaderComponent
},
pdf: {},
unsupported: {
showCaption: true,
caption: <h3><HTML msgId={'viewer.document.unSupportedMedia'}/></h3>,
enableFullscreen: false
}
};

const Media = ({resource}) => {
if (resource) {
const mediaType = determineResourceType(resource.extension);
const MediaViewer = mediaMap[mediaType];
return (<MediaViewer
mediaType={mediaType}
{...mediaDefaultProps[mediaType]}
description={resource.abstract}
id={resource.pk}
thumbnail={resource.thumbnail_url}
src={mediaType === 'unsupported' ? resource.thumbnail_url : resource.href}
/>);
}
return null;
};

export default Media;

Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import React, { useState, useEffect } from 'react';
import Loader from '@mapstore/framework/components/misc/Loader';

import { getFileFromDownload } from '@js/utils/FileUtils';

const PdfViewer = ({src}) => {
const [filePath, setFilePath] = useState(null);
const [loading, setLoading] = useState(false);

useEffect(() => {
setLoading(true);
getFileFromDownload(src)
.then((fileURL) => {
setLoading(false);
setFilePath(fileURL);
}).finally(() => {
setLoading(false);
});
}, []);

if (loading) {
return (<div
className="pdf-loader">
<Loader size={70}/>
</div>);
}

return (<iframe type="application/pdf"
frameBorder="0"
scrolling="auto"
height="100%"
width="100%" src={filePath}/>);
};

export default PdfViewer;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import Media from './Media';

export default Media;
56 changes: 56 additions & 0 deletions geonode_mapstore_client/client/js/plugins/MediaViewer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
/*
* Copyright 2021, GeoSolutions Sas.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree.
*/

import React from 'react';
import { createPlugin } from '@mapstore/framework/utils/PluginsUtils';
import MediaViewerComponent from '@js/components/MediaViewer';
import { connect } from 'react-redux';
import { createSelector } from 'reselect';
import gnresource from '@js/reducers/gnresource';

const ConnectedMediaViewer = connect(
createSelector([
state => state?.gnresource?.data || null,
state => state?.gnresource?.loading || false
], (resource, loading, editMode) => ({
resource,
loading,
editMode
}))
)(MediaViewerComponent);


function MediaViewer() {
return (
<div
className="gn-media-viewer">
<ConnectedMediaViewer/>
</div>
);
}

const MediaViewerPlugin = connect(
createSelector([
], () => ({})),
{}
)(MediaViewer);


export default createPlugin('MediaViewer', {
component: MediaViewerPlugin,
containers: {
ViewerLayout: {
name: 'MediaViewer',
priority: 1
}
},
epics: {},
reducers: {
gnresource
}
});
2 changes: 1 addition & 1 deletion geonode_mapstore_client/client/js/plugins/ViewerLayout.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ function ViewerLayout({
.filter(({ target }) => target === 'header')
.map(({ Component, name }) => <Component key={name} />)}
</header>
<div style={{display: 'flex'}}>
<div style={{display: 'flex', flex: 1}}>
<div
style={{
display: 'flex',
Expand Down
4 changes: 4 additions & 0 deletions geonode_mapstore_client/client/js/plugins/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -266,6 +266,10 @@ export const plugins = {
DetailViewerPlugin: toLazyPlugin(
'DetailViewer',
import(/* webpackChunkName: 'plugins/detail-viewer-plugin' */ '@js/plugins/DetailViewer')
),
MediaViewerPlugin: toLazyPlugin(
'MediaViewer',
import(/* webpackChunkName: 'plugins/media-viewer-plugin' */ '@js/plugins/MediaViewer')
)


Expand Down
36 changes: 36 additions & 0 deletions geonode_mapstore_client/client/js/utils/FileUtils.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import axios from '@mapstore/framework/libs/ajax';

/**
* Generates a blob path for a resource
* @memberof FileUtils
* @param {string} downloadURL remote path to a resource
* @param {string} type type of the file to be converted to default application/json
* @return {string} Object url to view resource in browser
*/
export const getFileFromDownload = (downloadURL, type = 'application/pdf') => {
return axios.get(downloadURL, {
responseType: 'blob'
}).then(({data}) => {
const file = new Blob([data], {type});
const fileURL = URL.createObjectURL(file);
return fileURL;
});
};


// Default Supported resources for MediaViewer
export const imageExtensions = ['jpg', 'jpeg', 'png'];
export const videoExtensions = ['mp4', 'mpg', 'avi', 'm4v', 'mp2', '3gp', 'flv', 'vdo', 'afl', 'mpga', 'webm'];

/**
* check if a resource extension is supported for display in the media viewer
* @memberof FileUtils
* @param {string} extension extension of the resource accessed on resource.extenstion
* @return {string} pdf image video unsupported
*/
export const determineResourceType = extension => {
if (extension === 'pdf') return 'pdf';
if (imageExtensions.includes(extension)) return 'image';
if (videoExtensions.includes(extension)) return 'video';
return 'unsupported';
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import expect from 'expect';
import { determineResourceType } from '@js/utils/FileUtils';

describe('FileUtils', () => {
it('should return image if extension is a supported image format', () => {
const mediaType = determineResourceType('jpg');
expect(mediaType).toEqual('image');
});

it('should return video if extension is a supported video format', () => {
const mediaType = determineResourceType('mp4');
expect(mediaType).toEqual('video');
});

it('should return pdf if extension pdf', () => {
const mediaType = determineResourceType('pdf');
expect(mediaType).toEqual('pdf');
});

it('should return unsupported if extension is not supported', () => {
const mediaType = determineResourceType('docx');
expect(mediaType).toEqual('unsupported');
});
});

2 changes: 1 addition & 1 deletion geonode_mapstore_client/client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@
"proxyTargetHost": "localhost:8000",
"protocol": "http"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3354,7 +3354,8 @@
{ "name": "ViewerLayout" },
{ "name": "ActionNavbar" },
{ "name": "BrandNavbar" },
{ "name": "DetailViewer"}
{ "name": "DetailViewer"},
{"name": "MediaViewer"}
]
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@
"customFiltersTitle": "Ressourcen",
"myResources": "Meine Ressourcen",
"pendingApproval": "Ausstehende Genehmigung"
},
"viewer":{
"document": {
"unSupportedMedia": "Das Medienformat wird nicht unterstützt"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@
"myResources": "My resources",
"pendingApproval": "Pending approval"

},
"viewer":{
"document": {
"unSupportedMedia": "Media format is unsupported"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,11 @@
"myResources": "Mis recursos",
"pendingApproval": "Aprobación pendiente"

},
"viewer":{
"document": {
"unSupportedMedia": "El formato de medios no es compatible"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@
"customFiltersTitle": "Ressources",
"myResources": "Mes ressources",
"pendingApproval": "En attente de validation"
},
"viewer":{
"document": {
"unSupportedMedia": "Le format multimédia n'est pas pris en charge"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,11 @@
"customFiltersTitle": "Risorse",
"myResources": "Le mie risorse",
"pendingApproval": "In attesa di approvazione"
},
"viewer":{
"document": {
"unSupportedMedia": "Il formato multimediale non è supportato"
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,12 @@
z-index: 1;
}

.ms-media .ms-media-image {
img {
width: 100%;
height: 100%;
}
}
.add-bar-popover {
max-width: 500px;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
.gn-media-viewer {
top: 0;
left: 0;
width: calc(100% - 2rem);
height: calc(100% - 2rem);
position: absolute;
margin: 1rem;

.ms-media,
.ms-media img {
position: relative;
height: 100%;
width: 100%
}

.pdf-loader {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(255, 255, 255, 0.8);
z-index: 2;
display: flex;
align-items: center;
justify-content: center
}
}
.gn-media-viewer .pdf-loader {
position: 'absolute';
top: 0;
left: 0;
width: '100%';
height: '100%';
background-color: 'rgba(255, 255, 255, 0.8)';
z-index: 2;
display: 'flex';
align-items: 'center';
justify-content: 'center'
}

// this gives a higher z-index than #ms-container inorder to make lightbox show
.ReactModal__Overlay.ReactModal__Overlay--after-open {
z-index: 100000 !important;
}
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
'swipe-menu',
'home-container',
'sub-flat-menu',
'media-viewer',
'tag';


Expand Down