Merge branch 'staging' into oo

pull/1/head
ansuz 7 years ago
commit a794efe931

@ -38,7 +38,7 @@
"scrypt-async": "1.2.0", "scrypt-async": "1.2.0",
"require-css": "0.1.10", "require-css": "0.1.10",
"less": "^2.7.2", "less": "^2.7.2",
"bootstrap": "#v4.0.0-alpha.6", "bootstrap": "^v4.0.0",
"diff-dom": "2.1.1", "diff-dom": "2.1.1",
"nthen": "^0.1.5", "nthen": "^0.1.5",
"open-sans-fontface": "^1.4.2", "open-sans-fontface": "^1.4.2",
@ -49,6 +49,6 @@
"sortablejs": "#^1.6.0" "sortablejs": "#^1.6.0"
}, },
"resolutions": { "resolutions": {
"bootstrap": "v4.0.0-alpha.6" "bootstrap": "^v4.0.0"
} }
} }

@ -75,6 +75,7 @@ define([
logLevel: 1, logLevel: 1,
classic: true, classic: true,
ChainPad: ChainPad, ChainPad: ChainPad,
owners: [opt.edPublic]
}; };
var rt = opt.rt = Listmap.create(config); var rt = opt.rt = Listmap.create(config);

@ -72,7 +72,7 @@ define([
]) ])
]) ])
]), ]),
h('div.cp-version-footer', "CryptPad v1.27.0 (null)") h('div.cp-version-footer', "CryptPad v1.28.0 (toString)")
]); ]);
}; };
@ -92,20 +92,25 @@ define([
]); ]);
} }
return h('nav.navbar.navbar-toggleable-md', return h('nav.navbar.navbar-expand-lg',
h('button.navbar-toggler.navbar-toggler-right', {'type':'button'}, {'data-toggle':'collapse'}, {'data-target':'#menuCollapse'}, {'aria-controls': 'menuCollapse'}, {'aria-expanded':'false'}, {'aria-label':'Toggle navigation'}, h('a.navbar-brand', { href: '/index.html'}),
[h('i.fa.fa-bars ') h('button.navbar-toggler', {
]), 'type':'button',
h('a.navbar-brand', { href: '/index.html'}), 'data-toggle':'collapse',
h('div.collapse.navbar-collapse.justify-content-end#menuCollapse', [ 'data-target':'#menuCollapse',
//h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.topbar_whatIsCryptpad), // Moved the FAQ 'aria-controls': 'menuCollapse',
h('a.nav-item.nav-link', { href: '/faq.html'}, Msg.faq_link), 'aria-expanded':'false',
h('a.nav-item.nav-link', { href: 'https://blog.cryptpad.fr/'}, Msg.blog), 'aria-label':'Toggle navigation'
h('a.nav-item.nav-link', { href: '/features.html'}, Msg.features), }, h('i.fa.fa-bars ')),
h('a.nav-item.nav-link', { href: '/privacy.html'}, Msg.privacy), h('div.collapse.navbar-collapse.justify-content-end#menuCollapse', [
h('a.nav-item.nav-link', { href: '/contact.html'}, Msg.contact), //h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.topbar_whatIsCryptpad), // Moved the FAQ
h('a.nav-item.nav-link', { href: '/about.html'}, Msg.about), h('a.nav-item.nav-link', { href: '/faq.html'}, Msg.faq_link),
].concat(rightLinks)) h('a.nav-item.nav-link', { href: 'https://blog.cryptpad.fr/'}, Msg.blog),
h('a.nav-item.nav-link', { href: '/features.html'}, Msg.features),
h('a.nav-item.nav-link', { href: '/privacy.html'}, Msg.privacy),
h('a.nav-item.nav-link', { href: '/contact.html'}, Msg.contact),
h('a.nav-item.nav-link', { href: '/about.html'}, Msg.about),
].concat(rightLinks))
); );
}; };
@ -144,10 +149,10 @@ define([
]), ]),
]), ]),
h('div.row.align-items-center',[ h('div.row.align-items-center',[
h('div.col-12.col-sm-12.col-md-12.col-lg-6.push-lg-6.cp-bio-avatar.cp-bio-avatar-right', [ h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-2.cp-bio-avatar.cp-bio-avatar-right', [
h('img.img-fluid', {'src': '/customize/images/AaronMacSween.jpg'}) h('img.img-fluid', {'src': '/customize/images/AaronMacSween.jpg'})
]), ]),
h('div.col-12.col-sm-12.col-md-12.col-lg-6.pull-lg-6.cp-profile-det',[ h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-1.cp-profile-det',[
h('h3', "Aaron MacSween"), h('h3', "Aaron MacSween"),
h('hr'), h('hr'),
setHTML(h('div#bioAaron'), '<p>Aaron transitioned into distributed systems development from a background in jazz and live stage performance. <br/> He appreciates the elegance of biological systems and functional programming, and focused on both as a student at the University of Toronto, where he studied cognitive and computer sciences.<br/>He moved to Paris in 2015 to work as a research engineer at XWiki SAS, after having dedicated significant time to various cryptography-related software projects.<br/>He spends his spare time experimenting with guitars, photography, science fiction, and spicy food.</p>'), setHTML(h('div#bioAaron'), '<p>Aaron transitioned into distributed systems development from a background in jazz and live stage performance. <br/> He appreciates the elegance of biological systems and functional programming, and focused on both as a student at the University of Toronto, where he studied cognitive and computer sciences.<br/>He moved to Paris in 2015 to work as a research engineer at XWiki SAS, after having dedicated significant time to various cryptography-related software projects.<br/>He spends his spare time experimenting with guitars, photography, science fiction, and spicy food.</p>'),
@ -195,10 +200,10 @@ define([
]), ]),
]), ]),
h('div.row.align-items-center',[ h('div.row.align-items-center',[
h('div.col-12.col-sm-12.col-md-12.col-lg-6.push-lg-6.cp-bio-avatar.cp-bio-avatar-right', [ h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-2.cp-bio-avatar.cp-bio-avatar-right', [
h('img.img-fluid', {'src': '/customize/images/Catalin.jpg'}) h('img.img-fluid', {'src': '/customize/images/Catalin.jpg'})
]), ]),
h('div.col-12.col-sm-12.col-md-12.col-lg-6.pull-lg-6.cp-profile-det',[ h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-1.cp-profile-det',[
h('h3', "Catalin Scripcariu"), h('h3', "Catalin Scripcariu"),
h('hr'), h('hr'),
setHTML(h('div#bioCatalin'), '<p> Catalin is a Maths majour and has worked in B2B sales for 12 years. Design was always his passion and 3 years ago he started to dedicate himself to web design and front-end.<br/>At the beginning of 2017 he joined the XWiki, where he worked both on the business and the community side of XWiki, including the research team and CryptPad. </p>'), setHTML(h('div#bioCatalin'), '<p> Catalin is a Maths majour and has worked in B2B sales for 12 years. Design was always his passion and 3 years ago he started to dedicate himself to web design and front-end.<br/>At the beginning of 2017 he joined the XWiki, where he worked both on the business and the community side of XWiki, including the research team and CryptPad. </p>'),
@ -384,7 +389,8 @@ define([
var item = faq[c][q]; var item = faq[c][q];
if (typeof item !== "object") { return; } if (typeof item !== "object") { return; }
var answer = h('p.cp-faq-questions-a'); var answer = h('p.cp-faq-questions-a');
var question = h('p.cp-faq-questions-q'); var hash = c + '-' + q;
var question = h('p.cp-faq-questions-q#' + hash);
$(question).click(function () { $(question).click(function () {
if ($(answer).is(':visible')) { if ($(answer).is(':visible')) {
return void $(answer).slideUp(); return void $(answer).slideUp();
@ -401,6 +407,10 @@ define([
h('div.cp-faq-category-questions', questions) h('div.cp-faq-category-questions', questions)
])); ]));
}); });
var hash = window.location.hash;
if (hash) {
$(categories).find(hash).click();
}
return h('div#cp-main', [ return h('div#cp-main', [
infopageTopbar(), infopageTopbar(),
h('div.container.cp-container', [ h('div.container.cp-container', [
@ -499,13 +509,13 @@ define([
]), ]),
]), ]),
h('div.row.align-items-center', [ h('div.row.align-items-center', [
h('div.col-12.col-sm-12.col-md-12.col-lg-6.push-lg-6', [ h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-2', [
setHTML(h('h2'), Msg.whatis_zeroknowledge), setHTML(h('h2'), Msg.whatis_zeroknowledge),
setHTML(h('p'), Msg.whatis_zeroknowledge_p1), setHTML(h('p'), Msg.whatis_zeroknowledge_p1),
setHTML(h('p'), Msg.whatis_zeroknowledge_p2), setHTML(h('p'), Msg.whatis_zeroknowledge_p2),
setHTML(h('p'), Msg.whatis_zeroknowledge_p3), setHTML(h('p'), Msg.whatis_zeroknowledge_p3),
]), ]),
h('div.col-12.col-sm-12.col-md-12.col-lg-6.pull-lg-6', [ h('div.col-12.col-sm-12.col-md-12.col-lg-6.order-1', [
h('img#zeroknowledge', { src: '/customize/images/zeroknowledge_small.png?' + urlArgs }), h('img#zeroknowledge', { src: '/customize/images/zeroknowledge_small.png?' + urlArgs }),
]), ]),
]), ]),

@ -0,0 +1,67 @@
@import (once) "./colortheme-all.less";
.checkmark_main(@size) {
@width: round(@size / 8);
@dim1: round(@size / 3);
@dim2: round(2 * @size / 3);
@top: round(@size / 12);
// <label.cp-checkmark><input><span.cp-checkmark-mark></span>Text</label>
.cp-checkmark {
margin: 0;
display: flex;
align-items: center;
position: relative;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
&.cp-checkmark-secondary {
.cp-checkmark-mark {
&:after {
border-color: @colortheme_checkmark-col2;
}
}
input {
&:checked ~ .cp-checkmark-mark {
background-color: @colortheme_checkmark-back2;
}
}
}
&:hover .cp-checkmark-mark {
background-color: @colortheme_checkmark-back0-active;
}
input {
display: none;
&:checked ~ .cp-checkmark-mark {
background-color: @colortheme_checkmark-back1;
&:after {
display: block;
}
}
}
.cp-checkmark-mark {
margin-right: 10px;
position: relative;
height: @size;
width: @size;
background-color: @colortheme_checkmark-back0;
display: flex;
justify-content: center;
&:after {
content: "";
display: none;
margin-top: @top;
width: @dim1;
height: @dim2;
transform: rotate(45deg);
border: solid @colortheme_checkmark-col1;
border-width: 0 @width @width 0;
}
}
}
}

@ -121,3 +121,10 @@
@cryptpad_color_grey: #999999; @cryptpad_color_grey: #999999;
@cryptpad_header_col: #1E1F1F; @cryptpad_header_col: #1E1F1F;
@cryptpad_text_col: #3F4141; @cryptpad_text_col: #3F4141;
@colortheme_checkmark-back0: #ffffff;
@colortheme_checkmark-back0-active: #bbbbbb;
@colortheme_checkmark-back1: #FF0073;
@colortheme_checkmark-col1: #ffffff;
@colortheme_checkmark-back2: #FFFFFF;
@colortheme_checkmark-col2: #000000;

@ -1,5 +1,7 @@
@import (once) "./colortheme-all.less"; @import (once) "./colortheme-all.less";
@import (once) "./tools.less"; @import (once) "./tools.less";
@import (once) "./checkmark.less";
@import (once) './icon-colors.less';
.creation_main() { .creation_main() {
.tippy-popper { .tippy-popper {
@ -31,149 +33,229 @@
max-width: 100%; max-width: 100%;
margin: 40px auto; margin: 40px auto;
text-align: left; text-align: left;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
h2 {
width: 100%;
display: flex;
margin-bottom: 20px;
justify-content: space-between;
.cp-creation-help {
display: none;
}
}
.cp-creation-help-container {
width: 100%;
display: flex;
justify-content: space-between;
p {
padding: 0 20px;
flex-grow: 0;
flex-shrink: 0;
flex-basis: 50%;
text-align: justify;
}
}
@media screen and (max-width: 500px) {
width: ~"calc(100% - 30px)";
}
@media screen and (max-height: 800px), screen and (max-width: 500px) {
h2 .cp-creation-help {
display: inline;
}
.cp-creation-help-container {
display: none;
}
}
@media screen and (min-height: 601px) {
@media screen and (min-width: 501px) {
p {
display: block !important;
}
}
}
} }
.cp-creation-create, .cp-creation-settings { .cp-creation-create, .cp-creation-settings {
margin-top: 0px;
@creation-button: #30B239;
button { button {
.tools_unselectable(); .tools_unselectable();
padding: 15px; padding: 15px;
background: darken(@colortheme_loading-bg, 10%); background: @creation-button;
color: @colortheme_loading-color; color: #FFF;
font-weight: bold;
margin: 3px 10px; margin: 3px 10px;
border: none; border: none;
cursor: pointer; cursor: pointer;
outline: none; outline: none;
width: 100%;
&:hover { &:hover {
background: darken(@colortheme_loading-bg, 5%); //background: darken(@creation-button, 5%);
} background: lighten(@creation-button, 5%);
&.cp-creation-button-selected {
color: darken(@colortheme_loading-bg, 10%);
background: @colortheme_loading-color;
} }
} }
} }
.cp-creation-create {
text-align: center;
margin: auto;
margin-top: 20px;
width: 400px;
max-width: 100%;
button {
margin: 0;
}
}
input[type="radio"] { #cp-creation-form {
display: none; display: flex;
&:checked { flex-flow: column;
& + label { align-items: center;
font-weight: bold; & > div {
background-color: lighten(@colortheme_loading-bg, 20%); width: 400px;
cursor: default; max-width: 100%;
border: 1px solid #c1158e; display: flex;
align-items: center;
flex-wrap: wrap;
font-size: 16px;
margin: 10px 0;
label {
flex: 1;
}
input[type="checkbox"] {
&+ label {
margin-bottom: 0;
flex: 1;
padding: 0 10px;
}
}
.cp-creation-help {
font-size: 18px;
color: white;
&:hover { &:hover {
background-color: lighten(@colortheme_loading-bg, 20%); color: #AAA;
text-decoration: none;
} }
} }
} }
} .cp-creation-slider {
input[type="radio"] + label { display: block;
.tools_unselectable(); overflow: hidden;
display: inline-flex; max-height: 0px;
align-items: center; transition: max-height 0.5s ease-in-out;
justify-content: center; width: 100%;
width: 200px; margin-top: 10px;
height: 50px; &.active {
padding: 5px; max-height: 40px;
margin: 0 20px; }
border: 1px solid @colortheme_loading-color;
cursor: pointer;
&:hover {
background-color: lighten(@colortheme_loading-bg, 10%);
} }
} .cp-creation-expire {
.cp-creation-expire { .cp-creation-expire-picker {
#cp-creation-expire-true { text-align: center;
display: none; input {
&:checked { width: 100px;
& + label {
height: 100px;
.cp-creation-expire-picker {
display: inline;
}
} }
} }
} }
label[for="cp-creation-expire-true"] { .cp-creation-settings {
flex-wrap: wrap; button {
.cp-creation-expire-picker { margin: 0;
display: none; padding: 0;
} }
input { .cp-filler { flex: 1; }
width: 70px; }
div.cp-creation-remember {
margin-top: 30px;
.cp-creation-remember-help {
font-style: italic;
} }
select { }
width: 100px; div.cp-creation-template {
width: 100%;
background-color: darken(@colortheme_modal-bg, 3%);
padding: 20px;
margin: 30px 0;
.cp-creation-title {
padding: 0 0 10px 10px;
margin: auto;
} }
input, select { }
border: none; .cp-creation-template-container {
height: 30px; width: 100%;
background: @colortheme_loading-bg; display: flex;
color: @colortheme_loading-color; flex-wrap: wrap;
border-radius: 3px; justify-content: center;
overflow-y: auto;
align-items: center;
.cp-creation-template-element {
@darker: darken(@colortheme_modal-fg, 30%);
width: 135px;
padding: 5px;
margin: 5px;
display: inline-flex;
flex-flow: column;
box-sizing: content-box;
text-align: left;
line-height: 1em;
cursor: pointer;
background-color: #111;
color: @darker;
border: 1px solid transparent;
&.cp-creation-template-selected {
border: 1px solid white;
background-color: #222;
}
transition: all 0.1s;
&:hover {
color: @colortheme_modal-fg;
}
align-items: center;
img {
max-width: 100px;
max-height: 100px;
background: #fff;
}
.cp-creation-template-element-name {
flex: 1;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
height: 20px;
line-height: 20px;
margin-top: 5px;
max-width: 100%;
}
.fa {
cursor: pointer;
width: 100px;
height: 100px;
font-size: 70px;
text-align: center;
line-height: 100px;
}
} }
} }
} }
.cp-creation-settings {
justify-content: left; .cp-creation-deleted-container {
a { text-align: center;
color: #0275d8; .cp-creation-deleted {
&:hover { background: #111;
color: lighten(#0275d8, 10%); padding: 10px;
} text-align: center;
font-weight: bold;
display: inline-block;
} }
&> span.fa { }
margin-left: 15px;
.checkmark_main(30px);
@media screen and (max-width: @browser_media-narrow-screen) {
& > div {
width: 95%;
margin: 10px auto;
} }
} }
.cp-creation-deleted { @media screen and (max-width: @browser_media-medium-screen) {
background: #111; #cp-creation-form {
padding: 10px; div.cp-creation-template {
text-align: justify; margin: 0;
font-weight: bold; padding: 5px;
.cp-creation-template-container {
.cp-creation-template-element {
flex-flow: row;
margin: 1px;
padding: 5px;
width: 155px;
img {
display: none;
}
.fa {
font-size: 18px;
width: 20px;
height: 20px;
line-height: 20px;
display: inline !important;
}
.cp-creation-template-element-name {
margin: 0;
margin-left: 5px;
}
}
}
}
}
} }
} }
} }

@ -18,7 +18,7 @@
margin: 0; margin: 0;
padding: 15px; padding: 15px;
a { a {
color: darken(@colortheme_link-color, 30%); //color: darken(@colortheme_link-color, 30%);
@spin: spin(lighten(@bg-color, 15%), 180); @spin: spin(lighten(@bg-color, 15%), 180);
color: contrast(lighten(@bg-color, 15%), lighten(@spin, 10%), darken(@spin, 10%)); color: contrast(lighten(@bg-color, 15%), lighten(@spin, 10%), darken(@spin, 10%));
//color: darken(spin(lighten(@bg-color, 15%), 180), 10%); //color: darken(spin(lighten(@bg-color, 15%), 180), 10%);

@ -164,6 +164,7 @@
} }
a { a {
border: 2px solid transparent; border: 2px solid transparent;
white-space: nowrap;
} }
.nav-link { .nav-link {
padding: 0.5em 0.7em; padding: 0.5em 0.7em;

@ -7,9 +7,6 @@ define([
], function ($, h, Pages) { ], function ($, h, Pages) {
$(function () { $(function () {
var $body = $('body'); var $body = $('body');
var isMainApp = function () {
return /^\/(pad|code|slide|poll|whiteboard|file|media|contacts|drive|settings|profile|todo)\/$/.test(location.pathname);
};
var infoPage = function () { var infoPage = function () {
return h('div#mainBlock.hidden', typeof(Pages[location.pathname]) === 'function'? return h('div#mainBlock.hidden', typeof(Pages[location.pathname]) === 'function'?
@ -20,80 +17,18 @@ $(function () {
var pathname = location.pathname; var pathname = location.pathname;
if (isMainApp()) { // add class on info-pages
if (typeof(Pages[pathname]) === 'function') { var css = location.pathname.replace(/(index)?\.html$/gi, "") // .html
var $flash = $('body, #iframe-container, #pad-iframe, textarea'); .replace(/[^a-zA-Z]+/gi, '-') // any non-alpha character
$flash.css({ .replace(/^-|-$/g, ''); // starting/trailing dashes
display: 'none', if (css === '') { css = 'index'; }
opacity: 0, $('body').addClass('cp-page-' + css);
overflow: 'hidden',
});
var ready = function () {
$flash.css({
display: '',
opacity: '',
overflow: '',
});
};
require([
'less!/customize/src/less2/loading.less'
], function () {
if (/whiteboard/.test(pathname)) {
$('body').html(h('body', Pages[pathname]()).innerHTML);
require(['/whiteboard/main.js'], ready);
} else if (/poll/.test(pathname)) {
$('body').html(h('body', Pages[pathname]()).innerHTML);
require(['/poll/main.js'], ready);
} else if (/drive/.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require(['/drive/main.js'], ready);
} else if (/\/file\//.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/file/main.js' ], ready);
} else if (/^\/contacts\/$/.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/contacts/main.js' ], ready);
} else if (/pad/.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/pad/main.js' ], ready);
} else if (/code/.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/code/main.js' ], ready);
} else if (/slide/.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/slide/main.js' ], ready);
} else if (/^\/settings\//.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/settings/main.js', ], ready);
} else if (/^\/profile\//.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/profile/main.js', ], ready);
} else if (/^\/todo\//.test(pathname)) {
$('body').append(h('body', Pages[pathname]()).innerHTML);
require([ '/todo/main.js', ], ready);
}
});
return;
}
} else {
// add class on info-pages
var css = location.pathname.replace(/(index)?\.html$/gi, "") // .html
.replace(/[^a-zA-Z]+/gi, '-') // any non-alpha character
.replace(/^-|-$/g, ''); // starting/trailing dashes
if (css === '')
{
css = 'index';
}
$('body').addClass('cp-page-' + css);
}
window.Tether = function () {}; window.Tether = function () {};
require([ require([
'less!/customize/src/less2/main.less', 'less!/customize/src/less2/main.less',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'/bower_components/bootstrap/dist/js/bootstrap.min.js' '/bower_components/bootstrap/dist/js/bootstrap.bundle.min.js'
], function () { ], function () {
$body.append($main); $body.append($main);
@ -108,6 +43,8 @@ $(function () {
require([ '/customize/main.js', ], function () {}); require([ '/customize/main.js', ], function () {});
} else if (/invite/.test(pathname)) { } else if (/invite/.test(pathname)) {
require([ '/invite/main.js'], function () {}); require([ '/invite/main.js'], function () {});
} else if (/faq/.test(pathname)) {
window.location.hash = window.location.hash;
} else { } else {
require([ '/customize/main.js', ], function () {}); require([ '/customize/main.js', ], function () {});
} }

@ -38,9 +38,11 @@ define(function () {
out.padNotPinned = 'Ce pad va expirer après 3 mois d\'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.'; out.padNotPinned = 'Ce pad va expirer après 3 mois d\'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.';
out.anonymousStoreDisabled = "L'administrateur de cette instance de CryptPad a désactivé le drive pour les utilisateurs non enregistrés. Vous devez vous connecter pour pouvoir utiliser CryptDrive."; out.anonymousStoreDisabled = "L'administrateur de cette instance de CryptPad a désactivé le drive pour les utilisateurs non enregistrés. Vous devez vous connecter pour pouvoir utiliser CryptDrive.";
out.expiredError = "Ce pad a atteint sa date d'expiration est n'est donc plus disponible."; out.expiredError = "Ce pad a atteint sa date d'expiration est n'est donc plus disponible.";
out.expiredErrorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur <em>Échap</em>.<br> Dés que vous aurez quitté la page, il sera impossible de le récupérer.';
out.deletedError = 'Ce pad a été supprimé par son propriétaire et n\'est donc plus disponible.'; out.deletedError = 'Ce pad a été supprimé par son propriétaire et n\'est donc plus disponible.';
out.inactiveError = 'Ce pad a été supprimé en raison de son inactivité. Appuyez sur Échap pour créer un nouveau pad.'; out.inactiveError = 'Ce pad a été supprimé en raison de son inactivité. Appuyez sur Échap pour créer un nouveau pad.';
out.chainpadError = 'Une erreur critique est survenue lors de la mise à jour du contenu. Le pad est désormais en mode lecture seule afin de s\'assurer que vous ne perdiez pas davantage de données.<br>' +
'Appuyez sur <em>Échap</em> pour voir le pad ou rechargez la page pour pouvoir le modifier à nouveau.';
out.errorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur <em>Échap</em>.<br> Dés que vous aurez quitté la page, il sera impossible de le récupérer.';
out.loading = "Chargement..."; out.loading = "Chargement...";
out.error = "Erreur"; out.error = "Erreur";
@ -367,7 +369,7 @@ define(function () {
out.fm_templateName = "Modèles"; out.fm_templateName = "Modèles";
out.fm_searchName = "Recherche"; out.fm_searchName = "Recherche";
out.fm_recentPadsName = "Pads récents"; out.fm_recentPadsName = "Pads récents";
out.fm_ownedPadsName = "Pads possédés"; out.fm_ownedPadsName = "Pads en votre possession";
out.fm_searchPlaceholder = "Rechercher..."; out.fm_searchPlaceholder = "Rechercher...";
out.fm_newButton = "Nouveau"; out.fm_newButton = "Nouveau";
out.fm_newButtonTitle = "Créer un nouveau pad ou un dossier, importer un fichier dans le dossier courant"; out.fm_newButtonTitle = "Créer un nouveau pad ou un dossier, importer un fichier dans le dossier courant";
@ -546,7 +548,12 @@ define(function () {
out.settings_userFeedbackHint2 = "Le contenu de vos pads et les clés de déchiffrement ne seront jamais partagés avec le serveur."; out.settings_userFeedbackHint2 = "Le contenu de vos pads et les clés de déchiffrement ne seront jamais partagés avec le serveur.";
out.settings_userFeedback = "Activer l'envoi de retours d'expérience"; out.settings_userFeedback = "Activer l'envoi de retours d'expérience";
out.settings_anonymous = "Vous n'êtes pas connectés. Ces préférences seront utilisées pour ce navigateur."; out.settings_deleteTitle = "Suppression du compte";
out.settings_deleteHint = "La suppression de votre compte utilisateur est permanente. Votre CryptDrive et votre liste de pads seront supprimés du serveur. Le reste de vos pads sera supprimé après 90 jours d'inactivité si personne ne les a stockés dans leur CryptDrive.";
out.settings_deleteButton = "Supprimer votre compte";
out.settings_deleteModal = "Veuillez envoyer les informations suivantes à votre administrateur CryptPad afin que vos données soient supprimées du serveur.";
out.settings_anonymous = "Vous n'êtes pas connecté. Ces préférences seront utilisées pour ce navigateur.";
out.settings_publicSigningKey = "Clé publique de signature"; out.settings_publicSigningKey = "Clé publique de signature";
out.settings_usage = "Utilisation"; out.settings_usage = "Utilisation";
@ -775,13 +782,13 @@ define(function () {
'Il désigne un document que vous pouvez modifier dans votre navigateur et, en général, vous pouvez voir les modifications effectuées par les autres utilisateurs de manière quasiment instantanée.' 'Il désigne un document que vous pouvez modifier dans votre navigateur et, en général, vous pouvez voir les modifications effectuées par les autres utilisateurs de manière quasiment instantanée.'
}, },
owned: { owned: {
q: "Qu'est-ce qu'un pad possédé ?", q: "Qu'est-ce qu'un pad avec propriétaire ?",
a: "Un <em>pad possédé</em> est un pad créé avec un <em>propriétaire</em> explicite, identifié sur le serveur par sa <em>clé de signature publique</em>.<br>" + a: "Être <em>propriétaire</em> d'un pad signifie que vous êtes identifié comme tel par le serveur avec à votre <em>clé de signature publique</em>.<br>" +
"Le propriétaire d'un pad peut décider de supprimer ce pad du serveur de manière permanente, afin de le rendre inaccessible aux autres collaborateurs même s'ils possédent le lien dans leur CryptDrive." "Le propriétaire d'un pad peut décider de supprimer ce pad du serveur de manière permanente, afin de le rendre inaccessible aux autres collaborateurs même s'ils possédent le lien dans leur CryptDrive."
}, },
expiring: { expiring: {
q: "Qu'est-ce qu'un pad expirant ?", q: "Qu'est-ce qu'un pad à durée de vie ?",
a: "Un <em>pad expirant</em> est un pad créé avec une date définie à partir de laquelle il sera supprimé automatiquement du serveur. Les pads expirants peuvent être configurés pour avoir une durée de vie comprise entre une heure et cent mois. Le pad et tout son historique sera alors inaccessible, de manière permanente, même s'il est en cours d'édition à sa date d'expiration.<br>" + a: "Un <em>pad à durée de vie</em> est un pad créé avec une date définie à partir de laquelle il sera supprimé automatiquement du serveur. Ils peuvent être configurés pour avoir une durée de vie comprise entre une heure et cent mois. Le pad et tout son historique sera alors inaccessible, de manière permanente, même s'il est en cours d'édition à sa date d'expiration.<br>" +
"Si un pad possède une date d'expiration, vous pouvez la vérifier en regardant les <em>propriétés</em> du pad, soit avec un clic-droit sur le pad dans votre CryptDrive, ou soit en cliquant sur Propriétés dans le sous-menu de la barre d'outils de l'application." "Si un pad possède une date d'expiration, vous pouvez la vérifier en regardant les <em>propriétés</em> du pad, soit avec un clic-droit sur le pad dans votre CryptDrive, ou soit en cliquant sur Propriétés dans le sous-menu de la barre d'outils de l'application."
}, },
tag: { tag: {
@ -875,9 +882,9 @@ define(function () {
}, },
remove: { remove: {
q: "J'ai supprimé un pad ou un fichier de mon CryptDrive, mais le contenu est encore disponible. Comment le supprimer ?", q: "J'ai supprimé un pad ou un fichier de mon CryptDrive, mais le contenu est encore disponible. Comment le supprimer ?",
a: "Seuls les <em>pads possédés</em> (introduits en février 2018) peuvent être supprimés du serveur. Ils ne peuvent d'ailleurs être supprimés du serveur que par leur <em>propriétaire</em> (l'utilisateur ayant créé le pad).<br>" + a: "Seuls les <em>pads avec propriétaire</em> (introduits en février 2018) peuvent être supprimés du serveur. Ils ne peuvent d'ailleurs être supprimés du serveur que par leur <em>propriétaire</em> (l'utilisateur ayant créé le pad).<br>" +
"Si vous n'êtes pas le créateur du pad, vous devrez demander au propriétaire de le supprimer pour vous.<br>" + "Si vous n'êtes pas le créateur du pad, vous devrez demander au propriétaire de le supprimer pour vous.<br>" +
"Pour les pads que vous possédez, vous pouvez effectuer un <b>clic-droit sur le pad dans votre CryptDrive</b>, et sélectionner <b>Supprimer du serveur</b>." "Pour les pads dont vous êtes le propriétaire, vous pouvez effectuer un <b>clic-droit sur le pad dans votre CryptDrive</b>, et sélectionner <b>Supprimer du serveur</b>."
}, },
forget: { forget: {
q: "Que faire si j'oublie mon mot de passe ?", q: "Que faire si j'oublie mon mot de passe ?",
@ -1032,7 +1039,7 @@ define(function () {
out.readme_cat1 = "Découvrez votre CryptDrive"; out.readme_cat1 = "Découvrez votre CryptDrive";
out.readme_cat1_l1 = "Créer un pad : Dans votre CryptDrive, cliquez sur {0} puis {1} et vous obtenez un nouveau pad."; // 0: New, 1: Rich Text out.readme_cat1_l1 = "Créer un pad : Dans votre CryptDrive, cliquez sur {0} puis {1} et vous obtenez un nouveau pad."; // 0: New, 1: Rich Text
out.readme_cat1_l2 = "Ouvrir des pads depuis votre CryptDrive : Double-cliquez sur l'icone d'un pad pour l'ouvrir."; out.readme_cat1_l2 = "Ouvrir des pads depuis votre CryptDrive : Double-cliquez sur l'icone d'un pad pour l'ouvrir.";
out.readme_cat1_l3 = "Organiser vos pads : Quand vous êtes connectés, tous les pads auquel vous accédez sont ajoutés dans la section {0} de votre CryptDrive."; // 0: Unsorted files out.readme_cat1_l3 = "Organiser vos pads : Quand vous êtes connecté, tous les pads auquel vous accédez sont ajoutés dans la section {0} de votre CryptDrive."; // 0: Unsorted files
out.readme_cat1_l3_l1 = "Vous pouvez cliquer et faire glisser des fichiers dans des dossiers dans la section {0} de votre CryptDrive, et créer de nouveaux dossiers."; // 0: Documents out.readme_cat1_l3_l1 = "Vous pouvez cliquer et faire glisser des fichiers dans des dossiers dans la section {0} de votre CryptDrive, et créer de nouveaux dossiers."; // 0: Documents
out.readme_cat1_l3_l2 = "N'hésitez pas à utiliser le clic droit sur les icones puisque des menus sont souvent disponibles."; out.readme_cat1_l3_l2 = "N'hésitez pas à utiliser le clic droit sur les icones puisque des menus sont souvent disponibles.";
out.readme_cat1_l4 = "Déplacer des pads vers la corbeille : Vous pouvez cliquer et faire glisser vos pads dans la {0} de la même manière que vous pouvez les déposer dans des dossiers."; // 0: Trash out.readme_cat1_l4 = "Déplacer des pads vers la corbeille : Vous pouvez cliquer et faire glisser vos pads dans la {0} de la même manière que vous pouvez les déposer dans des dossiers."; // 0: Trash
@ -1066,32 +1073,35 @@ define(function () {
// Creation page // Creation page
out.creation_404 = "Ce pad n'existe plus. Vous pouvez créer un nouveau pad en utilisant le formulaire suivant."; out.creation_404 = "Ce pad n'existe plus. Vous pouvez créer un nouveau pad en utilisant le formulaire suivant.";
out.creation_ownedTitle = "Type de pad"; out.creation_ownedTitle = "Type de pad";
out.creation_ownedTrue = "Pad possédé"; out.creation_owned = "Être propriétaire de ce pad";
out.creation_ownedFalse = "Pad ouvert"; out.creation_ownedTrue = "Être propriétaire";
out.creation_owned1 = "Un pad <b>possédé</b> peut être supprimé du serveur à tout moment quand son propriétaire le souhaite. Une fois supprimé, il disparaît du CryptDrive des autres utilisateurs."; out.creation_ownedFalse = "Pas de propriétaire";
out.creation_owned2 = "Un pad <b>ouvert</b> n'a pas de propriétaire et ne peut donc pas être supprimé du serveur à moins d'avoir dépassé sa date d'expiration."; out.creation_owned1 = "Être <b>propriétaire</b> d'un pad signifie que vous pouvez le supprimer du serveur à tout moment. Une fois supprimé, il disparaît du CryptDrive des autres utilisateurs.";
out.creation_owned2 = "Un pad <b>sans propriétaire</b> ne peut pas être supprimé du serveur à moins d'avoir dépassé son éventuelle date d'expiration.";
out.creation_expireTitle = "Durée de vie"; out.creation_expireTitle = "Durée de vie";
out.creation_expire = "Ajouter une durée de vie";
out.creation_expireTrue = "Ajouter durée de vie"; out.creation_expireTrue = "Ajouter durée de vie";
out.creation_expireFalse = "Illimité"; out.creation_expireFalse = "Illimité";
out.creation_expireHours = "Heure(s)"; out.creation_expireHours = "Heure(s)";
out.creation_expireDays = "Jour(s)"; out.creation_expireDays = "Jour(s)";
out.creation_expireMonths = "Mois"; out.creation_expireMonths = "Mois";
out.creation_expire1 = "Un pad <b>illimité</b> ne sera pas supprimé du serveur à moins que son propriétaire ne le décide."; out.creation_expire1 = "Un pad <b>illimité</b> ne sera pas supprimé du serveur à moins que son propriétaire ne le décide.";
out.creation_expire2 = "Un pad <b>expirant</b> a une durée de vie définie, après laquelle il sera supprimé automatiquement du serveur et du CryptDrive des utilisateurs."; out.creation_expire2 = "Un pad <b>à durée de vie</b> sera supprimé automatiquement du serveur et du CryptDrive des utilisateurs lorsque cette durée sera dépassée.";
out.creation_createTitle = "Créer un pad"; out.creation_noTemplate = "Pas de modèle";
out.creation_createFromTemplate = "Depuis un modèle"; out.creation_newTemplate = "Nouveau modèle";
out.creation_createFromScratch = "Nouveau pad vide"; out.creation_create = "Créer";
out.creation_settings = "Préférences des nouveaux pads"; out.creation_saveSettings = "Ne plus me demander";
out.creation_saveSettings = "Sauver les préférences"; out.creation_settings = "Voir davantage de préférences";
out.creation_rememberHelp = "Ouvrez votre page de Préférences pour voir ce formulaire à nouveau.";
// Properties about creation data // Properties about creation data
out.creation_owners = "Propriétaires"; out.creation_owners = "Propriétaires";
out.creation_ownedByOther = "Possédé par un autre utilisateur"; out.creation_ownedByOther = "Appartient à un autre utilisateur";
out.creation_noOwner = "Pas de propriétaire"; out.creation_noOwner = "Pas de propriétaire";
out.creation_expiration = "Date d'expiration"; out.creation_expiration = "Date d'expiration";
out.creation_propertiesTitle = "Disponibilité"; out.creation_propertiesTitle = "Disponibilité";
out.creation_appMenuName = "Mode avancé (Ctrl + E)"; out.creation_appMenuName = "Mode avancé (Ctrl + E)";
out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez aussi appuyer sur <b>Tab</b> pour sélectionner un type et appuyer sur <b>Entrée</b> pour valider."; out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez aussi appuyer sur <b>Tab</b> pour sélectionner un type et appuyer sur <b>Entrée</b> pour valider.";
out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads possédés ou à date d'expiration). Vous pouvez appuyer sur <b>Espace</b> pour changer sa valeur."; out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads avec propriétaire ou à durée de vie). Vous pouvez appuyer sur <b>Espace</b> pour changer sa valeur.";
out.creation_newPadModalAdvanced = "Afficher l'écran de création de pads"; out.creation_newPadModalAdvanced = "Afficher l'écran de création de pads";
// New share modal // New share modal

@ -39,9 +39,11 @@ define(function () {
out.padNotPinned = 'This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.'; out.padNotPinned = 'This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.';
out.anonymousStoreDisabled = "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive."; out.anonymousStoreDisabled = "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive.";
out.expiredError = 'This pad has reached its expiration time and is no longer available.'; out.expiredError = 'This pad has reached its expiration time and is no longer available.';
out.expiredErrorCopy = ' You can still copy the content to another location by pressing <em>Esc</em>.<br>Once you leave this page, it will disappear forever!';
out.deletedError = 'This pad has been deleted by its owner and is no longer available.'; out.deletedError = 'This pad has been deleted by its owner and is no longer available.';
out.inactiveError = 'This pad has been deleted due to inactivity. Press Esc to create a new pad.'; out.inactiveError = 'This pad has been deleted due to inactivity. Press Esc to create a new pad.';
out.chainpadError = 'A critical error occurred when updating your content. This page is in read-only mode to make sure you won\'t lose your work.<br>' +
'Hit <em>Esc</em> to continue to view this pad, or reload to try editing again.';
out.errorCopy = ' You can still copy the content to another location by pressing <em>Esc</em>.<br>Once you leave this page, it will disappear forever!';
out.loading = "Loading..."; out.loading = "Loading...";
out.error = "Error"; out.error = "Error";
@ -550,6 +552,11 @@ define(function () {
out.settings_userFeedbackHint2 = "Your pad's content will never be shared with the server."; out.settings_userFeedbackHint2 = "Your pad's content will never be shared with the server.";
out.settings_userFeedback = "Enable user feedback"; out.settings_userFeedback = "Enable user feedback";
out.settings_deleteTitle = "Account deletion";
out.settings_deleteHint = "Account deletion is permanent. Your CryptDrive and your list of pads will be deleted from the server. The rest of your pads will be deleted in 90 days if nobody else has stored them in their CryptDrive.";
out.settings_deleteButton = "Delete your account";
out.settings_deleteModal = "Share the following information with your CryptPad administrator in order to have your data removed from their server.";
out.settings_anonymous = "You are not logged in. Settings here are specific to this browser."; out.settings_anonymous = "You are not logged in. Settings here are specific to this browser.";
out.settings_publicSigningKey = "Public Signing Key"; out.settings_publicSigningKey = "Public Signing Key";
@ -1113,11 +1120,13 @@ define(function () {
// Creation page // Creation page
out.creation_404 = "This pad not longer exists. Use the following form to create a new pad."; out.creation_404 = "This pad not longer exists. Use the following form to create a new pad.";
out.creation_ownedTitle = "Type of pad"; out.creation_ownedTitle = "Type of pad";
out.creation_ownedTrue = "Owned pad"; out.creation_owned = "Owned pad"; // Creation page
out.creation_ownedTrue = "Owned pad"; // Settings
out.creation_ownedFalse = "Open pad"; out.creation_ownedFalse = "Open pad";
out.creation_owned1 = "An <b>owned</b> pad can be deleted from the server whenever the owner wants. Deleting an owned pad removes it from other users' CryptDrives."; out.creation_owned1 = "An <b>owned</b> pad can be deleted from the server whenever the owner wants. Deleting an owned pad removes it from other users' CryptDrives.";
out.creation_owned2 = "An <b>open</b> pad doesn't have any owner and thus, it can't be deleted from the server unless it has reached its expiration time."; out.creation_owned2 = "An <b>open</b> pad doesn't have any owner and thus, it can't be deleted from the server unless it has reached its expiration time.";
out.creation_expireTitle = "Life time"; out.creation_expireTitle = "Life time";
out.creation_expire = "Expiring pad";
out.creation_expireTrue = "Add a life time"; out.creation_expireTrue = "Add a life time";
out.creation_expireFalse = "Unlimited"; out.creation_expireFalse = "Unlimited";
out.creation_expireHours = "Hour(s)"; out.creation_expireHours = "Hour(s)";
@ -1125,11 +1134,12 @@ define(function () {
out.creation_expireMonths = "Month(s)"; out.creation_expireMonths = "Month(s)";
out.creation_expire1 = "An <b>unlimited</b> pad will not be removed from the server until its owner deletes it."; out.creation_expire1 = "An <b>unlimited</b> pad will not be removed from the server until its owner deletes it.";
out.creation_expire2 = "An <b>expiring</b> pad has a set lifetime, after which it will be automatically removed from the server and other users' CryptDrives."; out.creation_expire2 = "An <b>expiring</b> pad has a set lifetime, after which it will be automatically removed from the server and other users' CryptDrives.";
out.creation_createTitle = "Create a pad"; out.creation_noTemplate = "No template";
out.creation_createFromTemplate = "From template"; out.creation_newTemplate = "New template";
out.creation_createFromScratch = "From scratch"; out.creation_create = "Create";
out.creation_settings = "New Pad settings"; out.creation_saveSettings = "Don't show this again";
out.creation_saveSettings = "Save settings"; out.creation_settings = "View more settings";
out.creation_rememberHelp = "Visit your Settings page to reset this preference";
// Properties about creation data // Properties about creation data
out.creation_owners = "Owners"; out.creation_owners = "Owners";
out.creation_ownedByOther = "Owned by another user"; out.creation_ownedByOther = "Owned by another user";

@ -1,15 +1,17 @@
{ {
"name": "cryptpad", "name": "cryptpad",
"description": "realtime collaborative visual editor with zero knowlege server", "description": "realtime collaborative visual editor with zero knowlege server",
"version": "1.27.0", "version": "1.28.0",
"license": "AGPL-3.0-or-later", "license": "AGPL-3.0-or-later",
"dependencies": { "dependencies": {
"chainpad-server": "^2.0.0", "chainpad-server": "^2.0.0",
"express": "~4.16.0", "express": "~4.16.0",
"mkdirp": "^0.5.1",
"nthen": "~0.1.0", "nthen": "~0.1.0",
"pull-stream": "^3.6.1", "pull-stream": "^3.6.1",
"replify": "^1.2.0", "replify": "^1.2.0",
"saferphore": "0.0.1", "saferphore": "0.0.1",
"sortify": "^1.0.4",
"stream-to-pull-stream": "^1.7.2", "stream-to-pull-stream": "^1.7.2",
"tweetnacl": "~0.12.2", "tweetnacl": "~0.12.2",
"ws": "^1.0.1", "ws": "^1.0.1",

118
rpc.js

@ -13,6 +13,7 @@ const Package = require('./package.json');
const Pinned = require('./pinned'); const Pinned = require('./pinned');
const Saferphore = require("saferphore"); const Saferphore = require("saferphore");
const nThen = require("nthen"); const nThen = require("nthen");
const Mkdirp = require("mkdirp");
var RPC = module.exports; var RPC = module.exports;
@ -836,6 +837,17 @@ var removeOwnedChannel = function (Env, channelId, unsafeKey, cb) {
}); });
}; };
/* Users should be able to clear their own pin log with an authenticated RPC
*/
var removePins = function (Env, safeKey, cb) {
if (typeof(Env.pinStore.removeChannel) !== 'function') {
return void cb("E_NOT_IMPLEMENTED");
}
Env.pinStore.removeChannel(safeKey, function (err) {
cb(err);
});
};
var upload = function (Env, publicKey, content, cb) { var upload = function (Env, publicKey, content, cb) {
var paths = Env.paths; var paths = Env.paths;
var dec; var dec;
@ -980,6 +992,99 @@ var upload_complete = function (Env, publicKey, cb) {
tryRandomLocation(handleMove); tryRandomLocation(handleMove);
}; };
var owned_upload_complete = function (Env, safeKey, cb) {
var session = getSession(Env.Sessions, safeKey);
// the file has already been uploaded to the staging area
// close the pending writestream
if (session.blobstage && session.blobstage.close) {
session.blobstage.close();
delete session.blobstage;
}
var oldPath = makeFilePath(Env.paths.staging, safeKey);
if (typeof(oldPath) !== 'string') {
return void cb('EINVAL_CONFIG');
}
// construct relevant paths
var root = Env.paths.staging;
//var safeKey = escapeKeyCharacters(safeKey);
var safeKeyPrefix = safeKey.slice(0, 2);
var blobId = createFileId();
var blobIdPrefix = blobId.slice(0, 2);
var plannedPath = Path.join(root, safeKeyPrefix, safeKey, blobIdPrefix);
var tries = 0;
var chooseSafeId = function (cb) {
if (tries >= 3) {
// you've already failed three times in a row
// give up and return an error
cb('E_REPEATED_FAILURE');
}
var path = Path.join(plannedPath, blobId);
Fs.access(path, Fs.constants.R_OK | Fs.constants.W_OK, function (e) {
if (!e) {
// generate a new id (with the same prefix) and recurse
blobId = blobIdPrefix + createFileId().slice(2);
return void chooseSafeId(cb);
} else if (e.code === 'ENOENT') {
// no entry, so it's safe for us to proceed
return void cb(void 0, path);
} else {
// it failed in an unexpected way. log it
// try again, but no more than a fixed number of times...
tries++;
chooseSafeId(cb);
}
});
};
// the user wants to move it into their own space
// /blob/safeKeyPrefix/safeKey/blobPrefix/blobID
var finalPath;
nThen(function (w) {
// make the requisite directory structure using Mkdirp
Mkdirp(plannedPath, w(function (e /*, path */) {
if (e) { // does not throw error if the directory already existed
w.abort();
return void cb(e);
}
}));
}).nThen(function (w) {
// produce an id which confirmably does not collide with another
chooseSafeId(w(function (e, path) {
if (e) {
w.abort();
return void cb(e);
}
finalPath = path; // this is where you'll put the new file
}));
}).nThen(function (w) {
// move the existing file to its new path
// flow is dumb and I need to guard against this which will never happen
/*:: if (typeof(oldPath) === 'object') { throw new Error('should never happen'); } */
Fs.rename(oldPath /* XXX */, finalPath, w(function (e) {
if (e) {
w.abort();
return void cb(e.code);
}
// otherwise it worked...
}));
}).nThen(function () {
// clean up their session when you're done
// call back with the blob id...
cb(void 0, blobId);
});
};
var upload_status = function (Env, publicKey, filesize, cb) { var upload_status = function (Env, publicKey, filesize, cb) {
var paths = Env.paths; var paths = Env.paths;
@ -1054,10 +1159,12 @@ var isAuthenticatedCall = function (call) {
'GET_LIMIT', 'GET_LIMIT',
'UPLOAD_STATUS', 'UPLOAD_STATUS',
'UPLOAD_COMPLETE', 'UPLOAD_COMPLETE',
'OWNED_UPLOAD_COMPLETE',
'UPLOAD_CANCEL', 'UPLOAD_CANCEL',
'EXPIRE_SESSION', 'EXPIRE_SESSION',
'CLEAR_OWNED_CHANNEL', 'CLEAR_OWNED_CHANNEL',
'REMOVE_OWNED_CHANNEL', 'REMOVE_OWNED_CHANNEL',
'REMOVE_PINS',
].indexOf(call) !== -1; ].indexOf(call) !== -1;
}; };
@ -1350,6 +1457,11 @@ RPC.create = function (
if (e) { return void Respond(e); } if (e) { return void Respond(e); }
Respond(void 0, "OK"); Respond(void 0, "OK");
}); });
case 'REMOVE_PINS':
return void removePins(Env, safeKey, function (e, response) {
if (e) { return void Respond(e); }
Respond(void 0, response);
});
// restricted to privileged users... // restricted to privileged users...
case 'UPLOAD': case 'UPLOAD':
if (!privileged) { return deny(); } if (!privileged) { return deny(); }
@ -1375,6 +1487,12 @@ RPC.create = function (
WARN(e, hash); WARN(e, hash);
Respond(e, hash); Respond(e, hash);
}); });
case 'OWNED_UPLOAD_COMPLETE':
if (!privileged) { return deny(); }
return void owned_upload_complete(Env, safeKey, function (e, blobId) {
WARN(e, blobId);
Respond(e, blobId);
});
case 'UPLOAD_CANCEL': case 'UPLOAD_CANCEL':
if (!privileged) { return deny(); } if (!privileged) { return deny(); }
return void upload_cancel(Env, safeKey, function (e) { return void upload_cancel(Env, safeKey, function (e) {

@ -638,9 +638,10 @@ define([
var $icon = UI.getIcon(); var $icon = UI.getIcon();
if (!data) { return $icon; } if (!data) { return $icon; }
var href = data.href; var href = data.href;
if (!href) { return $icon; } var type = data.type;
if (!href && !type) { return $icon; }
var type = Hash.parsePadUrl(href).type; if (!type) { type = Hash.parsePadUrl(href).type; }
$icon = UI.getIcon(type); $icon = UI.getIcon(type);
return $icon; return $icon;

@ -237,6 +237,9 @@ define([
$span.prepend(img); $span.prepend(img);
cb($(img)); cb($(img));
}; };
Thumb.addThumbnail = function(thumb, $span, cb) {
return addThumbnail(null, thumb, $span, cb);
};
var getKey = function (href) { var getKey = function (href) {
var parsed = Hash.parsePadUrl(href); var parsed = Hash.parsePadUrl(href);
return 'thumbnail-' + parsed.type + '-' + parsed.hashData.channel; return 'thumbnail-' + parsed.type + '-' + parsed.hashData.channel;

@ -241,7 +241,6 @@ define([
type: 'radio', type: 'radio',
name: 'cp-share-editable', name: 'cp-share-editable',
value: 1, value: 1,
checked: 'checked'
}), }),
h('label', { 'for': 'cp-share-editable-true' }, Messages.share_linkEdit), h('label', { 'for': 'cp-share-editable-true' }, Messages.share_linkEdit),
h('input#cp-share-editable-false.cp-share-editable-value', { h('input#cp-share-editable-false.cp-share-editable-value', {
@ -271,12 +270,12 @@ define([
]); ]);
if (!hashes.editHash) { if (!hashes.editHash) {
$(link).find('#cp-share-editable-false').attr('checked', true); $(link).find('#cp-share-editable-false').attr('checked', true);
$(link).find('#cp-share-editable-true').attr('disabled', true); $(link).find('#cp-share-editable-true').removeAttr('checked').attr('disabled', true);
} }
var saveValue = function () { var saveValue = function () {
var edit = $(link).find('#cp-share-editable-true').is(':checked'); var edit = Util.isChecked($(link).find('#cp-share-editable-true'));
var embed = $(link).find('#cp-share-embed').is(':checked'); var embed = Util.isChecked($(link).find('#cp-share-embed'));
var present = $(link).find('#cp-share-present').is(':checked'); var present = Util.isChecked($(link).find('#cp-share-present'));
common.setAttribute(['general', 'share'], { common.setAttribute(['general', 'share'], {
edit: edit, edit: edit,
embed: embed, embed: embed,
@ -285,9 +284,9 @@ define([
}; };
var getLinkValue = function (initValue) { var getLinkValue = function (initValue) {
var val = initValue || {}; var val = initValue || {};
var edit = initValue ? val.edit : $(link).find('#cp-share-editable-true').is(':checked'); var edit = initValue ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
var embed = initValue ? val.embed : $(link).find('#cp-share-embed').is(':checked'); var embed = initValue ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
var present = initValue ? val.present : $(link).find('#cp-share-present').is(':checked'); var present = initValue ? val.present : Util.isChecked($(link).find('#cp-share-present'));
var hash = (edit && hashes.editHash) ? hashes.editHash : hashes.viewHash; var hash = (edit && hashes.editHash) ? hashes.editHash : hashes.viewHash;
var href = origin + pathname + '#' + hash; var href = origin + pathname + '#' + hash;
@ -372,10 +371,11 @@ define([
common.getAttribute(['general', 'share'], function (err, val) { common.getAttribute(['general', 'share'], function (err, val) {
val = val || {}; val = val || {};
if (val.edit === false) { if (val.edit === false) {
$(link).find('#cp-share-editable-false').attr('checked', true); $(link).find('#cp-share-editable-false').prop('checked', true);
} }
if (val.embed) { $(link).find('#cp-share-embed').attr('checked', true); } else { $(link).find('#cp-share-editable-true').prop('checked', true); }
if (val.present) { $(link).find('#cp-share-present').attr('checked', true); } if (val.embed) { $(link).find('#cp-share-embed').prop('checked', true); }
if (val.present) { $(link).find('#cp-share-present').prop('checked', true); }
$(link).find('#cp-share-link-preview').val(getLinkValue(val)); $(link).find('#cp-share-link-preview').val(getLinkValue(val));
}); });
common.getMetadataMgr().onChange(function () { common.getMetadataMgr().onChange(function () {
@ -865,7 +865,7 @@ define([
var tbState = true; var tbState = true;
common.getAttribute(['general', 'markdown-help'], function (e, data) { common.getAttribute(['general', 'markdown-help'], function (e, data) {
if (e) { return void console.error(e); } if (e) { return void console.error(e); }
if ($(window).height() < 800) { return; } if ($(window).height() < 800 && $(window).width() < 800) { return; }
if (data === true && $toolbarButton.length && tbState) { if (data === true && $toolbarButton.length && tbState) {
$toolbarButton.click(); $toolbarButton.click();
} }
@ -882,7 +882,7 @@ define([
} }
common.getAttribute(['general', 'markdown-help'], function (e, data) { common.getAttribute(['general', 'markdown-help'], function (e, data) {
if (e) { return void console.error(e); } if (e) { return void console.error(e); }
if ($(window).height() < 800) { return; } if ($(window).height() < 800 && $(window).width() < 800) { return; }
if (data === true && $toolbarButton) { if (data === true && $toolbarButton) {
// Show the toolbar using the button to make sure the icon in the button is // Show the toolbar using the button to make sure the icon in the button is
// correct (caret-down / caret-up) // correct (caret-down / caret-up)
@ -977,7 +977,7 @@ define([
}); });
common.getAttribute(['hideHelp', type], function (err, val) { common.getAttribute(['hideHelp', type], function (err, val) {
if ($(window).height() < 800) { return void toggleHelp(true); } if ($(window).height() < 800 && $(window).width() < 800) { return void toggleHelp(true); }
if (val === true) { toggleHelp(true); } if (val === true) { toggleHelp(true); }
}); });
@ -1694,7 +1694,7 @@ define([
$element.attr('data-type', p); $element.attr('data-type', p);
$element.click(function () { $element.click(function () {
$modal.hide(); $modal.hide();
if ($advanced && $advanced.is(':checked')) { if ($advanced && Util.isChecked($advanced)) {
common.sessionStorage.put(Constants.displayPadCreationScreen, true, function (){ common.sessionStorage.put(Constants.displayPadCreationScreen, true, function (){
common.openURL('/' + p + '/'); common.openURL('/' + p + '/');
}); });
@ -1805,6 +1805,7 @@ define([
UIElements.setExpirationValue = function (val, $expire) { UIElements.setExpirationValue = function (val, $expire) {
if (val && typeof (val) === "number") { if (val && typeof (val) === "number") {
$expire.find('#cp-creation-expire').attr('checked', true).trigger('change');
$expire.find('#cp-creation-expire-true').attr('checked', true); $expire.find('#cp-creation-expire-true').attr('checked', true);
if (val % (3600 * 24 * 30) === 0) { if (val % (3600 * 24 * 30) === 0) {
$expire.find('#cp-creation-expire-unit').val("month"); $expire.find('#cp-creation-expire-unit').val("month");
@ -1835,22 +1836,24 @@ define([
var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body); var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body);
var $creation = $('<div>', { id: 'cp-creation', tabindex: 1 }).appendTo($creationContainer); var $creation = $('<div>', { id: 'cp-creation', tabindex: 1 }).appendTo($creationContainer);
var setHTML = function (e, html) {
e.innerHTML = html;
return e;
};
// Title // Title
$creation.append(h('h1.cp-creation-title', Messages['button_new'+type])); var colorClass = 'cp-icon-color-'+type;
$creation.append(h('h2.cp-creation-title', Messages.newButtonTitle));
//$creation.append(h('h2.cp-creation-title.'+colorClass, Messages.newButtonTitle));
// Deleted pad warning // Deleted pad warning
if (metadataMgr.getPrivateData().isDeleted) { if (metadataMgr.getPrivateData().isDeleted) {
$creation.append(h('div.cp-creation-deleted', Messages.creation_404)); $creation.append(h('div.cp-creation-deleted-container',
h('div.cp-creation-deleted', Messages.creation_404)
));
} }
var createHelper = function (text) { var origin = common.getMetadataMgr().getPrivateData().origin;
var q = h('span.cp-creation-help.fa.fa-question', { var createHelper = function (href, text) {
title: text var q = h('a.cp-creation-help.fa.fa-question', {
title: text,
href: origin + href,
target: "_blank"
}); });
return q; return q;
}; };
@ -1858,78 +1861,158 @@ define([
// Owned pads // Owned pads
// Default is Owned pad // Default is Owned pad
var owned = h('div.cp-creation-owned', [ var owned = h('div.cp-creation-owned', [
h('h2', [ h('label.cp-checkmark', [
Messages.creation_ownedTitle, h('input', {
createHelper(Messages.creation_owned1 + '\n' + Messages.creation_owned2) type: 'checkbox',
]), id: 'cp-creation-owned',
h('div.cp-creation-help-container', [ checked: 'checked'
setHTML(h('p'), Messages.creation_owned1), }),
setHTML(h('p'), Messages.creation_owned2) h('span.cp-checkmark-mark'),
Messages.creation_owned
]), ]),
h('input#cp-creation-owned-true.cp-creation-owned-value', { createHelper('/faq.html#keywords-owned', Messages.creation_owned1)
type: 'radio',
name: 'cp-creation-owned',
value: 1,
checked: 'checked'
}),
h('label', { 'for': 'cp-creation-owned-true' }, Messages.creation_ownedTrue),
h('input#cp-creation-owned-false.cp-creation-owned-value', {
type: 'radio',
name: 'cp-creation-owned',
value: 0
}),
h('label', { 'for': 'cp-creation-owned-false' }, Messages.creation_ownedFalse)
]); ]);
$creation.append(owned);
// If set to "open pad", check "open pad"
if (!cfg.owned && typeof cfg.owned !== "undefined") {
$creation.find('#cp-creation-owned-false').attr('checked', true);
}
// Life time // Life time
var expire = h('div.cp-creation-expire', [ var expire = h('div.cp-creation-expire', [
h('h2', [ h('label.cp-checkmark', [
Messages.creation_expireTitle, h('input', {
createHelper(Messages.creation_expire1, Messages.creation_expire2) type: 'checkbox',
id: 'cp-creation-expire'
}),
h('span.cp-checkmark-mark'),
Messages.creation_expire
]), ]),
h('div.cp-creation-help-container', [ createHelper('/faq.html#keywords-expiring', Messages.creation_expire2),
setHTML(h('p'), Messages.creation_expire1), h('div.cp-creation-expire-picker.cp-creation-slider', [
setHTML(h('p'), Messages.creation_expire2) h('input#cp-creation-expire-val', {
]), type: "number",
h('input#cp-creation-expire-false.cp-creation-expire-value', { min: 1,
type: 'radio', max: 100,
name: 'cp-creation-expire', value: 3
value: 0, }),
checked: 'checked' h('select#cp-creation-expire-unit', [
}), h('option', { value: 'hour' }, Messages.creation_expireHours),
h('label', { 'for': 'cp-creation-expire-false' }, Messages.creation_expireFalse), h('option', { value: 'day' }, Messages.creation_expireDays),
h('input#cp-creation-expire-true.cp-creation-expire-value', { h('option', {
type: 'radio', value: 'month',
name: 'cp-creation-expire', selected: 'selected'
value: 1 }, Messages.creation_expireMonths)
}),
h('label', { 'for': 'cp-creation-expire-true' }, [
Messages.creation_expireTrue,
h('span.cp-creation-expire-picker', [
h('input#cp-creation-expire-val', {
type: "number",
min: 1,
max: 100,
value: 3
}),
h('select#cp-creation-expire-unit', [
h('option', { value: 'hour' }, Messages.creation_expireHours),
h('option', { value: 'day' }, Messages.creation_expireDays),
h('option', {
value: 'month',
selected: 'selected'
}, Messages.creation_expireMonths)
])
]) ])
]) ])
]); ]);
$creation.append(expire);
var createDiv = h('div.cp-creation-create');
var $create = $(createDiv);
var templates = h('div.cp-creation-template', [
h('h3.cp-creation-title.'+colorClass, Messages['button_new'+type]),
h('div.cp-creation-template-container', [
h('span.fa.fa-circle-o-notch.fa-spin.fa-4x.fa-fw')
]),
createDiv
]);
var settings = h('div.cp-creation-remember', [
h('label.cp-checkmark', [
h('input', {
type: 'checkbox',
id: 'cp-creation-remember'
}),
h('span.cp-checkmark-mark'),
Messages.creation_saveSettings
]),
createHelper('/settings/#creation', Messages.creation_settings),
h('div.cp-creation-remember-help.cp-creation-slider', Messages.creation_rememberHelp)
]);
$(h('div#cp-creation-form', [
owned,
expire,
settings,
templates
])).appendTo($creation);
// Display templates
var selected = 0;
sframeChan.query("Q_CREATE_TEMPLATES", type, function (err, res) {
if (!res.data || !Array.isArray(res.data)) {
return void console.error("Error: get the templates list");
}
var data = res.data.slice().sort(function (a, b) {
if (a.name === b.name) { return 0; }
return a.name < b.name ? -1 : 1;
});
data.unshift({
name: Messages.creation_noTemplate,
id: 0,
icon: h('span.fa.fa-file')
});
data.push({
name: Messages.creation_newTemplate,
id: -1,
icon: h('span.fa.fa-bookmark')
});
var $container = $(templates).find('.cp-creation-template-container').html('');
data.forEach(function (obj, idx) {
var name = obj.name;
var $span = $('<span>', {
'class': 'cp-creation-template-element',
'title': name,
}).appendTo($container);
$span.data('id', obj.id);
if (idx === 0) { $span.addClass('cp-creation-template-selected'); }
$span.append(obj.icon || UI.getFileIcon({type: type}));
$('<span>', {'class': 'cp-creation-template-element-name'}).text(name)
.appendTo($span);
$span.click(function () {
$container.find('.cp-creation-template-selected')
.removeClass('cp-creation-template-selected');
$span.addClass('cp-creation-template-selected');
selected = idx;
});
// Add thumbnail if it exists
if (obj.thumbnail) {
common.addThumbnail(obj.thumbnail, $span, function () {});
}
});
});
// Change template selection when Tab is pressed
var next = function (revert) {
var max = $creation.find('.cp-creation-template-element').length;
selected = revert ?
(--selected < 0 ? max-1 : selected) :
++selected % max;
$creation.find('.cp-creation-template-element')
.removeClass('cp-creation-template-selected');
$($creation.find('.cp-creation-template-element').get(selected))
.addClass('cp-creation-template-selected');
};
// Display expiration form when checkbox checked
$creation.find('#cp-creation-expire').on('change', function () {
if ($(this).is(':checked')) {
$creation.find('.cp-creation-expire-picker:not(.active)').addClass('active');
$creation.find('#cp-creation-expire-val').focus();
return;
}
$creation.find('.cp-creation-expire-picker').removeClass('active');
$creation.focus();
});
// Display settings help when checkbox checked
$creation.find('#cp-creation-remember').on('change', function () {
if ($(this).is(':checked')) {
$creation.find('.cp-creation-remember-help:not(.active)').addClass('active');
return;
}
$creation.find('.cp-creation-remember-help').removeClass('active');
$creation.focus();
});
// Keyboard shortcuts
$creation.find('#cp-creation-expire-val').keydown(function (e) { $creation.find('#cp-creation-expire-val').keydown(function (e) {
if (e.which === 9) { if (e.which === 9) {
e.stopPropagation(); e.stopPropagation();
@ -1941,15 +2024,23 @@ define([
} }
}); });
// Initial values
if (!cfg.owned && typeof cfg.owned !== "undefined") {
$creation.find('#cp-creation-owned').prop('checked', false);
}
if (cfg.skip) {
$creation.find('#cp-creation-remember').prop('checked', true).trigger('change');
}
UIElements.setExpirationValue(cfg.expire, $creation); UIElements.setExpirationValue(cfg.expire, $creation);
// Create the pad // Create the pad
var getFormValues = function (template) { var getFormValues = function () {
// Type of pad // Type of pad
var ownedVal = parseInt($('input[name="cp-creation-owned"]:checked').val()); var ownedVal = $('#cp-creation-owned').is(':checked') ? 1 : 0;
// Life time // Life time
var expireVal = 0; var expireVal = 0;
if(parseInt($('input[name="cp-creation-expire"]:checked').val())) { if($('#cp-creation-expire').is(':checked')) {
var unit = 0; var unit = 0;
switch ($('#cp-creation-expire-unit').val()) { switch ($('#cp-creation-expire-unit').val()) {
case "hour" : unit = 3600; break; case "hour" : unit = 3600; break;
@ -1960,113 +2051,55 @@ define([
expireVal = ($('#cp-creation-expire-val').val() || 0) * unit; expireVal = ($('#cp-creation-expire-val').val() || 0) * unit;
} }
var $template = $creation.find('.cp-creation-template-selected');
var templateId = $template.data('id') || undefined;
return { return {
owned: ownedVal, owned: ownedVal,
expire: expireVal, expire: expireVal,
template: template templateId: templateId
}; };
}; };
var create = function (template) { var create = function () {
$creationContainer.remove(); var val = getFormValues();
common.createPad(getFormValues(template), function () { var skip = $('#cp-creation-remember').is(':checked');
cb(); common.setAttribute(['general', 'creation', 'skip'], skip, function (e) {
if (e) { return void console.error(e); }
});
common.setAttribute(['general', 'creation', 'noTemplate'], skip, function (e) {
if (e) { return void console.error(e); }
}); });
};
var $create = $(h('div.cp-creation-create', [ common.setAttribute(['general', 'creation', 'owned'], val.owned, function (e) {
h('h2', Messages.creation_createTitle) if (e) { return void console.error(e); }
])).appendTo($creation); });
// Pick a template? common.setAttribute(['general', 'creation', 'expire'], val.expire, function (e) {
sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) { if (e) { return void console.error(e); }
if (!data) { return; } });
var $templateButton = $('<button>').text(Messages.creation_createFromTemplate)
.appendTo($create);
var pickerCfg = {
types: [type],
where: ['template'],
hidden: true
};
common.openFilePicker(pickerCfg);
$templateButton.click(function () { $creationContainer.remove();
// Show the template picker common.createPad(val, function () {
delete pickerCfg.hidden; cb();
common.openFilePicker(pickerCfg);
var first = true; // We can only pick a template once (for a new document)
var fileDialogCfg = {
onSelect: function (data) {
if (data.type === type && first) {
create(data.href);
first = false;
}
}
};
common.initFilePicker(fileDialogCfg);
}); });
}); };
var $button = $('<button>').text(Messages.creation_createFromScratch).appendTo($create); var $button = $('<button>').text(Messages.creation_create).appendTo($create);
$button.addClass('cp-creation-button-selected'); $button.addClass('cp-creation-button-selected');
$button.click(function () { $button.click(function () {
create(); create();
}); });
// Settings button
var origin = common.getMetadataMgr().getPrivateData().origin;
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide();
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide();
var okTo;
var $saveButton = $('<button>').text(Messages.creation_saveSettings).click(function () {
if (okTo) { clearTimeout(okTo); }
$ok.hide();
$spinner.show();
var val = getFormValues();
NThen(function (waitFor) {
common.setAttribute(['general', 'creation', 'owned'], val.owned, waitFor(function (e) {
if (e) { return void console.error(e); }
}));
common.setAttribute(['general', 'creation', 'expire'], val.expire, waitFor(function (e) {
if (e) { return void console.error(e); }
}));
}).nThen(function () {
$spinner.hide();
$ok.show();
okTo = setTimeout(function () {
$ok.hide();
}, 5000);
});
});
$(h('div.cp-creation-settings', [
$saveButton[0],
h('br'),
h('a', {
href: origin + '/settings/#creation',
target: '_blank'
}, Messages.creation_settings),
$ok[0],
$spinner[0]
])).appendTo($creation);
var selected = 0;
var next = function () {
selected = ++selected % $creation.find('button').length;
$creation.find('button').removeClass('cp-creation-button-selected');
$($creation.find('button').get(selected)).addClass('cp-creation-button-selected');
};
$creation.keydown(function (e) { $creation.keydown(function (e) {
if (e.which === 9) { if (e.which === 9) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
next(); next(e.shiftKey);
return; return;
} }
if (e.which === 13) { if (e.which === 13) {
if ($creation.find('.cp-creation-button-selected').length === 1) { $button.click();
$creation.find('.cp-creation-button-selected').click();
}
return; return;
} }
}); });
@ -2079,12 +2112,12 @@ define([
if (err.type === 'EEXPIRED') { if (err.type === 'EEXPIRED') {
msg = Messages.expiredError; msg = Messages.expiredError;
if (err.loaded) { if (err.loaded) {
msg += Messages.expiredErrorCopy; msg += Messages.errorCopy;
} }
} else if (err.type === 'EDELETED') { } else if (err.type === 'EDELETED') {
msg = Messages.deletedError; msg = Messages.deletedError;
if (err.loaded) { if (err.loaded) {
msg += Messages.expiredErrorCopy; msg += Messages.errorCopy;
} }
} }
if (toolbar && typeof toolbar.deleted === "function") { toolbar.deleted(); } if (toolbar && typeof toolbar.deleted === "function") { toolbar.deleted(); }

@ -246,6 +246,21 @@ define([], function () {
} }
}; };
Util.isChecked = function (el) {
// could be nothing...
if (!el) { return false; }
// check if it's a dom element
if (typeof(el.tagName) !== 'undefined') {
return Boolean(el.checked);
}
// sketchy test to see if it's jquery
if (typeof(el.prop) === 'function') {
return Boolean(el.prop('checked'));
}
// else just say it's not checked
return false;
};
return Util; return Util;
}); });
}(self)); }(self));

@ -75,13 +75,7 @@ define([
cb(); cb();
}); });
}; };
// Settings and drive // Settings and drive and auth
common.getUserObject = function (cb) {
postMessage("GET", [], function (obj) {
cb(obj);
});
};
// Settings and auth
common.getUserObject = function (cb) { common.getUserObject = function (cb) {
postMessage("GET", [], function (obj) { postMessage("GET", [], function (obj) {
cb(obj); cb(obj);
@ -94,6 +88,10 @@ define([
}; };
postMessage("MIGRATE_ANON_DRIVE", data, cb); postMessage("MIGRATE_ANON_DRIVE", data, cb);
}; };
// Settings
common.deleteAccount = function (cb) {
postMessage("DELETE_ACCOUNT", null, cb);
};
// Drive // Drive
common.userObjectCommand = function (data, cb) { common.userObjectCommand = function (data, cb) {
postMessage("DRIVE_USEROBJECT", data, cb); postMessage("DRIVE_USEROBJECT", data, cb);
@ -468,6 +466,16 @@ define([
cb(void 0, list); cb(void 0, list);
}); });
}; };
// Get a template href from its id
common.getPadData = function (id, cb) {
postMessage("GET_PAD_DATA", id, function (data) {
cb(void 0, data);
});
};
// Set initial path when creating a pad from pad creation screen
common.setInitialPath = function (path) {
postMessage("SET_INITIAL_PATH", path);
};
// Messaging (manage friends from the userlist) // Messaging (manage friends from the userlist)
common.inviteFromUserlist = function (netfluxId, cb) { common.inviteFromUserlist = function (netfluxId, cb) {

@ -1,4 +1,5 @@
define([ define([
'json.sortify',
'/common/userObject.js', '/common/userObject.js',
'/common/migrate-user-object.js', '/common/migrate-user-object.js',
'/common/common-hash.js', '/common/common-hash.js',
@ -15,7 +16,7 @@ define([
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5', '/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
'/bower_components/chainpad/chainpad.dist.js', '/bower_components/chainpad/chainpad.dist.js',
'/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-listmap/chainpad-listmap.js',
], function (UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger, ], function (Sortify, UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger,
CpNfWorker, NetConfig, AppConfig, CpNfWorker, NetConfig, AppConfig,
Crypto, ChainPad, Listmap) { Crypto, ChainPad, Listmap) {
var Store = {}; var Store = {};
@ -69,8 +70,16 @@ define([
var userChannel = userParsedHash && userParsedHash.channel; var userChannel = userParsedHash && userParsedHash.channel;
if (!userChannel) { return null; } if (!userChannel) { return null; }
var list = store.userObject.getFiles([store.userObject.FILES_DATA]).map(function (id) { // Get the list of pads' channel ID in your drive
return Hash.hrefToHexChannelId(store.userObject.getFileData(id).href); // This list is filtered so that it doesn't include pad owned by other users (you should
// not pin these pads)
var files = store.userObject.getFiles([store.userObject.FILES_DATA]);
var edPublic = store.proxy.edPublic;
var list = files.map(function (id) {
var d = store.userObject.getFileData(id);
if (d.owners && d.owners.length && edPublic &&
d.owners.indexOf(edPublic) === -1) { return; }
return Hash.hrefToHexChannelId(d.href);
}) })
.filter(function (x) { return x; }); .filter(function (x) { return x; });
@ -372,7 +381,7 @@ define([
var metadata = { var metadata = {
// "user" is shared with everybody via the userlist // "user" is shared with everybody via the userlist
user: { user: {
name: store.proxy[Constants.displayNameKey], name: store.proxy[Constants.displayNameKey] || "",
uid: store.proxy.uid, uid: store.proxy.uid,
avatar: Util.find(store.proxy, ['profile', 'avatar']), avatar: Util.find(store.proxy, ['profile', 'avatar']),
profile: Util.find(store.proxy, ['profile', 'view']), profile: Util.find(store.proxy, ['profile', 'view']),
@ -412,6 +421,23 @@ define([
}); });
}; };
Store.deleteAccount = function (data, cb) {
var toSign = {
intent: 'Please delete my account.'
};
var secret = Hash.getSecrets('drive', storeHash);
toSign.drive = secret.channel;
toSign.edPublic = store.proxy.edPublic;
var signKey = Crypto.Nacl.util.decodeBase64(secret.keys.signKey);
console.log(Sortify(toSign));
var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey);
var proofTxt = Crypto.Nacl.util.encodeBase64(proof);
cb({
proof: proofTxt,
toSign: JSON.parse(Sortify(toSign))
});
};
/** /**
* add a "What is CryptPad?" pad in the drive * add a "What is CryptPad?" pad in the drive
* data * data
@ -678,6 +704,13 @@ define([
}); });
cb(list); cb(list);
}; };
Store.getPadData = function (id, cb) {
cb(store.userObject.getFileData(id));
};
Store.setInitialPath = function (path) {
if (!store.data) { return; }
store.data.initialPath = path;
};
// Messaging (manage friends from the userlist) // Messaging (manage friends from the userlist)
var getMessagingCfg = function () { var getMessagingCfg = function () {

@ -117,6 +117,12 @@ define([
case 'GET_SECURE_FILES_LIST': { case 'GET_SECURE_FILES_LIST': {
Store.getSecureFilesList(data, cb); break; Store.getSecureFilesList(data, cb); break;
} }
case 'GET_PAD_DATA': {
Store.getPadData(data, cb); break;
}
case 'SET_INITIAL_PATH': {
Store.setInitialPath(data); break;
}
case 'GET_STRONGER_HASH': { case 'GET_STRONGER_HASH': {
Store.getStrongerHash(data, cb); break; Store.getStrongerHash(data, cb); break;
} }
@ -166,7 +172,10 @@ define([
case 'DRIVE_USEROBJECT': { case 'DRIVE_USEROBJECT': {
Store.userObjectCommand(data, cb); break; Store.userObjectCommand(data, cb); break;
} }
// Settings
case 'DELETE_ACCOUNT': {
Store.deleteAccount(data, cb); break;
}
case 'IS_NEW_CHANNEL': { case 'IS_NEW_CHANNEL': {
Store.isNewChannel(data, cb); break; Store.isNewChannel(data, cb); break;
} }

@ -45,6 +45,7 @@ define([
FORGOTTEN: 'FORGOTTEN', FORGOTTEN: 'FORGOTTEN',
DELETED: 'DELETED', DELETED: 'DELETED',
INFINITE_SPINNER: 'INFINITE_SPINNER', INFINITE_SPINNER: 'INFINITE_SPINNER',
ERROR: 'ERROR',
INITIALIZING: 'INITIALIZING', INITIALIZING: 'INITIALIZING',
HISTORY_MODE: 'HISTORY_MODE', HISTORY_MODE: 'HISTORY_MODE',
READY: 'READY' READY: 'READY'
@ -118,9 +119,9 @@ define([
return; return;
}; };
var stateChange = function (newState) { var stateChange = function (newState, text) {
var wasEditable = (state === STATE.READY); var wasEditable = (state === STATE.READY);
if (state === STATE.DELETED) { return; } if (state === STATE.DELETED || state === STATE.ERROR) { return; }
if (state === STATE.INFINITE_SPINNER && newState !== STATE.READY) { return; } if (state === STATE.INFINITE_SPINNER && newState !== STATE.READY) { return; }
if (newState === STATE.INFINITE_SPINNER || newState === STATE.DELETED) { if (newState === STATE.INFINITE_SPINNER || newState === STATE.DELETED) {
state = newState; state = newState;
@ -147,6 +148,14 @@ define([
evStart.reg(function () { toolbar.failed(); }); evStart.reg(function () { toolbar.failed(); });
break; break;
} }
case STATE.ERROR: {
evStart.reg(function () {
toolbar.errorState(true, text);
var msg = Messages.chainpadError;
UI.errorLoadingScreen(msg, true, true);
});
break;
}
case STATE.FORGOTTEN: { case STATE.FORGOTTEN: {
evStart.reg(function () { toolbar.forgotten(); }); evStart.reg(function () { toolbar.forgotten(); });
break; break;
@ -249,7 +258,12 @@ define([
} }
var contentStr = JSONSortify(content); var contentStr = JSONSortify(content);
cpNfInner.chainpad.contentUpdate(contentStr); try {
cpNfInner.chainpad.contentUpdate(contentStr);
} catch (e) {
stateChange(STATE.ERROR, e.message);
console.error(e);
}
if (cpNfInner.chainpad.getUserDoc() !== contentStr) { if (cpNfInner.chainpad.getUserDoc() !== contentStr) {
console.error("realtime.getUserDoc() !== shjson"); console.error("realtime.getUserDoc() !== shjson");
} }
@ -463,6 +477,7 @@ define([
window.setInterval(function () { window.setInterval(function () {
if (state === STATE.DISCONNECTED) { return; } if (state === STATE.DISCONNECTED) { return; }
if (state === STATE.DELETED) { return; } if (state === STATE.DELETED) { return; }
if (state === STATE.ERROR) { return; }
var l; var l;
try { try {
l = cpNfInner.chainpad.getLag(); l = cpNfInner.chainpad.getLag();

@ -469,6 +469,35 @@ define([
cb(templates.length > 0); cb(templates.length > 0);
}); });
}); });
var getKey = function (href) {
var parsed = Utils.Hash.parsePadUrl(href);
return 'thumbnail-' + parsed.type + '-' + parsed.hashData.channel;
};
sframeChan.on('Q_CREATE_TEMPLATES', function (type, cb) {
Cryptpad.getSecureFilesList({
types: [type],
where: ['template']
}, function (err, data) {
// NOTE: Never return data directly!
if (err) { return void cb({error: err}); }
var res = [];
nThen(function (waitFor) {
Object.keys(data).map(function (el) {
var k = getKey(data[el].href);
Utils.LocalStore.getThumbnail(k, waitFor(function (e, thumb) {
res.push({
id: el,
name: data[el].filename || data[el].title || '?',
thumbnail: thumb
});
}));
});
}).nThen(function () {
cb({data: res});
});
});
});
sframeChan.on('EV_GOTO_URL', function (url) { sframeChan.on('EV_GOTO_URL', function (url) {
if (url) { if (url) {
@ -584,7 +613,7 @@ define([
var replaceHash = function (hash) { var replaceHash = function (hash) {
if (window.history && window.history.replaceState) { if (window.history && window.history.replaceState) {
if (!/^#/.test(hash)) { hash = '#' + hash; } if (!/^#/.test(hash)) { hash = '#' + hash; }
void window.history.replaceState({}, window.document.title, hash); window.history.replaceState({}, window.document.title, hash);
if (typeof(window.onhashchange) === 'function') { if (typeof(window.onhashchange) === 'function') {
window.onhashchange(); window.onhashchange();
} }
@ -646,19 +675,31 @@ define([
if (data.expire) { if (data.expire) {
rtConfig.expire = data.expire; rtConfig.expire = data.expire;
} }
if (data.template) { nThen(function(waitFor) {
// Pass rtConfig to useTemplate because Cryptput will create the file and if (data.templateId) {
// we need to have the owners and expiration time in the first line on the if (data.templateId === -1) {
// server Cryptpad.setInitialPath(['template']);
Cryptpad.useTemplate(data.template, Cryptget, function () { return;
startRealtime(); }
cb(); Cryptpad.getPadData(data.templateId, waitFor(function (err, d) {
}, rtConfig); data.template = d.href;
return; }));
} }
// Start realtime outside the iframe and callback }).nThen(function () {
startRealtime(rtConfig); if (data.template) {
cb(); // Pass rtConfig to useTemplate because Cryptput will create the file and
// we need to have the owners and expiration time in the first line on the
// server
Cryptpad.useTemplate(data.template, Cryptget, function () {
startRealtime();
cb();
}, rtConfig);
return;
}
// Start realtime outside the iframe and callback
startRealtime(rtConfig);
cb();
});
}); });
sframeChan.ready(); sframeChan.ready();

@ -97,6 +97,7 @@ define([
// Thumb // Thumb
funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail); funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail);
funcs.addThumbnail = Thumb.addThumbnail;
// History // History
funcs.getHistory = callWithCommon(History.create); funcs.getHistory = callWithCommon(History.create);
@ -188,7 +189,6 @@ define([
return void funcs.createPad(c, waitFor()); return void funcs.createPad(c, waitFor());
} }
// If we display the pad creation screen, it will handle deleted pads directly // If we display the pad creation screen, it will handle deleted pads directly
console.log('here');
funcs.getPadCreationScreen(c, waitFor()); funcs.getPadCreationScreen(c, waitFor());
} }
}; };
@ -196,7 +196,8 @@ define([
ctx.sframeChan.query("Q_CREATE_PAD", { ctx.sframeChan.query("Q_CREATE_PAD", {
owned: cfg.owned, owned: cfg.owned,
expire: cfg.expire, expire: cfg.expire,
template: cfg.template template: cfg.template,
templateId: cfg.templateId
}, cb); }, cb);
}; };

@ -193,6 +193,7 @@ define({
'Q_SETTINGS_LOGOUT': true, 'Q_SETTINGS_LOGOUT': true,
// Import pads from this computer's anon session into the current user account // Import pads from this computer's anon session into the current user account
'Q_SETTINGS_IMPORT_LOCAL': true, 'Q_SETTINGS_IMPORT_LOCAL': true,
'Q_SETTINGS_DELETE_ACCOUNT': true,
// Store the language selected in the iframe into localStorage outside // Store the language selected in the iframe into localStorage outside
'Q_LANGUAGE_SET': true, 'Q_LANGUAGE_SET': true,
@ -220,6 +221,8 @@ define({
// Pad creation screen: create a pad with the selected attributes (owned, expire) // Pad creation screen: create a pad with the selected attributes (owned, expire)
'Q_CREATE_PAD': true, 'Q_CREATE_PAD': true,
// Get the available templates
'Q_CREATE_TEMPLATES': true,
// This is for sending data out of the iframe when we are in testing mode // This is for sending data out of the iframe when we are in testing mode
// The exact protocol is defined in common/test.js // The exact protocol is defined in common/test.js

@ -400,7 +400,9 @@ define([
}); });
show(); show();
Common.getAttribute(['toolbar', 'userlist-drawer'], function (err, val) { Common.getAttribute(['toolbar', 'userlist-drawer'], function (err, val) {
if (val === false || $(window).height() < 800) { return void hide(); } if (val === false || ($(window).height() < 800 && $(window).width() < 800)) {
return void hide();
}
show(); show();
}); });
@ -885,7 +887,6 @@ define([
var oldUserData; var oldUserData;
if (!config.metadataMgr) { return; } if (!config.metadataMgr) { return; }
var metadataMgr = config.metadataMgr; var metadataMgr = config.metadataMgr;
var userNetfluxId = metadataMgr.getNetfluxId();
var notify = function(type, name, oldname) { var notify = function(type, name, oldname) {
// type : 1 (+1 user), 0 (rename existing user), -1 (-1 user) // type : 1 (+1 user), 0 (rename existing user), -1 (-1 user)
if (typeof name === "undefined") { return; } if (typeof name === "undefined") { return; }
@ -929,6 +930,7 @@ define([
metadataMgr.onChange(function () { metadataMgr.onChange(function () {
var newdata = metadataMgr.getMetadata().users; var newdata = metadataMgr.getMetadata().users;
var netfluxIds = Object.keys(newdata); var netfluxIds = Object.keys(newdata);
var userNetfluxId = metadataMgr.getNetfluxId();
// Notify for disconnected users // Notify for disconnected users
if (typeof oldUserData !== "undefined") { if (typeof oldUserData !== "undefined") {
for (var u in oldUserData) { for (var u in oldUserData) {
@ -1061,6 +1063,7 @@ define([
toolbar.errorState = function (state, error) { toolbar.errorState = function (state, error) {
toolbar.isErrorState = state; toolbar.isErrorState = state;
if (state) { toolbar.connected = false; }
if (toolbar.spinner) { if (toolbar.spinner) {
if (!state) { if (!state) {
return void kickSpinner(toolbar, config); return void kickSpinner(toolbar, config);

@ -2,7 +2,7 @@
<html class="cp-app-noscroll"> <html class="cp-app-noscroll">
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script async data-bootload="/contacts/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script> <script async data-bootload="/contacts/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style> <style>
.loading-hidden { display: none; } .loading-hidden { display: none; }
</style> </style>

@ -280,7 +280,8 @@ define([
framework._.sfCommon.setAttribute(['pad', 'showToolbar'], visible); framework._.sfCommon.setAttribute(['pad', 'showToolbar'], visible);
}; };
framework._.sfCommon.getAttribute(['pad', 'showToolbar'], function (err, data) { framework._.sfCommon.getAttribute(['pad', 'showToolbar'], function (err, data) {
if ($(window).height() >= 800 && (typeof(data) === "undefined" || data)) { $('.cke_toolbox_main').show(); } if (($(window).height() >= 800 || $(window).width() >= 800) &&
(typeof(data) === "undefined" || data)) { $('.cke_toolbox_main').show(); }
else { $('.cke_toolbox_main').hide(); } else { $('.cke_toolbox_main').hide(); }
var $collapse = framework._.sfCommon.createButton('toggle', true, cfg, onClick); var $collapse = framework._.sfCommon.createButton('toggle', true, cfg, onClick);
framework._.toolbar.$rightside.append($collapse); framework._.toolbar.$rightside.append($collapse);

@ -111,11 +111,9 @@ table#cp-app-poll-table {
} }
#cp-app-poll-table-container { #cp-app-poll-table-container {
position: relative; position: relative;
padding: 30px 0; margin: 20px;
width: ~"calc(100% - 30px)";
} }
#cp-app-poll-table-container button { #cp-app-poll-table-container button {
//display: none;
border-radius: 0; border-radius: 0;
border: 0; border: 0;
} }
@ -148,8 +146,8 @@ table#cp-app-poll-table {
#cp-app-poll-table-scroll { #cp-app-poll-table-scroll {
overflow-y: hidden; overflow-y: hidden;
overflow-x: auto; overflow-x: auto;
margin-left: ~"calc(25% + 30px)"; margin-left: 25%;
max-width: ~"calc(75% - 30px - 100px - 100px)"; max-width: ~"calc(75% - 100px - 100px)";
width: auto; width: auto;
display: inline-block; display: inline-block;
} }
@ -227,7 +225,6 @@ table {
margin: 20px; margin: 20px;
} }
tbody { tbody {
//border: 1px solid @poll-border-color;
* { * {
box-sizing: border-box; box-sizing: border-box;
} }
@ -298,7 +295,7 @@ div.cp-app-poll-realtime {
/* Options */ /* Options */
td:first-child { td:first-child {
position:absolute; position:absolute;
left: 30px; left: 0;
top: auto; top: auto;
width: 25%; width: 25%;
} }
@ -454,7 +451,6 @@ div.cp-app-poll-realtime {
&:nth-last-child(2) { &:nth-last-child(2) {
border-right: 1px solid @poll-border-color; border-right: 1px solid @poll-border-color;
} }
//text-align: center;
&.cp-app-poll-table-own { &.cp-app-poll-table-own {
background: @poll-th-user-bg; background: @poll-th-user-bg;
.cp-app-poll-table-lock { .cp-app-poll-table-lock {
@ -631,8 +627,42 @@ div.cp-app-poll-realtime {
} }
} }
} }
@media screen and (max-width: 500px) {
#cp-app-poll-table-scroll {
max-width: 100%;
padding: 0;
margin: 0;
table {
tr {
td {
&:first-child {
position: unset;
min-width: 100px;
&:hover:not(:empty) {
position: absolute;
min-width: 100px;
width: auto;
z-index: 100;
}
}
&:nth-last-child(2) {
position: unset;
}
&:last-child {
position: unset;
}
}
}
}
}
#cp-app-poll-comments {
min-width: 90%;
}
}
} }
.btn { .btn {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;

@ -163,11 +163,10 @@ define([
var sortColumns = function (order, firstcol) { var sortColumns = function (order, firstcol) {
var colsOrder = order.slice(); var colsOrder = order.slice();
// Never put at the first position an uncommitted column // Never put at the first position an uncommitted column
if (APP.proxy.content.colsOrder.indexOf(firstcol) === -1) { return colsOrder; } var idx = APP.proxy.content.colsOrder.indexOf(firstcol);
colsOrder.sort(function (a, b) { if (!firstcol || idx === -1) { return colsOrder; }
return (a === firstcol) ? -1 : colsOrder.splice(idx, 1);
((b === firstcol) ? 1 : 0); colsOrder.unshift(firstcol);
});
return colsOrder; return colsOrder;
}; };
@ -618,7 +617,6 @@ define([
// If readOnly, always put the app in published mode // If readOnly, always put the app in published mode
bool = true; bool = true;
} }
console.log(bool);
$(APP.$mediaTagButton).toggle(!bool); $(APP.$mediaTagButton).toggle(!bool);
setTablePublished(bool); setTablePublished(bool);
/*['textarea'].forEach(function (sel) { /*['textarea'].forEach(function (sel) {
@ -1106,6 +1104,25 @@ define([
} }
}; };
var onError = function (info) {
if (info && info.type) {
if (info.type === 'CHAINPAD') {
APP.unrecoverable = true;
setEditable(false);
APP.toolbar.errorState(true, info.error);
var msg = Messages.chainpadError;
UI.errorLoadingScreen(msg, true, true);
console.error(info.error);
return;
}
// Server error
return void common.onServerError(info, APP.toolbar, function () {
APP.unrecoverable = true;
setEditable(false);
});
}
};
// Manage disconnections because of network or error // Manage disconnections because of network or error
var onDisconnect = function (info) { var onDisconnect = function (info) {
if (APP.unrecoverable) { return; } if (APP.unrecoverable) { return; }
@ -1251,7 +1268,6 @@ define([
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
common.handleNewFile(waitFor); common.handleNewFile(waitFor);
}).nThen(function (/* waitFor */) { }).nThen(function (/* waitFor */) {
console.log('here');
Test.registerInner(common.getSframeChannel()); Test.registerInner(common.getSframeChannel());
var metadataMgr = common.getMetadataMgr(); var metadataMgr = common.getMetadataMgr();
APP.locked = APP.readOnly = metadataMgr.getPrivateData().readOnly; APP.locked = APP.readOnly = metadataMgr.getPrivateData().readOnly;
@ -1318,7 +1334,8 @@ define([
}); });
}) })
.on('disconnect', onDisconnect) .on('disconnect', onDisconnect)
.on('reconnect', onReconnect); .on('reconnect', onReconnect)
.on('error', onError);
}); });
}; };
main(); main();

@ -2,7 +2,7 @@
<html class="cp-app-noscroll"> <html class="cp-app-noscroll">
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script async data-bootload="/profile/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script> <script async data-bootload="/profile/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style> <style>
.loading-hidden { display: none; } .loading-hidden { display: none; }
</style> </style>

@ -138,5 +138,9 @@
} }
} }
} }
.cp-app-settings-delete-alert {
pre { color: inherit; }
}
} }

@ -2,7 +2,7 @@
<html class="cp-app-noscroll"> <html class="cp-app-noscroll">
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script async data-bootload="/settings/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script> <script async data-bootload="/settings/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style> <style>
.loading-hidden { display: none; } .loading-hidden { display: none; }
</style> </style>

@ -47,7 +47,8 @@ define([
'cp-settings-logout-everywhere', 'cp-settings-logout-everywhere',
'cp-settings-resettips', 'cp-settings-resettips',
'cp-settings-thumbnails', 'cp-settings-thumbnails',
'cp-settings-userfeedback' 'cp-settings-userfeedback',
'cp-settings-delete'
], ],
'creation': [ 'creation': [
'cp-settings-creation-owned', 'cp-settings-creation-owned',
@ -317,6 +318,48 @@ define([
return $div; return $div;
}; };
create['delete'] = function () {
var $div = $('<div>', { 'class': 'cp-settings-delete cp-sidebarlayout-element'});
$('<span>', {'class': 'label'}).text(Messages.settings_deleteTitle).appendTo($div);
$('<span>', {'class': 'cp-sidebarlayout-description'})
.append(Messages.settings_deleteHint).appendTo($div);
//var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
var $button = $('<button>', {'id': 'cp-settings-delete', 'class': 'btn btn-danger'})
.text(Messages.settings_deleteButton).appendTo($div);
$button.click(function () {
$spinner.show();
sframeChan.query("Q_SETTINGS_DELETE_ACCOUNT", null, function (err, data) {
var msg = h('div.cp-app-settings-delete-alert', [
h('p', Messages.settings_deleteModal),
h('pre', JSON.stringify(data, 0, 2))
]);
UI.alert(msg);
$spinner.hide();
});
// TODO
/*
UI.confirm("Are you sure?", function (yes) {
// Logout everywhere
// Disconnect other tabs
// Remove owned pads
// Remove owned drive
// Remove pinstore
// Alert: "Account deleted", press OK to be redirected to the home page
$spinner.hide();
});*/
});
$spinner.hide().appendTo($div);
return $div;
};
// Pad Creation settings // Pad Creation settings
var setHTML = function (e, html) { var setHTML = function (e, html) {

@ -65,6 +65,9 @@ define([
sframeChan.on('Q_SETTINGS_IMPORT_LOCAL', function (data, cb) { sframeChan.on('Q_SETTINGS_IMPORT_LOCAL', function (data, cb) {
Cryptpad.mergeAnonDrive(cb); Cryptpad.mergeAnonDrive(cb);
}); });
sframeChan.on('Q_SETTINGS_DELETE_ACCOUNT', function (data, cb) {
Cryptpad.deleteAccount(cb);
});
}; };
var category; var category;
if (window.location.hash) { if (window.location.hash) {

@ -2,7 +2,7 @@
<html class="cp-app-noscroll"> <html class="cp-app-noscroll">
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script async data-bootload="/todo/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script> <script async data-bootload="/todo/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style> <style>
.loading-hidden { display: none; } .loading-hidden { display: none; }
</style> </style>

@ -346,7 +346,16 @@ define([
var content = stringifyInner(canvas.toDatalessJSON()); var content = stringifyInner(canvas.toDatalessJSON());
APP.realtime.contentUpdate(content); try {
APP.realtime.contentUpdate(content);
} catch (e) {
APP.unrecoverable = true;
setEditable(false);
APP.toolbar.errorState(true, e.message);
var msg = Messages.chainpadError;
UI.errorLoadingScreen(msg, true, true);
console.error(e);
}
}; };
var addImageToCanvas = function (img) { var addImageToCanvas = function (img) {

@ -2,7 +2,7 @@
<html class="cp-app-noscroll"> <html class="cp-app-noscroll">
<head> <head>
<meta content="text/html; charset=utf-8" http-equiv="content-type"/> <meta content="text/html; charset=utf-8" http-equiv="content-type"/>
<script async data-bootload="/worker/inner.js" data-main="/common/sframe-boot.js?ver=1.4" src="/bower_components/requirejs/require.js?ver=2.3.5"></script> <script async data-bootload="/worker/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
<style> <style>
.loading-hidden { display: none; } .loading-hidden { display: none; }
</style> </style>

Loading…
Cancel
Save