diff --git a/README.md b/README.md index 2917d8af..c52460ec 100644 --- a/README.md +++ b/README.md @@ -46,6 +46,7 @@ - Audio player - Full Text Search - Shared links are full fledge network drive +- Office documents (docx, xlsx and more) - User friendly - Mobile friendly - Customisable diff --git a/client/helpers/mimetype.js b/client/helpers/mimetype.js index cb70a010..902473a0 100644 --- a/client/helpers/mimetype.js +++ b/client/helpers/mimetype.js @@ -1,34 +1,38 @@ import Path from 'path'; export function getMimeType(file){ - let ext = Path.extname(file).replace(/^\./, '').toLowerCase(); + let ext = Path.extname(file).replace(/^\./, "").toLowerCase(); let mime = CONFIG.mime[ext]; if(mime){ return mime; }else{ - return 'text/plain'; + return "text/plain"; } } export function opener(file){ let mime = getMimeType(file); - if(mime.split('/')[0] === 'text'){ - return 'editor'; - }else if(mime === 'application/pdf'){ - return 'pdf'; - }else if(mime.split('/')[0] === 'image'){ - return 'image'; - }else if(['application/javascript', 'application/xml', 'application/json', 'application/x-perl'].indexOf(mime) !== -1){ - return 'editor'; - }else if(['audio/wav', 'audio/mp3', 'audio/flac', 'audio/ogg'].indexOf(mime) !== -1){ - return 'audio'; + + let openerFromPlugin = window.overrides["xdg-open"](mime); + if(openerFromPlugin !== null){ + return openerFromPlugin; + }else if(mime.split("/")[0] === "text"){ + return ["editor", null]; + }else if(mime === "application/pdf"){ + return ["pdf", null]; + }else if(mime.split("/")[0] === "image"){ + return ["image", null]; + }else if(["application/javascript", "application/xml", "application/json", "application/x-perl"].indexOf(mime) !== -1){ + return ["editor", null]; + }else if(["audio/wav", "audio/mp3", "audio/flac", "audio/ogg"].indexOf(mime) !== -1){ + return ["audio", null]; }else if(mime === "application/x-form"){ - return 'form'; - }else if(mime.split('/')[0] === 'video' || mime === "application/ogg"){ - return 'video'; - }else if(mime.split('/')[0] === "application"){ - return 'download'; + return ["form", null]; + }else if(mime.split("/")[0] === "video" || mime === "application/ogg"){ + return ["video", null]; + }else if(mime.split("/")[0] === "application"){ + return ["download", null]; }else{ - return 'editor'; + return ["editor", null]; } } diff --git a/client/index.js b/client/index.js index 47516f3a..b1aeb3d3 100644 --- a/client/index.js +++ b/client/index.js @@ -3,6 +3,7 @@ import ReactDOM from 'react-dom'; import Router from './router'; import { Config, Log } from "./model/"; +import load from "little-loader"; import './assets/css/reset.scss'; @@ -35,7 +36,7 @@ window.addEventListener("DOMContentLoaded", () => { return Promise.resolve(); } - Config.refresh().then(() => { + Promise.all([Config.refresh(), setup_xdg_open()]).then(() => { const timeSinceBoot = new Date() - window.initTime; if(timeSinceBoot >= 1500){ const timeoutToAvoidFlickering = timeSinceBoot > 2500 ? 0 : 500; @@ -55,8 +56,6 @@ window.onerror = function (msg, url, lineNo, colNo, error) { Log.report(msg, url, lineNo, colNo, error) } -window.overrides = {}; // server generated frontend overrides - if ("serviceWorker" in navigator) { window.addEventListener("load", function() { navigator.serviceWorker.register("/sw_cache.js").catch(function(err){ @@ -64,3 +63,14 @@ if ("serviceWorker" in navigator) { }); }); } + +// server generated frontend overrides +window.overrides = {}; +function setup_xdg_open(){ + return new Promise((done, err) => { + load("/overrides/xdg-open.js", function(error) { + if(error) return err(error); + done() + }); + }); +} diff --git a/client/pages/viewerpage.js b/client/pages/viewerpage.js index be0e53c7..da7b495c 100644 --- a/client/pages/viewerpage.js +++ b/client/pages/viewerpage.js @@ -9,17 +9,22 @@ import { debounce, opener, notify } from '../helpers/'; import { FileDownloader, ImageViewer, PDFViewer, FormViewer } from './viewerpage/'; const VideoPlayer = (props) => ( - + {(Comp) => } ); const IDE = (props) => ( - + {(Comp) => } ); const AudioPlayer = (props) => ( - + + {(Comp) => } + +); +const Appframe = (props) => ( + {(Comp) => } ); @@ -38,7 +43,8 @@ export class ViewerPage extends React.Component { content: null, needSaving: false, isSaving: false, - loading: true + loading: true, + application_arguments: null }; this.props.subscribe('file.select', this.onPathUpdate.bind(this)); } @@ -53,11 +59,12 @@ export class ViewerPage extends React.Component { componentDidMount(){ const metadata = () => { return new Promise((done, err) => { - let app_opener = opener(this.state.path); + let [app_opener, app_args] = opener(this.state.path); Files.url(this.state.path).then((url) => { this.setState({ url: url, - opener: app_opener + opener: app_opener, + application_arguments: app_args }, () => done(app_opener)); }).catch(error => { this.props.error(error); @@ -173,6 +180,9 @@ export class ViewerPage extends React.Component { + + + diff --git a/client/pages/viewerpage/appframe.js b/client/pages/viewerpage/appframe.js new file mode 100644 index 00000000..2254bfe5 --- /dev/null +++ b/client/pages/viewerpage/appframe.js @@ -0,0 +1,30 @@ +import React from 'react'; + +import { MenuBar } from './menubar'; +import { currentShare } from '../../helpers/'; +import './appframe.scss'; + +export class AppFrame extends React.Component{ + constructor(props){ + super(props); + } + + render(){ + let error = null; + if(!this.props.args) { + error = "Missing configuration. Contact your administrator"; + } else if(!this.props.args.endpoint) { + error = "Missing endpoint configuration. Contact your administrator"; + } + if(error !== null) return ( +
+
{error}
+
+ ); + return ( +
+