Commit 3444ee90 authored by Laurent Wouters's avatar Laurent Wouters
Browse files

Transform into a web extension

parent c515a85fb525
......@@ -53,9 +53,9 @@ export class LinkedData {
}
/**
* A typed content
* A typed raw content
*/
export class Content {
export class RawContent {
/**
* The MIME type
*/
......@@ -87,3 +87,20 @@ export const MIME: { [mime: string]: string } = {
"application/ld+json": "JSON",
"application/trig": "TRIG"
};
/**
* The public interface for the application
*/
export interface Application {
/**
* Sets the content for the application
* @param content The content
*/
onContent(content: RawContent): void;
/**
* Sets the application on error
* @param description The error's description
*/
onError(description: string): void;
}
/*******************************************************************************
* Copyright 2003-2018 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
*
* This file is part of CubicWeb.
*
* CubicWeb is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 2.1 of the License, or (at your option)
* any later version.
*
* CubicWeb is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import * as React from "react";
import { RawContent, Application } from "../../common/api";
class LoadingState {
message: string;
}
class ErrorState {
error: string;
}
class DisplayingState {
content: RawContent;
}
type State = LoadingState | ErrorState | DisplayingState;
export class Viewer extends React.Component<any, State> implements Application {
constructor(props: any) {
super(props);
this.state = { message: "Loading" };
this.onContent = this.onContent.bind(this);
this.onError = this.onError.bind(this);
}
/**
* Sets the content for the application
* @param content The content
*/
public onContent(content: RawContent): void {
this.setState({
content: content
});
}
/**
* Sets the application on error
* @param description The error's description
*/
public onError(description: string): void {
this.setState({
error: description
});
}
render() {
return <div>Content</div>;
}
}
/*******************************************************************************
* Copyright 2003-2018 LOGILAB S.A. (Paris, FRANCE), all rights reserved.
* contact http://www.logilab.fr/ -- mailto:contact@logilab.fr
*
* This file is part of CubicWeb.
*
* CubicWeb is free software: you can redistribute it and/or modify it under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation, either version 2.1 of the License, or (at your option)
* any later version.
*
* CubicWeb is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*
* You should have received a copy of the GNU Lesser General Public License along
* with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import * as React from "react";
import * as ReactDOM from "react-dom";
import { Application } from "../../common/api";
import { Viewer } from "./Viewer";
/**
* Identifier of the DOM element for the injected application
*/
const ID: string = "linked-data-injectable-app";
/**
* Get the maximum z-index value in this page
*/
function maxZIndex(): number {
return Array.from(document.querySelectorAll("body *"))
.map(a => parseFloat(window.getComputedStyle(a).zIndex))
.filter(a => !isNaN(a))
.reduce(function(acc, value) {
return acc > value ? acc : value;
}, 0);
}
let currentApp: Viewer = null;
/**
* Get the current application
*/
export function getApp(): Application {
return currentApp;
}
/**
* Inject the application stub into the current page
*/
export function injectApplication(): Application {
if (currentApp != null) return currentApp;
let zIndex = maxZIndex();
let appContent = document.createElement("div");
appContent.id = ID;
appContent.style.zIndex = (zIndex + 10).toString();
document.body.insertBefore(appContent, document.body.firstChild);
let viewer = <Viewer />;
let x = ReactDOM.render(viewer, document.getElementById(ID));
currentApp = x as Viewer;
return currentApp;
}
/**
* Remove the application
*/
export function removeApplication(): void {
if (currentApp == null) return;
let root = document.getElementById(ID);
root.parentNode.removeChild(root);
currentApp = null;
}
......@@ -18,43 +18,15 @@
* with CubicWeb. If not, see <http://www.gnu.org/licenses/>.
******************************************************************************/
import { Content, Link, LinkedData } from "../common/api";
import { RawContent, Link, LinkedData } from "../common/api";
import * as App from "./app/index";
import "chrome";
/**
* Identifier of the DOM element for the injected application
*/
const ID: string = "linked-data-injectable-app";
/**
* Get the maximum z-index value in this page
*/
function maxZIndex(): number {
return Array.from(document.querySelectorAll("body *"))
.map(a => parseFloat(window.getComputedStyle(a).zIndex))
.filter(a => !isNaN(a))
.reduce(function(acc, value) {
return acc > value ? acc : value;
}, 0);
}
/**
* Injecte the application stub into the HTML
*/
function injectApplication(): void {
let zIndex = maxZIndex();
let appContent = document.createElement("div");
appContent.id = ID;
appContent.style.zIndex = (zIndex + 10).toString();
appContent.appendChild(document.createTextNode("Loading ..."));
document.body.insertBefore(appContent, document.body.firstChild);
}
/**
* Get a promise to fetch the content of the current document
* @param contentType The MIME type for the page's content
*/
function doFetchContent(contentType: string): Promise<Content> {
function doFetchContent(contentType: string): Promise<RawContent> {
return new Promise(function(resolve, reject) {
resolve({
contentType: contentType,
......@@ -67,7 +39,7 @@ function doFetchContent(contentType: string): Promise<Content> {
* Get a promise to fetch content at a URI
* @param link The link to use
*/
function doFetchLink(link: Link): Promise<Content> {
function doFetchLink(link: Link): Promise<RawContent> {
return new Promise(function(resolve, reject) {
let xmlHttp = new XMLHttpRequest();
xmlHttp.onreadystatechange = function() {
......@@ -88,25 +60,11 @@ function doFetchLink(link: Link): Promise<Content> {
});
}
/**
* Injects content into the appliation
* @param data The data to inject
*/
function injectContent(data: Content): void {
let root = document.getElementById(ID);
while (root.hasChildNodes()) {
root.removeChild(root.lastChild);
}
root.appendChild(document.createTextNode(data.content));
}
/**
* Reacts to the deactivation
*/
function onUpdateDeactivate(): void {
let root = document.getElementById(ID);
if (root == null) return;
root.parentNode.removeChild(root);
App.removeApplication();
}
/**
......@@ -114,8 +72,7 @@ function onUpdateDeactivate(): void {
* @param linkedData The linked data to use
*/
function onUpdateActivate(linkedData: LinkedData): void {
onUpdateDeactivate();
injectApplication();
let app = App.injectApplication();
let fetch = null;
if (linkedData.target == "content") {
fetch = doFetchContent(linkedData.syntax);
......@@ -124,11 +81,10 @@ function onUpdateActivate(linkedData: LinkedData): void {
}
fetch
.then(function(result) {
injectContent(result);
app.onContent(result);
})
.catch(function(reason) {
let root = document.getElementById(ID);
root.innerText = reason;
app.onError(reason);
});
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment