Merge pull request #55 from xwiki-labs/soon

Merge 'soon' into master
pull/1/head
ansuz 8 years ago committed by GitHub
commit 5c53f172a1

@ -8,6 +8,31 @@ module.exports = {
httpAddress: '::', httpAddress: '::',
// the port on which your httpd will listen // the port on which your httpd will listen
/* Cryptpad can be configured to send customized HTTP Headers
* These settings may vary widely depending on your needs
* Examples are provided below
*/
/*
httpHeaders: {
"Content-Security-Policy": [
"default-serc 'none'",
"style-src 'unsafe-inline' 'self'",
"script-src 'self' 'unsafe-eval' 'unsafe-inline'",
"child-src 'self' cryptpad.fr *.cryptpad.fr",
"font-src 'self'",
"connect-src 'self' wss://cryptpad.fr",
// data: is used by codemirror, (insecure remote) images are included by
// users of the wysiwyg who embed photos in their pads
"img-src data: *",
].join('; '),
"X-XSS-Protection": "1; mode=block",
"X-Content-Type-Options": "nosniff",
// 'X-Frame-Options': 'SAMEORIGIN',
},*/
httpPort: 3000, httpPort: 3000,
/* your server's websocket url is configurable /* your server's websocket url is configurable

@ -13,7 +13,7 @@ define([
$.ajax({ $.ajax({
url: isHtml ? '/customize/BottomBar.html' : '/customize/Header.html', url: isHtml ? '/customize/BottomBar.html' : '/customize/Header.html',
success: function (ret) { success: function (ret) {
$('iframe').height('96%'); //:$('iframe').height('96%');
$('body').append(ret); $('body').append(ret);
LS.main(); LS.main();
Messages._applyTranslation(); Messages._applyTranslation();

@ -8,14 +8,16 @@
<option value="fr">Français</option> <option value="fr">Français</option>
</select> </select>
</span> </span>
<p data-localization="header_france"> <p data-localization="header_france" class="big">
</p> </p>
</div> </div>
<div class="bottom-bar-center"> <div class="bottom-bar-center">
<p><a id="cryptpad-logo" href="/" data-localization-title="header_logoTitle">CryptPad</a></p> <p><a id="cryptpad-logo" class="big" href="/" data-localization-title="header_logoTitle">CryptPad</a></p>
<p><a id="cryptpad-logo" class="small" href="/" data-localization-title="header_logoTitle"><img src="/customize/cryptofist_mini.png" alt="Cryptpad" class="cryptofist" /></a></p>
</div> </div>
<div class="bottom-bar-right"> <div class="bottom-bar-right">
<p data-localization="header_support"> <p data-localization="header_xwiki" class="small">
<p data-localization="header_support" class="big">
</p> </p>
</div> </div>
</div> </div>

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

@ -3,7 +3,7 @@
<head> <head>
<title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title> <title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<link rel="stylesheet" type="text/css" href="customize/main.css" /> <link rel="stylesheet" type="text/css" href="/customize/main.css" />
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/> <link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
<script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script> <script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script>
<script src="/bower_components/requirejs/require.js"></script> <script src="/bower_components/requirejs/require.js"></script>

@ -146,6 +146,7 @@ tr {
.buttons { .buttons {
margin-bottom: 50px; margin-bottom: 50px;
margin-top: 20px; margin-top: 20px;
line-height: 2.5em;
} }
.button { .button {
padding: 4px 12px 4px 12px; padding: 4px 12px 4px 12px;
@ -242,6 +243,34 @@ tbody td:last-child {
margin-right: 4px; margin-right: 4px;
position: relative; position: relative;
} }
@media screen and (max-width: 800px) {
.top-bar .big,
.bottom-bar .big {
display: none;
}
}
@media screen and (min-width: 801px) {
.top-bar .big,
.bottom-bar .big {
display: inline-block;
}
}
@media screen and (max-width: 800px) {
.top-bar .small,
.bottom-bar .small {
display: inline-block;
}
}
@media screen and (min-width: 801px) {
.top-bar .small,
.bottom-bar .small {
display: none;
}
}
.top-bar .small img,
.bottom-bar .small img {
height: 1.25em;
}
.bottom-bar { .bottom-bar {
bottom: 0px; bottom: 0px;
right: 0px; right: 0px;

@ -3,7 +3,7 @@
<head> <head>
<title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title> <title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<link rel="stylesheet" type="text/css" href="customize/main.css" /> <link rel="stylesheet" type="text/css" href="/customize/main.css" />
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/> <link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
<script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script> <script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script>
<script src="/bower_components/requirejs/require.js"></script> <script src="/bower_components/requirejs/require.js"></script>

@ -175,6 +175,7 @@ p, pre, td, a, table, tr {
.buttons { .buttons {
margin-bottom: 50px; margin-bottom: 50px;
margin-top: 20px; margin-top: 20px;
line-height: 2.5em;
} }
.button { .button {
@ -278,6 +279,27 @@ tbody {
margin-right: 4px; margin-right: 4px;
position: relative; position: relative;
} }
.big {
@media screen and (max-width: 800px) {
display: none;
}
@media screen and (min-width: 801px) {
display: inline-block;
}
}
.small {
@media screen and (max-width: 800px) {
display: inline-block;
}
@media screen and (min-width: 801px) {
display: none;
}
img {
height: 1.25em;
}
}
} }
.bottom-bar { .bottom-bar {
bottom: 0px; bottom: 0px;

@ -3,7 +3,7 @@
<head> <head>
<title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title> <title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<link rel="stylesheet" type="text/css" href="customize/main.css" /> <link rel="stylesheet" type="text/css" href="/customize/main.css" />
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/> <link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
<script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script> <script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script>
<script src="/bower_components/requirejs/require.js"></script> <script src="/bower_components/requirejs/require.js"></script>

@ -16,8 +16,6 @@
color: #666; color: #666;
font-weight: bold; font-weight: bold;
height: 30px;
margin-bottom: -3px;
display: inline-block; display: inline-block;
width: 100%; width: 100%;
z-index: 9001; z-index: 9001;
@ -27,32 +25,58 @@
} }
div { div {
padding: 0 3px; white-space: normal;
height: 1.5em;
line-height: 25px;
height: 100%;
&.cryptpad-back { &.cryptpad-back {
padding: 0; padding: 0;
font-weight: bold; font-weight: bold;
cursor: pointer; cursor: pointer;
color: #000; color: #000;
} }
&.cryptpad-lag {
float: right;
line-height: 26px;
margin: 2px 0px 2px 4px;
}
} }
button { button, .rightside-element {
height: 26px; height: 26px;
padding-right: 5px;
padding-left: 5px;
margin: 2px;
}
button {
background-color: inherit; background-color: inherit;
background-image: linear-gradient(to bottom,#fff,#e4e4e4); background-image: linear-gradient(to bottom,#fff,#e4e4e4);
border: 1px solid #A6A6A6; border: 1px solid #A6A6A6;
border-bottom-color: #979797; border-bottom-color: #979797;
border-radius: 3px; border-radius: 3px;
margin-right: 5px;
padding-right: 5px;
padding-left: 5px;
&:hover { &:hover {
background-image:linear-gradient(to bottom,#f2f2f2,#ccc); background-image:linear-gradient(to bottom,#f2f2f2,#ccc);
} }
&.userlist {
@media screen and (max-width: 800px) {
display: none;
} }
@media screen and (min-width: 801px) {
display: inline-block;
}
&.small {
@media screen and (max-width: 800px) {
display: inline-block;
}
@media screen and (min-width: 801px) {
display: none;
}
}
}
}
.cryptpad-state {
line-height: 30px; /* equivalent to 26px + 2*2px margin used for buttons */
}
.rightside-button { .rightside-button {
float: right; float: right;
cursor: pointer; cursor: pointer;
@ -63,30 +87,89 @@
float: left; float: left;
} }
.rightside-element {
vertical-align: middle;
white-space: nowrap;
&.float {
float: right;
}
}
select { select {
border: 0px; border: 0px;
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
padding-left: 5px; padding-left: 5px;
border: 1px solid #A6A6A6;
border-bottom-color: #979797;
} }
} }
.cryptpad-toolbar-leftside { .cryptpad-toolbar-leftside {
float: left; float: left;
div { margin-bottom: -1px;
float: left; .cryptpad-dropdown-container {
position: relative;
display: inline-block;
padding: 0px;
.cryptpad-dropdown {
z-index:1000;
display:none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0,0,0,0.2);
height: auto;
padding: 5px;
white-space: normal;
p {
width: 210px;
padding: 0;
margin: 0;
white-space: normal;
&.cryptpad-dropdown-users {
text-align:baseline;
.yourself {
font-style: italic;
}
.anonymous {
font-style: italic;
}
}
h2 {
font-weight: bold;
text-align: center;
background-color: #EEEEEE;
padding: 5px 0px;
margin: 5px 0px;
font-size: 16px;
}
}
button {
margin: 2px 0px;
}
}
}
button {
margin: 2px 4px 2px 0px;
}
.cryptpad-userbuttons-container {
display: none;
} }
} }
.cryptpad-toolbar-rightside { .cryptpad-toolbar-rightside {
text-align: right; text-align: right;
margin-right: 30px;
//float: right; //float: right;
} }
.cryptpad-lag {
float: right;
}
.cryptpad-spinner { .cryptpad-spinner {
float: left; float: left;
display: inline-block;
height: 26px;
margin: 2px;
line-height: 26px;
font-size: 20px;
} }
.cryptpad-readonly { .cryptpad-readonly {
margin-right: 20px; margin-right: 20px;
@ -94,13 +177,12 @@
text-transform: uppercase; text-transform: uppercase;
} }
.cryptpad-toolbar-username { .cryptpad-toolbar-username {
font-style: italic;
} }
.lag { .lag {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 5px !important;
height: 15px !important; height: 15px !important;
width: 15px !important; width: 15px !important;
border-radius: 50%; border-radius: 50%;

@ -3,7 +3,7 @@
<head> <head>
<title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title> <title data-localization="main_title">Cryptpad: Zero Knowledge, Collaborative Real Time Editing</title>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<link rel="stylesheet" type="text/css" href="customize/main.css" /> <link rel="stylesheet" type="text/css" href="/customize/main.css" />
<link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/> <link rel="icon" type="image/png" href="/customize/main-favicon.png" id="favicon"/>
<script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script> <script data-main="/customize/main" src="/bower_components/requirejs/require.js"></script>
<script src="/bower_components/requirejs/require.js"></script> <script src="/bower_components/requirejs/require.js"></script>

@ -16,8 +16,6 @@
user-select: none; user-select: none;
color: #666; color: #666;
font-weight: bold; font-weight: bold;
height: 30px;
margin-bottom: -3px;
display: inline-block; display: inline-block;
width: 100%; width: 100%;
z-index: 9001; z-index: 9001;
@ -26,10 +24,7 @@
float: right; float: right;
} }
.cryptpad-toolbar div { .cryptpad-toolbar div {
padding: 0 3px; white-space: normal;
height: 1.5em;
line-height: 25px;
height: 100%;
} }
.cryptpad-toolbar div.cryptpad-back { .cryptpad-toolbar div.cryptpad-back {
padding: 0; padding: 0;
@ -37,20 +32,52 @@
cursor: pointer; cursor: pointer;
color: #000; color: #000;
} }
.cryptpad-toolbar button { .cryptpad-toolbar div.cryptpad-lag {
float: right;
line-height: 26px;
margin: 2px 0px 2px 4px;
}
.cryptpad-toolbar button,
.cryptpad-toolbar .rightside-element {
height: 26px; height: 26px;
padding-right: 5px;
padding-left: 5px;
margin: 2px;
}
.cryptpad-toolbar button {
background-color: inherit; background-color: inherit;
background-image: linear-gradient(to bottom, #fff, #e4e4e4); background-image: linear-gradient(to bottom, #fff, #e4e4e4);
border: 1px solid #A6A6A6; border: 1px solid #A6A6A6;
border-bottom-color: #979797; border-bottom-color: #979797;
border-radius: 3px; border-radius: 3px;
margin-right: 5px;
padding-right: 5px;
padding-left: 5px;
} }
.cryptpad-toolbar button:hover { .cryptpad-toolbar button:hover {
background-image: linear-gradient(to bottom, #f2f2f2, #ccc); background-image: linear-gradient(to bottom, #f2f2f2, #ccc);
} }
@media screen and (max-width: 800px) {
.cryptpad-toolbar button.userlist {
display: none;
}
}
@media screen and (min-width: 801px) {
.cryptpad-toolbar button.userlist {
display: inline-block;
}
}
@media screen and (max-width: 800px) {
.cryptpad-toolbar button.userlist.small {
display: inline-block;
}
}
@media screen and (min-width: 801px) {
.cryptpad-toolbar button.userlist.small {
display: none;
}
}
.cryptpad-toolbar .cryptpad-state {
line-height: 30px;
/* equivalent to 26px + 2*2px margin used for buttons */
}
.cryptpad-toolbar .rightside-button { .cryptpad-toolbar .rightside-button {
float: right; float: right;
cursor: pointer; cursor: pointer;
@ -59,40 +86,96 @@
cursor: pointer; cursor: pointer;
float: left; float: left;
} }
.cryptpad-toolbar .rightside-element {
vertical-align: middle;
white-space: nowrap;
}
.cryptpad-toolbar .rightside-element.float {
float: right;
}
.cryptpad-toolbar select { .cryptpad-toolbar select {
border: 0px; border: 0px;
margin-left: 5px; margin-left: 5px;
margin-right: 5px; margin-right: 5px;
padding-left: 5px; padding-left: 5px;
border: 1px solid #A6A6A6;
border-bottom-color: #979797;
} }
.cryptpad-toolbar-leftside { .cryptpad-toolbar-leftside {
float: left; float: left;
margin-bottom: -1px;
} }
.cryptpad-toolbar-leftside div { .cryptpad-toolbar-leftside .cryptpad-dropdown-container {
float: left; position: relative;
display: inline-block;
padding: 0px;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown {
z-index: 1000;
display: none;
position: absolute;
background-color: #f9f9f9;
min-width: 160px;
overflow: auto;
box-shadow: 0px 8px 16px 0px rgba(0, 0, 0, 0.2);
height: auto;
padding: 5px;
white-space: normal;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown p {
width: 210px;
padding: 0;
margin: 0;
white-space: normal;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown p.cryptpad-dropdown-users {
text-align: baseline;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown p.cryptpad-dropdown-users .yourself {
font-style: italic;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown p.cryptpad-dropdown-users .anonymous {
font-style: italic;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown p h2 {
font-weight: bold;
text-align: center;
background-color: #EEEEEE;
padding: 5px 0px;
margin: 5px 0px;
font-size: 16px;
}
.cryptpad-toolbar-leftside .cryptpad-dropdown-container .cryptpad-dropdown button {
margin: 2px 0px;
}
.cryptpad-toolbar-leftside button {
margin: 2px 4px 2px 0px;
}
.cryptpad-toolbar-leftside .cryptpad-userbuttons-container {
display: none;
} }
.cryptpad-toolbar-rightside { .cryptpad-toolbar-rightside {
text-align: right; text-align: right;
} margin-right: 30px;
.cryptpad-lag {
float: right;
} }
.cryptpad-spinner { .cryptpad-spinner {
float: left; float: left;
display: inline-block;
height: 26px;
margin: 2px;
line-height: 26px;
font-size: 20px;
} }
.cryptpad-readonly { .cryptpad-readonly {
margin-right: 20px; margin-right: 20px;
font-weight: bold; font-weight: bold;
text-transform: uppercase; text-transform: uppercase;
} }
.cryptpad-toolbar-username {
font-style: italic;
}
.lag { .lag {
display: inline-block; display: inline-block;
vertical-align: middle; vertical-align: middle;
padding: 0 !important; padding: 0 !important;
margin: 0 !important; margin: 0 5px !important;
height: 15px !important; height: 15px !important;
width: 15px !important; width: 15px !important;
border-radius: 50%; border-radius: 50%;

@ -17,21 +17,17 @@ define(function () {
out.common_connectionLost = 'Connexion au serveur perdue'; out.common_connectionLost = 'Connexion au serveur perdue';
out.editingAlone = 'Pas d\'autre participant';
out.editingWithOneOtherPerson = 'Édition avec une autre personne';
out.editingWith = 'Édition avec';
out.otherPeople = 'autres personnes';
out.disconnected = 'Déconnecté'; out.disconnected = 'Déconnecté';
out.synchronizing = 'Synchronisation'; out.synchronizing = 'Synchronisation';
out.reconnecting = 'Reconnexion...'; out.reconnecting = 'Reconnexion...';
out.lag = 'Latence'; out.lag = 'Latence';
out.readonly = 'Lecture seule'; out.readonly = 'Lecture seule';
out.nobodyIsEditing = "Personne n'édite le document"; out.anonymous = "Anonyme";
out.onePersonIsEditing = 'Une personne édite le document'; out.yourself = "Vous-même";
out.peopleAreEditing = '{0} personnes éditent le document'; out.anonymousUsers = "utilisateurs anonymes";
out.oneViewer = '1 lecteur'; out.anonymousUser = "utilisateur anonyme";
out.viewers = '{0} lecteurs'; out.share = "Partage";
out.anonymous = "Vous êtes actuellement anonyme"; out.users = "Utilisateurs";
out.greenLight = "Tout fonctionne bien"; out.greenLight = "Tout fonctionne bien";
out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur"; out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur";
@ -82,7 +78,14 @@ define(function () {
out.readonlyUrl = 'Document en lecture seule'; out.readonlyUrl = 'Document en lecture seule';
out.copyReadOnly = "Copier l'URL dans le presse-papiers"; out.copyReadOnly = "Copier l'URL dans le presse-papiers";
out.openReadOnly = "Ouvrir dans un nouvel onglet"; out.openReadOnly = "Ouvrir dans un nouvel onglet";
out.editing = "éditeur(s)";
out.viewing = "lecteur(s)";
out.editShare = "Partager l'URL";
out.editShareTitle = "Copier l'URL d'édition dans le presse-papiers";
out.viewShare = "Partager l'URL de lecture";
out.viewShareTitle = "Copier l'URL d'accès en lecture seule dans le presse-papiers";
out.viewOpen = "Voir dans un nouvel onglet";
out.viewOpenTitle = "Ouvrir le document en lecture seule dans un nouvel onglet";
out.disconnectAlert = 'Perte de la connexion au réseau !'; out.disconnectAlert = 'Perte de la connexion au réseau !';
@ -143,7 +146,7 @@ define(function () {
// index.html // index.html
out.main_p1 = 'CryptPad est l\'éditeur collaboratif en temps réel <strong>zero knowledge</strong>. Le cryptage est effectué depuis votre navigateur, ce qui protège les données contre le serveur, le cloud, et la NSA. La clé de cryptage est stockée dans l\'<a href="https://fr.wikipedia.org/wiki/Identificateur_de_fragment">identifieur de fragment</a> de l\'URL qui n\'est jamais envoyée au serveur mais est accessible depuis javascript, de sorte qu\'en partageant l\'URL, vous donner l\'accès au pad à ceux qui souhaitent participer.'; out.main_p1 = 'CryptPad est l\'éditeur collaboratif en temps réel <strong>zero knowledge</strong>. Le chiffrement est effectué depuis votre navigateur, ce qui protège les données contre le serveur, le cloud, et la NSA. La clé de chiffrement est stockée dans l\'<a href="https://fr.wikipedia.org/wiki/Identificateur_de_fragment">identifieur de fragment</a> de l\'URL qui n\'est jamais envoyée au serveur mais est accessible depuis javascript, de sorte qu\'en partageant l\'URL, vous donnez l\'accès au pad à ceux qui souhaitent participer.';
out.main_p2 = 'Ce projet utilise l\'éditeur visuel (WYSIWYG) <a href="http://ckeditor.com/">CKEditor</a>, l\'éditeur de code source <a href="https://codemirror.net/">CodeMirror</a>, et le moteur temps-réel <a href="https://github.com/xwiki-contrib/chainpad">ChainPad</a>.'; out.main_p2 = 'Ce projet utilise l\'éditeur visuel (WYSIWYG) <a href="http://ckeditor.com/">CKEditor</a>, l\'éditeur de code source <a href="https://codemirror.net/">CodeMirror</a>, et le moteur temps-réel <a href="https://github.com/xwiki-contrib/chainpad">ChainPad</a>.';
out.main_howitworks = 'Comment ça fonctionne'; out.main_howitworks = 'Comment ça fonctionne';
out.main_howitworks_p1 = 'CryptPad utilise une variante de l\'algorithme d\'<a href="https://en.wikipedia.org/wiki/Operational_transformation">Operational transformation</a> qui est capable de trouver un consensus distribué en utilisant une chaîne de bloc Nakamoto, un outil popularisé par le <a href="https://fr.wikipedia.org/wiki/Bitcoin">Bitcoin</a>. De cette manière, l\'algorithme évite la nécessité d\'utiliser un serveur central pour résoudre les conflits d\'édition de l\'Operational Transformation, et sans ce besoin de résolution des conflits le serveur peut rester ignorant du contenu qui est édité dans le pad.'; out.main_howitworks_p1 = 'CryptPad utilise une variante de l\'algorithme d\'<a href="https://en.wikipedia.org/wiki/Operational_transformation">Operational transformation</a> qui est capable de trouver un consensus distribué en utilisant une chaîne de bloc Nakamoto, un outil popularisé par le <a href="https://fr.wikipedia.org/wiki/Bitcoin">Bitcoin</a>. De cette manière, l\'algorithme évite la nécessité d\'utiliser un serveur central pour résoudre les conflits d\'édition de l\'Operational Transformation, et sans ce besoin de résolution des conflits le serveur peut rester ignorant du contenu qui est édité dans le pad.';
@ -187,7 +190,7 @@ define(function () {
out.tos_title = "Conditions d'utilisation de Cryptpad"; out.tos_title = "Conditions d'utilisation de Cryptpad";
out.tos_legal = "Veuillez ne pas être malveillant, abusif, ou faire quoi que ce soit d'illégal."; out.tos_legal = "Veuillez ne pas être malveillant, abusif, ou faire quoi que ce soit d'illégal.";
out.tos_availability = "Nous espérons que vous trouvez ce service utile, mais nous ne pouvons garantir ses performances et disponibilités. Nous vous recommandons d'exporter vos données régurlièrement."; out.tos_availability = "Nous espérons que vous trouvez ce service utile, mais nous ne pouvons garantir ses performances et disponibilités. Nous vous recommandons d'exporter vos données régurlièrement.";
out.tos_e2ee = "Les document sur Cryptpad peuvent être lus et modifiés par quiconque est en mesure de deviner ou d'obtenir de quelque manière que ce soit l'identificateur de fragment (hash) du document. Nous vous recommandons d'utiliser des technologies de messagerie cryptées de bout à bout (end-to-end encryption ou e2ee) pour partager les URLs, et déclinons toute responsabilité dans le cas ou une telle URL serait divulguée."; out.tos_e2ee = "Les document sur Cryptpad peuvent être lus et modifiés par quiconque est en mesure de deviner ou d'obtenir de quelque manière que ce soit l'identificateur de fragment (hash) du document. Nous vous recommandons d'utiliser des technologies de messagerie chiffrées de bout à bout (end-to-end encryption ou e2ee) pour partager les URLs, et déclinons toute responsabilité dans le cas ou une telle URL serait divulguée.";
out.tos_logs = "Les meta-données fournies par votre navigateur au serveur peuvent être enregistrées dans le but de maintenir le service."; out.tos_logs = "Les meta-données fournies par votre navigateur au serveur peuvent être enregistrées dans le but de maintenir le service.";
out.tos_3rdparties = "Nous ne fournissons aucune donnée individuelle à des tierces parties à moins d'y être contraints par la loi."; out.tos_3rdparties = "Nous ne fournissons aucune donnée individuelle à des tierces parties à moins d'y être contraints par la loi.";
@ -199,6 +202,7 @@ define(function () {
// Header.html // Header.html
out.header_france = '<a href="http://www.xwiki.com/fr" target="_blank" rel="noopener noreferrer">Fait avec <img class="bottom-bar-heart" src="/customize/heart.png" /> en <img class="bottom-bar-fr" title="France" alt="France" src="/customize/fr.png" /> par <img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>'; out.header_france = '<a href="http://www.xwiki.com/fr" target="_blank" rel="noopener noreferrer">Fait avec <img class="bottom-bar-heart" src="/customize/heart.png" /> en <img class="bottom-bar-fr" title="France" alt="France" src="/customize/fr.png" /> par <img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>';
out.header_xwiki = '<a href="http://www.xwiki.com/fr" target="_blank" rel="noopener noreferrer"><img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>';
out.header_support = '<a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>'; out.header_support = '<a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
out.header_logoTitle = "Aller vers la page d'accueil"; out.header_logoTitle = "Aller vers la page d'accueil";

@ -17,21 +17,17 @@ define(function () {
out.common_connectionLost = 'Server Connection Lost'; out.common_connectionLost = 'Server Connection Lost';
out.editingAlone = 'Editing alone';
out.editingWithOneOtherPerson = 'Editing with one other person';
out.editingWith = 'Editing with';
out.otherPeople = 'other people';
out.disconnected = 'Disconnected'; out.disconnected = 'Disconnected';
out.synchronizing = 'Synchronizing'; out.synchronizing = 'Synchronizing';
out.reconnecting = 'Reconnecting...'; out.reconnecting = 'Reconnecting...';
out.lag = 'Lag'; out.lag = 'Lag';
out.readonly = 'Read only'; out.readonly = 'Read only';
out.nobodyIsEditing = 'Nobody is editing'; out.anonymous = "Anonymous";
out.onePersonIsEditing = 'One person is editing'; out.yourself = "Yourself";
out.peopleAreEditing = '{0} people are editing'; out.anonymousUsers = "anonymous users";
out.oneViewer = '1 viewer'; out.anonymousUser = "anonymous user";
out.viewers = '{0} viewers'; out.share = "Share";
out.anonymous = "You are currently anonymous"; out.users = "Users";
out.greenLight = "Everything is working fine"; out.greenLight = "Everything is working fine";
out.orangeLight = "Your slow connection may impact your experience"; out.orangeLight = "Your slow connection may impact your experience";
@ -83,6 +79,14 @@ define(function () {
out.readonlyUrl = 'Read only document'; out.readonlyUrl = 'Read only document';
out.copyReadOnly = "Copy URL to clipboard"; out.copyReadOnly = "Copy URL to clipboard";
out.openReadOnly = "Open in a new tab"; out.openReadOnly = "Open in a new tab";
out.editing = "editing";
out.viewing = "viewing";
out.editShare = "Share";
out.editShareTitle = "Copy the edit URL to clipboard";
out.viewShare = "Share view URL";
out.viewShareTitle = "Copy the read-only URL to clipboard";
out.viewOpen = "View in new tab";
out.viewOpenTitle = "Open the document in read-only mode in a new tab";
out.disconnectAlert = 'Network connection lost!'; out.disconnectAlert = 'Network connection lost!';
@ -200,6 +204,7 @@ define(function () {
// Header.html // Header.html
out.header_france = '<a href="http://www.xwiki.com/" target="_blank" rel="noopener noreferrer">With <img class="bottom-bar-heart" src="/customize/heart.png" /> from <img class="bottom-bar-fr" src="/customize/fr.png" title="France" alt="France"/> by <img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>'; out.header_france = '<a href="http://www.xwiki.com/" target="_blank" rel="noopener noreferrer">With <img class="bottom-bar-heart" src="/customize/heart.png" /> from <img class="bottom-bar-fr" src="/customize/fr.png" title="France" alt="France"/> by <img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>';
out.header_xwiki = '<a href="http://www.xwiki.com/" target="_blank" rel="noopener noreferrer"><img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>';
out.header_support = '<a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>'; out.header_support = '<a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
out.header_logoTitle = 'Go to the main page'; out.header_logoTitle = 'Go to the main page';

@ -19,33 +19,20 @@ var app = Express();
var httpsOpts; var httpsOpts;
app.use(function (req, res, next) { var setHeaders = (function () {
var host = req.headers.host; if (typeof(config.httpHeaders) !== 'object') { return function () {}; }
if (config.websocketPort) {
host = host.replace(/\:[0-9]+/, ':' + config.websocketPort);
}
var proto = (httpsOpts || config.useSecureWebsockets) ? 'wss://' : 'ws://';
res.setHeader('Content-Security-Policy', [
"default-src 'none'",
"style-src 'unsafe-inline' 'self'",
// No way to load ckeditor without unsafe-eval and unsafe-inline
// https://dev.ckeditor.com/ticket/8584
"script-src 'self' 'unsafe-eval' 'unsafe-inline'",
"connect-src 'self' " + proto + host,
"child-src 'self'",
"font-src 'self'",
// data: is used by codemirror, (insecure remote) images are included by people making
// documents in ckeditor.
"img-src data: *"
].join('; '));
res.setHeader('X-XSS-Protection', '1; mode=block'); var headers = JSON.parse(JSON.stringify(config.httpHeaders));
res.setHeader('X-Content-Type-Options', 'nosniff'); if (Object.keys(headers).length) {
res.setHeader('X-Frame-Options', 'SAMEORIGIN'); return function (res) {
for (var header in headers) { res.setHeader(header, headers[header]); }
};
}
return function () {};
}());
app.use(function (req, res, next) {
setHeaders(res);
next(); next();
}); });
@ -56,6 +43,10 @@ Fs.exists(__dirname + "/customize", function (e) {
console.log("Cryptpad is customizable, see customize.dist/readme.md for details"); console.log("Cryptpad is customizable, see customize.dist/readme.md for details");
}); });
// FIXME I think this is a regression caused by a recent PR
// correct this hack without breaking the contributor's intended behaviour.
app.get(/\/(privacy|index|terms)\.html/, Express.static(__dirname + '/customize.dist'));
app.use("/customize", Express.static(__dirname + '/customize')); app.use("/customize", Express.static(__dirname + '/customize'));
app.use("/customize", Express.static(__dirname + '/customize.dist')); app.use("/customize", Express.static(__dirname + '/customize.dist'));
app.use(/^\/[^\/]*$/, Express.static('customize')); app.use(/^\/[^\/]*$/, Express.static('customize'));

@ -7,6 +7,8 @@ There are a few guidelines for creating a module:
Dependencies for your storage engine **should not** be added to Cryptpad. Dependencies for your storage engine **should not** be added to Cryptpad.
Instead, write an adaptor, and place it in `cryptpad/storage/yourAdaptor.js`. Instead, write an adaptor, and place it in `cryptpad/storage/yourAdaptor.js`.
Alternatively, storage adaptors can be published to npm, and required from your config (once installed).
## Your adaptor should conform to a simple API. ## Your adaptor should conform to a simple API.
It must export an object with a single property, `create`, which is a function. It must export an object with a single property, `create`, which is a function.

@ -19,23 +19,35 @@
html, body { html, body {
overflow-y: hidden; overflow-y: hidden;
} }
#pad-iframe { #iframe-container {
position: fixed; position: fixed;
top:2.5em; top: 2.6em;
left:0px;
bottom: 0px; bottom: 0px;
right: 0px; right: 0px;
left: 0px;
padding: 0px;
}
#pad-iframe {
width:100%; width:100%;
height:100%; height:100%;
border:none; border:none;
margin:0; margin:0;
padding:0; padding:0;
overflow:hidden; overflow:hidden;
box-sizing: border-box;
}
/* We use !important here to override the 96% set to the element in DecorateToolbar.js
when we enter fullscreen mode. It allows us to avoid changing the iframe's size in JS */
#pad-iframe.fullscreen {
top: 0px;
height: 100% !important;
} }
</style> </style>
</head> </head>
<body> <body>
<div id="iframe-container">
<iframe id="pad-iframe" src="inner.html"></iframe> <iframe id="pad-iframe" src="inner.html"></iframe>
</div>
</body> </body>
</html> </html>

@ -31,24 +31,30 @@
<script src="/bower_components/codemirror/addon/fold/markdown-fold.js"></script> <script src="/bower_components/codemirror/addon/fold/markdown-fold.js"></script>
<script src="/bower_components/codemirror/addon/fold/comment-fold.js"></script> <script src="/bower_components/codemirror/addon/fold/comment-fold.js"></script>
<style> <style>
html { html, body{
height: 100%; height: 100%;
width: 100%;
padding: 0px;
margin: 0px;
overflow: hidden;
box-sizing: border-box;
position: relative;
} }
body { body {
height: 100%; display: flex;
margin: 0px; flex-flow: column;
} }
.CodeMirror { .CodeMirror {
position: absolute; height: 100%;
top: 25px; }
bottom: 0px; .cryptpad-toolbar {
left: 0px; padding: 0px 6px;
right: 0px; }
height: auto; #cme_toolbox div.cryptpad-lag {
line-height: 24px;
} }
#cme_toolbox { #cme_toolbox {
font: 12px Arial,Helvetica,Tahoma,Verdana,sans-serif; font: 12px Arial,Helvetica,Tahoma,Verdana,sans-serif;
height: 25px;
background: -webkit-linear-gradient(#EEEEEE, #DADADA); /* For Safari 5.1 to 6.0 */ background: -webkit-linear-gradient(#EEEEEE, #DADADA); /* For Safari 5.1 to 6.0 */
background: -o-linear-gradient(white, #DDDDDD); /* For Opera 11.1 to 12.0 */ background: -o-linear-gradient(white, #DDDDDD); /* For Opera 11.1 to 12.0 */
background: -moz-linear-gradient(white, #DDDDDD); /* For Firefox 3.6 to 15 */ background: -moz-linear-gradient(white, #DDDDDD); /* For Firefox 3.6 to 15 */

@ -303,12 +303,16 @@ define([
toolbarList = info.userList; toolbarList = info.userList;
var config = { var config = {
userData: userList, userData: userList,
readOnly: readOnly readOnly: readOnly,
ifrw: ifrw
}; };
if (readOnly) {delete config.changeNameID; } if (readOnly) {delete config.changeNameID; }
toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside); var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username);
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
var editHash; var editHash;
var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys); var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys);
@ -322,8 +326,8 @@ define([
var usernameCb = function (newName) { var usernameCb = function (newName) {
setName (newName); setName (newName);
}; };
var $username = Cryptpad.createButton('username', true, {lastName: lastName}, usernameCb); var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb);
$rightside.append($username); $userBlock.append($username).hide();
}); });
/* add an export button */ /* add an export button */
@ -353,10 +357,15 @@ define([
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb); var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad); $rightside.append($forgetPad);
if (!readOnly && viewHash) { if (!readOnly) {
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
}
if (viewHash) {
/* add a 'links' button */ /* add a 'links' button */
var $links = Cryptpad.createButton('readonly', true, {viewHash: viewHash}); $viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash}));
$rightside.append($links); if (!readOnly) {
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash}));
}
} }
var configureLanguage = function (cb) { var configureLanguage = function (cb) {
@ -366,6 +375,7 @@ define([
var $language = module.$language = $('<select>', { var $language = module.$language = $('<select>', {
title: 'syntax highlighting', title: 'syntax highlighting',
id: 'language-mode', id: 'language-mode',
'class': 'rightside-element'
}).on('change', function () { }).on('change', function () {
setMode($language.val()); setMode($language.val());
onLocal(); onLocal();
@ -390,6 +400,7 @@ define([
var $themeDropdown = $('<select>', { var $themeDropdown = $('<select>', {
title: 'color theme', title: 'color theme',
id: 'display-theme', id: 'display-theme',
'class': 'rightside-element'
}); });
Themes.forEach(function (o) { Themes.forEach(function (o) {
$themeDropdown.append($('<option>', { $themeDropdown.append($('<option>', {

@ -716,10 +716,8 @@ define([
break; break;
case 'username': case 'username':
button = $('<button>', { button = $('<button>', {
title: Messages.userButton + '\n' + Messages.userButtonTitle, title: Messages.userButton + '\n' + Messages.userButtonTitle
'class': "fa fa-user", }).html('<span class="fa fa-user" style="font-family:FontAwesome;"></span>');
style: 'font:'+size+' FontAwesome'
});
if (data && typeof data.lastName !== "undefined" && callback) { if (data && typeof data.lastName !== "undefined" && callback) {
var lastName = data.lastName; var lastName = data.lastName;
button.click(function() { button.click(function() {
@ -729,29 +727,34 @@ define([
}); });
} }
break; break;
case 'readonly': case 'editshare':
button = $('<button>', { button = $('<button>', {
title: Messages.getViewButton + '\n' + Messages.getViewButtonTitle, title: Messages.editShareTitle,
'class': "fa fa-eye", 'class': "button action"
style: 'font:'+size+' FontAwesome' }).text(Messages.editShare);
if (data && data.editHash) {
var editHash = data.editHash;
button.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#';
var url = baseUrl + editHash;
var success = Clipboard.copy(url);
if (success) {
common.log(Messages.shareSuccess);
common.findOKButton().click();
return;
}
}); });
}
break;
case 'viewshare':
button = $('<button>', {
title: Messages.viewShareTitle,
'class': "button action"
}).text(Messages.viewShare);
if (data && data.viewHash) { if (data && data.viewHash) {
var viewHash = data.viewHash;
button.click(function () { button.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#'; var baseUrl = window.location.origin + window.location.pathname + '#';
var url = baseUrl + viewHash; var url = baseUrl + data.viewHash;
var $content = $('<div>').text(Messages.readonlyUrl);
var $copy = $('<button>', {
id: "cryptpad-readonly-copy",
'class': "button action"
}).text(Messages.copyReadOnly);
var $open = $('<button>', {
id: "cryptpad-readonly-open",
'class': "button action"
}).text(Messages.openReadOnly);
$content.append('<br>').append($copy).append($open);
common.alert($content.html());
$("#cryptpad-readonly-copy").click(function() {
var success = Clipboard.copy(url); var success = Clipboard.copy(url);
if (success) { if (success) {
common.log(Messages.shareSuccess); common.log(Messages.shareSuccess);
@ -759,13 +762,20 @@ define([
return; return;
} }
}); });
$("#cryptpad-readonly-open").click(function() { }
break;
case 'viewopen':
button = $('<button>', {
title: Messages.viewOpenTitle,
'class': "button action"
}).text(Messages.viewOpen);
if (data && data.viewHash) {
button.click(function () {
var baseUrl = window.location.origin + window.location.pathname + '#';
var url = baseUrl + data.viewHash;
common.findOKButton().click(); common.findOKButton().click();
window.open(url); window.open(url);
}); });
if (callback) { callback(); }
});
} }
break; break;
case 'present': case 'present':

@ -1,6 +1,6 @@
define([ define([
'/customize/messages.js', '/customize/messages.js',
'/bower_components/jquery/dist/jquery.min.js', '/bower_components/jquery/dist/jquery.min.js'
], function (Messages) { ], function (Messages) {
var $ = window.jQuery; var $ = window.jQuery;
@ -22,9 +22,19 @@ define([
var SPINNER_CLS = Bar.constants.spinner = 'cryptpad-spinner'; var SPINNER_CLS = Bar.constants.spinner = 'cryptpad-spinner';
var STATE_CLS = Bar.constants.state = 'cryptpad-state';
var USERNAME_CLS = Bar.constants.username = 'cryptpad-toolbar-username'; var USERNAME_CLS = Bar.constants.username = 'cryptpad-toolbar-username';
var READONLY_CLS = Bar.constants.readonly = 'cryptpad-readonly'; var READONLY_CLS = Bar.constants.readonly = 'cryptpad-readonly';
var USERBUTTONS_CONTAINER_CLS = Bar.constants.userButtonsContainer = "cryptpad-userbuttons-container";
var USERLIST_CLS = Bar.constants.userlist = "cryptpad-dropdown-users";
var EDITSHARE_CLS = Bar.constants.editShare = "cryptpad-dropdown-editShare";
var VIEWSHARE_CLS = Bar.constants.viewShare = "cryptpad-dropdown-viewShare";
var DROPDOWN_CONTAINER_CLS = Bar.constants.dropdownContainer = "cryptpad-dropdown-container";
var DROPDOWN_CLS = Bar.constants.dropdown = "cryptpad-dropdown";
/** Key in the localStore which indicates realtime activity should be disallowed. */ /** Key in the localStore which indicates realtime activity should be disallowed. */
// TODO remove? will never be used in cryptpad // TODO remove? will never be used in cryptpad
var LOCALSTORAGE_DISALLOW = Bar.constants.localstorageDisallow = 'cryptpad-disallow'; var LOCALSTORAGE_DISALLOW = Bar.constants.localstorageDisallow = 'cryptpad-disallow';
@ -84,30 +94,91 @@ define([
}, SPINNER_DISAPPEAR_TIME); }, SPINNER_DISAPPEAR_TIME);
}; };
var createUserList = function ($container) { var createUserButtons = function ($userlistElement, readOnly) {
var $listElement = $('<span>', {
id: 'userButtons',
'class': USERBUTTONS_CONTAINER_CLS
}).appendTo($userlistElement);
var $editIcon = $('<button>', {
'class': 'userlist dropbtn edit',
});
var $editIconSmall = $editIcon.clone().addClass('small');
var $viewIcon = $('<button>', {
'class': 'userlist dropbtn view',
});
var $viewIconSmall = $viewIcon.clone().addClass('small');
var $shareTitle = $('<h2>').text(Messages.share);
var $dropdownEditUsers = $('<p>', {'class': USERLIST_CLS});
var $dropdownEditShare = $('<p>', {'class': EDITSHARE_CLS});
if (readOnly !== 1) {
$dropdownEditShare.append($shareTitle);
}
var $dropdownEditContainer = $('<div>', {'class': DROPDOWN_CONTAINER_CLS});
var $dropdownEdit = $('<div>', {
id: "cryptpad-dropdown-edit",
'class': DROPDOWN_CLS
}).append($dropdownEditUsers).append($dropdownEditShare);
var $dropdownViewShare = $('<p>', {'class': VIEWSHARE_CLS}).append($shareTitle.clone());
var $dropdownViewContainer = $('<div>', {'class': DROPDOWN_CONTAINER_CLS});
var $dropdownView = $('<div>', {
id: "cryptpad-dropdown-view",
'class': DROPDOWN_CLS
}).append($dropdownViewShare);
var createHandler = function ($elmt) {
return function () {
if ($elmt.is(':visible')) {
$elmt.hide();
return;
}
$userlistElement.find('.' + DROPDOWN_CLS).hide();
$elmt.show();
};
};
$editIcon.click(createHandler($dropdownEdit));
$editIconSmall.click(createHandler($dropdownEdit));
$viewIcon.click(createHandler($dropdownView));
$viewIconSmall.click(createHandler($dropdownView));
$dropdownEditContainer.append($editIcon).append($editIconSmall).append($dropdownEdit);
$dropdownViewContainer.append($viewIcon).append($viewIconSmall).append($dropdownView);
$listElement.append($dropdownEditContainer);
if (readOnly !== -1) {
$listElement.append($dropdownViewContainer);
}
};
var createUserList = function ($container, readOnly) {
var $state = $('<span>', {'class': STATE_CLS}).text(Messages.synchronizing);
var $usernameElement = $('<span>', {'class': USERNAME_CLS});
var $userlist = $('<div>', { var $userlist = $('<div>', {
'class': USER_LIST_CLS, 'class': USER_LIST_CLS,
id: uid(), id: uid(),
}); }).append($state).append($usernameElement);
createUserButtons($userlist, readOnly);
$container.append($userlist); $container.append($userlist);
return $userlist[0]; return $userlist[0];
}; };
var getOtherUsers = function(myUserName, userList, userData) { var getOtherUsers = function(myUserName, userList, userData) {
var i = 0; var i = 0;
var list = ''; var list = [];
userList.forEach(function(user) { userList.forEach(function(user) {
if(user !== myUserName) { if(user !== myUserName) {
var data = (userData) ? (userData[user] || null) : null; var data = (userData) ? (userData[user] || null) : null;
var userName = (data) ? data.name : null; var userName = (data) ? data.name : null;
if(userName) { if(userName) {
if(i === 0) { list = ' : '; } list.push(userName);
list += userName + ', ';
i++;
} }
} }
}); });
return (i > 0) ? list.slice(0, -2) : list; return list;
}; };
var arrayIntersect = function(a, b) { var arrayIntersect = function(a, b) {
@ -121,46 +192,74 @@ define([
if (n === 1) { return '; + ' + Messages.oneViewer; } if (n === 1) { return '; + ' + Messages.oneViewer; }
return '; + ' + Messages._getKey('viewers', [n]); return '; + ' + Messages._getKey('viewers', [n]);
}; };
var updateUserList = function (myUserName, listElement, userList, userData, readOnly) { var updateUserList = function (myUserName, userlistElement, userList, userData, readOnly, $stateElement) {
var meIdx = userList.indexOf(myUserName); var meIdx = userList.indexOf(myUserName);
if (meIdx === -1) { if (meIdx === -1) {
listElement.textContent = Messages.synchronizing; $stateElement.text(Messages.synchronizing);
return; return;
} }
$stateElement.text('');
// Make sure the user block elements are displayed
var $userButtons = $(userlistElement).find("#userButtons");
$userButtons.show();
var $userElement = $(userlistElement).find('.' + USERNAME_CLS);
$userElement.show();
var numberOfUsers = userList.length; var numberOfUsers = userList.length;
// If we are using old pads (readonly unavailable), only editing users are in userList.
// With new pads, we also have readonly users in userList, so we have to intersect with
// the userData to have only the editing users. We can't use userData directly since it
// contains data about users that have already left the channel.
userList = readOnly === -1 ? userList : arrayIntersect(userList, Object.keys(userData)); userList = readOnly === -1 ? userList : arrayIntersect(userList, Object.keys(userData));
var innerHTML;
var numberOfViewUsers = numberOfUsers - userList.length; var numberOfViewUsers = numberOfUsers - userList.length;
if (readOnly === 1) {
innerHTML = '<span class="' + READONLY_CLS + '">' + Messages.readonly + '</span>'; // Names of editing users
if (userList.length === 0) { var editUsersNames = getOtherUsers(myUserName, userList, userData);
innerHTML += Messages.nobodyIsEditing;
} else if (userList.length === 1) { // Number of anonymous editing users
innerHTML += Messages.onePersonIsEditing + getOtherUsers(myUserName, userList, userData); var anonymous = numberOfUsers - editUsersNames.length;
} else {
innerHTML += Messages._getKey('peopleAreEditing', [userList.length]) + getOtherUsers(myUserName, userList, userData); // Update the userlist
var editUsersList = '';
if (readOnly !== 1) {
editUsersNames.unshift('<span class="yourself">' + Messages.yourself + '</span>');
anonymous--;
} }
// Remove the current user if (anonymous > 0) {
numberOfViewUsers--; var text = anonymous === 1 ? Messages.anonymousUser : Messages.anonymousUsers;
editUsersNames.push('<span class="anonymous">' + anonymous + ' ' + text + '</span>');
} }
else { if (editUsersNames.length > 0) {
if (userList.length === 1) { editUsersList += editUsersNames.join('<br>');
innerHTML = Messages.editingAlone;
} else if (userList.length === 2) {
innerHTML = Messages.editingWithOneOtherPerson + getOtherUsers(myUserName, userList, userData);
} else {
innerHTML = Messages.editingWith + ' ' + (userList.length - 1) + ' ' + Messages.otherPeople + getOtherUsers(myUserName, userList, userData);
} }
var $usersTitle = $('<h2>').text(Messages.users);
var $editUsers = $userButtons.find('.' + USERLIST_CLS);
$editUsers.html('').append($usersTitle).append(editUsersList);
// Update the buttons
var fa_caretdown = '<span class="fa fa-caret-down" style="font-family:FontAwesome;"></span>';
var fa_editusers = '<span class="fa fa-users" style="font-family:FontAwesome;"></span>';
var fa_viewusers = '<span class="fa fa-eye" style="font-family:FontAwesome;"></span>';
$userButtons.find('.userlist.edit').html(fa_editusers + ' ' + userList.length + ' ' + Messages.editing + ' ' + fa_caretdown);
$userButtons.find('.userlist.edit.small').html(fa_editusers + ' ' + userList.length + ' ' + fa_caretdown);
$userButtons.find('.userlist.view').html(fa_viewusers + ' ' + numberOfViewUsers + ' ' + Messages.viewing + ' ' + fa_caretdown);
$userButtons.find('.userlist.view.small').html(fa_viewusers + ' ' + numberOfViewUsers + ' ' + fa_caretdown);
if (readOnly === 1) {
// TODO
$userElement.html('<span class="' + READONLY_CLS + '">' + Messages.readonly + '</span>');
} }
innerHTML += getViewers(numberOfViewUsers); else {
if (userData[myUserName]) { var name = userData[myUserName] && userData[myUserName].name;
var name = userData[myUserName].name; var icon = '<span class="fa fa-user" style="font-family:FontAwesome;"></span>';
if (!name) { if (!name) {
name = '<span title="' + Messages.anonymous + '" class="fa fa-user-secret" style="font-family:FontAwesome"></span>'; name = Messages.anonymous;
} }
innerHTML = '<span class="' + USERNAME_CLS + '">' + name + '</span> | ' + innerHTML; $userElement.find("button").html(icon + ' ' + name);
} }
listElement.innerHTML = innerHTML;
}; };
var createLagElement = function ($container) { var createLagElement = function ($container) {
@ -168,7 +267,7 @@ define([
'class': LAG_ELEM_CLS, 'class': LAG_ELEM_CLS,
id: uid(), id: uid(),
}); });
$container.append($lag); $container.before($lag);
return $lag[0]; return $lag[0];
}; };
@ -202,18 +301,35 @@ define([
}; };
var create = Bar.create = function ($container, myUserName, realtime, getLag, userList, config) { var create = Bar.create = function ($container, myUserName, realtime, getLag, userList, config) {
var readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1;
var toolbar = createRealtimeToolbar($container); var toolbar = createRealtimeToolbar($container);
var userListElement = createUserList(toolbar.find('.' + LEFTSIDE_CLS)); var userListElement = createUserList(toolbar.find('.' + LEFTSIDE_CLS), readOnly);
var spinner = createSpinner(toolbar.find('.' + RIGHTSIDE_CLS)); var spinner = createSpinner(toolbar.find('.' + RIGHTSIDE_CLS));
var lagElement = createLagElement(toolbar.find('.' + RIGHTSIDE_CLS)); var lagElement = createLagElement(toolbar.find('.' + RIGHTSIDE_CLS));
var userData = config.userData; var userData = config.userData;
// readOnly = 1 (readOnly enabled), 0 (disabled), -1 (old pad without readOnly mode) // readOnly = 1 (readOnly enabled), 0 (disabled), -1 (old pad without readOnly mode)
var readOnly = (typeof config.readOnly !== "undefined") ? (config.readOnly ? 1 : 0) : -1;
var saveElement; var saveElement;
var loadElement; var loadElement;
var $stateElement = $(userListElement).find('.' + STATE_CLS);
var connected = false; var connected = false;
if (config.ifrw) {
var removeDropdowns = function (e) {
if ($(e.target).parents('.cryptpad-dropdown-container').length) {
return;
}
$container.find('.cryptpad-dropdown').hide();
};
$(config.ifrw).on('click',removeDropdowns);
if (config.ifrw.$('iframe').length) {
var innerIfrw = config.ifrw.$('iframe').each(function (i, el) {
$(el.contentWindow).on('click', removeDropdowns);
});
}
}
userList.onChange = function(newUserData) { userList.onChange = function(newUserData) {
var users = userList.users; var users = userList.users;
if (users.indexOf(myUserName) !== -1) { connected = true; } if (users.indexOf(myUserName) !== -1) { connected = true; }
@ -221,7 +337,7 @@ define([
if(newUserData) { // Someone has changed his name/color if(newUserData) { // Someone has changed his name/color
userData = newUserData; userData = newUserData;
} }
updateUserList(myUserName, userListElement, users, userData, readOnly); updateUserList(myUserName, userListElement, users, userData, readOnly, $stateElement);
}; };
var ks = function () { var ks = function () {
@ -241,13 +357,13 @@ define([
return { return {
failed: function () { failed: function () {
connected = false; connected = false;
userListElement.textContent = Messages.disconnected; $stateElement.text(Messages.disconnected);
checkLag(undefined, lagElement); checkLag(undefined, lagElement);
}, },
reconnecting: function (userId) { reconnecting: function (userId) {
myUserName = userId; myUserName = userId;
connected = false; connected = false;
userListElement.textContent = Messages.reconnecting; $stateElement.text(Messages.reconnecting);
checkLag(getLag, lagElement); checkLag(getLag, lagElement);
}, },
connected: function () { connected: function () {

@ -5,6 +5,18 @@
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css"> <link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
<script src="/bower_components/jquery/dist/jquery.min.js"></script> <script src="/bower_components/jquery/dist/jquery.min.js"></script>
<script src="/bower_components/ckeditor/ckeditor.js"></script> <script src="/bower_components/ckeditor/ckeditor.js"></script>
<style>
#cke_1_top {
overflow: visible;
}
#cke_1_toolbox {
display: inline-block;
width: 100%;
}
#cke_1_top .cryptpad-toolbar {
margin-bottom: 1px;
}
</style>
</head> </head>
<body> <body>
<textarea style="display:none" id="editor1" name="editor1"></textarea> <textarea style="display:none" id="editor1" name="editor1"></textarea>

@ -250,9 +250,16 @@ define([
}; };
var initializing = true; var initializing = true;
var userList = {}; // List of pretty name of all users (mapped with their server ID) var userList = module.userList = {}; // List of pretty name of all users (mapped with their server ID)
var toolbarList; // List of users still connected to the channel (server IDs) var toolbarList; // List of users still connected to the channel (server IDs)
var addToUserList = function(data) { var addToUserList = function(data) {
var users = module.users;
if (users && users.length) {
for (var userKey in userList) {
if (users.indexOf(userKey) === -1) { delete userList[userKey]; }
}
}
for (var attrname in data) { userList[attrname] = data[attrname]; } for (var attrname in data) { userList[attrname] = data[attrname]; }
if(toolbarList && typeof toolbarList.onChange === "function") { if(toolbarList && typeof toolbarList.onChange === "function") {
toolbarList.onChange(userList); toolbarList.onChange(userList);
@ -510,12 +517,16 @@ define([
toolbarList = info.userList; toolbarList = info.userList;
var config = { var config = {
userData: userList, userData: userList,
readOnly: readOnly readOnly: readOnly,
ifrw: ifrw
}; };
if (readOnly) {delete config.changeNameID; } if (readOnly) {delete config.changeNameID; }
toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); toolbar = info.realtime.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside); var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username);
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
var editHash; var editHash;
var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys); var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys);
@ -529,8 +540,8 @@ define([
var usernameCb = function (newName) { var usernameCb = function (newName) {
setName (newName); setName (newName);
}; };
var $username = Cryptpad.createButton('username', true, {lastName: lastName}, usernameCb); var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb);
$rightside.append($username); $userBlock.append($username).hide();
}); });
/* add an export button */ /* add an export button */
@ -560,10 +571,15 @@ define([
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb); var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad); $rightside.append($forgetPad);
if (!readOnly && viewHash) { if (!readOnly) {
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
}
if (viewHash) {
/* add a 'links' button */ /* add a 'links' button */
var $links = Cryptpad.createButton('readonly', true, {viewHash: viewHash}); $viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash}));
$rightside.append($links); if (!readOnly) {
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash}));
}
} }
// set the hash // set the hash
@ -594,6 +610,7 @@ define([
//logging: true, //logging: true,
}); });
module.users = info.userList.users;
module.realtime = info.realtime; module.realtime = info.realtime;
var shjson = info.realtime.getUserDoc(); var shjson = info.realtime.getUserDoc();

@ -19,18 +19,22 @@
html, body { html, body {
overflow-y: hidden; overflow-y: hidden;
} }
#pad-iframe { #iframe-container {
position: fixed; position: fixed;
top:2.5em; top: 2.6em;
left:0px;
bottom: 0px; bottom: 0px;
right: 0px; right: 0px;
left: 0px;
padding: 0px;
}
#pad-iframe {
width:100%; width:100%;
height:100%; height:100%;
border:none; border:none;
margin:0; margin:0;
padding:0; padding:0;
overflow:hidden; overflow:hidden;
box-sizing: border-box;
} }
/* We use !important here to override the 96% set to the element in DecorateToolbar.js /* We use !important here to override the 96% set to the element in DecorateToolbar.js
when we enter fullscreen mode. It allows us to avoid changing the iframe's size in JS */ when we enter fullscreen mode. It allows us to avoid changing the iframe's size in JS */
@ -38,10 +42,16 @@
top: 0px; top: 0px;
height: 100% !important; height: 100% !important;
} }
#iframe-container.fullscreen {
top: 0px;
height: 100% !important;
}
</style> </style>
</head> </head>
<body> <body>
<div id="iframe-container">
<iframe id="pad-iframe" src="inner.html"></iframe> <iframe id="pad-iframe" src="inner.html"></iframe>
</div>
</body> </body>
</html> </html>

@ -41,6 +41,10 @@
box-sizing: border-box; box-sizing: border-box;
position: relative; position: relative;
} }
body {
display: flex;
flex-flow: column;
}
#bar > button { #bar > button {
margin: 5px; margin: 5px;
} }
@ -111,21 +115,17 @@
html { html {
height: 100%; height: 100%;
} }
body { .CodeMirror {
height: 100%; height: 100%;
margin: 0px;
} }
.CodeMirror { .cryptpad-toolbar {
position: absolute; padding: 0px 6px;
top: 25px; }
bottom: 0px; #cme_toolbox div.cryptpad-lag {
left: 0px; line-height: 24px;
right: 0px;
height: auto;
} }
#cme_toolbox { #cme_toolbox {
font: 12px Arial,Helvetica,Tahoma,Verdana,sans-serif; font: 12px Arial,Helvetica,Tahoma,Verdana,sans-serif;
height: 25px;
background: -webkit-linear-gradient(#EEEEEE, #DADADA); /* For Safari 5.1 to 6.0 */ background: -webkit-linear-gradient(#EEEEEE, #DADADA); /* For Safari 5.1 to 6.0 */
background: -o-linear-gradient(white, #DDDDDD); /* For Opera 11.1 to 12.0 */ background: -o-linear-gradient(white, #DDDDDD); /* For Opera 11.1 to 12.0 */
background: -moz-linear-gradient(white, #DDDDDD); /* For Firefox 3.6 to 15 */ background: -moz-linear-gradient(white, #DDDDDD); /* For Firefox 3.6 to 15 */

@ -328,17 +328,68 @@ define([
onLocal(); onLocal();
}; };
var updateTitle = function (newTitle) {
if (newTitle === APP.title) { return; }
// Change the title now, and set it back to the old value if there is an error
var oldTitle = APP.title;
APP.title = newTitle;
setTabTitle();
Cryptpad.setPadTitle(newTitle, function (err, data) {
if (err) {
console.log("Couldn't set pad title");
console.error(err);
APP.title = oldTitle;
setTabTitle();
return;
}
});
};
var updateColors = function (text, back) {
if (text) {
textColor = text;
$modal.css('color', text);
$pad.contents().find('#' + SLIDE_COLOR_ID).css('color', text);
}
if (back) {
backColor = back;
$modal.css('background-color', back);
$pad.contents().find('#' + SLIDE_COLOR_ID).css('background', back);
$pad.contents().find('#' + SLIDE_BACKCOLOR_ID).css('color', back);
}
};
var updateMetadata = function(shjson) {
// Extract the user list (metadata) from the hyperjson
var json = (shjson === "") ? "" : JSON.parse(shjson);
if (json && json.metadata) {
if (json.metadata.users) {
var userData = json.metadata.users;
// Update the local user data
addToUserList(userData);
}
if (json.metadata.title) {
updateTitle(json.metadata.title);
}
updateColors(json.metadata.color, json.metadata.backColor);
}
};
var onInit = config.onInit = function (info) { var onInit = config.onInit = function (info) {
var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox'); var $bar = $('#pad-iframe')[0].contentWindow.$('#cme_toolbox');
toolbarList = info.userList; toolbarList = info.userList;
var config = { var config = {
userData: userList, userData: userList,
readOnly: readOnly readOnly: readOnly,
ifrw: $('#pad-iframe')[0].contentWindow
}; };
if (readOnly) {delete config.changeNameID; } if (readOnly) {delete config.changeNameID; }
toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config); toolbar = module.toolbar = Toolbar.create($bar, info.myID, info.realtime, info.getLag, info.userList, config);
var $rightside = $bar.find('.' + Toolbar.constants.rightside); var $rightside = $bar.find('.' + Toolbar.constants.rightside);
var $userBlock = $bar.find('.' + Toolbar.constants.username);
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
var editHash; var editHash;
var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys); var viewHash = Cryptpad.getViewHashFromKeys(info.channel, secret.keys);
@ -352,8 +403,8 @@ define([
var usernameCb = function (newName) { var usernameCb = function (newName) {
setName (newName); setName (newName);
}; };
var $username = Cryptpad.createButton('username', true, {lastName: lastName}, usernameCb); var $username = Cryptpad.createButton('username', false, {lastName: lastName}, usernameCb);
$rightside.append($username); $userBlock.append($username).hide();
}); });
/* add an export button */ /* add an export button */
@ -385,10 +436,15 @@ define([
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb); var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
$rightside.append($forgetPad); $rightside.append($forgetPad);
if (!readOnly && viewHash) { if (!readOnly) {
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
}
if (viewHash) {
/* add a 'links' button */ /* add a 'links' button */
var $links = Cryptpad.createButton('readonly', true, {viewHash: viewHash + '/present'}); $viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash + '/present'}));
$rightside.append($links); if (!readOnly) {
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash + '/present'}));
}
} }
var $present = Cryptpad.createButton('present', true) var $present = Cryptpad.createButton('present', true)
@ -407,13 +463,14 @@ define([
} }
$rightside.append($leavePresent); $rightside.append($leavePresent);
var $language = $('<span>', {
'style': "margin-right: 10px;"
}).text(Messages.type.slide + " (Markdown)");
$rightside.append($language);
var configureTheme = function () { var configureTheme = function () {
/*var $language = $('<span>', {
'style': "margin-right: 10px;",
'class': 'rightside-element'
}).text("Markdown");
$rightside.append($language);*/
/* Remember the user's last choice of theme using localStorage */ /* Remember the user's last choice of theme using localStorage */
var themeKey = 'CRYPTPAD_CODE_THEME'; var themeKey = 'CRYPTPAD_CODE_THEME';
var lastTheme = localStorage.getItem(themeKey) || 'default'; var lastTheme = localStorage.getItem(themeKey) || 'default';
@ -422,6 +479,7 @@ define([
var $themeDropdown = $('<select>', { var $themeDropdown = $('<select>', {
title: 'color theme', title: 'color theme',
id: 'display-theme', id: 'display-theme',
'class': 'rightside-element'
}); });
Themes.forEach(function (o) { Themes.forEach(function (o) {
$themeDropdown.append($('<option>', { $themeDropdown.append($('<option>', {
@ -446,23 +504,24 @@ define([
}; };
var configureColors = function () { var configureColors = function () {
$back = $('<button>', { var $back = $('<button>', {
id: SLIDE_BACKCOLOR_ID, id: SLIDE_BACKCOLOR_ID,
'class': 'fa fa-square', 'class': 'fa fa-square rightside-button',
'style': 'font-family: FontAwesome; color: #000;', 'style': 'font-family: FontAwesome; color: #000;',
title: Messages.backgroundButton + '\n' + Messages.backgroundButtonTitle title: Messages.backgroundButton + '\n' + Messages.backgroundButtonTitle
}); });
$text = $('<button>', { var $text = $('<button>', {
id: SLIDE_COLOR_ID, id: SLIDE_COLOR_ID,
'class': 'fa fa-i-cursor', 'class': 'fa fa-i-cursor rightside-button',
'style': 'font-family: FontAwesome; font-weight: bold; color: #fff; background: #000;', 'style': 'font-family: FontAwesome; font-weight: bold; color: #fff; background: #000;',
title: Messages.colorButton + '\n' + Messages.colorButtonTitle title: Messages.colorButton + '\n' + Messages.colorButtonTitle
}); });
$testColor = $('<input>', { type: 'color', value: '!' }); var $testColor = $('<input>', { type: 'color', value: '!' });
var $check = $pad.contents().find("#colorPicker_check"); var $check = $pad.contents().find("#colorPicker_check");
if ($testColor.attr('type') !== "color" || $testColor.val() === '!') { return; } // TODO if ($testColor.attr('type') !== "color" || $testColor.val() === '!') { return; } // TODO
$back.on('click', function() { $back.on('click', function() {
var $picker = $('<input>', { type: 'color', value: backColor }) var $picker = $('<input>', { type: 'color', value: backColor })
.css({ display: 'none', })
.on('change', function() { .on('change', function() {
updateColors(undefined, this.value); updateColors(undefined, this.value);
onLocal(); onLocal();
@ -474,6 +533,7 @@ define([
}); });
$text.on('click', function() { $text.on('click', function() {
var $picker = $('<input>', { type: 'color', value: textColor }) var $picker = $('<input>', { type: 'color', value: textColor })
.css({ display: 'none', })
.on('change', function() { .on('change', function() {
updateColors(this.value, undefined); updateColors(this.value, undefined);
onLocal(); onLocal();
@ -488,8 +548,8 @@ define([
$rightside.append($back).append($text); $rightside.append($back).append($text);
}; };
configureTheme();
configureColors(); configureColors();
configureTheme();
if (presentMode) { if (presentMode) {
$('#top-bar').hide(); $('#top-bar').hide();
@ -517,53 +577,6 @@ define([
}); });
}; };
var updateTitle = function (newTitle) {
if (newTitle === APP.title) { return; }
// Change the title now, and set it back to the old value if there is an error
var oldTitle = APP.title;
APP.title = newTitle;
setTabTitle();
Cryptpad.setPadTitle(newTitle, function (err, data) {
if (err) {
console.log("Couldn't set pad title");
console.error(err);
APP.title = oldTitle;
setTabTitle();
return;
}
});
};
var updateColors = function (text, back) {
if (text) {
textColor = text;
$modal.css('color', text);
$pad.contents().find('#' + SLIDE_COLOR_ID).css('color', text);
}
if (back) {
backColor = back;
$modal.css('background-color', back);
$pad.contents().find('#' + SLIDE_COLOR_ID).css('background', back);
$pad.contents().find('#' + SLIDE_BACKCOLOR_ID).css('color', back);
}
};
var updateMetadata = function(shjson) {
// Extract the user list (metadata) from the hyperjson
var json = (shjson === "") ? "" : JSON.parse(shjson);
if (json && json.metadata) {
if (json.metadata.users) {
var userData = json.metadata.users;
// Update the local user data
addToUserList(userData);
}
if (json.metadata.title) {
updateTitle(json.metadata.title);
}
updateColors(json.metadata.color, json.metadata.backColor);
}
};
var unnotify = module.unnotify = function () { var unnotify = module.unnotify = function () {
if (module.tabNotification && if (module.tabNotification &&
typeof(module.tabNotification.cancel) === 'function') { typeof(module.tabNotification.cancel) === 'function') {

@ -18,13 +18,6 @@ define([
var $modal; var $modal;
var $content; var $content;
var $pad; var $pad;
Slide.setModal = function ($m, $c, $p, iframe) {
$modal = Slide.$modal = $m;
$content = Slide.$content = $c;
$pad = Slide.$pad = $p;
ifrw = Slide.ifrw = iframe;
addEvent();
};
Slide.onChange = function (f) { Slide.onChange = function (f) {
if (typeof(f) === 'function') { if (typeof(f) === 'function') {
@ -135,6 +128,7 @@ define([
$pad.contents().find('.cryptpad-present-button').hide(); $pad.contents().find('.cryptpad-present-button').hide();
$pad.contents().find('.cryptpad-source-button').show(); $pad.contents().find('.cryptpad-source-button').show();
$pad.addClass('fullscreen'); $pad.addClass('fullscreen');
$('#iframe-container').addClass('fullscreen');
$('.top-bar').hide(); $('.top-bar').hide();
return; return;
} }
@ -143,6 +137,7 @@ define([
$pad.contents().find('.cryptpad-present-button').show(); $pad.contents().find('.cryptpad-present-button').show();
$pad.contents().find('.cryptpad-source-button').hide(); $pad.contents().find('.cryptpad-source-button').hide();
$pad.removeClass('fullscreen'); $pad.removeClass('fullscreen');
$('#iframe-container').removeClass('fullscreen');
$('.top-bar').show(); $('.top-bar').show();
$modal.removeClass('shown'); $modal.removeClass('shown');
}; };
@ -174,7 +169,7 @@ define([
Slide.draw(i); Slide.draw(i);
}; };
var first = Slide.first = function () {$ var first = Slide.first = function () {
console.log('first'); console.log('first');
Slide.lastIndex = Slide.index; Slide.lastIndex = Slide.index;
@ -210,7 +205,7 @@ define([
break; break;
case 35: // end case 35: // end
Slide.last(); Slide.last();
break break;
case 27: // esc case 27: // esc
show(false); show(false);
break; break;
@ -220,5 +215,13 @@ define([
}); });
}; };
Slide.setModal = function ($m, $c, $p, iframe) {
$modal = Slide.$modal = $m;
$content = Slide.$content = $c;
$pad = Slide.$pad = $p;
ifrw = Slide.ifrw = iframe;
addEvent();
};
return Slide; return Slide;
}); });

Loading…
Cancel
Save