mirror of
https://github.com/RetroShare/RetroShare.git
synced 2025-03-07 22:46:55 -05:00
webui: switch from react to mithril
This commit is contained in:
parent
cef07fff91
commit
30193fe79a
1
libresapi/src/.gitignore
vendored
Normal file
1
libresapi/src/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
webui/*
|
@ -2,14 +2,13 @@ libresapi: resource_api and new webinterface
|
||||
============================================
|
||||
|
||||
* ./api contains a C++ backend to control retroshare from webinterfaces or scripting
|
||||
* ./webfiles contains compiled files for the webinterface
|
||||
* ./webui contains HTML/CSS/JavaScript source files for the webinterface (OLD)
|
||||
* ./webui contains contains compiled files for the webinterface (after build)
|
||||
* ./webui-src contains HTML/CSS/JavaScript source files for the webinterface (NEW, webinterface made with mithril.js)
|
||||
|
||||
Quickinfo for builders and packagers
|
||||
====================================
|
||||
|
||||
* copy the files in ./webfiles to
|
||||
* copy the files in ./webui to
|
||||
* ./webui (Windows)
|
||||
* /usr/share/RetroShare06/webui (Linux)
|
||||
* other OS: see RsAccountsDetail::PathDataDirectory()
|
||||
* other OS: see RsAccountsDetail::PathDataDirectory()
|
||||
|
@ -15,21 +15,19 @@ INCLUDEPATH += ../../libretroshare/src
|
||||
unix {
|
||||
|
||||
webui_files.path = "$${DATA_DIR}/webui"
|
||||
webui_files.files = webui-src/public-gen/app.js
|
||||
webui_files.files += webui-src/public-gen/app.css
|
||||
webui_files.files += webui-src/public-gen/index.html
|
||||
webui_files.files = webfiles/*
|
||||
INSTALLS += webui_files
|
||||
|
||||
webui_img_files.path = "$${DATA_DIR}/webui/img"
|
||||
webui_img_files.files = ../../retroshare-gui/src/gui/images/logo/logo_splash.png
|
||||
INSTALLS += webui_img_files
|
||||
|
||||
create_webfiles.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_/webui-src
|
||||
create_webfiles.commands = sh $$_PRO_FILE_PWD_/webui-src/make-src/build.sh $$_PRO_FILE_PWD_
|
||||
QMAKE_EXTRA_TARGETS += create_webfiles
|
||||
PRE_TARGETDEPS += create_webfiles
|
||||
|
||||
system($$create_webfiles.commands)
|
||||
|
||||
# create dummy files
|
||||
system(webui-src/make-src/init.sh .)
|
||||
}
|
||||
|
||||
win32{
|
||||
|
File diff suppressed because one or more lines are too long
@ -1,109 +0,0 @@
|
||||
/**
|
||||
* JS Api for Retroshare
|
||||
* @constructor
|
||||
* @param {object} connection - an object which implements a request() function.
|
||||
* The request function should take two parameters: an object to be send as request and a callback.
|
||||
* The callback should get called with an response object on success.
|
||||
*/
|
||||
function RsApi(connection)
|
||||
{
|
||||
var runnign = true;
|
||||
/**
|
||||
* Send a request to the server
|
||||
* @param req - the request so send
|
||||
* @param {Function} cb - callback function which takes the response as parameter
|
||||
*/
|
||||
this.request = function(req, cb)
|
||||
{
|
||||
connection.request(req, cb);
|
||||
};
|
||||
var tokenlisteners = [];
|
||||
/**
|
||||
* Register a callback to be called when the state token expired.
|
||||
* @param {Function} listener - the callback function, which does not take arguments
|
||||
* @param token - the state token to listen for
|
||||
*/
|
||||
this.register_token_listener = function(listener, token)
|
||||
{
|
||||
tokenlisteners.push({listener:listener, token:token});
|
||||
};
|
||||
/**
|
||||
* Unregister a previously registered callback.
|
||||
*/
|
||||
this.unregister_token_listener = function(listener) // no token as parameter, assuming unregister from all listening tokens
|
||||
{
|
||||
var to_delete = [];
|
||||
for(var i=0; i<tokenlisteners.length; i++){
|
||||
if(tokenlisteners[i].listener === listener){
|
||||
to_delete.push(i);
|
||||
}
|
||||
}
|
||||
for(var i=0; i<to_delete.length; i++){
|
||||
// copy the last element to the current index
|
||||
var index = to_delete[i];
|
||||
tokenlisteners[index] = tokenlisteners[tokenlisteners.length-1];
|
||||
// remove last element
|
||||
tokenlisteners.pop();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* start polling for state changes
|
||||
*/
|
||||
this.start = function(){
|
||||
running = true;
|
||||
setTimeout(tick, TICK_INTERVAL);
|
||||
}
|
||||
/**
|
||||
* stop polling for state changes
|
||||
*/
|
||||
this.stop = function(){
|
||||
running = false;
|
||||
}
|
||||
|
||||
// ************** interal stuff **************
|
||||
var TICK_INTERVAL = 3000;
|
||||
function received_tokenstates(resp)
|
||||
{
|
||||
if(resp.data){
|
||||
for(var i=0; i<resp.data.length; i++){
|
||||
var token = resp.data[i];
|
||||
// search the listener for this token
|
||||
for(var j=0; j<tokenlisteners.length; j++){
|
||||
if(tokenlisteners[j].token === token){
|
||||
// call the listener
|
||||
tokenlisteners[j].listener();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// schedule new update
|
||||
if(running)
|
||||
setTimeout(tick, TICK_INTERVAL);
|
||||
};
|
||||
function received_error()
|
||||
{
|
||||
// try again, maybe want a better logic later
|
||||
if(running)
|
||||
setTimeout(tick, TICK_INTERVAL);
|
||||
};
|
||||
function tick()
|
||||
{
|
||||
var data = [];
|
||||
// maybe cache the token list?
|
||||
// profiler will tell us if we should
|
||||
for(var i=0; i<tokenlisteners.length; i++){
|
||||
data.push(tokenlisteners[i].token);
|
||||
}
|
||||
connection.request({
|
||||
path: "statetokenservice",
|
||||
data: data,
|
||||
}, received_tokenstates, received_error);
|
||||
};
|
||||
};
|
||||
|
||||
// with this trick, we should be able to run in browser or nodejs
|
||||
if(typeof window === 'undefined')
|
||||
{
|
||||
// we are running in nodejs, so have to add to export
|
||||
module.exports = RsApi;
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/**
|
||||
* Connection to the RS backend using XHR
|
||||
* (could add other connections later, for example WebSockets)
|
||||
* @constructor
|
||||
*/
|
||||
function RsXHRConnection(server_hostname, server_port)
|
||||
{
|
||||
var debug;
|
||||
//debug = function(str){console.log(str);};
|
||||
debug = function(str){};
|
||||
|
||||
//server_hostname = "localhost";
|
||||
//server_port = "9090";
|
||||
var api_root_path = "/api/v2/";
|
||||
|
||||
var status_listeners = [];
|
||||
|
||||
function notify_status(status)
|
||||
{
|
||||
for(var i = 0; i < status_listeners.length; i++)
|
||||
{
|
||||
status_listeners[i](status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called when the state of the connection changes.
|
||||
* @param {function} cb - callback which receives a single argument. The arguments value is "connected" or "not_connected".
|
||||
*/
|
||||
this.register_status_listener = function(cb)
|
||||
{
|
||||
status_listeners.push(cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregister a status callback function.
|
||||
* @param {function} cb - a privously registered callback function
|
||||
*/
|
||||
this.unregister_status_listener = function(cb)
|
||||
{
|
||||
var to_delete = [];
|
||||
for(var i = 0; i < status_listeners.length; i++)
|
||||
{
|
||||
if(status_listeners[i] === cb){
|
||||
to_delete.push(i);
|
||||
}
|
||||
}
|
||||
for(var i = 0; i < to_delete.length; i++)
|
||||
{
|
||||
// copy the last element to the current index
|
||||
var index = to_delete[i];
|
||||
status_listeners[i] = status_listeners[status_listeners.length-1];
|
||||
// remove the last element
|
||||
status_listeners.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a request to the backend
|
||||
* automatically encodes the request as JSON before sending it to the server
|
||||
* @param {object} req - the request to send to the server
|
||||
* @param {function} cb - callback function to be called to handle the response. The callback takes one object as parameter. Can be left undefined.
|
||||
* @param {function} err_cb - callback function to signal a failed request. Can be undefined.
|
||||
*/
|
||||
this.request = function(req, cb, err_cb)
|
||||
{
|
||||
//var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
|
||||
// TODO: window is not available in QML
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function(){
|
||||
//console.log("onreadystatechanged state"+xhr.readyState);
|
||||
// TODO: figure out how to catch errors like connection refused
|
||||
// maybe want to have to set a state variable like ok=false
|
||||
// the gui could then display: "no connection to server"
|
||||
if (xhr.readyState === 4) {
|
||||
if(xhr.status !== 200)
|
||||
{
|
||||
console.log("RsXHRConnection: request failed with status: "+xhr.status);
|
||||
console.log("request was:");
|
||||
console.log(req);
|
||||
notify_status("not_connected");
|
||||
if(err_cb !== undefined)
|
||||
err_cb();
|
||||
return;
|
||||
}
|
||||
// received response
|
||||
notify_status("connected");
|
||||
debug("RsXHRConnection received response:");
|
||||
debug(xhr.responseText);
|
||||
if(false)//if(xhr.responseText === "")
|
||||
{
|
||||
debug("Warning: response is empty");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var respObj = JSON.parse(xhr.responseText);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
debug("Exception during response handling: "+e);
|
||||
}
|
||||
if(cb === undefined)
|
||||
debug("No callback function specified");
|
||||
else
|
||||
cb(respObj);
|
||||
}
|
||||
}
|
||||
// post is required for sending data
|
||||
var method;
|
||||
if(req.data){
|
||||
method = "POST";
|
||||
} else {
|
||||
method = "GET";
|
||||
}
|
||||
xhr.open(method, "http://"+server_hostname+":"+server_port+api_root_path+req.path);
|
||||
var data = JSON.stringify(req.data);
|
||||
debug("RsXHRConnection sending data:");
|
||||
debug(data);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(data);
|
||||
};
|
||||
};
|
@ -1,134 +0,0 @@
|
||||
body {
|
||||
background-color: black;
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
margin: 0em;
|
||||
/*padding: 1.5em;*/
|
||||
padding: 2mm;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#overlay{
|
||||
z-index: 10;
|
||||
position: fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
}
|
||||
|
||||
.paddingbox{
|
||||
padding:2mm;
|
||||
}
|
||||
|
||||
.nav{
|
||||
list-style-type: none;
|
||||
padding: 0em;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
.nav li{
|
||||
display: inline;
|
||||
padding: 0.1em;
|
||||
margin-right: 1em;
|
||||
border-width: 0.1em;
|
||||
border-color: blue;
|
||||
border-bottom-style: solid;
|
||||
cursor: pointer;
|
||||
}
|
||||
td{
|
||||
padding: 0.3em;
|
||||
border-style: solid;
|
||||
border-width: 0.1em;
|
||||
border-color: lime;
|
||||
}
|
||||
.btn{
|
||||
border-style: solid;
|
||||
border-color: lime;
|
||||
border-width: 0.1em;
|
||||
cursor: pointer;
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
.btn2, .box{
|
||||
border-style: solid;
|
||||
/*border-color: lime;*/
|
||||
border-color: limeGreen;
|
||||
/*border-width: 1px;*/
|
||||
border-radius: 3mm;
|
||||
padding: 2mm;
|
||||
font-size: 10mm;
|
||||
cursor: pointer;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
.btn2:hover{
|
||||
background-color: midnightblue;
|
||||
}
|
||||
|
||||
.filelink{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input, textarea{
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
background-color: black;
|
||||
border-color: lime;
|
||||
font-size: 10mm;
|
||||
border-radius: 3mm;
|
||||
border-width: 1mm;
|
||||
padding: 2mm;
|
||||
margin-bottom: 2mm;
|
||||
margin-right: 2mm;
|
||||
|
||||
/* make the button the whole screen width */
|
||||
width: 100%;
|
||||
/* make the text input fit small screens*/
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input:hover{
|
||||
background-color: midnightblue;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.flexbox{
|
||||
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
|
||||
display: -ms-flexbox; /* TWEENER - IE 10 */
|
||||
display: -webkit-flex; /* NEW - Chrome */
|
||||
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
}
|
||||
|
||||
.flexwidemember{
|
||||
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
-moz-box-flex: 1; /* OLD - Firefox 19- */
|
||||
width: 20%; /* For old syntax, otherwise collapses. */
|
||||
-webkit-flex: 1; /* Chrome */
|
||||
-ms-flex: 1; /* IE 10 */
|
||||
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
}
|
||||
|
||||
#logo_splash{
|
||||
-webkit-animation-fill-mode: forwards; /* Chrome, Safari, Opera */
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation-name: logo_splash; /* Chrome, Safari, Opera */
|
||||
-webkit-animation-duration: 3s; /* Chrome, Safari, Opera */
|
||||
animation-name: logo_splash;
|
||||
animation-duration: 3s;
|
||||
text-align: center;
|
||||
}
|
||||
/* Chrome, Safari, Opera */
|
||||
@-webkit-keyframes logo_splash {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
||||
|
||||
/* Standard syntax */
|
||||
@keyframes logo_splash {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>New webinterface for Retroshare</title>
|
||||
|
||||
<script src="RsXHRConnection.js"></script>
|
||||
<script src="RsApi.js"></script>
|
||||
|
||||
<!-- it seems to work more reliable, if the jsx file is loaded before react -->
|
||||
<script type="text/jsx" src="gui.jsx"></script>
|
||||
|
||||
<script src="react.js"></script>
|
||||
<script src="JSXTransformer.js"></script>
|
||||
|
||||
<link href="green-black.css" rel="stylesheet">
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
document.write("<p>loading lots of stuff...</p>");
|
||||
</script>
|
||||
<p><noscript>The Retroshare web interface requires JavaScript. Please enable JavaScript in your browser.</noscript></p>
|
||||
<!--<div id="logo_splash">
|
||||
<img src="img/logo_splash.png"></img>
|
||||
</div>-->
|
||||
</body>
|
||||
</html>
|
19541
libresapi/src/webfiles/react.js
vendored
19541
libresapi/src/webfiles/react.js
vendored
File diff suppressed because it is too large
Load Diff
1
libresapi/src/webui-src/.gitignore
vendored
1
libresapi/src/webui-src/.gitignore
vendored
@ -1,3 +1,2 @@
|
||||
node_modules/*
|
||||
public/*
|
||||
public-gen/*
|
||||
|
@ -56,4 +56,4 @@ need 4 master
|
||||
[X] unsubscribe lobby
|
||||
[X] unread chat message counter in menu
|
||||
[X] list chat-lobby participants
|
||||
[ ] creating app.js on build (no need for npm on regulary build)
|
||||
[X] creating app.js on build (no need for npm on regulary build)
|
||||
|
@ -1,28 +1,31 @@
|
||||
#!/usr/bin/sh
|
||||
echo $1
|
||||
|
||||
# create webfiles from sources at compile time (works without npm/node.js)
|
||||
|
||||
if [ "$1" == "" ];then
|
||||
publicdest=../public-gen
|
||||
publicdest=../../webui
|
||||
src=..
|
||||
else
|
||||
publicdest=$1/public-gen
|
||||
src=$1
|
||||
publicdest=$1/webui
|
||||
src=$1/webui-src
|
||||
fi
|
||||
echo $publicdest
|
||||
|
||||
if [ -d "$publicdest" ]; then
|
||||
echo remove $publicdest
|
||||
echo remove existing $publicdest
|
||||
rm $publicdest -R
|
||||
fi
|
||||
|
||||
echo mkdir $publicdest
|
||||
mkdir $publicdest
|
||||
|
||||
echo copy template.js ...
|
||||
echo building app.js
|
||||
echo - copy template.js ...
|
||||
cp $src/make-src/template.js $publicdest/app.js
|
||||
|
||||
for filename in $src/app/*.js; do
|
||||
fname=$(basename "$filename")
|
||||
fname="${fname%.*}"
|
||||
echo adding $fname ...
|
||||
echo - adding $fname ...
|
||||
echo require.register\(\"$fname\", function\(exports, require, module\) { >> $publicdest/app.js
|
||||
cat $filename >> $publicdest/app.js
|
||||
echo >> $publicdest/app.js
|
||||
|
22
libresapi/src/webui-src/make-src/init.sh
Executable file
22
libresapi/src/webui-src/make-src/init.sh
Executable file
@ -0,0 +1,22 @@
|
||||
#!/usr/bin/sh
|
||||
|
||||
# create dummy webfiles at qmake run
|
||||
|
||||
if [ "$1" == "" ];then
|
||||
publicdest=../../webui
|
||||
else
|
||||
publicdest=$1/webui
|
||||
fi
|
||||
|
||||
if [ -d "$publicdest" ]; then
|
||||
echo remove $publicdest
|
||||
rm $publicdest -R
|
||||
fi
|
||||
|
||||
echo create $publicdest
|
||||
mkdir $publicdest
|
||||
|
||||
echo touch $publicdest/app.js, $publicdest/app.css, $publicdest/index.html
|
||||
touch $publicdest/app.js
|
||||
touch $publicdest/app.css
|
||||
touch $publicdest/index.html
|
7
libresapi/src/webui-src/make-src/readme.md
Normal file
7
libresapi/src/webui-src/make-src/readme.md
Normal file
@ -0,0 +1,7 @@
|
||||
this folder contains files needed to create webfiles at compile-time and qmake
|
||||
|
||||
* init.sh creates dummy files at qmake
|
||||
* build.sh creates files at compile time
|
||||
* chat.css compiled version of _chat.sass (.sass should replaced by .scss)
|
||||
* main.css simple template extracted from main.sass
|
||||
* template.js start of compiled app.js, containing additional created content
|
@ -1,36 +0,0 @@
|
||||
REACT_VERSION = 0.13.1
|
||||
|
||||
DISTDIR = ../webfiles
|
||||
JSEXTLIBS = $(DISTDIR)/react.js $(DISTDIR)/JSXTransformer.js
|
||||
JSLIBS = RsXHRConnection.js RsApi.js
|
||||
HTML = index.html
|
||||
JSGUI = gui.jsx
|
||||
CSS = green-black.css
|
||||
|
||||
all: $(DISTDIR) $(JSEXTLIBS) $(addprefix $(DISTDIR)/, $(JSLIBS)) $(addprefix $(DISTDIR)/, $(HTML)) $(addprefix $(DISTDIR)/, $(JSGUI)) $(addprefix $(DISTDIR)/, $(CSS))
|
||||
.PHONY: all
|
||||
|
||||
$(DISTDIR)/livereload: $(DISTDIR) $(JSEXTLIBS) $(addprefix $(DISTDIR)/, $(JSLIBS)) $(addprefix $(DISTDIR)/, $(HTML)) $(addprefix $(DISTDIR)/, $(JSGUI)) $(addprefix $(DISTDIR)/, $(CSS))
|
||||
wget -qO- http://localhost:9090/api/v2/livereload/trigger
|
||||
touch $(DISTDIR)/livereload
|
||||
|
||||
$(DISTDIR)/react.js:
|
||||
cd $(DISTDIR) && wget --no-check-certificate --output-document react.js http://fb.me/react-$(REACT_VERSION).js
|
||||
|
||||
$(DISTDIR)/JSXTransformer.js:
|
||||
cd $(DISTDIR) && wget --no-check-certificate --output-document JSXTransformer.js http://fb.me/JSXTransformer-$(REACT_VERSION).js
|
||||
|
||||
$(addprefix $(DISTDIR)/, $(JSLIBS)): $(DISTDIR)/%: %
|
||||
cp $< $@
|
||||
|
||||
$(addprefix $(DISTDIR)/, $(HTML)): $(DISTDIR)/%: %
|
||||
cp $< $@
|
||||
|
||||
$(addprefix $(DISTDIR)/, $(JSGUI)): $(DISTDIR)/%: %
|
||||
cp $< $@
|
||||
|
||||
$(addprefix $(DISTDIR)/, $(CSS)): $(DISTDIR)/%: %
|
||||
cp $< $@
|
||||
|
||||
$(DISTDIR):
|
||||
mkdir $(DISTDIR)
|
@ -1,142 +0,0 @@
|
||||
var TypesMod = require("./Types.js");
|
||||
var Type = TypesMod.Type;
|
||||
var string = TypesMod.string;
|
||||
var bool = TypesMod.bool;
|
||||
var any = TypesMod.any;
|
||||
|
||||
if(require.main === module)
|
||||
{
|
||||
var RsNodeHttpConnection = require("./RsNodeHttpConnection.js");
|
||||
debugger;
|
||||
var connection = new RsNodeHttpConnection();
|
||||
var RsApi = require("./RsApi.js");
|
||||
var RS = new RsApi(connection);
|
||||
|
||||
var tests = [];
|
||||
var doc = {
|
||||
counter: 0,
|
||||
toc: [],
|
||||
content: [],
|
||||
header: function(h){
|
||||
this.toc.push(h);
|
||||
this.content.push("<a name=\""+this.counter+"\"><h1>"+h+"</h1></a>");
|
||||
this.counter += 1;
|
||||
},
|
||||
paragraph: function(p){
|
||||
this.content.push("<p>"+p+"</p>");
|
||||
},
|
||||
|
||||
};
|
||||
PeersTest(tests, doc);
|
||||
|
||||
var docstr = "<!DOCTYPE html><html><body>";
|
||||
docstr += "<h1>Table of Contents</h1>";
|
||||
docstr += "<ul>";
|
||||
for(var i in doc.toc)
|
||||
{
|
||||
docstr += "<li><a href=\"#"+i+"\">"+doc.toc[i]+"</a></li>";
|
||||
}
|
||||
docstr += "</ul>";
|
||||
for(var i in doc.content)
|
||||
{
|
||||
docstr += doc.content[i];
|
||||
}
|
||||
docstr += "</body></html>";
|
||||
|
||||
var fs = require('fs');
|
||||
fs.writeFile("dist/api_documentation.html", docstr);
|
||||
|
||||
tests.map(function(test){
|
||||
test(RS);
|
||||
});
|
||||
}
|
||||
|
||||
function PeersTest(tests, doc)
|
||||
{
|
||||
// compound types
|
||||
var location = new Type("location",
|
||||
{
|
||||
avatar_address: string,
|
||||
groups: any,
|
||||
is_online: bool,
|
||||
location: string,
|
||||
peer_id: any,
|
||||
});
|
||||
var peer_info = new Type("peer_info",
|
||||
{
|
||||
name: string,
|
||||
pgp_id: any,
|
||||
locations: [location],
|
||||
});
|
||||
var peers_list = new Type("peers_list",[peer_info]);
|
||||
|
||||
doc.header("peers");
|
||||
doc.paragraph("<pre>"+graphToText(peers_list)+"</pre>");
|
||||
|
||||
tests.push(function(RS){
|
||||
console.log("testing peers module...");
|
||||
console.log("expected schema is:")
|
||||
console.log(graphToText(peers_list));
|
||||
RS.request({path: "peers"}, function(resp){
|
||||
//console.log("got response:"+JSON.stringify(resp));
|
||||
var ok = peers_list.check(function(str){console.log(str);}, resp.data, [])
|
||||
if(ok)
|
||||
console.log("success");
|
||||
else
|
||||
console.log("fail");
|
||||
});
|
||||
});
|
||||
|
||||
function graphToText(top_node)
|
||||
{
|
||||
//var dbg = function(str){console.log(str);};
|
||||
var dbg = function(str){};
|
||||
|
||||
dbg("called graphToText with " + top_node);
|
||||
|
||||
var res = "";
|
||||
|
||||
_visit(top_node.getObj(), 0);
|
||||
|
||||
return res;
|
||||
|
||||
function _indent(count)
|
||||
{
|
||||
var str = "";
|
||||
for(var i = 0; i < count; i++)
|
||||
{
|
||||
str = str + " ";
|
||||
}
|
||||
return str;
|
||||
}
|
||||
function _visit(node, indent)
|
||||
{
|
||||
dbg("_visit");
|
||||
if(node instanceof Array)
|
||||
{
|
||||
dbg("is instanceof Array");
|
||||
//res = res + "[";
|
||||
res = res + "array\n";
|
||||
_visit(node[0], indent);
|
||||
//res = res + _indent(indent) + "]\n";
|
||||
}
|
||||
else if(node instanceof Type && node.isLeaf())
|
||||
{
|
||||
dbg("is instanceof Type");
|
||||
res = res + node.getName() + "\n";
|
||||
}
|
||||
else // Object, have to check all children
|
||||
{
|
||||
dbg("is Object");
|
||||
//res = res + "{\n";
|
||||
for(m in node.getObj())
|
||||
{
|
||||
res = res + _indent(indent+1) + m + ": ";
|
||||
_visit(node.getObj()[m], indent+1);
|
||||
}
|
||||
//res = res + _indent(indent) + "}\n";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
A new approach to build a webinterface for RS
|
||||
=============================================
|
||||
|
||||
1. get JSON encoded data from the backend, data contains a state token
|
||||
2. render data with react.js
|
||||
3. ask the backend if the state token from step 1 expired. If yes, then start again with step 1.
|
||||
|
||||
Steps 1. and 3. are common for most things, only Step 2. differs. This allows to re-use code for steps 1. and 3.
|
||||
|
||||
BUILD / INSTALLATION
|
||||
------------
|
||||
|
||||
- run (requires wget, use MinGW shell on Windows)
|
||||
make
|
||||
- all output files are now in libresapi/src/webfiles
|
||||
- use the --webinterface 9090 command line parameter to enable webui in retroshare-nogui
|
||||
- set the --docroot parameter of retroshare-nogui to point to the "libresapi/src/webfiles" directory
|
||||
(or symlink from /usr/share/RetroShare06/webui on Linux, ./webui on Windows)
|
||||
- retroshare-gui does not have a --docroot parameter. Use symlinks then.
|
||||
|
||||
DEVELOPMENT
|
||||
-----------
|
||||
|
||||
- Ubuntu: install nodejs package
|
||||
sudo apt-get install nodejs
|
||||
- Windows: download and install nodejs from http://nodejs.org
|
||||
- Download development tools with the nodejs package manager (short npm)
|
||||
npm install
|
||||
- run Retroshare with webinterface on port 9090
|
||||
- during development, run this command (use MinGW shell on Windows)
|
||||
while true; do make ../webfiles/livereload --silent; sleep 1; done
|
||||
- the command will copy the source files to libresapi/src/webfiles if they change
|
||||
- it will trigger livereload at http://localhost:9090/api/v2/livereload/trigger
|
||||
|
||||
API DOCUMENTATION
|
||||
-----------------
|
||||
|
||||
- run
|
||||
node PeersTest.js
|
||||
- this will print the expected schema of the api output, and it will try to test it with real data
|
||||
- run retroshare-nogui with webinterface enabled on port 9090, to test if the real output of the api matches the expected schema
|
||||
|
||||
CONTRIBUTE
|
||||
----------
|
||||
|
||||
- if you are a web developer or want to become one
|
||||
get in contact!
|
||||
- lots of work to do, i need you!
|
@ -1,109 +0,0 @@
|
||||
/**
|
||||
* JS Api for Retroshare
|
||||
* @constructor
|
||||
* @param {object} connection - an object which implements a request() function.
|
||||
* The request function should take two parameters: an object to be send as request and a callback.
|
||||
* The callback should get called with an response object on success.
|
||||
*/
|
||||
function RsApi(connection)
|
||||
{
|
||||
var runnign = true;
|
||||
/**
|
||||
* Send a request to the server
|
||||
* @param req - the request so send
|
||||
* @param {Function} cb - callback function which takes the response as parameter
|
||||
*/
|
||||
this.request = function(req, cb)
|
||||
{
|
||||
connection.request(req, cb);
|
||||
};
|
||||
var tokenlisteners = [];
|
||||
/**
|
||||
* Register a callback to be called when the state token expired.
|
||||
* @param {Function} listener - the callback function, which does not take arguments
|
||||
* @param token - the state token to listen for
|
||||
*/
|
||||
this.register_token_listener = function(listener, token)
|
||||
{
|
||||
tokenlisteners.push({listener:listener, token:token});
|
||||
};
|
||||
/**
|
||||
* Unregister a previously registered callback.
|
||||
*/
|
||||
this.unregister_token_listener = function(listener) // no token as parameter, assuming unregister from all listening tokens
|
||||
{
|
||||
var to_delete = [];
|
||||
for(var i=0; i<tokenlisteners.length; i++){
|
||||
if(tokenlisteners[i].listener === listener){
|
||||
to_delete.push(i);
|
||||
}
|
||||
}
|
||||
for(var i=0; i<to_delete.length; i++){
|
||||
// copy the last element to the current index
|
||||
var index = to_delete[i];
|
||||
tokenlisteners[index] = tokenlisteners[tokenlisteners.length-1];
|
||||
// remove last element
|
||||
tokenlisteners.pop();
|
||||
}
|
||||
};
|
||||
/**
|
||||
* start polling for state changes
|
||||
*/
|
||||
this.start = function(){
|
||||
running = true;
|
||||
setTimeout(tick, TICK_INTERVAL);
|
||||
}
|
||||
/**
|
||||
* stop polling for state changes
|
||||
*/
|
||||
this.stop = function(){
|
||||
running = false;
|
||||
}
|
||||
|
||||
// ************** interal stuff **************
|
||||
var TICK_INTERVAL = 3000;
|
||||
function received_tokenstates(resp)
|
||||
{
|
||||
if(resp.data){
|
||||
for(var i=0; i<resp.data.length; i++){
|
||||
var token = resp.data[i];
|
||||
// search the listener for this token
|
||||
for(var j=0; j<tokenlisteners.length; j++){
|
||||
if(tokenlisteners[j].token === token){
|
||||
// call the listener
|
||||
tokenlisteners[j].listener();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// schedule new update
|
||||
if(running)
|
||||
setTimeout(tick, TICK_INTERVAL);
|
||||
};
|
||||
function received_error()
|
||||
{
|
||||
// try again, maybe want a better logic later
|
||||
if(running)
|
||||
setTimeout(tick, TICK_INTERVAL);
|
||||
};
|
||||
function tick()
|
||||
{
|
||||
var data = [];
|
||||
// maybe cache the token list?
|
||||
// profiler will tell us if we should
|
||||
for(var i=0; i<tokenlisteners.length; i++){
|
||||
data.push(tokenlisteners[i].token);
|
||||
}
|
||||
connection.request({
|
||||
path: "statetokenservice",
|
||||
data: data,
|
||||
}, received_tokenstates, received_error);
|
||||
};
|
||||
};
|
||||
|
||||
// with this trick, we should be able to run in browser or nodejs
|
||||
if(typeof window === 'undefined')
|
||||
{
|
||||
// we are running in nodejs, so have to add to export
|
||||
module.exports = RsApi;
|
||||
}
|
@ -1,51 +0,0 @@
|
||||
var http = require('http');
|
||||
|
||||
/**
|
||||
* Connection to the RS backend using http for running under node.js
|
||||
* Mainly for testing, but could also use it for general purpose scripting.
|
||||
* @constructor
|
||||
*/
|
||||
module.exports = function()
|
||||
{
|
||||
var server_hostname = "localhost";
|
||||
var server_port = "9090";
|
||||
var api_root_path = "/api/v2/";
|
||||
|
||||
this.request = function(request, callback)
|
||||
{
|
||||
var data;
|
||||
if(request.data)
|
||||
data = JSON.stringify(request.data);
|
||||
else
|
||||
data = "";
|
||||
|
||||
// NODEJS specific
|
||||
var req = http.request({
|
||||
host: server_hostname,
|
||||
port: server_port,
|
||||
path: api_root_path + request.path,
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
"Content-Length": data.length, // content length is required, else Wt will not provide the data (maybe WT does not like chunked encoding?)
|
||||
}
|
||||
//method: "POST",
|
||||
}, function(response){
|
||||
var databuffer = [];
|
||||
response.on("data", function(chunk){
|
||||
//console.log("got some data");
|
||||
databuffer = databuffer + chunk;
|
||||
})
|
||||
response.on("end", function(){
|
||||
//console.log("finished receiving data");
|
||||
//console.log("data:"+databuffer);
|
||||
callback(JSON.parse(databuffer));
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
//console.log("uploading data:");
|
||||
//console.log(data);
|
||||
req.write(data);
|
||||
req.end();
|
||||
}
|
||||
}
|
@ -1,123 +0,0 @@
|
||||
/**
|
||||
* Connection to the RS backend using XHR
|
||||
* (could add other connections later, for example WebSockets)
|
||||
* @constructor
|
||||
*/
|
||||
function RsXHRConnection(server_hostname, server_port)
|
||||
{
|
||||
var debug;
|
||||
//debug = function(str){console.log(str);};
|
||||
debug = function(str){};
|
||||
|
||||
//server_hostname = "localhost";
|
||||
//server_port = "9090";
|
||||
var api_root_path = "/api/v2/";
|
||||
|
||||
var status_listeners = [];
|
||||
|
||||
function notify_status(status)
|
||||
{
|
||||
for(var i = 0; i < status_listeners.length; i++)
|
||||
{
|
||||
status_listeners[i](status);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback to be called when the state of the connection changes.
|
||||
* @param {function} cb - callback which receives a single argument. The arguments value is "connected" or "not_connected".
|
||||
*/
|
||||
this.register_status_listener = function(cb)
|
||||
{
|
||||
status_listeners.push(cb);
|
||||
};
|
||||
|
||||
/**
|
||||
* Unregister a status callback function.
|
||||
* @param {function} cb - a privously registered callback function
|
||||
*/
|
||||
this.unregister_status_listener = function(cb)
|
||||
{
|
||||
var to_delete = [];
|
||||
for(var i = 0; i < status_listeners.length; i++)
|
||||
{
|
||||
if(status_listeners[i] === cb){
|
||||
to_delete.push(i);
|
||||
}
|
||||
}
|
||||
for(var i = 0; i < to_delete.length; i++)
|
||||
{
|
||||
// copy the last element to the current index
|
||||
var index = to_delete[i];
|
||||
status_listeners[i] = status_listeners[status_listeners.length-1];
|
||||
// remove the last element
|
||||
status_listeners.pop();
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a request to the backend
|
||||
* automatically encodes the request as JSON before sending it to the server
|
||||
* @param {object} req - the request to send to the server
|
||||
* @param {function} cb - callback function to be called to handle the response. The callback takes one object as parameter. Can be left undefined.
|
||||
* @param {function} err_cb - callback function to signal a failed request. Can be undefined.
|
||||
*/
|
||||
this.request = function(req, cb, err_cb)
|
||||
{
|
||||
//var xhr = window.XMLHttpRequest ? new XMLHttpRequest() : new ActiveXObject("Microsoft.XMLHTTP");
|
||||
// TODO: window is not available in QML
|
||||
var xhr = new XMLHttpRequest();
|
||||
xhr.onreadystatechange = function(){
|
||||
//console.log("onreadystatechanged state"+xhr.readyState);
|
||||
// TODO: figure out how to catch errors like connection refused
|
||||
// maybe want to have to set a state variable like ok=false
|
||||
// the gui could then display: "no connection to server"
|
||||
if (xhr.readyState === 4) {
|
||||
if(xhr.status !== 200)
|
||||
{
|
||||
console.log("RsXHRConnection: request failed with status: "+xhr.status);
|
||||
console.log("request was:");
|
||||
console.log(req);
|
||||
notify_status("not_connected");
|
||||
if(err_cb !== undefined)
|
||||
err_cb();
|
||||
return;
|
||||
}
|
||||
// received response
|
||||
notify_status("connected");
|
||||
debug("RsXHRConnection received response:");
|
||||
debug(xhr.responseText);
|
||||
if(false)//if(xhr.responseText === "")
|
||||
{
|
||||
debug("Warning: response is empty");
|
||||
return;
|
||||
}
|
||||
try
|
||||
{
|
||||
var respObj = JSON.parse(xhr.responseText);
|
||||
}
|
||||
catch(e)
|
||||
{
|
||||
debug("Exception during response handling: "+e);
|
||||
}
|
||||
if(cb === undefined)
|
||||
debug("No callback function specified");
|
||||
else
|
||||
cb(respObj);
|
||||
}
|
||||
}
|
||||
// post is required for sending data
|
||||
var method;
|
||||
if(req.data){
|
||||
method = "POST";
|
||||
} else {
|
||||
method = "GET";
|
||||
}
|
||||
xhr.open(method, "http://"+server_hostname+":"+server_port+api_root_path+req.path);
|
||||
var data = JSON.stringify(req.data);
|
||||
debug("RsXHRConnection sending data:");
|
||||
debug(data);
|
||||
xhr.setRequestHeader('Content-Type', 'application/json');
|
||||
xhr.send(data);
|
||||
};
|
||||
};
|
@ -1,146 +0,0 @@
|
||||
/**
|
||||
* Construct a new type from an array, object or function.
|
||||
* Use instances of this class to build a schema graph.
|
||||
* The schema graph must not contain data other than arrays and instances of this class.
|
||||
* Use the check function to check if arbitrary JS objects matches the schema.
|
||||
* @constructor
|
||||
* @param {String} name - name for the new type
|
||||
* @param obj - array, object or function
|
||||
* array: array should contain one instance of class "Type"
|
||||
* object: object members can be arrays or instances of class "Type".
|
||||
* Can also have child objects, but the leaf members have to be instances of class "Type"
|
||||
* function: a function which takes three parameters: log, other, stack
|
||||
* must return true if other matches the type, can report errors using the function passed in log.
|
||||
*/
|
||||
function Type(name, obj)
|
||||
{
|
||||
//var dbg = function(str){console.log(str);};
|
||||
var dbg = function(str){};
|
||||
|
||||
this.getName = function(){
|
||||
return name;
|
||||
}
|
||||
this.isLeaf = function(){
|
||||
return typeof(obj) === "function";
|
||||
}
|
||||
this.getObj = function(){
|
||||
return obj;
|
||||
}
|
||||
this.check = function(log, other, stack)
|
||||
{
|
||||
if(typeof(obj) === "object")
|
||||
{
|
||||
stack.push("<"+name+">");
|
||||
var ok = _check(log, obj, other, stack);
|
||||
stack.pop;
|
||||
return ok;
|
||||
}
|
||||
if(typeof(obj) === "function")
|
||||
return obj(log, other, stack);
|
||||
log("FATAL Error: wrong usage of new Type(), second parameter should be an object or checker function");
|
||||
return false;
|
||||
}
|
||||
function _check(log, ref, other, stack)
|
||||
{
|
||||
dbg("_check");
|
||||
dbg("ref=" + ref);
|
||||
dbg("other=" + other);
|
||||
dbg("stack=[" + stack + "]");
|
||||
if(ref instanceof Array)
|
||||
{
|
||||
dbg("is instanceof Array");
|
||||
if(other instanceof Array)
|
||||
{
|
||||
if(other.length > 0)
|
||||
{
|
||||
return _check(log, ref[0], other[0], stack);
|
||||
}
|
||||
else
|
||||
{
|
||||
log("Warning: can't check array of length 0 in ["+stack+"]");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
log("Error: not an Array ["+stack+"]");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(ref instanceof Type)
|
||||
{
|
||||
dbg("is instanceof Type");
|
||||
return ref.check(log, other, stack);
|
||||
}
|
||||
else // Object, have to check all children
|
||||
{
|
||||
dbg("is Object");
|
||||
var ok = true;
|
||||
for(m in ref)
|
||||
{
|
||||
if(m in other)
|
||||
{
|
||||
stack.push(m);
|
||||
ok = ok && _check(log, ref[m], other[m], stack);
|
||||
stack.pop();
|
||||
}
|
||||
else
|
||||
{
|
||||
log("Error: missing member \""+m+"\" in ["+stack+"]");
|
||||
ok = false;
|
||||
}
|
||||
}
|
||||
// check for additionally undocumented members
|
||||
for(m in other)
|
||||
{
|
||||
if(!(m in ref))
|
||||
{
|
||||
log("Warning: found additional member \""+m+"\" in ["+stack+"]");
|
||||
}
|
||||
}
|
||||
return ok;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
// basic data types
|
||||
// - string
|
||||
// - bool
|
||||
// - any (placeholder for unknown type)
|
||||
|
||||
var string = new Type("string",
|
||||
function(log, other, stack)
|
||||
{
|
||||
if(typeof(other) !== "string")
|
||||
{
|
||||
log("Error: not a string ["+stack+"]");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
);
|
||||
var bool = new Type("bool",
|
||||
function(log, other, stack)
|
||||
{
|
||||
if(typeof(other) !== "boolean")
|
||||
{
|
||||
log("Error: not a bool ["+stack+"]");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return true;
|
||||
}
|
||||
);
|
||||
var any = new Type("any",
|
||||
function(log, other, stack)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
);
|
||||
|
||||
exports.Type = Type;
|
||||
exports.string = string;
|
||||
exports.bool = bool;
|
||||
exports.any = any;
|
@ -1,134 +0,0 @@
|
||||
body {
|
||||
background-color: black;
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
margin: 0em;
|
||||
/*padding: 1.5em;*/
|
||||
padding: 2mm;
|
||||
font-size: 1.1em;
|
||||
}
|
||||
|
||||
#overlay{
|
||||
z-index: 10;
|
||||
position: fixed;
|
||||
top:0;
|
||||
left:0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: rgba(0,0,0,0.8);
|
||||
}
|
||||
|
||||
.paddingbox{
|
||||
padding:2mm;
|
||||
}
|
||||
|
||||
.nav{
|
||||
list-style-type: none;
|
||||
padding: 0em;
|
||||
margin: 0em;
|
||||
}
|
||||
|
||||
.nav li{
|
||||
display: inline;
|
||||
padding: 0.1em;
|
||||
margin-right: 1em;
|
||||
border-width: 0.1em;
|
||||
border-color: blue;
|
||||
border-bottom-style: solid;
|
||||
cursor: pointer;
|
||||
}
|
||||
td{
|
||||
padding: 0.3em;
|
||||
border-style: solid;
|
||||
border-width: 0.1em;
|
||||
border-color: lime;
|
||||
}
|
||||
.btn{
|
||||
border-style: solid;
|
||||
border-color: lime;
|
||||
border-width: 0.1em;
|
||||
cursor: pointer;
|
||||
padding: 0.1em;
|
||||
}
|
||||
|
||||
.btn2, .box{
|
||||
border-style: solid;
|
||||
/*border-color: lime;*/
|
||||
border-color: limeGreen;
|
||||
/*border-width: 1px;*/
|
||||
border-radius: 3mm;
|
||||
padding: 2mm;
|
||||
font-size: 10mm;
|
||||
cursor: pointer;
|
||||
margin-bottom: 2mm;
|
||||
}
|
||||
.btn2:hover{
|
||||
background-color: midnightblue;
|
||||
}
|
||||
|
||||
.filelink{
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
input, textarea{
|
||||
color: lime;
|
||||
font-family: monospace;
|
||||
background-color: black;
|
||||
border-color: lime;
|
||||
font-size: 10mm;
|
||||
border-radius: 3mm;
|
||||
border-width: 1mm;
|
||||
padding: 2mm;
|
||||
margin-bottom: 2mm;
|
||||
margin-right: 2mm;
|
||||
|
||||
/* make the button the whole screen width */
|
||||
width: 100%;
|
||||
/* make the text input fit small screens*/
|
||||
box-sizing: border-box;
|
||||
}
|
||||
input:hover{
|
||||
background-color: midnightblue;
|
||||
}
|
||||
|
||||
.checkbox {
|
||||
width: auto;
|
||||
}
|
||||
|
||||
.flexbox{
|
||||
display: -webkit-box; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
display: -moz-box; /* OLD - Firefox 19- (buggy but mostly works) */
|
||||
display: -ms-flexbox; /* TWEENER - IE 10 */
|
||||
display: -webkit-flex; /* NEW - Chrome */
|
||||
display: flex; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
}
|
||||
|
||||
.flexwidemember{
|
||||
-webkit-box-flex: 1; /* OLD - iOS 6-, Safari 3.1-6 */
|
||||
-moz-box-flex: 1; /* OLD - Firefox 19- */
|
||||
width: 20%; /* For old syntax, otherwise collapses. */
|
||||
-webkit-flex: 1; /* Chrome */
|
||||
-ms-flex: 1; /* IE 10 */
|
||||
flex: 1; /* NEW, Spec - Opera 12.1, Firefox 20+ */
|
||||
}
|
||||
|
||||
#logo_splash{
|
||||
-webkit-animation-fill-mode: forwards; /* Chrome, Safari, Opera */
|
||||
animation-fill-mode: forwards;
|
||||
-webkit-animation-name: logo_splash; /* Chrome, Safari, Opera */
|
||||
-webkit-animation-duration: 3s; /* Chrome, Safari, Opera */
|
||||
animation-name: logo_splash;
|
||||
animation-duration: 3s;
|
||||
text-align: center;
|
||||
}
|
||||
/* Chrome, Safari, Opera */
|
||||
@-webkit-keyframes logo_splash {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
||||
|
||||
/* Standard syntax */
|
||||
@keyframes logo_splash {
|
||||
from {opacity: 0;}
|
||||
to {opacity: 1;}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
@ -1,29 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>New webinterface for Retroshare</title>
|
||||
|
||||
<script src="RsXHRConnection.js"></script>
|
||||
<script src="RsApi.js"></script>
|
||||
|
||||
<!-- it seems to work more reliable, if the jsx file is loaded before react -->
|
||||
<script type="text/jsx" src="gui.jsx"></script>
|
||||
|
||||
<script src="react.js"></script>
|
||||
<script src="JSXTransformer.js"></script>
|
||||
|
||||
<link href="green-black.css" rel="stylesheet">
|
||||
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="initial-scale=1">
|
||||
</head>
|
||||
<body>
|
||||
<script>
|
||||
document.write("<p>loading lots of stuff...</p>");
|
||||
</script>
|
||||
<p><noscript>The Retroshare web interface requires JavaScript. Please enable JavaScript in your browser.</noscript></p>
|
||||
<!--<div id="logo_splash">
|
||||
<img src="img/logo_splash.png"></img>
|
||||
</div>-->
|
||||
</body>
|
||||
</html>
|
@ -1,10 +0,0 @@
|
||||
{
|
||||
"name": "rswebui",
|
||||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
},
|
||||
"devDependencies": {
|
||||
},
|
||||
"scripts": {
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user