mirror of https://github.com/xwiki-labs/cryptpad
Server app prototype to display listed servers from accounts.cryptpad.fr
This commit is contained in:
parent
825820f6bf
commit
ba0a39f00c
|
@ -50,7 +50,8 @@
|
||||||
"jszip": "Stuk/jszip#^3.1.5",
|
"jszip": "Stuk/jszip#^3.1.5",
|
||||||
"requirejs-plugins": "^1.0.3",
|
"requirejs-plugins": "^1.0.3",
|
||||||
"dragula.js": "3.7.2",
|
"dragula.js": "3.7.2",
|
||||||
"MathJax": "3.0.5"
|
"MathJax": "3.0.5",
|
||||||
|
"datatables": "^1.10.21"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"bootstrap": "^v4.0.0",
|
"bootstrap": "^v4.0.0",
|
||||||
|
|
|
@ -0,0 +1,306 @@
|
||||||
|
@import (reference) '../../customize/src/less2/include/framework.less';
|
||||||
|
@import (reference) '../../customize/src/less2/include/sidebar-layout.less';
|
||||||
|
@import (reference) '../../customize/src/less2/include/avatar.less';
|
||||||
|
@import (reference) "../../customize/src/less2/include/limit-bar.less";
|
||||||
|
|
||||||
|
&.cp-app-accounts {
|
||||||
|
.limit-bar_main();
|
||||||
|
|
||||||
|
.framework_min_main(
|
||||||
|
@bg-color: @colortheme_admin-bg,
|
||||||
|
@warn-color: @colortheme_admin-warn,
|
||||||
|
@color: @colortheme_admin-color
|
||||||
|
);
|
||||||
|
.sidebar-layout_main();
|
||||||
|
|
||||||
|
.cp-hidden {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
|
||||||
|
@plan_basic: #DDEFFF;
|
||||||
|
@plan_pro: #E4FFDD;
|
||||||
|
@plan_power: #F6DDFF;
|
||||||
|
@alert-neutral: #EFEFEF;
|
||||||
|
@active-color: #AFFDC2;
|
||||||
|
@inactive-color: #FFD4D4;
|
||||||
|
|
||||||
|
|
||||||
|
#cp-sidebarlayout-rightside {
|
||||||
|
color: @cryptpad_text_col !important;
|
||||||
|
.alert {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-accounts-subscribe-anon, .cp-accounts-subscribe-form, .cp-accounts-subscribe-admin {
|
||||||
|
max-width: 940px;
|
||||||
|
margin: 10px auto 20px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-accounts-donate {
|
||||||
|
max-width: 650px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-limit-container {
|
||||||
|
.cp-limit-buttons {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-accounts-mysubs-addplan {
|
||||||
|
max-width: 830px;
|
||||||
|
#gift label {
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-top: 10px;
|
||||||
|
font-weight: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-accounts-subscribe-form {
|
||||||
|
ul {
|
||||||
|
list-style-position: outside;
|
||||||
|
padding-left: 10px;
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
.subscription-info {
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
.subscription-terms {
|
||||||
|
font-size: 14px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-plan {
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.choose-plan {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
@media (max-width: @browser_media-medium-screen) {
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plan {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
width: 300px;
|
||||||
|
min-height: 350px;
|
||||||
|
&:not(:last-child) {
|
||||||
|
margin-right: 20px;
|
||||||
|
@media (max-width: @browser_media-medium-screen) {
|
||||||
|
margin-right: 0;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plan-header-text {
|
||||||
|
text-transform: capitalize;
|
||||||
|
font-size: 30px;
|
||||||
|
}
|
||||||
|
.plan-price-area {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
.plan-price-text {
|
||||||
|
font-size: 60px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ul.plan-details {
|
||||||
|
flex: 1;
|
||||||
|
padding-right: 10px;
|
||||||
|
margin-left: 15px;
|
||||||
|
}
|
||||||
|
.buttons {
|
||||||
|
margin: 10px;
|
||||||
|
button {
|
||||||
|
width: 100%;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.alert {
|
||||||
|
margin: 0 10px;
|
||||||
|
background: white;
|
||||||
|
border: none;
|
||||||
|
color: inherit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.plan-basic {
|
||||||
|
background-color: @plan_basic;
|
||||||
|
}
|
||||||
|
.plan-pro {
|
||||||
|
background-color: @plan_pro;
|
||||||
|
}
|
||||||
|
.plan-power {
|
||||||
|
background-color: @plan_power;
|
||||||
|
}
|
||||||
|
.link-to-stripe {
|
||||||
|
margin-top: 30px;
|
||||||
|
margin-bottom: 10px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.info-bottom {
|
||||||
|
font-size: 14px;
|
||||||
|
p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-accounts-mysubs-data {
|
||||||
|
.active-subs {
|
||||||
|
.subscription {
|
||||||
|
min-height: 300px;
|
||||||
|
width: 500px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.alert {
|
||||||
|
background: white;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row;
|
||||||
|
color: inherit;
|
||||||
|
border: none;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 14px;
|
||||||
|
button {
|
||||||
|
flex-shrink: 0;
|
||||||
|
margin-top: 0px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.users {
|
||||||
|
display: flex;
|
||||||
|
width: 100%;
|
||||||
|
& > span {
|
||||||
|
width: 180px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subscription-container {
|
||||||
|
.subscription {
|
||||||
|
min-height: 175px;
|
||||||
|
width: 300px;
|
||||||
|
&:not(.details) {
|
||||||
|
.creation, .notes, .expired, .cancel, .close-d, .storage {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.details {
|
||||||
|
.open-d {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.subscription-container, .active-subs {
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
align-items: baseline;
|
||||||
|
|
||||||
|
.subscription {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: baseline;
|
||||||
|
justify-content: space-between;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
margin-right: 20px;
|
||||||
|
padding: 10px;
|
||||||
|
background-color: #eee;
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
& > span {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
button.open-details {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.open-d, .close-d {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
i {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.billing, .shared, .expired {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
width: 100%;
|
||||||
|
button {
|
||||||
|
margin-right: 0 !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.billing {
|
||||||
|
.text {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.plan {
|
||||||
|
font-size: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active, .inactive {
|
||||||
|
position: absolute;
|
||||||
|
padding: 0 5px;
|
||||||
|
right: 5px;
|
||||||
|
top: 5px;
|
||||||
|
}
|
||||||
|
.inactive {
|
||||||
|
background-color: @inactive-color;
|
||||||
|
}
|
||||||
|
.active {
|
||||||
|
background-color: @active-color;
|
||||||
|
}
|
||||||
|
|
||||||
|
.benificiary-data {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
background: white;
|
||||||
|
padding: 5px;
|
||||||
|
.cp-avatar {
|
||||||
|
margin-right: 10px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
.name {
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.notes {
|
||||||
|
flex: 1;
|
||||||
|
max-height: 60px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.avatar_main(30px);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-accounts-mysubs-addplan {
|
||||||
|
.avatar_main(30px);
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-accounts-subscribe-admin {
|
||||||
|
div.admin {
|
||||||
|
margin-bottom: 150px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-accounts-admin {
|
||||||
|
input[type="text"] {
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
@ -0,0 +1,34 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html class="cp-app-noscroll">
|
||||||
|
<head>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<script async data-bootload="/servers/app/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
<style>
|
||||||
|
.loading-hidden { display: none; }
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div id="cp-toolbar" class="cp-toolbar-container"></div>
|
||||||
|
<div id="cp-sidebarlayout-container" style="display: none;">
|
||||||
|
<div id="cp-sidebarlayout-rightside">
|
||||||
|
<h1 id="cp-servers-title">CryptPad Server List</h1>
|
||||||
|
<p id="cp-servers-desc">
|
||||||
|
Lorem ipso sum. Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.Lorem ipso sum.
|
||||||
|
</p>
|
||||||
|
<table id="servers" class="display" style="width:100%">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>URL</th>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Description</th>
|
||||||
|
<th>Version</th>
|
||||||
|
<th>Registered Users</th>
|
||||||
|
<th>Max connections</th>
|
||||||
|
<th>First Connection</th>
|
||||||
|
<th>Last Connection</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|
|
@ -0,0 +1,56 @@
|
||||||
|
// Load #1, load as little as possible because we are in a race to get the loading screen up.
|
||||||
|
define([
|
||||||
|
'jquery',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
'/customize/application_config.js',
|
||||||
|
'/common/dom-ready.js',
|
||||||
|
'/common/common-interface.js',
|
||||||
|
'/common/sframe-common.js',
|
||||||
|
'/common/toolbar.js',
|
||||||
|
'/bower_components/datatables/media/js/jquery.dataTables.min.js',
|
||||||
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
|
'css!/bower_components/datatables/media/css/dataTables.bootstrap4.min.css',
|
||||||
|
'css!/bower_components/datatables/media/css/jquery.dataTables.min.css',
|
||||||
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
|
'css!/servers/app/servers.css',
|
||||||
|
'less!/servers/app/app-servers.less',
|
||||||
|
], function ($, nThen, ApiConfig, DomReady, UI, SFCommon, Toolbar, DataTable) {
|
||||||
|
var APP = {}
|
||||||
|
|
||||||
|
// Loaded in load #2
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
DomReady.onReady(waitFor());
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
$(waitFor(UI.addLoadingScreen));
|
||||||
|
SFCommon.create(waitFor(function (c) { APP.common = common = c; }));
|
||||||
|
}).nThen(function (/*waitFor*/) {
|
||||||
|
APP.$container = $('#cp-sidebarlayout-container');
|
||||||
|
APP.$toolbar = $('#cp-toolbar');
|
||||||
|
var displayed = ['pageTitle'];
|
||||||
|
var configTb = {
|
||||||
|
displayed: displayed,
|
||||||
|
$container: APP.$toolbar,
|
||||||
|
sfCommon: common,
|
||||||
|
pageTitle: "CryptPad Servers",
|
||||||
|
metadataMgr: common.getMetadataMgr(),
|
||||||
|
};
|
||||||
|
APP.toolbar = Toolbar.create(configTb);
|
||||||
|
APP.toolbar.$rightside.hide();
|
||||||
|
APP.$container.show();
|
||||||
|
UI.removeLoadingScreen();
|
||||||
|
|
||||||
|
$('#servers').DataTable( {
|
||||||
|
"ajax": ApiConfig.accounts_api + "/api/servers",
|
||||||
|
"columns" : [
|
||||||
|
{ "data" : "url" },
|
||||||
|
{ "data" : "name" },
|
||||||
|
{ "data" : "desc" },
|
||||||
|
{ "data" : "version" },
|
||||||
|
{ "data" : "registeredUsers" },
|
||||||
|
{ "data" : "maxOpenUniqueWebSockets" },
|
||||||
|
{ "data" : "firstConnection" },
|
||||||
|
{ "data" : "lastConnection" }
|
||||||
|
]
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,65 @@
|
||||||
|
// Load #1, load as little as possible because we are in a race to get the loading screen up.
|
||||||
|
define([
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
'/api/config',
|
||||||
|
'/common/dom-ready.js',
|
||||||
|
'/common/requireconfig.js',
|
||||||
|
'/common/sframe-common-outer.js',
|
||||||
|
], function (nThen, ApiConfig, DomReady, RequireConfig, SFCommonO) {
|
||||||
|
var requireConfig = RequireConfig();
|
||||||
|
|
||||||
|
// Loaded in load #2
|
||||||
|
nThen(function (waitFor) {
|
||||||
|
DomReady.onReady(waitFor());
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
var req = {
|
||||||
|
cfg: requireConfig,
|
||||||
|
req: [ '/common/loading.js' ],
|
||||||
|
pfx: window.location.origin
|
||||||
|
};
|
||||||
|
window.rc = requireConfig;
|
||||||
|
window.apiconf = ApiConfig;
|
||||||
|
document.getElementById('sbox-iframe').setAttribute('src',
|
||||||
|
ApiConfig.httpSafeOrigin + '/servers/app/inner.html?' + requireConfig.urlArgs +
|
||||||
|
'#' + encodeURIComponent(JSON.stringify(req)));
|
||||||
|
|
||||||
|
// This is a cheap trick to avoid loading sframe-channel in parallel with the
|
||||||
|
// loading screen setup.
|
||||||
|
var done = waitFor();
|
||||||
|
var onMsg = function (msg) {
|
||||||
|
var data = JSON.parse(msg.data);
|
||||||
|
if (data.q !== 'READY') { return; }
|
||||||
|
window.removeEventListener('message', onMsg);
|
||||||
|
var _done = done;
|
||||||
|
done = function () { };
|
||||||
|
_done();
|
||||||
|
};
|
||||||
|
window.addEventListener('message', onMsg);
|
||||||
|
}).nThen(function (/*waitFor*/) {
|
||||||
|
var addRpc = function (sframeChan, Cryptpad/*, Utils*/) {
|
||||||
|
sframeChan.on('ACCOUNTS_GET_KEYS', function (data, cb) {
|
||||||
|
Cryptpad.getUserObject(null, function (obj) {
|
||||||
|
cb(obj);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
sframeChan.on('Q_UPDATE_LIMIT', function (data, cb) {
|
||||||
|
Cryptpad.updatePinLimit(function (e) {
|
||||||
|
cb({error: e});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
var category;
|
||||||
|
if (window.location.hash) {
|
||||||
|
category = window.location.hash.slice(1);
|
||||||
|
window.location.hash = '';
|
||||||
|
}
|
||||||
|
var addData = function (obj) {
|
||||||
|
if (category) { obj.category = category; }
|
||||||
|
};
|
||||||
|
SFCommonO.start({
|
||||||
|
noRealtime: true,
|
||||||
|
addRpc: addRpc,
|
||||||
|
addData: addData
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,192 @@
|
||||||
|
(function () {
|
||||||
|
var LS_LANG = "CRYPTPAD_LANG";
|
||||||
|
|
||||||
|
// add your module to this map so it gets used
|
||||||
|
var map = {
|
||||||
|
'de': 'Deutsch',
|
||||||
|
'es': 'Español',
|
||||||
|
'fr': 'Français',
|
||||||
|
//'it': 'Italiano',
|
||||||
|
};
|
||||||
|
|
||||||
|
var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); };
|
||||||
|
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage; };
|
||||||
|
var getLanguage = function () {
|
||||||
|
if (window.cryptpadLanguage) { return window.cryptpadLanguage; }
|
||||||
|
if (getStoredLanguage()) { return getStoredLanguage(); }
|
||||||
|
var l = getBrowserLanguage() || '';
|
||||||
|
if (Object.keys(map).indexOf(l) !== -1) {
|
||||||
|
return l;
|
||||||
|
}
|
||||||
|
// Edge returns 'fr-FR' --> transform it to 'fr' and check again
|
||||||
|
return Object.keys(map).indexOf(l.split('-')[0]) !== -1 ? l.split('-')[0] : 'en';
|
||||||
|
};
|
||||||
|
var language = getLanguage();
|
||||||
|
|
||||||
|
var req = ['jquery', 'json!/accounts/resources/translations/messages.json'];
|
||||||
|
if (language && map[language]) { req.push('json!/accounts/resources/translations/messages.' + language + '.json'); }
|
||||||
|
|
||||||
|
define(req, function($, Default, Language) {
|
||||||
|
|
||||||
|
var externalMap = JSON.parse(JSON.stringify(map));
|
||||||
|
|
||||||
|
map.en = 'English';
|
||||||
|
var defaultLanguage = 'en';
|
||||||
|
|
||||||
|
var messages;
|
||||||
|
|
||||||
|
if (!Language || !language || language === defaultLanguage || language === 'default' || !map[language]) {
|
||||||
|
messages = Default;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Add the translated keys to the returned object
|
||||||
|
messages = $.extend(true, {}, Default, Language);
|
||||||
|
}
|
||||||
|
|
||||||
|
messages._languages = map;
|
||||||
|
|
||||||
|
// TODO
|
||||||
|
messages._checkTranslationState = function (cb) {
|
||||||
|
if (typeof(cb) !== "function") { return; }
|
||||||
|
var allMissing = [];
|
||||||
|
var reqs = [];
|
||||||
|
Object.keys(externalMap).forEach(function (code) {
|
||||||
|
reqs.push('/resources/translations/messages.' + code + '.js');
|
||||||
|
});
|
||||||
|
require(reqs, function () {
|
||||||
|
var langs = arguments;
|
||||||
|
Object.keys(externalMap).forEach(function (code, i) {
|
||||||
|
var translation = langs[i];
|
||||||
|
var missing = [];
|
||||||
|
var checkInObject = function (ref, translated, path) {
|
||||||
|
var updated = {};
|
||||||
|
Object.keys(ref).forEach(function (k) {
|
||||||
|
if (/^updated_[0-9]+_/.test(k) && !translated[k]) {
|
||||||
|
var key = k.split('_').slice(2).join('_');
|
||||||
|
// Make sure we don't already have an update for that key. It should not happen
|
||||||
|
// but if it does, keep the latest version
|
||||||
|
if (updated[key]) {
|
||||||
|
var ek = updated[key];
|
||||||
|
if (parseInt(ek.split('_')[1]) > parseInt(k.split('_')[1])) { return; }
|
||||||
|
}
|
||||||
|
updated[key] = k;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.keys(ref).forEach(function (k) {
|
||||||
|
if (/^_/.test(k) || k === 'driveReadme') { return; }
|
||||||
|
var nPath = path.slice();
|
||||||
|
nPath.push(k);
|
||||||
|
if (!translated[k] || updated[k]) {
|
||||||
|
if (updated[k]) {
|
||||||
|
var uPath = path.slice();
|
||||||
|
uPath.unshift('out');
|
||||||
|
missing.push([code, nPath, 2, uPath.join('.') + '.' + updated[k]]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return void missing.push([code, nPath, 1]);
|
||||||
|
}
|
||||||
|
if (typeof ref[k] !== typeof translated[k]) {
|
||||||
|
return void missing.push([code, nPath, 3]);
|
||||||
|
}
|
||||||
|
if (typeof ref[k] === "object" && !Array.isArray(ref[k])) {
|
||||||
|
checkInObject(ref[k], translated[k], nPath);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Object.keys(translated).forEach(function (k) {
|
||||||
|
if (/^_/.test(k) || k === 'driveReadme') { return; }
|
||||||
|
var nPath = path.slice();
|
||||||
|
nPath.push(k);
|
||||||
|
if (typeof ref[k] === "undefined") {
|
||||||
|
missing.push([code, nPath, 0]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
checkInObject(Default, translation, []);
|
||||||
|
// Push the removals at the end
|
||||||
|
missing.sort(function (a, b) {
|
||||||
|
if (a[2] === 0 && b[2] !== 0) { return 1; }
|
||||||
|
if (a[2] !== 0 && b[2] === 0) { return -1; }
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
Array.prototype.push.apply(allMissing, missing); // Destructive concat
|
||||||
|
});
|
||||||
|
cb(allMissing);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get keys with parameters
|
||||||
|
messages._getKey = function (key, argArray) {
|
||||||
|
if (!messages[key]) { return '?'; }
|
||||||
|
var text = messages[key];
|
||||||
|
if (typeof(text) === 'string') {
|
||||||
|
return text.replace(/\{(\d+)\}/g, function (str, p1) {
|
||||||
|
if (typeof(argArray[p1]) === 'string' || typeof(argArray[p1]) === "number") {
|
||||||
|
return argArray[p1];
|
||||||
|
}
|
||||||
|
console.error("Only strings and numbers can be used in _getKey params!");
|
||||||
|
return '';
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add handler to the language selector
|
||||||
|
var storeLanguage = function (l) {
|
||||||
|
localStorage.setItem(LS_LANG, l);
|
||||||
|
};
|
||||||
|
messages._initSelector = function ($select) {
|
||||||
|
var selector = $select || $('#language-selector');
|
||||||
|
|
||||||
|
if (!selector.length) { return; }
|
||||||
|
|
||||||
|
var $button = $(selector).find('button .buttonTitle');
|
||||||
|
// Select the current language in the list
|
||||||
|
var option = $(selector).find('[data-value="' + language + '"]');
|
||||||
|
selector.setValue(language || 'English');
|
||||||
|
|
||||||
|
// Listen for language change
|
||||||
|
$(selector).find('a.languageValue').on('click', function () {
|
||||||
|
var newLanguage = $(this).attr('data-value');
|
||||||
|
storeLanguage(newLanguage);
|
||||||
|
if (newLanguage !== language) {
|
||||||
|
setTimeout(function () { window.location.reload(); });
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
var translateText = function (i, e) {
|
||||||
|
var $el = $(e);
|
||||||
|
var key = $el.data('localization');
|
||||||
|
$el.html(messages[key]);
|
||||||
|
};
|
||||||
|
var translateAppend = function (i, e) {
|
||||||
|
var $el = $(e);
|
||||||
|
var key = $el.data('localization-append');
|
||||||
|
$el.append(messages[key]);
|
||||||
|
};
|
||||||
|
var translateTitle = function (i, e) {
|
||||||
|
var $el = $(this);
|
||||||
|
var key = $el.data('localization-title');
|
||||||
|
$el.attr('title', messages[key]);
|
||||||
|
};
|
||||||
|
var translatePlaceholder = function (i, e) {
|
||||||
|
var $el = $(this);
|
||||||
|
var key = $el.data('localization-placeholder');
|
||||||
|
$el.attr('placeholder', messages[key]);
|
||||||
|
};
|
||||||
|
messages._applyTranslation = function () {
|
||||||
|
$('[data-localization]').each(translateText);
|
||||||
|
$('[data-localization-append]').each(translateAppend);
|
||||||
|
$('#pad-iframe').contents().find('[data-localization]').each(translateText);
|
||||||
|
$('[data-localization-title]').each(translateTitle);
|
||||||
|
$('[data-localization-placeholder]').each(translatePlaceholder);
|
||||||
|
$('#pad-iframe').contents().find('[data-localization-title]').each(translateTitle);
|
||||||
|
};
|
||||||
|
|
||||||
|
messages._getLanguage = function () { return language; };
|
||||||
|
|
||||||
|
return messages;
|
||||||
|
|
||||||
|
});
|
||||||
|
}());
|
|
@ -0,0 +1,360 @@
|
||||||
|
.hide {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
div.plan, div.renewal {
|
||||||
|
border: 1px solid transparent;
|
||||||
|
}
|
||||||
|
div.plan-selected, div.renewal-selected {
|
||||||
|
border: 1px solid #dde;
|
||||||
|
background: #eef;
|
||||||
|
}
|
||||||
|
#info {
|
||||||
|
margin-bottom: 20px;
|
||||||
|
}
|
||||||
|
.bold {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.choose-plan .plan img {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.spinner-div {
|
||||||
|
margin: 20px auto;
|
||||||
|
text-align: center;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.loading-message {
|
||||||
|
font-size: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* login form */
|
||||||
|
|
||||||
|
.login-form {
|
||||||
|
width: 300px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-form-entry {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.support-disabled {
|
||||||
|
opacity: 0.4;
|
||||||
|
background: #eee;
|
||||||
|
}
|
||||||
|
.support-pro-noauth {
|
||||||
|
width: 90%;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.plan-details, .support-details, .donate-details {
|
||||||
|
margin-top: 20px;
|
||||||
|
text-align:left;
|
||||||
|
font-family: lato, Helvetica, sans-serif;
|
||||||
|
font-size: 1.02em;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*End of Plan Style*/
|
||||||
|
|
||||||
|
.choose-renewal {
|
||||||
|
margin: 10px 10%;
|
||||||
|
padding: 20px;
|
||||||
|
flex-flow: column;
|
||||||
|
display: flex;
|
||||||
|
background: #efe;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.renewal-options {
|
||||||
|
width: 100%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
}
|
||||||
|
.cp h3.renewal-description {
|
||||||
|
padding-top: 0;
|
||||||
|
}
|
||||||
|
.renewal-label {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.renewal-label input {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cp button.btn-plan-basic, button.btn-donate5, button.btn-gift {
|
||||||
|
background-color: #00ADEE;
|
||||||
|
border-color: #00ADEE;
|
||||||
|
}
|
||||||
|
.cp button.btn-plan-pro {
|
||||||
|
background-color: #78b336;
|
||||||
|
border-color: #78b336;
|
||||||
|
}
|
||||||
|
.cp button.btn-plan-power, .cp button.btn-donate10 {
|
||||||
|
background-color: #F87217;
|
||||||
|
border-color: #F87217;
|
||||||
|
}
|
||||||
|
.cp button.paybutton:hover {
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.center {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
table.subscription-table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
table.subscription-table .cell-benificiary {
|
||||||
|
max-width: 200px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
table.subscription-table tr.personnal-subscription {
|
||||||
|
background-color: #eef;
|
||||||
|
}
|
||||||
|
table.subscription-table .cell-cancel {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-subs div.buttons {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
.active-subs div.buttons button {
|
||||||
|
margin-left: 10px;
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
|
.active-subs div.buttons .show-active-only-box {
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-contacts-container {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: row wrap;
|
||||||
|
}
|
||||||
|
.cp-contacts-container .cp-contact {
|
||||||
|
padding: 5px;
|
||||||
|
margin-right: 5px;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 20px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cp-contacts-container .cp-contact:hover {
|
||||||
|
background: rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
.cp-contacts-container .cp-avatar {
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
.cp-contacts-container .cp-name {
|
||||||
|
width: 100px;
|
||||||
|
white-space: nowrap;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
user-select: none;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.subscription-form div.buttons {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
#info .button-container {
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#info div.row > div {
|
||||||
|
height: 40px;
|
||||||
|
line-height: 40px;
|
||||||
|
}
|
||||||
|
#info div.row {
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-left: 0px;
|
||||||
|
}
|
||||||
|
#info #error {
|
||||||
|
padding: 0 10px 0 10px;
|
||||||
|
}
|
||||||
|
/* TODO(cjd) this is crap */
|
||||||
|
#info > span {
|
||||||
|
padding-left: 15px;
|
||||||
|
}
|
||||||
|
#info a.btn {
|
||||||
|
color: white;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
line-height: normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
#heading {
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pay-spinner {
|
||||||
|
position: fixed;
|
||||||
|
top:0;
|
||||||
|
left:0;
|
||||||
|
right:0;
|
||||||
|
bottom:0;
|
||||||
|
background-color:rgba(0, 0, 0, 0.6);
|
||||||
|
z-index: 999999;
|
||||||
|
color:white;
|
||||||
|
|
||||||
|
min-height: 100%;
|
||||||
|
min-height: 100vh;
|
||||||
|
height: 100%;
|
||||||
|
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
.pay-spinner div {
|
||||||
|
width: 100%
|
||||||
|
}
|
||||||
|
|
||||||
|
#hallOfFameCheck {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.faq-container .faq-questions-q {
|
||||||
|
color: #3a84b6;
|
||||||
|
padding: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
margin-top: 5px;
|
||||||
|
cursor: pointer;
|
||||||
|
-webkit-touch-callout: none;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-khtml-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
}
|
||||||
|
.faq-container .faq-questions-q:hover {
|
||||||
|
color: #2e688f;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
.faq-container .faq-questions-a {
|
||||||
|
display: none;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.crypto input {
|
||||||
|
width: 100%;
|
||||||
|
background-color: rgba(0,0,0,0.03);
|
||||||
|
border: 0px;
|
||||||
|
}
|
||||||
|
.crypto table {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.crypto .coin-address {
|
||||||
|
width: 100%;
|
||||||
|
padding-left: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-admin-tabs-container {
|
||||||
|
height: 50px;
|
||||||
|
margin: 20px 0;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-admin-tab {
|
||||||
|
height: 100%;
|
||||||
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
|
background: #EEF;
|
||||||
|
border-top-left-radius: 10px;
|
||||||
|
border-top-right-radius: 10px;
|
||||||
|
border-top: 1px solid #AAA;
|
||||||
|
border-left: 1px solid #AAA;
|
||||||
|
border-right: 1px solid #AAA;
|
||||||
|
padding: 10px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cp-admin-tab:hover {
|
||||||
|
background: #DDE;
|
||||||
|
}
|
||||||
|
.cp-admin-tab.active {
|
||||||
|
background: #DDE;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-admin-stats {
|
||||||
|
background-color: #EEE;
|
||||||
|
padding: 20px;
|
||||||
|
margin: 20px;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-between;
|
||||||
|
}
|
||||||
|
.cp-admin-stats p {
|
||||||
|
margin-bottom: 0;
|
||||||
|
}
|
||||||
|
.cp div.cp-stats {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
.cp div.cp-stats * {
|
||||||
|
padding: 0;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-admin-stats .cp-stats-note {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: 14px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-admin-edit-getform input {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-found th {
|
||||||
|
border: 1px solid #CCC;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-found tbody tr:hover {
|
||||||
|
background: #EEE;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-found td {
|
||||||
|
padding: 5px;
|
||||||
|
border: 1px solid #CCC;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-getform input {
|
||||||
|
margin: 0 10px;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-form p {
|
||||||
|
background: #AA0000;
|
||||||
|
color: white;
|
||||||
|
font-weight: bold;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-form-content .cp-edit-field {
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-form-content .cp-edit-note {
|
||||||
|
font-size: 0.9em;
|
||||||
|
font-style: italic;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-form-content input {
|
||||||
|
margin: 0 10px;
|
||||||
|
padding: 0 5px;
|
||||||
|
border: 1px solid #888;
|
||||||
|
}
|
||||||
|
.cp-admin-edit-form-content {
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>CryptPad</title>
|
||||||
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<meta name="referrer" content="no-referrer" />
|
||||||
|
<script async data-bootload="app/main.js" data-main="/common/boot.js?ver=1.0" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
<link href="/customize/src/outer.css?ver=1.1" rel="stylesheet" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<iframe id="sbox-iframe">
|
Loading…
Reference in New Issue