Merge branch 'soon'
commit
9818c562fb
|
@ -10,3 +10,4 @@ messages.log
|
|||
.DS_Store
|
||||
www/scratch
|
||||
data
|
||||
npm-debug.log
|
||||
|
|
|
@ -9,7 +9,7 @@ branches:
|
|||
- soon
|
||||
- staging
|
||||
node_js:
|
||||
- "4.2.1"
|
||||
- "6.6.0"
|
||||
before_script:
|
||||
- npm run-script lint
|
||||
- cp config.js.dist config.js
|
||||
|
|
|
@ -24,23 +24,19 @@
|
|||
"ckeditor": "~4.5.6",
|
||||
"codemirror": "^5.19.0",
|
||||
"requirejs": "~2.1.15",
|
||||
"reconnectingWebsocket": "",
|
||||
"marked": "~0.3.5",
|
||||
"rangy": "rangy-release#~1.3.0",
|
||||
"json.sortify": "~2.1.0",
|
||||
"fabric.js": "fabric#~1.6.0",
|
||||
"hyperjson": "~1.4.0",
|
||||
"textpatcher": "^1.3.0",
|
||||
"proxy-polyfill": "^0.1.5",
|
||||
"chainpad": "^0.3.0",
|
||||
"chainpad-json-validator": "^0.2.0",
|
||||
"chainpad-crypto": "^0.1.3",
|
||||
"chainpad-listmap": "^0.3.0",
|
||||
"lil-uri": "^0.2.1",
|
||||
"file-saver": "^1.3.1",
|
||||
"diff-dom": "^2.1.1",
|
||||
"alertifyjs": "^1.0.11",
|
||||
"spin.js": "^2.3.2",
|
||||
"scrypt-async": "^1.2.0",
|
||||
"bootstrap": "#v4.0.0-alpha.6"
|
||||
}
|
||||
|
|
|
@ -115,6 +115,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -112,6 +112,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -234,6 +234,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
/* Logs are shown to inform the user that something has happened
|
||||
They are only displayed briefly
|
||||
*/
|
||||
@media print {
|
||||
.alertify-logs {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
.alertify-logs > * {
|
||||
padding: 12px 48px;
|
||||
color: #fafafa;
|
||||
|
@ -56,11 +61,25 @@
|
|||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.alertify .dialog .bright,
|
||||
.alertify .alert .bright {
|
||||
color: #ffffff;
|
||||
}
|
||||
.alertify .dialog > div,
|
||||
.alertify .alert > div {
|
||||
background-color: #444;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.alertify .dialog > div.half,
|
||||
.alertify .alert > div.half {
|
||||
width: 50%;
|
||||
}
|
||||
@media (max-width: 600px) {
|
||||
.alertify .dialog > div.half,
|
||||
.alertify .alert > div.half {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
.alertify .dialog > *,
|
||||
.alertify .alert > * {
|
||||
width: 30%;
|
||||
|
@ -118,6 +137,34 @@
|
|||
border: 1px solid #302B28;
|
||||
border-radius: 5px;
|
||||
}
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe,
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger {
|
||||
color: #302B28;
|
||||
white-space: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger {
|
||||
background-color: #FA5858;
|
||||
}
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:hover,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:hover,
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:active,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).danger:active {
|
||||
background-color: #fb7171;
|
||||
}
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe {
|
||||
background-color: #46E981;
|
||||
}
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:hover,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:hover,
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:active,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button).safe:active {
|
||||
background-color: #74eea0;
|
||||
}
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,
|
||||
.alertify .alert nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):hover,
|
||||
.alertify .dialog nav button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button):active,
|
||||
|
@ -319,6 +366,7 @@
|
|||
.cp #loading .cryptofist {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 300px;
|
||||
}
|
||||
@media screen and (max-height: 450px) {
|
||||
.cp #loading .cryptofist {
|
||||
|
@ -332,6 +380,25 @@
|
|||
.cp #loading .spinnerContainer > div {
|
||||
height: 100px;
|
||||
}
|
||||
.cp #loadingTip {
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
top: 80%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
.cp #loadingTip span {
|
||||
background-color: #302B28;
|
||||
color: #fafafa;
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
opacity: 0.7;
|
||||
font-family: lato, Helvetica, sans-serif;
|
||||
padding: 15px;
|
||||
max-width: 60%;
|
||||
display: inline-block;
|
||||
}
|
||||
/* The container <div> - needed to position the dropdown content */
|
||||
.dropdown-bar {
|
||||
position: relative;
|
||||
|
@ -376,6 +443,10 @@
|
|||
background-color: #f1f1f1;
|
||||
color: black !important;
|
||||
}
|
||||
.dropdown-bar .dropdown-bar-content a.active {
|
||||
background-color: #e8e8e8;
|
||||
color: black !important;
|
||||
}
|
||||
.dropdown-bar .dropdown-bar-content hr {
|
||||
margin: 5px 0px;
|
||||
height: 1px;
|
||||
|
@ -487,6 +558,14 @@
|
|||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
.cp footer div.version-footer {
|
||||
background-color: #302B28;
|
||||
color: #fafafa;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
html.cp,
|
||||
.cp body {
|
||||
font-size: .875em;
|
||||
|
@ -977,11 +1056,6 @@ html.cp,
|
|||
.cp #main_other .buttons {
|
||||
margin-top: 15px;
|
||||
}
|
||||
.cp #fileManagerIframe {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
.cp .create,
|
||||
.cp .action {
|
||||
display: inline-block;
|
||||
|
@ -1271,196 +1345,6 @@ html.cp,
|
|||
.cp div.realtime #addoption {
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
.cp.slide #modal .button {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
opacity: 0.6;
|
||||
display: none;
|
||||
}
|
||||
.cp.slide #modal .button:hover {
|
||||
opacity: 1;
|
||||
display: block !important;
|
||||
}
|
||||
.cp.slide #modal #button_exit {
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
z-index: 9001;
|
||||
}
|
||||
.cp.slide #modal #button_left {
|
||||
left: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
.cp.slide #modal #button_right {
|
||||
right: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
.cp.slide #modal #content p,
|
||||
.cp.slide #modal #content ul,
|
||||
.cp.slide #modal #content ol {
|
||||
font-size: 26px;
|
||||
}
|
||||
.cp.slide #modal #content img {
|
||||
position: relative;
|
||||
min-width: 1%;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
.cp div.modal,
|
||||
.cp div#modal {
|
||||
box-sizing: border-box;
|
||||
z-index: 9001;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: none;
|
||||
background-color: #000;
|
||||
}
|
||||
.cp div.modal #content,
|
||||
.cp div#modal #content {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid white;
|
||||
vertical-align: middle;
|
||||
padding: 2.5vw;
|
||||
/* center things as much as possible
|
||||
|
||||
margin-top: 50vh;
|
||||
margin-bottom: 50vh;
|
||||
transform: translateY(-50%);
|
||||
|
||||
*/
|
||||
width: 100vw;
|
||||
height: 56.25vw;
|
||||
max-height: 100vh;
|
||||
max-width: 177.78vh;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.cp div.modal #content p,
|
||||
.cp div#modal #content p,
|
||||
.cp div.modal #content li,
|
||||
.cp div#modal #content li,
|
||||
.cp div.modal #content pre,
|
||||
.cp div#modal #content pre,
|
||||
.cp div.modal #content code,
|
||||
.cp div#modal #content code {
|
||||
font-size: 2.75vw;
|
||||
line-height: 3.025vw;
|
||||
}
|
||||
.cp div.modal #content h1,
|
||||
.cp div#modal #content h1 {
|
||||
font-size: 5vw;
|
||||
line-height: 5.5vw;
|
||||
}
|
||||
.cp div.modal #content h2,
|
||||
.cp div#modal #content h2 {
|
||||
font-size: 4.2vw;
|
||||
line-height: 4.62vw;
|
||||
}
|
||||
.cp div.modal #content h3,
|
||||
.cp div#modal #content h3 {
|
||||
font-size: 3.6vw;
|
||||
line-height: 3.96vw;
|
||||
}
|
||||
.cp div.modal #content h4,
|
||||
.cp div#modal #content h4 {
|
||||
font-size: 3vw;
|
||||
line-height: 3.3vw;
|
||||
}
|
||||
.cp div.modal #content h5,
|
||||
.cp div#modal #content h5 {
|
||||
font-size: 2.2vw;
|
||||
line-height: 2.42vw;
|
||||
}
|
||||
.cp div.modal #content h6,
|
||||
.cp div#modal #content h6 {
|
||||
font-size: 1.6vw;
|
||||
line-height: 1.76vw;
|
||||
}
|
||||
.cp div.modal #content h1,
|
||||
.cp div#modal #content h1,
|
||||
.cp div.modal #content h2,
|
||||
.cp div#modal #content h2,
|
||||
.cp div.modal #content h3,
|
||||
.cp div#modal #content h3,
|
||||
.cp div.modal #content h4,
|
||||
.cp div#modal #content h4,
|
||||
.cp div.modal #content h5,
|
||||
.cp div#modal #content h5,
|
||||
.cp div.modal #content h6,
|
||||
.cp div#modal #content h6 {
|
||||
color: inherit;
|
||||
}
|
||||
.cp div.modal #content pre > code,
|
||||
.cp div#modal #content pre > code {
|
||||
display: block;
|
||||
position: relative;
|
||||
border: 1px solid #333;
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
padding-left: .25vw;
|
||||
}
|
||||
.cp div.modal #content ul,
|
||||
.cp div#modal #content ul,
|
||||
.cp div.modal #content ol,
|
||||
.cp div#modal #content ol {
|
||||
min-width: 50%;
|
||||
max-width: 100%;
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cp div.modal .center,
|
||||
.cp div#modal .center {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: auto;
|
||||
border: 1px solid #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
.cp div.modal.shown,
|
||||
.cp div#modal.shown {
|
||||
display: block;
|
||||
}
|
||||
.cp div.modal table,
|
||||
.cp div#modal table {
|
||||
margin: 30px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.cp div.modal table input,
|
||||
.cp div#modal table input {
|
||||
height: 100%;
|
||||
width: 90%;
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
.cp div.modal table tfoot tr td,
|
||||
.cp div#modal table tfoot tr td {
|
||||
z-index: 4000;
|
||||
cursor: pointer;
|
||||
}
|
||||
.cp div.modal #addtime,
|
||||
.cp div#modal #addtime,
|
||||
.cp div.modal #adddate,
|
||||
.cp div#modal #adddate {
|
||||
color: #46E981;
|
||||
border: 1px solid #46E981;
|
||||
padding: 15px;
|
||||
}
|
||||
.cp div.modal #adddate,
|
||||
.cp div#modal #adddate {
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
.cp div.modal #addtime,
|
||||
.cp div#modal #addtime {
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
||||
#cors-store {
|
||||
display: none;
|
||||
}
|
||||
|
|
|
@ -1,9 +1,8 @@
|
|||
define([
|
||||
'/customize/application_config.js',
|
||||
'/common/cryptpad-common.js',
|
||||
'/bower_components/lil-uri/uri.min.js',
|
||||
'/bower_components/jquery/dist/jquery.min.js',
|
||||
], function (Config, Cryptpad, LilUri) {
|
||||
], function (Config, Cryptpad) {
|
||||
var $ = window.$;
|
||||
|
||||
var APP = window.APP = {
|
||||
|
@ -133,8 +132,10 @@ define([
|
|||
if (result.proxy && !result.proxy.login_name) {
|
||||
result.proxy.login_name = result.userName;
|
||||
}
|
||||
Cryptpad.login(result.userHash, result.userName, function () {
|
||||
document.location.href = '/drive/';
|
||||
Cryptpad.whenRealtimeSyncs(result.realtime, function () {
|
||||
Cryptpad.login(result.userHash, result.userName, function () {
|
||||
document.location.href = '/drive/';
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,6 @@
|
|||
(function () {
|
||||
var LS_LANG = "CRYPTPAD_LANG";
|
||||
|
||||
var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); };
|
||||
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage; };
|
||||
var getLanguage = function () { return getStoredLanguage() || getBrowserLanguage(); };
|
||||
var language = getLanguage();
|
||||
|
||||
// add your module to this map so it gets used
|
||||
var map = {
|
||||
'fr': 'Français',
|
||||
|
@ -15,6 +10,19 @@ var map = {
|
|||
'pt-br': 'Português do Brasil'
|
||||
};
|
||||
|
||||
var getStoredLanguage = function () { return localStorage.getItem(LS_LANG); };
|
||||
var getBrowserLanguage = function () { return navigator.language || navigator.userLanguage; };
|
||||
var getLanguage = function () {
|
||||
if (getStoredLanguage()) { return getStoredLanguage(); }
|
||||
var l = getBrowserLanguage() || '';
|
||||
if (Object.keys(map).indexOf(l) !== -1) {
|
||||
return l;
|
||||
}
|
||||
// Edge returns 'fr-FR' --> transform it to 'fr' and check again
|
||||
return Object.keys(map).indexOf(l.split('-')[0]) !== -1 ? l.split('-')[0] : 'en';
|
||||
};
|
||||
var language = getLanguage();
|
||||
|
||||
var req = ['/customize/translations/messages.js'];
|
||||
if (language && map[language]) { req.push('/customize/translations/messages.' + language + '.js'); }
|
||||
req.push('/bower_components/jquery/dist/jquery.min.js');
|
||||
|
@ -109,12 +117,7 @@ define(req, function(Default, Language) {
|
|||
var $button = $(selector).find('button .buttonTitle');
|
||||
// Select the current language in the list
|
||||
var option = $(selector).find('[data-value="' + language + '"]');
|
||||
if ($(option).length) {
|
||||
$button.text($(option).text());
|
||||
}
|
||||
else {
|
||||
$button.text('English');
|
||||
}
|
||||
selector.setValue(language || 'English');
|
||||
|
||||
// Listen for language change
|
||||
$(selector).find('a.languageValue').on('click', function () {
|
||||
|
|
|
@ -133,6 +133,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -39,4 +39,5 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
They are only displayed briefly
|
||||
*/
|
||||
.alertify-logs {
|
||||
@media print {
|
||||
visibility: hidden;
|
||||
}
|
||||
> * {
|
||||
padding: @padding-base @padding-base * 4;
|
||||
color: @alertify-fore;
|
||||
|
@ -58,10 +61,19 @@
|
|||
}
|
||||
|
||||
.dialog, .alert {
|
||||
.bright {
|
||||
color: @light-base;
|
||||
}
|
||||
|
||||
& > div {
|
||||
background-color: @alertify-dialog-bg;
|
||||
border-radius: 5px;
|
||||
&.half {
|
||||
width: 50%;
|
||||
@media (max-width: @media-medium-screen) {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
width: 100%;
|
||||
|
@ -133,6 +145,25 @@
|
|||
border: 1px solid @alertify-base;
|
||||
border-radius: 5px;
|
||||
|
||||
&.safe, &.danger {
|
||||
color: @old-base;
|
||||
white-space: normal;
|
||||
font-weight: bold;
|
||||
}
|
||||
&.danger {
|
||||
background-color: @cp-red;
|
||||
&:hover, &:active {
|
||||
background-color: lighten(@cp-red, 5%);
|
||||
}
|
||||
}
|
||||
|
||||
&.safe {
|
||||
background-color: @cp-green;
|
||||
&:hover, &:active {
|
||||
background-color: lighten(@cp-green, 10%);
|
||||
}
|
||||
}
|
||||
|
||||
&:hover, &:active {
|
||||
background-color: @alertify-btn-bg-hover;
|
||||
}
|
||||
|
|
|
@ -494,12 +494,6 @@ noscript {
|
|||
}
|
||||
}
|
||||
|
||||
#fileManagerIframe {
|
||||
width: 100%;
|
||||
height: 500px;
|
||||
margin-top: 15px;
|
||||
}
|
||||
|
||||
/* buttons */
|
||||
|
||||
.create, .action {
|
||||
|
@ -816,192 +810,6 @@ form.realtime, div.realtime {
|
|||
#adduser { .top-left; }
|
||||
#addoption { .bottom-left; }
|
||||
}
|
||||
|
||||
// used for slides
|
||||
.viewportRatio (@x, @y, @p: 100) {
|
||||
width: @p * 100vw;
|
||||
height: @y * (@p * 100vw) / @x;
|
||||
max-width: @x / @y * (@p * 100vh);
|
||||
max-height: (@p * 100vh);
|
||||
}
|
||||
|
||||
&.slide {
|
||||
#modal {
|
||||
.button {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
opacity: 0.6;
|
||||
display: none;
|
||||
}
|
||||
.button:hover {
|
||||
opacity: 1;
|
||||
display: block !important;
|
||||
}
|
||||
#button_exit {
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
z-index: 9001;
|
||||
}
|
||||
#button_left {
|
||||
left: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
#button_right {
|
||||
right: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
}
|
||||
#modal #content {
|
||||
p, ul, ol { font-size: 26px; }
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
min-width: 1%;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.modal, div#modal {
|
||||
display: none;
|
||||
|
||||
#content {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid white;
|
||||
|
||||
vertical-align: middle;
|
||||
padding: 2.5vw;
|
||||
|
||||
/* center things as much as possible
|
||||
|
||||
margin-top: 50vh;
|
||||
margin-bottom: 50vh;
|
||||
transform: translateY(-50%);
|
||||
|
||||
*/
|
||||
|
||||
width: 100vw;
|
||||
height: 56.25vw; // height:width ratio = 9/16 = .5625
|
||||
max-height: 100vh;
|
||||
max-width: 177.78vh; // 16/9 = 1.778
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top:0;bottom:0; // vertical center
|
||||
left:0;right:0; // horizontal center
|
||||
|
||||
p, li, pre, code {
|
||||
.size(2.75);
|
||||
}
|
||||
|
||||
h1 { .size(5); }
|
||||
h2 { .size(4.2); }
|
||||
h3 { .size(3.6); }
|
||||
h4 { .size (3); }
|
||||
h5 { .size(2.2); }
|
||||
h6 { .size(1.6); }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: inherit;
|
||||
}
|
||||
|
||||
pre > code {
|
||||
display: block;
|
||||
position: relative;
|
||||
border: 1px solid #333;
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
padding-left: .25vw;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
min-width: 50%;
|
||||
max-width: 100%;
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
box-sizing: border-box;
|
||||
z-index: 9001;
|
||||
position: fixed;
|
||||
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: none;
|
||||
|
||||
background-color: @slide-default-bg;
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: auto;
|
||||
border: 1px solid @light-base;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.shown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 30px;
|
||||
|
||||
border-collapse: collapse;
|
||||
tr {
|
||||
td {
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
height: 100%;
|
||||
width: 90%;
|
||||
border: 3px solid @base;
|
||||
}
|
||||
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
span.remove {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
tr {
|
||||
td {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
tfoot {
|
||||
tr {
|
||||
td {
|
||||
z-index: 4000;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#addtime,
|
||||
#adddate {
|
||||
color: @cp-green;
|
||||
border: 1px solid @cp-green;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#adddate { .top-left; }
|
||||
#addtime { .bottom-left; }
|
||||
}
|
||||
}
|
||||
|
||||
// hack for our cross-origin iframe
|
||||
|
|
|
@ -57,6 +57,11 @@
|
|||
background-color: #f1f1f1;
|
||||
color: black !important;
|
||||
}
|
||||
|
||||
&.active {
|
||||
background-color: #e8e8e8;
|
||||
color: black !important;
|
||||
}
|
||||
}
|
||||
|
||||
hr {
|
||||
|
|
|
@ -18,4 +18,12 @@
|
|||
font-size: 1.2em;
|
||||
font-weight: bold;
|
||||
}
|
||||
div.version-footer {
|
||||
background-color: @old-base;
|
||||
color: @old-fore;
|
||||
text-align: center;
|
||||
width: 100%;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 10px;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,6 +16,7 @@
|
|||
.cryptofist {
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
height: 300px;
|
||||
@media screen and (max-height: @media-short-screen) {
|
||||
display: none;
|
||||
}
|
||||
|
@ -28,4 +29,22 @@
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cp #loadingTip {
|
||||
position: fixed;
|
||||
z-index: 99999;
|
||||
top: 80%;
|
||||
left: 0;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
span {
|
||||
background-color: @bg-loading;
|
||||
color: @color-loading;
|
||||
text-align: center;
|
||||
font-size: 1.5em;
|
||||
opacity: 0.7;
|
||||
font-family: lato, Helvetica, sans-serif;
|
||||
padding: 15px;
|
||||
max-width: 60%;
|
||||
display: inline-block;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -95,6 +95,7 @@
|
|||
}
|
||||
|
||||
button {
|
||||
color: #000;
|
||||
background-color: inherit;
|
||||
background-image: linear-gradient(to bottom,#fff,#e4e4e4);
|
||||
border: 1px solid #A6A6A6;
|
||||
|
@ -253,13 +254,12 @@
|
|||
input {
|
||||
font-size: 1.5em;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid black;
|
||||
background: #fff;
|
||||
cursor: auto;
|
||||
width: 300px;
|
||||
padding: 0px 5px;
|
||||
padding: 5px 5px;
|
||||
}
|
||||
}
|
||||
.cryptpad-link {
|
||||
|
@ -312,6 +312,7 @@
|
|||
//float: right;
|
||||
pre {
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
button {
|
||||
|
|
|
@ -116,6 +116,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -42,6 +42,10 @@
|
|||
background-color: #f1f1f1;
|
||||
color: black !important;
|
||||
}
|
||||
.dropdown-bar .dropdown-bar-content a.active {
|
||||
background-color: #e8e8e8;
|
||||
color: black !important;
|
||||
}
|
||||
.dropdown-bar .dropdown-bar-content hr {
|
||||
margin: 5px 0px;
|
||||
height: 1px;
|
||||
|
@ -164,6 +168,7 @@
|
|||
margin-right: 2px;
|
||||
}
|
||||
.cryptpad-toolbar button {
|
||||
color: #000;
|
||||
background-color: inherit;
|
||||
background-image: linear-gradient(to bottom, #fff, #e4e4e4);
|
||||
border: 1px solid #A6A6A6;
|
||||
|
@ -324,13 +329,12 @@
|
|||
.cryptpad-toolbar-top .cryptpad-title input {
|
||||
font-size: 1.5em;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
border: 1px solid black;
|
||||
background: #fff;
|
||||
cursor: auto;
|
||||
width: 300px;
|
||||
padding: 0px 5px;
|
||||
padding: 5px 5px;
|
||||
}
|
||||
.cryptpad-toolbar-top .cryptpad-link {
|
||||
position: absolute;
|
||||
|
@ -374,6 +378,7 @@
|
|||
}
|
||||
.cryptpad-toolbar-leftside .cryptpad-user-list pre {
|
||||
white-space: pre;
|
||||
margin: 0;
|
||||
}
|
||||
.cryptpad-toolbar-leftside button {
|
||||
margin: 2px 4px 2px 0px;
|
||||
|
|
|
@ -35,10 +35,8 @@ define(function () {
|
|||
out.orangeLight = "La conexión es lenta y podria impactar la experiencia";
|
||||
out.redLight = "Has sido desconectado de la sesión";
|
||||
|
||||
out.importButton = 'Importar';
|
||||
out.importButtonTitle = 'Importar un documento de tus archivos locales';
|
||||
|
||||
out.exportButton = 'Exportar';
|
||||
out.exportButtonTitle = 'Exportar este documento a un archivo local';
|
||||
out.exportPrompt = '¿Cómo te gustaría llamar a este archivo?';
|
||||
|
||||
|
@ -46,22 +44,16 @@ define(function () {
|
|||
|
||||
out.clickToEdit = "Haz clic para cambiar";
|
||||
|
||||
out.forgetButton = 'Olvidar';
|
||||
out.forgetButtonTitle = 'Eliminar este documento de la lista en la pagina de inicio';
|
||||
out.forgetPrompt = 'Pulser OK eliminará este documento del almacenamiento local (localStorage), ¿estás seguro?';
|
||||
|
||||
out.shareButton = 'Compartir';
|
||||
out.shareSuccess = 'URL copiada al portapapeles';
|
||||
|
||||
out.presentButton = 'Presentar';
|
||||
out.presentButtonTitle = "Entrar en el modo presentación";
|
||||
out.presentSuccess = 'ESC para salir del modo presentación';
|
||||
out.sourceButton = 'Ver código fuente';
|
||||
out.sourceButtonTitle = "Abandonar modo presentación";
|
||||
|
||||
out.backgroundButton = 'Color de fondo';
|
||||
out.backgroundButtonTitle = 'Cambiar el color de fondo en el modo presentación';
|
||||
out.colorButton = 'Color de texto';
|
||||
out.colorButtonTitle = 'Cambiar el color de texto en el modo presentación';
|
||||
|
||||
out.editShare = "URL de edición compartida";
|
||||
|
@ -88,7 +80,6 @@ define(function () {
|
|||
out.poll_p_save = "Tus configuraciones se actualizan instantaneamente, no es necesario guardar cambios.";
|
||||
out.poll_p_encryption = "Todos los datos entrados son cifrados, solo las personas que poseen el enlace tienen acceso. Incluso el servidor no puede ver el contenido.";
|
||||
|
||||
out.wizardButton = 'Asistente';
|
||||
out.wizardLog = "Presiona el boton en la parte superior izquierda para volver a la encuesta";
|
||||
out.wizardTitle = "Utiliza el asistente para crear tu encuesta";
|
||||
out.wizardConfirm = "¿Estás realmente seguro de agregar estas opciones a tu encuesta?";
|
||||
|
@ -326,5 +317,35 @@ define(function () {
|
|||
out.readme_cat3_l2 = "Con los slides CryptPad, puedes hacer presentaciones rápidas con Markdown";
|
||||
out.readme_cat3_l3 = "Con CryptPoll puedes tomar votos rápidos, especialmente utíl para programar un horario que conviene a todo el mundo";
|
||||
|
||||
return out;
|
||||
// 1.2.0 - Chupacabra
|
||||
|
||||
out.settings_resetError = "Verificación no válida. Tu CryptDrive no fue cambiado.";
|
||||
out.saved = "Guardado";
|
||||
out.printButton = "Imprimir";
|
||||
out.printButtonTitle = "Imprimir tu presentación o exportar a PDF";
|
||||
out.printOptions = "Opciones de impresión";
|
||||
out.printSlideNumber = "Mostrar el número de diapositiva";
|
||||
out.printDate = "Mostrar la fecha";
|
||||
out.printTitle = "Mostrar el título";
|
||||
out.printCSS = "CSS personalizado:";
|
||||
out.editOpen = "Abrir enlances de edición en pestaña nueva";
|
||||
out.editOpenTitle = "Abrir en modo edición en pestaña nueva";
|
||||
out.settings_importTitle = "Importar pads recientes locales en CryptDrive";
|
||||
out.settings_import = "Importar";
|
||||
out.settings_importConfirm = "¿Seguro qué quieres importar tus pads recientes a tu cuenta CryptDrive?";
|
||||
out.settings_importDone = "Importación terminada";
|
||||
|
||||
out.tips = {};
|
||||
out.tips.lag = "El icono verde en la parte superior derecha muestra la calidad de tu connexión a CryptPad.";
|
||||
out.tips.shortcuts = "`ctrl+b`, `ctrl+i`, y `ctrl+u` son accesos rápidos para negrita, itálica y subrayado.";
|
||||
out.tips.indent = "Cuando editas listas, puedes usar tab o shift+tab para icrementar o decrementar indentación.";
|
||||
out.tips.title = "Puedes cambiar el título de tus pads en la parte superior de la pantalla.";
|
||||
out.tips.store = "Cada vez que visitas un pad con una sesión iniciada se guardará a tu CryptDrive.";
|
||||
out.tips.marker = "Puedes resaltar texto en un pad utilizando el \"marcador\" en el menú de estílo.";
|
||||
|
||||
out.feedback_about = "Si estas leyendo esto, quizas estés curioso de saber porqué CryptPad solicita esta página cuando haces algunas acciones";
|
||||
out.feedback_privacy = "Nos importa tu privacidad, y al mismo tiempo queremos que CryptPad sea muy fácil de usar. Utilizamos esta página para conocer las funcionalidades que importan a nuestros usuarios, pidiendolo con un parametro que nos dice que accion fue realizada.";
|
||||
out.feedback_optout = "Si quieres darte de baja, visita <a href='/settings/'>tus preferencias</a>, donde podrás activar o desactivar feedback";
|
||||
|
||||
return out;
|
||||
});
|
||||
|
|
|
@ -25,6 +25,7 @@ define(function () {
|
|||
|
||||
out.loading = "Chargement...";
|
||||
out.error = "Erreur";
|
||||
out.saved = "Enregistré";
|
||||
|
||||
out.disconnected = 'Déconnecté';
|
||||
out.synchronizing = 'Synchronisation';
|
||||
|
@ -48,10 +49,8 @@ define(function () {
|
|||
out.orangeLight = "Votre connexion est lente, ce qui réduit la qualité de l'éditeur";
|
||||
out.redLight = "Vous êtes déconnectés de la session";
|
||||
|
||||
out.importButton = 'Import';
|
||||
out.importButtonTitle = 'Importer un pad depuis un fichier local';
|
||||
|
||||
out.exportButton = 'Exporter';
|
||||
out.exportButtonTitle = 'Exporter ce pad vers un fichier local';
|
||||
out.exportPrompt = 'Comment souhaitez-vous nommer ce fichier ?';
|
||||
|
||||
|
@ -62,7 +61,6 @@ define(function () {
|
|||
|
||||
out.clickToEdit = 'Cliquer pour modifier';
|
||||
|
||||
out.forgetButton = 'Supprimer';
|
||||
out.forgetButtonTitle = 'Déplacer ce pad vers la corbeille';
|
||||
out.forgetPrompt = 'Cliquer sur OK déplacera ce pad vers la corbeille de votre CryptDrive, êtes-vous sûr ?';
|
||||
out.movedToTrash = 'Ce pad a été déplacé vers la corbeille.<br><a href="/drive/">Accéder à mon Drive</a>';
|
||||
|
@ -73,20 +71,25 @@ define(function () {
|
|||
out.newButton = 'Nouveau';
|
||||
out.newButtonTitle = 'Créer un nouveau pad';
|
||||
|
||||
out.presentButton = 'Present';
|
||||
out.presentButtonTitle = "Entrer en mode présentation";
|
||||
out.presentSuccess = 'Appuyer sur Échap pour quitter le mode présentation';
|
||||
out.sourceButton = 'Voir la source';
|
||||
out.sourceButtonTitle = "Quitter le mode présentation";
|
||||
|
||||
out.backgroundButton = 'Couleur de fond';
|
||||
out.backgroundButtonTitle = 'Changer la couleur de fond de la présentation';
|
||||
out.colorButton = 'Couleur du texte';
|
||||
out.colorButtonTitle = 'Changer la couleur du texte en mode présentation';
|
||||
|
||||
out.editShare = "Partager le lien d'édition";
|
||||
out.printButton = "Imprimer";
|
||||
out.printButtonTitle = "Imprimer votre présentation ou l'enregistrer au format PDF";
|
||||
out.printOptions = "Options d'impression";
|
||||
out.printSlideNumber = "Afficher le numéro des slides";
|
||||
out.printDate = "Afficher la date";
|
||||
out.printTitle = "Afficher le titre du pad";
|
||||
out.printCSS = "Personnaliser l'apparence (CSS):";
|
||||
|
||||
out.editShare = "Lien d'édition";
|
||||
out.editShareTitle = "Copier le lien d'édition dans le presse-papiers";
|
||||
out.viewShare = "Partager lien de lecture-seule";
|
||||
out.editOpen = "Éditer dans un nouvel onglet";
|
||||
out.editOpenTitle = "Ouvrir le lien d'édition dans un nouvel onglet";
|
||||
out.viewShare = "Lien de lecture-seule";
|
||||
out.viewShareTitle = "Copier lien d'accès en lecture seule dans le presse-papiers";
|
||||
out.viewOpen = "Voir dans un nouvel onglet";
|
||||
out.viewOpenTitle = "Ouvrir le lien en lecture seule dans un nouvel onglet";
|
||||
|
@ -108,7 +111,6 @@ define(function () {
|
|||
out.poll_p_save = "Vos modifications sont mises à jour instantanément, donc vous n'avez jamais besoin de sauver le contenu.";
|
||||
out.poll_p_encryption = "Tout ce que vous entrez est chiffré donc seules les personnes possédant le lien du sondage y ont accès. Même le serveur ne peut pas voir le contenu.";
|
||||
|
||||
out.wizardButton = 'Assistant';
|
||||
out.wizardLog = "Cliquez sur le bouton dans le coin supérieur gauche pour retourner au sondage";
|
||||
out.wizardTitle = "Utiliser l'assistant pour créer votre sondage";
|
||||
out.wizardConfirm = "Êtes-vous vraiment prêt à ajouter ces options au sondage ?";
|
||||
|
@ -223,10 +225,13 @@ define(function () {
|
|||
|
||||
out.register_importRecent = "Importer l'historique (Recommendé)";
|
||||
out.register_acceptTerms = "J'accepte <a href='/terms.html'>les conditions d'utilisation</a>";
|
||||
out.register_rememberPassword = "Je vais me souvenir de mes identifiants";
|
||||
out.register_passwordsDontMatch = "Les mots de passe doivent être identiques!";
|
||||
out.register_mustAcceptTerms = "Vous devez accepter les conditions d'utilisation.";
|
||||
out.register_mustRememberPass = "Nous ne pouvons pas réinitialiser votre mot de passe si vous l'oubliez. C'est important que vous vous en souveniez! Veuillez cocher la case pour confirmer.";
|
||||
out.register_writtenPassword = "J'ai bien noté mon nom d'utilisateur et mon mot de passe, continuer";
|
||||
out.register_cancel = "Retour";
|
||||
out.register_warning = "Zero Knowledge signifie que nous ne pouvons pas récupérer vos données si vous perdez vos identifiants.";
|
||||
out.register_alreadyRegistered = "Cet utilisateur existe déjà, souhaitez-vous vous connecter ?";
|
||||
|
||||
out.register_header = "Bienvenue dans CryptPad";
|
||||
out.register_explanation = [
|
||||
|
@ -250,10 +255,16 @@ define(function () {
|
|||
"Êtes-vous sûr de vouloir continuer ?<br>" +
|
||||
"Tapez “<em>I love CryptPad</em>” pour confirmer.";
|
||||
out.settings_resetDone = "Votre drive est désormais vide!";
|
||||
out.settings_resetError = "Texte de vérification incorrect. Votre CryptDrive n'a pas été modifié.";
|
||||
out.settings_resetTips = "Astuces et informations dans CryptDrive";
|
||||
out.settings_resetTipsButton = "Réinitialiser les astuces visibles dans CryptDrive";
|
||||
out.settings_resetTipsDone = "Toutes les astuces sont de nouveau visibles.";
|
||||
|
||||
out.settings_importTitle = "Importer les pads récents de ce navigateur dans mon CryptDrive";
|
||||
out.settings_import = "Importer";
|
||||
out.settings_importConfirm = "Êtes-vous sûr de vouloir importer les pads récents de ce navigateur dans le CryptDrive de votre compte utilisateur ?";
|
||||
out.settings_importDone = "Importation terminée";
|
||||
|
||||
out.settings_userFeedbackHint1 = "CryptPad peut envoyer des retours d'expérience très limités vers le serveur, de manière à nous permettre d'améliorer l'expérience des utilisateurs.";
|
||||
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";
|
||||
|
@ -306,7 +317,6 @@ define(function () {
|
|||
out.policy_whatweknow = 'Ce que nous savons de vous';
|
||||
out.policy_whatweknow_p1 = 'En tant qu\'application hébergée sur le web, CryptPad a accès aux meta-données exposées par le protocole HTTP. Ceci inclus votre adresse IP et d\'autres en-têtes HTTP qui peuvent être utilisées pour identifier votre propre navigateur. Vous pouvez voir quelles informations votre navigateur partage en visitant <a target="_blank" rel="noopener noreferrer" href="https://www.whatismybrowser.com/detect/what-http-headers-is-my-browser-sending" title="what http headers is my browser sending">WhatIsMyBrowser.com</a>.';
|
||||
out.policy_whatweknow_p2 = 'Nous utilisons <a href="https://piwik.org/" target="_blank" rel="noopener noreferrer" title="open source analytics platform">Piwik</a>, une plateforme open source d\'analytique, afin d\'en apprendre plus sur nos utilisateurs. Piwik nous indique comment vous avez trouvé CryptPad, que ce soit par une entrée directe, par un moteur de recherche ou depuis un lien provenant d\'un autre site web tel que Reddit ou Twitter. Nous savons également quand vous visitez le site, sur quels liens vous cliquez dans les pages informatives et combien de temps vous restez sur une page donnée.';
|
||||
out.policy_whatweknow_p3 = 'Ces outils d\'analytique sont utilisés uniquement sur les pages informatives. Nous ne collectons aucune information concernant votre utilisation de nos applications "zero knowledge".';
|
||||
out.policy_howweuse = 'Comment nous utilisons ce que nous apprenons';
|
||||
out.policy_howweuse_p1 = 'Nous utilisons ces informations pour prendre de meilleures décisions concernant la communication autour de CryptPad, en évaluant le succès de ce qui a été realisé par le passé. Les informations concernant votre localisation nous permettent de savoir si nous devons considérer l\'ajout de traductions de CryptPad dans d\'autres langues que l\'anglais.';
|
||||
out.policy_howweuse_p2 = "Les informations concernant votre navigateur (que ce soit un système d\'exploitation de bureau ou d\'appareil portable) nous aident à prendre des décisions lors de la priorisation des ajouts et améliorations de fonctionnalités. Notre équipe de développement est petite, et nous essayons de prendre des décisions qui amélioreront l\'expérience du plus grand nombre d\'utilisateurs possible.";
|
||||
|
@ -357,13 +367,23 @@ define(function () {
|
|||
'</small>',
|
||||
'</p>',
|
||||
].join('');
|
||||
out.initialState = [
|
||||
'<span style="font-size:18px;"><p>',
|
||||
'Voici <strong>CryptPad</strong>, l\'éditeur collaboratif en temps-réel Zero Knowledge. Tout est sauvegardé dés que vous le tapez.',
|
||||
'<br>',
|
||||
'Partagez le lien vers ce pad avec des amis ou utilisez le bouton <span style="background-color:#449d44;color:#ffffff;"> Partager </span> pour obtenir le <em>lien de lecture-seule</em>, qui permet la lecture mais non la modification.',
|
||||
'</p>',
|
||||
'<p><span style="color:#808080; font-size: 18px;">',
|
||||
'<em>',
|
||||
'Lancez-vous, commencez à taper...',
|
||||
'</em></span></p></span>'
|
||||
].join('');
|
||||
|
||||
out.codeInitialState = [
|
||||
'/*\n',
|
||||
' Voici CryptPad, l\'éditeur collaboratif en temps-réel Zero Knowledge.\n',
|
||||
' Voici l\'éditeur de code collaboratif et Zero Knowledge de CryptPad.\n',
|
||||
' Ce que vous tapez ici est chiffré de manière que seules les personnes avec le lien peuvent y accéder.\n',
|
||||
' Même le serveur est incapable de voir ce que vous tapez.\n',
|
||||
' Ce que vous voyez ici, ce que vous entendez, quand vous partez, ça reste ici.\n',
|
||||
' Vous pouvez choisir le langage de programmation pour la coloration syntaxique, ainsi que le thème de couleurs, dans le coin supérieur droit.\n',
|
||||
'*/'
|
||||
].join('');
|
||||
|
||||
|
@ -405,5 +425,18 @@ define(function () {
|
|||
out.readme_cat3_l2 = "Avec l'éditeur de présentations de CryptPad, vous pouvez réaliser des présentations rapides en utilisant Markdown";
|
||||
out.readme_cat3_l3 = "Avec CryptPoll vous pouvez créer rapidement des sondages, et en particulier plannifier des meetings qui rentrent dans l'agenda de tout ceux qui souhaitent participer.";
|
||||
|
||||
// Tips
|
||||
out.tips = {};
|
||||
out.tips.lag = "L'icône verte dans le coin supérieur droit montre la qualité de votre connexion Internet vers le serveur CryptPad.";
|
||||
out.tips.shortcuts = "`ctrl+b`, `ctrl+i` et `ctrl+u` sont des raccourcis rapides pour mettre en gras, en italique ou souligner.";
|
||||
out.tips.indent = "Dans les listes à puces ou numérotées, vous pouvez utiliser `Tab` ou `Maj+Tab` pour augmenter ou réduire rapidement l'indentation.";
|
||||
out.tips.title = "Vous pouvez changer le titre de votre pad en cliquant au centre en haut de la page.";
|
||||
out.tips.store = "Dés que vous ouvrez un nouveau pad, il est automatiquement stocké dans votre CryptDrive si vous êtes connectés.";
|
||||
out.tips.marker = "Vous pouvez surligner du texte dans un pad en utilisant l'option \"marker\" dans le menu déroulant des styles.";
|
||||
|
||||
out.feedback_about = "Si vous lisez ceci, vous vous demandez probablement pourquoi CryptPad envoie des requêtes vers des pages web quand vous realisez certaines actions.";
|
||||
out.feedback_privacy = "Nous prenons au sérieux le respect de votre vie privée, et en même temps nous souhaitons rendre CryptPad très simple à utiliser. Nous utilisons cette page pour comprendre quelles foncitonnalités dans l'interface comptent le plus pour les utilisateurs, en l'appelant avec un paramètre spécifiant quelle action a été réalisée.";
|
||||
out.feedback_optout = "Si vous le souhaitez, vous pouvez désactiver ces requêtes en vous rendant dans <a href='/settings/'>votre page de préférences</a>, où vous trouverez une case à cocher pour désactiver le retour d'expérience.";
|
||||
|
||||
return out;
|
||||
});
|
||||
|
|
|
@ -27,6 +27,7 @@ define(function () {
|
|||
|
||||
out.loading = "Loading...";
|
||||
out.error = "Error";
|
||||
out.saved = "Saved";
|
||||
|
||||
out.disconnected = 'Disconnected';
|
||||
out.synchronizing = 'Synchronizing';
|
||||
|
@ -50,10 +51,8 @@ define(function () {
|
|||
out.orangeLight = "Your slow connection may impact your experience";
|
||||
out.redLight = "You are disconnected from the session";
|
||||
|
||||
out.importButton = 'IMPORT';
|
||||
out.importButtonTitle = 'Import a pad from a local file';
|
||||
|
||||
out.exportButton = 'EXPORT';
|
||||
out.exportButtonTitle = 'Export this pad to a local file';
|
||||
out.exportPrompt = 'What would you like to name your file?';
|
||||
|
||||
|
@ -64,7 +63,6 @@ define(function () {
|
|||
|
||||
out.clickToEdit = "Click to edit";
|
||||
|
||||
out.forgetButton = 'FORGET';
|
||||
out.forgetButtonTitle = 'Move this pad to the trash';
|
||||
out.forgetPrompt = 'Clicking OK will move this pad to your trash. Are you sure?';
|
||||
out.movedToTrash = 'That pad has been moved to the trash.<br><a href="/drive/">Access my Drive</a>';
|
||||
|
@ -75,22 +73,27 @@ define(function () {
|
|||
out.newButton = 'New';
|
||||
out.newButtonTitle = 'Create a new pad';
|
||||
|
||||
out.presentButton = 'PRESENT';
|
||||
out.presentButtonTitle = "Enter presentation mode";
|
||||
out.presentSuccess = 'Hit ESC to exit presentation mode';
|
||||
out.sourceButton = 'VIEW SOURCE'; //TODO remove? hidden behind the present mode
|
||||
out.sourceButtonTitle = "Leave presentation mode";
|
||||
|
||||
out.backgroundButton = 'BACKGROUND COLOR';
|
||||
out.backgroundButtonTitle = 'Change the background color in the presentation';
|
||||
out.colorButton = 'TEXT COLOR';
|
||||
out.colorButtonTitle = 'Change the text color in presentation mode';
|
||||
|
||||
out.printButton = "Print";
|
||||
out.printButtonTitle = "Print your slides or export them as a PDF file";
|
||||
out.printOptions = "Print options";
|
||||
out.printSlideNumber = "Display the slide number";
|
||||
out.printDate = "Display the date";
|
||||
out.printTitle = "Display the pad title";
|
||||
out.printCSS = "Custom style rules (CSS):";
|
||||
|
||||
out.editShare = "Editing link";
|
||||
out.editShareTitle = "Copy the edit link to clipboard";
|
||||
out.editShareTitle = "Copy the editing link to clipboard";
|
||||
out.editOpen = "Open editing link in a new tab";
|
||||
out.editOpenTitle = "Open this pad in editing mode in a new tab";
|
||||
out.viewShare = "Read-only link";
|
||||
out.viewShareTitle = "Copy the read-only link to clipboard";
|
||||
out.viewOpen = "Open read-only link in new tab";
|
||||
out.viewOpen = "Open read-only link in a new tab";
|
||||
out.viewOpenTitle = "Open this pad in read-only mode in a new tab";
|
||||
|
||||
out.notifyJoined = "{0} has joined the collaborative session";
|
||||
|
@ -99,7 +102,7 @@ define(function () {
|
|||
|
||||
out.okButton = 'OK (enter)';
|
||||
|
||||
out.cancel = "Cancel"; // Not used?
|
||||
out.cancel = "Cancel";
|
||||
out.cancelButton = 'Cancel (esc)';
|
||||
|
||||
// Polls
|
||||
|
@ -110,7 +113,6 @@ define(function () {
|
|||
out.poll_p_save = "Your settings are updated instantly, so you never need to save.";
|
||||
out.poll_p_encryption = "All your input is encrypted so only people who have the link can access it. Even the server cannot see what you change.";
|
||||
|
||||
out.wizardButton = 'WIZARD';
|
||||
out.wizardLog = "Click the button in the top left to return to your poll";
|
||||
out.wizardTitle = "Use the wizard to create your poll";
|
||||
out.wizardConfirm = "Are you really ready to add these options to your poll?";
|
||||
|
@ -225,7 +227,6 @@ define(function () {
|
|||
|
||||
out.register_importRecent = "Import pad history (Recommended)";
|
||||
out.register_acceptTerms = "I accept <a href='/terms.html'>the terms of service</a>";
|
||||
out.register_rememberPassword = "I will remember my login name and password";
|
||||
out.register_passwordsDontMatch = "Passwords do not match!";
|
||||
out.register_mustAcceptTerms = "You must accept the terms of service.";
|
||||
out.register_mustRememberPass = "We cannot reset your password if you forget it. It's very important that you remember it! Please check the checkbox to confirm.";
|
||||
|
@ -240,6 +241,13 @@ define(function () {
|
|||
"</ul>"
|
||||
].join('');
|
||||
|
||||
out.register_writtenPassword = "I have written down my username and password, proceed";
|
||||
out.register_cancel = "Go back";
|
||||
|
||||
out.register_warning = "Zero Knowledge means that we can't recover your data if you lose your password.";
|
||||
|
||||
out.register_alreadyRegistered = "This user already exists, do you want to log in?";
|
||||
|
||||
// Settings
|
||||
out.settings_title = "Settings";
|
||||
out.settings_save = "Save";
|
||||
|
@ -252,10 +260,16 @@ define(function () {
|
|||
"Are you sure you want to continue?<br>" +
|
||||
"Type “<em>I love CryptPad</em>” to confirm.";
|
||||
out.settings_resetDone = "Your drive is now empty!";
|
||||
out.settings_resetError = "Incorrect verification text. Your CryptDrive has not been changed.";
|
||||
out.settings_resetTips = "Tips in CryptDrive";
|
||||
out.settings_resetTipsButton = "Reset the available tips in CryptDrive";
|
||||
out.settings_resetTipsDone = "All the tips are now visible again.";
|
||||
|
||||
out.settings_importTitle = "Import this browser's recent pads in my CryptDrive";
|
||||
out.settings_import = "Import";
|
||||
out.settings_importConfirm = "Are you sure you want to import recent pads from this browser to your user account's CryptDrive?";
|
||||
out.settings_importDone = "Import completed";
|
||||
|
||||
out.settings_userFeedbackHint1 = "CryptPad provides some very basic feedback to the server, to let us know how to improve your experience.";
|
||||
out.settings_userFeedbackHint2 = "Your pad's content will never be shared with the server.";
|
||||
out.settings_userFeedback = "Enable user feedback";
|
||||
|
@ -351,26 +365,22 @@ define(function () {
|
|||
// Initial states
|
||||
|
||||
out.initialState = [
|
||||
'<p>',
|
||||
'This is <strong>CryptPad</strong>, the zero knowledge realtime collaborative editor.',
|
||||
'<span style="font-size:18px;"><p>',
|
||||
'This is <strong>CryptPad</strong>, the Zero Knowledge realtime collaborative editor. Everything is saved as you type.',
|
||||
'<br>',
|
||||
'What you type here is encrypted so only people who have the link can access it.',
|
||||
'<br>',
|
||||
'Even the server cannot see what you type.',
|
||||
'</p>',
|
||||
'<p>',
|
||||
'<small>',
|
||||
'<i>What you see here, what you hear here, when you leave here, let it stay here</i>',
|
||||
'</small>',
|
||||
'Share the link to this pad to edit with friends or use the <span style="background-color:#449d44;color:#ffffff;"> Share </span> button to share a <em>read-only link</em> which allows viewing but not editing.',
|
||||
'</p>',
|
||||
|
||||
'<p><span style="color:#808080;"><em>',
|
||||
'Go ahead, just start typing...',
|
||||
'</em></span></p></span>'
|
||||
].join('');
|
||||
|
||||
out.codeInitialState = [
|
||||
'/*\n',
|
||||
' This is CryptPad, the zero knowledge realtime collaborative editor.\n',
|
||||
' This is the CryptPad Zero Knowledge collaborative code editor.\n',
|
||||
' What you type here is encrypted so only people who have the link can access it.\n',
|
||||
' Even the server cannot see what you type.\n',
|
||||
' What you see here, what you hear here, when you leave here, let it stay here.\n',
|
||||
' You can choose the programming language to highlight and the UI color scheme in the upper right.\n',
|
||||
'*/'
|
||||
].join('');
|
||||
|
||||
|
@ -391,6 +401,8 @@ define(function () {
|
|||
' - Your slides are updated in realtime'
|
||||
].join('');
|
||||
|
||||
// Readme
|
||||
|
||||
out.driveReadmeTitle = "What is CryptDrive?";
|
||||
out.readme_welcome = "Welcome to CryptPad !";
|
||||
out.readme_p1 = "Welcome to CryptPad, this is where you can take note of things alone and with friends.";
|
||||
|
@ -412,5 +424,18 @@ define(function () {
|
|||
out.readme_cat3_l2 = "With CryptPad slide editor, you can make quick presentations using Markdown";
|
||||
out.readme_cat3_l3 = "With CryptPoll you can take quick votes, especially for scheduling meetings which fit with everybody's calendar";
|
||||
|
||||
// Tips
|
||||
out.tips = {};
|
||||
out.tips.lag = "The green icon in the upper right shows the quality of your internet connection to the CryptPad server.";
|
||||
out.tips.shortcuts = "`ctrl+b`, `ctrl+i` and `ctrl+u` are quick shortcuts for bold, italic and underline.";
|
||||
out.tips.indent = "In numbered and bulleted lists, you can use tab or shift+tab to quickly increase or decrease indentation.";
|
||||
out.tips.title = "You can set the title of your pad by clicking the top center.";
|
||||
out.tips.store = "Every time you visit a pad, if you're logged in it will be saved to your CryptDrive.";
|
||||
out.tips.marker = "You can highlight text in a pad using the \"marker\" item in the styles dropdown menu.";
|
||||
|
||||
out.feedback_about = "If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions";
|
||||
out.feedback_privacy = "We care about your privacy, and at the same time we want CryptPad to be very easy to use. We use this file to figure out which UI features matter to our users, by requesting it along with a parameter specifying which action was taken.";
|
||||
out.feedback_optout = "If you would like to opt out, visit <a href='/settings/'>your user settings page</a>, where you'll find a checkbox to enable or disable user feedback";
|
||||
|
||||
return out;
|
||||
});
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "cryptpad",
|
||||
"description": "realtime collaborative visual editor with zero knowlege server",
|
||||
"version": "1.1.1",
|
||||
"version": "1.2.0",
|
||||
"dependencies": {
|
||||
"express": "~4.10.1",
|
||||
"ws": "^1.0.1",
|
||||
|
@ -16,7 +16,7 @@
|
|||
"scripts": {
|
||||
"lint": "jshint --config .jshintrc --exclude-path .jshintignore .",
|
||||
"test": "node TestSelenium.js",
|
||||
"style": "lessc ./customize.dist/src/less/cryptpad.less > ./customize.dist/main.css && lessc ./customize.dist/src/less/toolbar.less > ./customize.dist/toolbar.css && lessc ./www/drive/file.less > ./www/drive/file.css && lessc ./www/settings/main.less > ./www/settings/main.css",
|
||||
"style": "lessc ./customize.dist/src/less/cryptpad.less > ./customize.dist/main.css && lessc ./customize.dist/src/less/toolbar.less > ./customize.dist/toolbar.css && lessc ./www/drive/file.less > ./www/drive/file.css && lessc ./www/settings/main.less > ./www/settings/main.css && lessc ./www/slide/slide.less > ./www/slide/slide.css",
|
||||
"template": "cd customize.dist/src && node build.js"
|
||||
}
|
||||
}
|
||||
|
|
41
readme.md
41
readme.md
|
@ -35,13 +35,18 @@ bower install
|
|||
## copy config.js.dist to config.js
|
||||
cp config.js.dist config.js
|
||||
|
||||
## modify configuration to use your own mongodb instance
|
||||
## for example aon the default mongodb port `mongodb://localhost:27017/demo_database`
|
||||
$EDITOR config.js
|
||||
|
||||
node ./server.js
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
CryptPad _should_ work with an unmodified configuration file, though there are many things which you may want to customize.
|
||||
Attributes in the config should have comments indicating how they are used.
|
||||
|
||||
```
|
||||
$EDITOR config.js
|
||||
```
|
||||
|
||||
## Maintenance
|
||||
|
||||
To get access to the most recent codebase:
|
||||
|
@ -63,18 +68,20 @@ npm update;
|
|||
|
||||
To reset your instance of Cryptpad and remove all the data that is being stored:
|
||||
|
||||
If you are using the leveldb adaptor, this is as simple as deleting the folder which contains your leveldb datastore:
|
||||
|
||||
|
||||
```
|
||||
# change into your cryptpade directory
|
||||
# change into your cryptpad directory
|
||||
cd /your/cryptpad/instance/location;
|
||||
|
||||
# delete the datastore
|
||||
rm -rf ./cryptpad.db
|
||||
rm -rf ./datastore
|
||||
```
|
||||
|
||||
If you are using the mongodb adaptor, [drop the relevant collection](https://docs.mongodb.org/manual/reference/method/db.collection.drop/#db.collection.drop).
|
||||
|
||||
If you are using the [leveldb adaptor](https://github.com/xwiki-labs/cryptpad-level-store), delete the datastore directory you have configured.
|
||||
|
||||
## Testing
|
||||
|
||||
To test CryptPad, go to http://your.server:3000/assert/
|
||||
|
@ -82,6 +89,16 @@ To test CryptPad, go to http://your.server:3000/assert/
|
|||
You can use WebDriver to run this test automatically by running TestSelenium.js but you will need chromedriver installed.
|
||||
If you use Mac, you can `brew install chromedriver`.
|
||||
|
||||
## Developing CryptPad
|
||||
|
||||
CryptPad is built with a lot of small javascript libraries.
|
||||
To make js files load faster, we apply an aggressive caching policy.
|
||||
|
||||
If you want to add new features to CryptPad, you'll want to turn off caching.
|
||||
You can do so by launching your server in _dev mode_, like so:
|
||||
|
||||
`DEV=1 node server.js`
|
||||
|
||||
# Setup using Docker
|
||||
|
||||
See [Cryptpad-Docker](cryptpad-docker.md)
|
||||
|
@ -108,14 +125,14 @@ Still there are other low-lives in the world so using CryptPad over HTTPS is pro
|
|||
## Translations
|
||||
|
||||
We'd like to make it easy for more people to use encryption in their routine activities.
|
||||
As such, we've tried to make language-specific parts of Cryptpad translatable. If you're
|
||||
able to translate Cryptpad's interface, and would like to help, please contact us!
|
||||
As such, we've tried to make language-specific parts of CryptPad translatable. If you're
|
||||
able to translate CryptPad's interface, and would like to help, please contact us!
|
||||
|
||||
You can also see [our translation guide](/customize.dist/translations/README.md).
|
||||
|
||||
## Contacting Us
|
||||
|
||||
You can reach members of the Cryptpad development team on [twitter](https://twitter.com/cryptpad),
|
||||
You can reach members of the CryptPad development team on [twitter](https://twitter.com/cryptpad),
|
||||
via our [github issue tracker](https://github.com/xwiki-labs/cryptpad/issues/), on the
|
||||
[freenode](http://webchat.freenode.net/?channels=%23cryptpad&uio=MT1mYWxzZSY5PXRydWUmMTE9Mjg3JjE1PXRydWUe7)
|
||||
irc network, or by [email](mailto:research@xwiki.com).
|
||||
|
@ -137,11 +154,9 @@ published by the Free Software Foundation, either version 3 of the License, or (
|
|||
any later version. If you wish to use this technology in a proprietary product, please contact
|
||||
sales@xwiki.com
|
||||
|
||||
* Icons thanks to http://www.famfamfam.com/ licensed [Creative Commons Attribution 2.5 License]
|
||||
|
||||
|
||||
[ChainPad]: https://github.com/xwiki-contrib/chainpad
|
||||
[CKEditor]: http://ckeditor.com/
|
||||
[fragment identifier]: https://en.wikipedia.org/wiki/Fragment_identifier
|
||||
[active attack]: https://en.wikipedia.org/wiki/Attack_(computing)#Types_of_attacks
|
||||
[Creative Commons Attribution 2.5 License]: http://creativecommons.org/licenses/by/2.5/
|
||||
|
||||
|
|
|
@ -20,6 +20,11 @@ var app = Express();
|
|||
|
||||
var httpsOpts;
|
||||
|
||||
var DEV_MODE = !!process.env.DEV
|
||||
if (DEV_MODE) {
|
||||
console.log("DEV MODE ENABLED");
|
||||
}
|
||||
|
||||
const clone = (x) => (JSON.parse(JSON.stringify(x)));
|
||||
|
||||
var setHeaders = (function () {
|
||||
|
@ -96,7 +101,7 @@ app.get('/api/config', function(req, res){
|
|||
res.send('define(' + JSON.stringify({
|
||||
requireConf: {
|
||||
waitSeconds: 60,
|
||||
urlArgs: 'ver=' + Package.version
|
||||
urlArgs: 'ver=' + Package.version + (DEV_MODE? '-' + (+new Date()): ''),
|
||||
},
|
||||
websocketPath: config.useExternalWebsocket ? undefined : config.websocketPath,
|
||||
websocketURL:'ws' + ((useSecureWebsockets) ? 's' : '') + '://' + host + ':' +
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
data-main-favicon="/customize/main-favicon.png"
|
||||
data-alt-favicon="/customize/alt-favicon.png"
|
||||
id="favicon" />
|
||||
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="/customize/main.css" />
|
||||
<style>
|
||||
html, body {
|
||||
|
@ -45,5 +46,14 @@
|
|||
<div id="iframe-container">
|
||||
<iframe id="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||
</div>
|
||||
<div id="loading">
|
||||
<div class="loadingContainer">
|
||||
<img class="cryptofist" src="/customize/cryptofist_small.png" />
|
||||
<div class="spinnerContainer">
|
||||
<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>
|
||||
</div>
|
||||
<p data-localization="loading"></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -81,7 +81,7 @@ define([
|
|||
editor.setOption('mode', mode);
|
||||
if ($select) {
|
||||
var name = $select.find('a[data-value="' + mode + '"]').text() || 'Mode';
|
||||
$select.find('.buttonTitle').text(name);
|
||||
$select.setValue(name);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -110,7 +110,9 @@ define([
|
|||
}
|
||||
editor.setOption('theme', theme);
|
||||
}
|
||||
if ($select) { $select.find('.buttonTitle').text(theme || 'Theme'); }
|
||||
if ($select) {
|
||||
$select.setValue(theme || 'Theme');
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
|
@ -374,6 +376,10 @@ define([
|
|||
userData: userData,
|
||||
readOnly: readOnly,
|
||||
ifrw: ifrw,
|
||||
share: {
|
||||
secret: secret,
|
||||
channel: info.channel
|
||||
},
|
||||
title: {
|
||||
onRename: renameCb,
|
||||
defaultName: defaultName,
|
||||
|
@ -386,8 +392,6 @@ define([
|
|||
|
||||
var $rightside = $bar.find('.' + Toolbar.constants.rightside);
|
||||
var $userBlock = $bar.find('.' + Toolbar.constants.username);
|
||||
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
|
||||
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
|
||||
var $usernameButton = module.$userNameButton = $($bar.find('.' + Toolbar.constants.changeUsername));
|
||||
|
||||
var editHash;
|
||||
|
@ -419,17 +423,6 @@ define([
|
|||
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
|
||||
$rightside.append($forgetPad);
|
||||
|
||||
if (!readOnly) {
|
||||
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
|
||||
}
|
||||
if (viewHash) {
|
||||
/* add a 'links' button */
|
||||
$viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash}));
|
||||
if (!readOnly) {
|
||||
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash}));
|
||||
}
|
||||
}
|
||||
|
||||
var configureLanguage = function (cb) {
|
||||
// FIXME this is async so make it happen as early as possible
|
||||
var options = [];
|
||||
|
@ -447,13 +440,14 @@ define([
|
|||
text: 'Mode', // Button initial text
|
||||
options: options, // Entries displayed in the menu
|
||||
left: true, // Open to the left of the button
|
||||
isSelect: true,
|
||||
};
|
||||
var $block = module.$language = Cryptpad.createDropdown(dropdownConfig);
|
||||
var $button = $block.find('.buttonTitle');
|
||||
|
||||
$block.find('a').click(function (e) {
|
||||
setMode($(this).attr('data-value'));
|
||||
$button.text($(this).text());
|
||||
setMode($(this).attr('data-value'), $block);
|
||||
onLocal();
|
||||
});
|
||||
|
||||
$rightside.append($block);
|
||||
|
@ -480,6 +474,8 @@ define([
|
|||
text: 'Theme', // Button initial text
|
||||
options: options, // Entries displayed in the menu
|
||||
left: true, // Open to the left of the button
|
||||
isSelect: true,
|
||||
initialValue: lastTheme
|
||||
};
|
||||
var $block = module.$theme = Cryptpad.createDropdown(dropdownConfig);
|
||||
var $button = $block.find('.buttonTitle');
|
||||
|
@ -489,7 +485,6 @@ define([
|
|||
$block.find('a').click(function (e) {
|
||||
var theme = $(this).attr('data-value');
|
||||
setTheme(theme, $block);
|
||||
$button.text($(this).text());
|
||||
localStorage.setItem(themeKey, theme);
|
||||
});
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ define([
|
|||
S.cb(err, doc);
|
||||
S.done = true;
|
||||
|
||||
var disconnect = Cryptpad.find(S, ['network', 'disconnect']);
|
||||
if (typeof(disconnect) === 'function') { disconnect(); }
|
||||
var abort = Cryptpad.find(S, ['realtime', 'realtime', 'abort']);
|
||||
if (typeof(abort) === 'function') {
|
||||
S.realtime.realtime.sync();
|
||||
|
@ -50,6 +52,7 @@ define([
|
|||
|
||||
var onReady = config.onReady = function (info) {
|
||||
var rt = Session.session = info.realtime;
|
||||
Session.network = info.network;
|
||||
finish(Session, void 0, rt.getUserDoc());
|
||||
};
|
||||
overwrite(config, opt);
|
||||
|
@ -66,6 +69,7 @@ define([
|
|||
var Session = { cb: cb, };
|
||||
config.onReady = function (info) {
|
||||
var realtime = Session.session = info.realtime;
|
||||
Session.network = info.network;
|
||||
|
||||
TextPatcher.create({
|
||||
realtime: realtime,
|
||||
|
|
|
@ -1,16 +1,14 @@
|
|||
define([
|
||||
'/api/config',
|
||||
'/customize/messages.js?app=' + window.location.pathname.split('/').filter(function (x) { return x; }).join('.'),
|
||||
'/customize/fsStore.js',
|
||||
'/common/fsStore.js',
|
||||
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
|
||||
'/bower_components/alertifyjs/dist/js/alertify.js',
|
||||
'/bower_components/spin.js/spin.min.js',
|
||||
'/common/clipboard.js',
|
||||
'/customize/fsStore.js',
|
||||
'/customize/application_config.js',
|
||||
|
||||
'/bower_components/jquery/dist/jquery.min.js',
|
||||
], function (Config, Messages, Store, Crypto, Alertify, Spinner, Clipboard, AppConfig) {
|
||||
], function (Config, Messages, Store, Crypto, Alertify, Clipboard, AppConfig) {
|
||||
/* This file exposes functionality which is specific to Cryptpad, but not to
|
||||
any particular pad type. This includes functions for committing metadata
|
||||
about pads to your local storage for future use and improved usability.
|
||||
|
@ -22,6 +20,7 @@ define([
|
|||
var common = window.Cryptpad = {
|
||||
Messages: Messages,
|
||||
Alertify: Alertify,
|
||||
Clipboard: Clipboard
|
||||
};
|
||||
|
||||
var store;
|
||||
|
@ -223,6 +222,7 @@ define([
|
|||
if (typeof keys === 'string') {
|
||||
return chanKey + keys;
|
||||
}
|
||||
if (!keys.editKeyStr) { return; }
|
||||
return '/1/edit/' + hexToBase64(chanKey) + '/' + Crypto.b64RemoveSlashes(keys.editKeyStr);
|
||||
};
|
||||
var getViewHashFromKeys = common.getViewHashFromKeys = function (chanKey, keys) {
|
||||
|
@ -304,6 +304,18 @@ define([
|
|||
return secret;
|
||||
};
|
||||
|
||||
var getHashes = common.getHashes = function (channel, secret) {
|
||||
var hashes = {};
|
||||
if (secret.keys.editKeyStr) {
|
||||
hashes.editHash = getEditHashFromKeys(channel, secret.keys);
|
||||
}
|
||||
if (secret.keys.viewKeyStr) {
|
||||
hashes.viewHash = getViewHashFromKeys(channel, secret.keys);
|
||||
}
|
||||
return hashes;
|
||||
};
|
||||
|
||||
|
||||
var uint8ArrayToHex = common.uint8ArrayToHex = function (a) {
|
||||
// call slice so Uint8Arrays work as expected
|
||||
return Array.prototype.slice.call(a).map(function (e, i) {
|
||||
|
@ -427,6 +439,8 @@ define([
|
|||
|
||||
var ret = {};
|
||||
|
||||
if (!href) { return ret; }
|
||||
|
||||
if (!/^https*:\/\//.test(href)) {
|
||||
var idx = href.indexOf('/#');
|
||||
ret.type = href.slice(1, idx);
|
||||
|
@ -605,22 +619,52 @@ define([
|
|||
};
|
||||
|
||||
// STORAGE
|
||||
var isNotStrongestStored = common.isNotStrongestStored = function (href, recents) {
|
||||
var parsed = parsePadUrl(href);
|
||||
var findWeaker = common.findWeaker = function (href, recents) {
|
||||
var rHref = href || getRelativeHref(window.location.href);
|
||||
var parsed = parsePadUrl(rHref);
|
||||
if (!parsed.hash) { return false; }
|
||||
return recents.some(function (pad) {
|
||||
var weaker;
|
||||
recents.some(function (pad) {
|
||||
var p = parsePadUrl(pad.href);
|
||||
if (p.type !== parsed.type) { return false; } // Not the same type
|
||||
if (p.hash === parsed.hash) { return false; } // Same hash, not stronger
|
||||
if (p.type !== parsed.type) { return; } // Not the same type
|
||||
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
||||
var pHash = parseHash(p.hash);
|
||||
var parsedHash = parseHash(parsed.hash);
|
||||
if (!parsedHash || !pHash) { return; }
|
||||
if (pHash.version !== parsedHash.version) { return false; }
|
||||
if (pHash.channel !== parsedHash.channel) { return false; }
|
||||
if (pHash.mode === 'edit' && parsedHash.mode === 'view') { return true; }
|
||||
if (pHash.mode === parsedHash.mode && parsedHash.present) { return true; }
|
||||
return false;
|
||||
if (pHash.version !== parsedHash.version) { return; }
|
||||
if (pHash.channel !== parsedHash.channel) { return; }
|
||||
if (pHash.mode === 'view' && parsedHash.mode === 'edit') {
|
||||
weaker = pad.href;
|
||||
return true;
|
||||
}
|
||||
return;
|
||||
});
|
||||
return weaker;
|
||||
};
|
||||
var findStronger = common.findStronger = function (href, recents) {
|
||||
var rHref = href || getRelativeHref(window.location.href);
|
||||
var parsed = parsePadUrl(rHref);
|
||||
if (!parsed.hash) { return false; }
|
||||
var stronger;
|
||||
recents.some(function (pad) {
|
||||
var p = parsePadUrl(pad.href);
|
||||
if (p.type !== parsed.type) { return; } // Not the same type
|
||||
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
||||
var pHash = parseHash(p.hash);
|
||||
var parsedHash = parseHash(parsed.hash);
|
||||
if (!parsedHash || !pHash) { return; }
|
||||
if (pHash.version !== parsedHash.version) { return; }
|
||||
if (pHash.channel !== parsedHash.channel) { return; }
|
||||
if (pHash.mode === 'edit' && parsedHash.mode === 'view') {
|
||||
stronger = pad.href;
|
||||
return true;
|
||||
}
|
||||
return;
|
||||
});
|
||||
return stronger;
|
||||
};
|
||||
var isNotStrongestStored = common.isNotStrongestStored = function (href, recents) {
|
||||
return findStronger(href, recents);
|
||||
};
|
||||
var setPadTitle = common.setPadTitle = function (name, cb) {
|
||||
var href = window.location.href;
|
||||
|
@ -632,6 +676,7 @@ define([
|
|||
return;
|
||||
}
|
||||
|
||||
var updateWeaker = [];
|
||||
var contains;
|
||||
var renamed = recent.map(function (pad) {
|
||||
var p = parsePadUrl(pad.href);
|
||||
|
@ -665,6 +710,14 @@ define([
|
|||
|
||||
// set the name
|
||||
pad.title = name;
|
||||
|
||||
// If we now have a stronger version of a stored href, replace the weaker one by the strong one
|
||||
if (pad && pad.href && href !== pad.href) {
|
||||
updateWeaker.push({
|
||||
o: pad.href,
|
||||
n: href
|
||||
});
|
||||
}
|
||||
pad.href = href;
|
||||
}
|
||||
return pad;
|
||||
|
@ -679,6 +732,11 @@ define([
|
|||
}
|
||||
|
||||
setRecentPads(renamed, function (err, data) {
|
||||
if (updateWeaker.length > 0) {
|
||||
updateWeaker.forEach(function (obj) {
|
||||
getStore().replaceHref(obj.o, obj.n);
|
||||
});
|
||||
}
|
||||
cb(err, data);
|
||||
});
|
||||
});
|
||||
|
@ -817,23 +875,46 @@ define([
|
|||
};
|
||||
|
||||
var LOADING = 'loading';
|
||||
var getRandomTip = function () {
|
||||
if (!Messages.tips || !Object.keys(Messages.tips).length) { return ''; }
|
||||
var keys = Object.keys(Messages.tips);
|
||||
var rdm = Math.floor(Math.random() * keys.length);
|
||||
return Messages.tips[keys[rdm]];
|
||||
};
|
||||
common.addLoadingScreen = function (loadingText) {
|
||||
var $loading, $container;
|
||||
if ($('#' + LOADING).length) {
|
||||
$('#' + LOADING).show();
|
||||
return;
|
||||
$loading = $('#' + LOADING).show();
|
||||
if (loadingText) {
|
||||
$('#' + LOADING).find('p').text(loadingText);
|
||||
}
|
||||
$container = $loading.find('.loadingContainer');
|
||||
} else {
|
||||
$loading = $('<div>', {id: LOADING});
|
||||
$container = $('<div>', {'class': 'loadingContainer'});
|
||||
$container.append('<img class="cryptofist" src="/customize/cryptofist_small.png" />');
|
||||
var $spinner = $('<div>', {'class': 'spinnerContainer'});
|
||||
common.spinner($spinner).show();
|
||||
var $text = $('<p>').text(loadingText || Messages.loading);
|
||||
$container.append($spinner).append($text);
|
||||
$loading.append($container);
|
||||
$('body').append($loading);
|
||||
}
|
||||
if (Messages.tips) {
|
||||
var $loadingTip = $('<div>', {'id': 'loadingTip'});
|
||||
var $tip = $('<span>', {'class': 'tips'}).text(getRandomTip()).appendTo($loadingTip);
|
||||
$loadingTip.css({
|
||||
'top': $('body').height()/2 + $container.height()/2 + 20 + 'px'
|
||||
});
|
||||
$('body').append($loadingTip);
|
||||
}
|
||||
var $loading = $('<div>', {id: LOADING});
|
||||
var $container = $('<div>', {'class': 'loadingContainer'});
|
||||
$container.append('<img class="cryptofist" src="/customize/cryptofist_small.png" />');
|
||||
var $spinner = $('<div>', {'class': 'spinnerContainer'});
|
||||
var loadingSpinner = common.spinner($spinner).show();
|
||||
var $text = $('<p>').text(loadingText || Messages.loading);
|
||||
$container.append($spinner).append($text);
|
||||
$loading.append($container);
|
||||
$('body').append($loading);
|
||||
};
|
||||
common.removeLoadingScreen = function (cb) {
|
||||
$('#' + LOADING).fadeOut(750, cb);
|
||||
$('#loadingTip').css('top', '');
|
||||
window.setTimeout(function () {
|
||||
$('#loadingTip').fadeOut(750);
|
||||
}, 3000);
|
||||
};
|
||||
common.errorLoadingScreen = function (error, transparent) {
|
||||
if (!$('#' + LOADING).is(':visible')) { common.addLoadingScreen(); }
|
||||
|
@ -912,7 +993,7 @@ define([
|
|||
switch (type) {
|
||||
case 'export':
|
||||
button = $('<button>', {
|
||||
title: Messages.exportButton + '\n' + Messages.exportButtonTitle,
|
||||
title: Messages.exportButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-download', style: 'font:'+size+' FontAwesome'}));
|
||||
if (callback) {
|
||||
button.click(callback);
|
||||
|
@ -920,7 +1001,7 @@ define([
|
|||
break;
|
||||
case 'import':
|
||||
button = $('<button>', {
|
||||
title: Messages.importButton + '\n' + Messages.importButtonTitle,
|
||||
title: Messages.importButtonTitle,
|
||||
}).append($('<span>', {'class':'fa fa-upload', style: 'font:'+size+' FontAwesome'}));
|
||||
if (callback) {
|
||||
button.click(common.importContent('text/plain', function (content, file) {
|
||||
|
@ -931,7 +1012,7 @@ define([
|
|||
case 'forget':
|
||||
button = $('<button>', {
|
||||
id: 'cryptpad-forget',
|
||||
title: Messages.forgetButton + '\n' + Messages.forgetButtonTitle,
|
||||
title: Messages.forgetButtonTitle,
|
||||
'class': "fa fa-trash cryptpad-forget",
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
|
@ -970,6 +1051,7 @@ define([
|
|||
});
|
||||
}
|
||||
break;
|
||||
// TODO remove editshare, viewshare, and viewopen
|
||||
case 'editshare':
|
||||
button = $('<a>', {
|
||||
title: Messages.editShareTitle,
|
||||
|
@ -1020,14 +1102,14 @@ define([
|
|||
break;
|
||||
case 'present':
|
||||
button = $('<button>', {
|
||||
title: Messages.presentButton + '\n' + Messages.presentButtonTitle,
|
||||
title: Messages.presentButtonTitle,
|
||||
'class': "fa fa-play-circle cryptpad-present-button", // class used in slide.js
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
break;
|
||||
case 'source':
|
||||
button = $('<button>', {
|
||||
title: Messages.sourceButton + '\n' + Messages.sourceButtonTitle,
|
||||
title: Messages.sourceButtonTitle,
|
||||
'class': "fa fa-stop-circle cryptpad-source-button", // class used in slide.js
|
||||
style: 'font:'+size+' FontAwesome'
|
||||
});
|
||||
|
@ -1063,10 +1145,15 @@ define([
|
|||
|
||||
// Container
|
||||
var $container = $(config.container);
|
||||
var containerConfig = {
|
||||
'class': 'dropdown-bar'
|
||||
};
|
||||
if (config.buttonTitle) {
|
||||
containerConfig.title = config.buttonTitle;
|
||||
}
|
||||
|
||||
if (!config.container) {
|
||||
$container = $('<span>', {
|
||||
'class': 'dropdown-bar'
|
||||
});
|
||||
$container = $('<span>', containerConfig);
|
||||
}
|
||||
|
||||
// Button
|
||||
|
@ -1088,6 +1175,34 @@ define([
|
|||
|
||||
$container.append($button).append($innerblock);
|
||||
|
||||
var value = config.initialValue || '';
|
||||
|
||||
var setActive = function ($el) {
|
||||
if ($el.length !== 1) { return; }
|
||||
$innerblock.find('.active').removeClass('active');
|
||||
$el.addClass('active');
|
||||
var scroll = $el.position().top + $innerblock.scrollTop();
|
||||
if (scroll < $innerblock.scrollTop()) {
|
||||
$innerblock.scrollTop(scroll);
|
||||
} else if (scroll > ($innerblock.scrollTop() + 280)) {
|
||||
$innerblock.scrollTop(scroll-270);
|
||||
}
|
||||
};
|
||||
|
||||
var hide = function () {
|
||||
window.setTimeout(function () { $innerblock.hide(); }, 0);
|
||||
};
|
||||
|
||||
var show = function () {
|
||||
$innerblock.show();
|
||||
$innerblock.find('.active').removeClass('active');
|
||||
if (config.isSelect && value) {
|
||||
var $val = $innerblock.find('[data-value="'+value+'"]');
|
||||
setActive($val);
|
||||
$innerblock.scrollTop($val.position().top + $innerblock.scrollTop());
|
||||
}
|
||||
};
|
||||
|
||||
$button.click(function (e) {
|
||||
e.stopPropagation();
|
||||
var state = $innerblock.is(':visible');
|
||||
|
@ -1100,12 +1215,64 @@ define([
|
|||
// empty try catch in case this iframe is problematic (cross-origin)
|
||||
}
|
||||
if (state) {
|
||||
$innerblock.hide();
|
||||
hide();
|
||||
return;
|
||||
}
|
||||
$innerblock.show();
|
||||
show();
|
||||
});
|
||||
|
||||
if (config.isSelect) {
|
||||
var pressed = '';
|
||||
var to;
|
||||
$container.keydown(function (e) {
|
||||
var $value = $innerblock.find('[data-value].active');
|
||||
if (e.which === 38) { // Up
|
||||
if ($value.length) {
|
||||
var $prev = $value.prev();
|
||||
setActive($prev);
|
||||
}
|
||||
}
|
||||
if (e.which === 40) { // Down
|
||||
if ($value.length) {
|
||||
var $next = $value.next();
|
||||
setActive($next);
|
||||
}
|
||||
}
|
||||
if (e.which === 13) { //Enter
|
||||
if ($value.length) {
|
||||
$value.click();
|
||||
hide();
|
||||
}
|
||||
}
|
||||
if (e.which === 27) { // Esc
|
||||
hide();
|
||||
}
|
||||
});
|
||||
$container.keypress(function (e) {
|
||||
window.clearTimeout(to);
|
||||
var c = String.fromCharCode(e.which);
|
||||
pressed += c;
|
||||
var $value = $innerblock.find('[data-value^="'+pressed+'"]:first');
|
||||
if ($value.length) {
|
||||
setActive($value);
|
||||
$innerblock.scrollTop($value.position().top + $innerblock.scrollTop());
|
||||
}
|
||||
to = window.setTimeout(function () {
|
||||
pressed = '';
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
$container.setValue = function (val) {
|
||||
value = val;
|
||||
var $val = $innerblock.find('[data-value="'+val+'"]');
|
||||
var textValue = $val.html() || val;
|
||||
$button.find('.buttonTitle').html(textValue);
|
||||
};
|
||||
$container.getValue = function () {
|
||||
return value || '';
|
||||
};
|
||||
}
|
||||
|
||||
return $container;
|
||||
};
|
||||
|
||||
|
@ -1130,7 +1297,8 @@ define([
|
|||
text: Messages.language, // Button initial text
|
||||
options: options, // Entries displayed in the menu
|
||||
left: true, // Open to the left of the button
|
||||
container: $initBlock // optional
|
||||
container: $initBlock, // optional
|
||||
isSelect: true
|
||||
};
|
||||
var $block = createDropdown(dropdownConfig);
|
||||
$block.attr('id', 'language-selector');
|
||||
|
@ -1187,7 +1355,7 @@ define([
|
|||
content: Messages.user_rename
|
||||
});
|
||||
}
|
||||
if (parsed && parsed.type && parsed.type !== 'settings') {
|
||||
if (parsed && (!parsed.type || parsed.type !== 'settings')) {
|
||||
options.push({
|
||||
tag: 'a',
|
||||
attributes: {'class': 'settings'},
|
||||
|
@ -1332,7 +1500,7 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
common.confirm = function (msg, cb, opt, force) {
|
||||
common.confirm = function (msg, cb, opt, force, styleCB) {
|
||||
opt = opt || {};
|
||||
cb = cb || function () {};
|
||||
if (force !== true) { msg = fixHTML(msg); }
|
||||
|
@ -1353,6 +1521,19 @@ define([
|
|||
cb(false);
|
||||
stopListening(keyHandler);
|
||||
});
|
||||
|
||||
window.setTimeout(function () {
|
||||
var $ok = findOKButton();
|
||||
var $cancel = findCancelButton();
|
||||
if (opt.okClass) { $ok.addClass(opt.okClass); }
|
||||
if (opt.cancelClass) { $cancel.addClass(opt.cancelClass); }
|
||||
if (opt.reverseOrder) {
|
||||
$ok.insertBefore($ok.prev());
|
||||
}
|
||||
if (typeof(styleCB) === 'function') {
|
||||
styleCB($ok.closest('.dialog'));
|
||||
}
|
||||
}, 0);
|
||||
};
|
||||
|
||||
common.log = function (msg) {
|
||||
|
@ -1367,37 +1548,12 @@ define([
|
|||
* spinner
|
||||
*/
|
||||
common.spinner = function (parent) {
|
||||
var $target = $('<div>', {
|
||||
//
|
||||
var $target = $('<span>', {
|
||||
'class': 'fa fa-spinner fa-pulse fa-4x fa-fw'
|
||||
}).hide();
|
||||
|
||||
$(parent).append($target);
|
||||
|
||||
var opts = {
|
||||
lines: 20, // The number of lines to draw
|
||||
length: 5, // The length of each line
|
||||
width: 2, // The line thickness
|
||||
radius: 15, // The radius of the inner circle
|
||||
scale: 2, // Scales overall size of the spinner
|
||||
corners: 1, // Corner roundness (0..1)
|
||||
color: '#ddd', // #rgb or #rrggbb or array of colors
|
||||
opacity: 0.3, // Opacity of the lines
|
||||
rotate: 31, // The rotation offset
|
||||
direction: 1, // 1: clockwise, -1: counterclockwise
|
||||
speed: 1, // Rounds per second
|
||||
trail: 49, // Afterglow percentage
|
||||
fps: 20, // Frames per second when using setTimeout() as a fallback for CSS
|
||||
zIndex: 2e9, // The z-index (defaults to 2000000000)
|
||||
className: 'spinner', // The CSS class to assign to the spinner
|
||||
top: '50%', // Top position relative to parent
|
||||
left: '50%', // Left position relative to parent
|
||||
shadow: false, // Whether to render a shadow
|
||||
hwaccel: false, // Whether to use hardware acceleration
|
||||
position: 'relative', // Element positioning
|
||||
height: '100px'
|
||||
};
|
||||
var spinner = new Spinner(opts).spin($target[0]);
|
||||
|
||||
return {
|
||||
show: function () {
|
||||
$target.show();
|
||||
|
@ -1408,7 +1564,7 @@ define([
|
|||
return this;
|
||||
},
|
||||
get: function () {
|
||||
return spinner;
|
||||
return $target;
|
||||
},
|
||||
};
|
||||
};
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
define([
|
||||
'/customize/messages.js',
|
||||
], function (Messages) {
|
||||
Messages._applyTranslation();
|
||||
});
|
|
@ -1,5 +1,7 @@
|
|||
<!DOCTYPE html>
|
||||
<head>
|
||||
<title>About our feedback api</title>
|
||||
<script data-main="feedback-main.js" src="/bower_components/requirejs/require.js"></script>
|
||||
<style>
|
||||
body {
|
||||
max-width: 60vw;
|
||||
|
@ -9,9 +11,9 @@ body {
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<p>If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.</p>
|
||||
<p>We care about your privacy, and at the same time we want CryptPad to be very easy to use.
|
||||
<p data-localization="feedback_about">If you're reading this, you were probably curious why CryptPad is requesting web pages when you perform certain actions.</p>
|
||||
<p data-localization="feedback_privacy">We care about your privacy, and at the same time we want CryptPad to be very easy to use.
|
||||
We use this file to figure out which UI features matter to our users, by requesting it along with a parameter specifying which action was taken.</p>
|
||||
<p>If you would like to opt out, visit <a href="/settings/">your user settings page</a>, where you'll find a checkbox to enable or disable user feedback</p>
|
||||
<p data-localization="feedback_optout">If you would like to opt out, visit <a href="/settings/">your user settings page</a>, where you'll find a checkbox to enable or disable user feedback</p>
|
||||
|
||||
|
||||
|
|
|
@ -6,10 +6,10 @@ define([
|
|||
|
||||
var Messages = {};
|
||||
|
||||
var ROOT = "root";
|
||||
var UNSORTED = "unsorted";
|
||||
var TRASH = "trash";
|
||||
var TEMPLATE = "template";
|
||||
var ROOT = module.ROOT = "root";
|
||||
var UNSORTED = module.UNSORTED = "unsorted";
|
||||
var TRASH = module.TRASH = "trash";
|
||||
var TEMPLATE = module.TEMPLATE = "template";
|
||||
|
||||
var init = module.init = function (files, config) {
|
||||
var Cryptpad = config.Cryptpad;
|
||||
|
@ -232,15 +232,95 @@ define([
|
|||
return ret;
|
||||
};
|
||||
|
||||
var getFilesDataFiles = function () {
|
||||
var getFilesDataFiles = exp.getFilesDataFiles = function () {
|
||||
var ret = [];
|
||||
for (var el in files[FILES_DATA]) {
|
||||
files[FILES_DATA].forEach(function (el) {
|
||||
if (el.href && ret.indexOf(el.href) === -1) {
|
||||
ret.push(el.href);
|
||||
}
|
||||
});
|
||||
return ret;
|
||||
};
|
||||
|
||||
var _findFileInRoot = function (path, href) {
|
||||
if (path[0] !== ROOT && path[0] !== TRASH) { return []; }
|
||||
var paths = [];
|
||||
var root = exp.findElement(files, path);
|
||||
var addPaths = function (p) {
|
||||
if (paths.indexOf(p) === -1) {
|
||||
paths.push(p);
|
||||
}
|
||||
};
|
||||
|
||||
if (isFile(root)) {
|
||||
if (compareFiles(href, root)) {
|
||||
if (paths.indexOf(path) === -1) {
|
||||
paths.push(path);
|
||||
}
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
for (var e in root) {
|
||||
var nPath = path.slice();
|
||||
nPath.push(e);
|
||||
_findFileInRoot(nPath, href).forEach(addPaths);
|
||||
}
|
||||
|
||||
return paths;
|
||||
};
|
||||
var _findFileInHrefArray = function (rootName, href) {
|
||||
var unsorted = files[rootName].slice();
|
||||
var ret = [];
|
||||
var i = -1;
|
||||
while ((i = unsorted.indexOf(href, i+1)) !== -1){
|
||||
ret.push([rootName, i]);
|
||||
}
|
||||
return ret;
|
||||
};
|
||||
var _findFileInTrash = function (path, href) {
|
||||
var root = exp.findElement(files, path);
|
||||
var paths = [];
|
||||
var addPaths = function (p) {
|
||||
if (paths.indexOf(p) === -1) {
|
||||
paths.push(p);
|
||||
}
|
||||
};
|
||||
if (path.length === 1) {
|
||||
Object.keys(root).forEach(function (key) {
|
||||
var arr = root[key];
|
||||
if (!Array.isArray(arr)) { return; }
|
||||
var nPath = path.slice();
|
||||
nPath.push(key);
|
||||
_findFileInTrash(nPath, href).forEach(addPaths);
|
||||
});
|
||||
}
|
||||
if (path.length === 2) {
|
||||
if (!Array.isArray(root)) { return []; }
|
||||
root.forEach(function (el, i) {
|
||||
var nPath = path.slice();
|
||||
nPath.push(i);
|
||||
nPath.push('element');
|
||||
if (isFile(el.element)) {
|
||||
if (compareFiles(href, el.element)) {
|
||||
addPaths(nPath);
|
||||
}
|
||||
return;
|
||||
}
|
||||
_findFileInTrash(nPath, href).forEach(addPaths);
|
||||
});
|
||||
}
|
||||
if (path.length >= 4) {
|
||||
_findFileInRoot(path, href).forEach(addPaths);
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
var findFile = exp.findFile = function (href) {
|
||||
var rootpaths = _findFileInRoot([ROOT], href);
|
||||
var unsortedpaths = _findFileInHrefArray(UNSORTED, href);
|
||||
var templatepaths = _findFileInHrefArray(TEMPLATE, href);
|
||||
var trashpaths = _findFileInTrash([TRASH], href);
|
||||
return rootpaths.concat(unsortedpaths, templatepaths, trashpaths);
|
||||
};
|
||||
|
||||
// Remove the selected 'href' from the tree located at 'path', and push its locations to the 'paths' array
|
||||
var removeFileFromRoot = function (path, href) {
|
||||
|
@ -374,7 +454,6 @@ define([
|
|||
var parentEl = exp.findElement(files, parentPath);
|
||||
// Trash root: we have array here, we can't just splice with the path otherwise we might break the path
|
||||
// of another element in the loop
|
||||
console.log(path);
|
||||
if (path.length === 4) {
|
||||
trashRoot.push({
|
||||
name: path[1],
|
||||
|
@ -573,7 +652,6 @@ define([
|
|||
// Import elements in the file manager
|
||||
var importElements = exp.importElements = function (elements, path, cb) {
|
||||
if (!elements || elements.length === 0) { return; }
|
||||
console.log(elements);
|
||||
var newParent = findElement(files, path);
|
||||
if (!newParent) { debug("Trying to import elements into a non-existing folder"); return; }
|
||||
elements.forEach(function (e) {
|
||||
|
@ -670,7 +748,7 @@ define([
|
|||
};
|
||||
|
||||
// Delete permanently (remove from the trash root and from filesData)
|
||||
var removeFromTrash = exp.removeFromTrash = function (path, cb) {
|
||||
var removeFromTrash = exp.removeFromTrash = function (path, cb, nocheck) {
|
||||
if (!path || path.length < 4 || path[0] !== TRASH) { return; }
|
||||
// Remove the last element from the path to get the parent path and the element name
|
||||
var parentPath = path.slice();
|
||||
|
@ -691,7 +769,9 @@ define([
|
|||
parentEl[name] = undefined;
|
||||
delete parentEl[name];
|
||||
}
|
||||
checkDeletedFiles();
|
||||
if (!nocheck) {
|
||||
checkDeletedFiles();
|
||||
}
|
||||
if(cb) { cb(); }
|
||||
};
|
||||
|
||||
|
@ -773,7 +853,7 @@ define([
|
|||
pushToTrash(key, href, path);
|
||||
};
|
||||
|
||||
var addUnsortedPad = exp.addPad = function (href, path, name) {
|
||||
var addPad = exp.addPad = function (href, path, name) {
|
||||
if (workgroup) { return; }
|
||||
if (!href) { return; }
|
||||
var unsortedFiles = getUnsortedFiles();
|
||||
|
@ -798,10 +878,54 @@ define([
|
|||
}
|
||||
}
|
||||
if (unsortedFiles.indexOf(href) === -1 && rootFiles.indexOf(href) === -1 && templateFiles.indexOf(href) === -1 && trashFiles.indexOf(href) === -1) {
|
||||
console.log('push', href);
|
||||
files[UNSORTED].push(href);
|
||||
}
|
||||
};
|
||||
|
||||
var replaceFile = function (path, o, n) {
|
||||
var root = exp.findElement(files, path);
|
||||
|
||||
if (isFile(root)) { return; }
|
||||
for (var e in root) {
|
||||
if (isFile(root[e])) {
|
||||
if (compareFiles(o, root[e])) {
|
||||
root[e] = n;
|
||||
}
|
||||
} else {
|
||||
var nPath = path.slice();
|
||||
nPath.push(e);
|
||||
replaceFile(nPath, o, n);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Replace a href by a stronger one everywhere in the drive (except FILES_DATA)
|
||||
var replaceHref = exp.replaceHref = function (o, n) {
|
||||
if (!isFile(o) || !isFile(n)) { return; }
|
||||
var paths = findFile(o);
|
||||
|
||||
// Remove all the occurences in the trash
|
||||
// Replace all the occurences not in the trash
|
||||
// If all the occurences are in the trash or no occurence, add the pad to unsorted
|
||||
var allInTrash = true;
|
||||
paths.forEach(function (p) {
|
||||
if (p[0] === TRASH) {
|
||||
removeFromTrash(p, null, true); // 3rd parameter means skip "checkDeletedFiles"
|
||||
return;
|
||||
} else {
|
||||
allInTrash = false;
|
||||
var parentPath = p.slice();
|
||||
var key = parentPath.pop();
|
||||
var parentEl = findElement(files, parentPath);
|
||||
parentEl[key] = n;
|
||||
}
|
||||
});
|
||||
if (allInTrash) {
|
||||
addPad(n);
|
||||
}
|
||||
};
|
||||
|
||||
// addTemplate is called when we want to add a new pad, never visited, to the templates list
|
||||
// first, we must add it to FILES_DATA, so the input has to be an fileDAta object
|
||||
var addTemplate = exp.addTemplate = function (fileData) {
|
||||
|
|
|
@ -119,6 +119,10 @@ define([
|
|||
return filesOp.getStructure();
|
||||
};
|
||||
|
||||
ret.replaceHref = function (o, n) {
|
||||
return filesOp.replaceHref(o, n);
|
||||
};
|
||||
|
||||
var changeHandlers = ret.changeHandlers = [];
|
||||
|
||||
ret.change = function (f) {};
|
||||
|
@ -127,9 +131,10 @@ define([
|
|||
};
|
||||
|
||||
var onReady = function (f, proxy, Cryptpad, exp) {
|
||||
var fo = FO.init(proxy.drive, {
|
||||
var fo = exp.fo = FO.init(proxy.drive, {
|
||||
Cryptpad: Cryptpad
|
||||
});
|
||||
|
||||
//storeObj = proxy;
|
||||
store = initStore(fo, proxy, exp);
|
||||
if (typeof(f) === 'function') {
|
|
@ -94,17 +94,21 @@ define([
|
|||
res.realtime = rt.realtime;
|
||||
res.network = rt.network;
|
||||
|
||||
// they're registering...
|
||||
res.userHash = opt.userHash;
|
||||
res.userName = uname;
|
||||
|
||||
// they tried to just log in but there's no such user
|
||||
if (!isRegister && isProxyEmpty(rt.proxy)) {
|
||||
rt.network.disconnect(); // clean up after yourself
|
||||
return void cb('NO_SUCH_USER', res);
|
||||
}
|
||||
|
||||
// they're registering...
|
||||
|
||||
res.userHash = opt.userHash;
|
||||
res.userName = uname;
|
||||
//res.displayName // TODO
|
||||
// they tried to register, but those exact credentials exist
|
||||
if (isRegister && !isProxyEmpty(rt.proxy)) {
|
||||
rt.network.disconnect();
|
||||
return void cb('ALREADY_REGISTERED', res);
|
||||
}
|
||||
|
||||
cb(void 0, res);
|
||||
});
|
||||
|
|
|
@ -0,0 +1,198 @@
|
|||
require.config({ paths: { 'json.sortify': '/bower_components/json.sortify/dist/JSON.sortify' } });
|
||||
define([
|
||||
'/common/cryptpad-common.js',
|
||||
'/common/cryptget.js',
|
||||
'/common/fileObject.js',
|
||||
'json.sortify'
|
||||
], function (Cryptpad, Crypt, FO, Sortify) {
|
||||
var exp = {};
|
||||
|
||||
var getType = function (el) {
|
||||
if (el === null) { return "null"; }
|
||||
return Array.isArray(el) ? "array" : typeof(el);
|
||||
};
|
||||
|
||||
var findAvailableKey = function (obj, key) {
|
||||
if (typeof (obj[key]) === "undefined") { return key; }
|
||||
var i = 1;
|
||||
var nkey = key;
|
||||
while (typeof (obj[nkey]) !== "undefined") {
|
||||
nkey = key + '_' + i;
|
||||
i++;
|
||||
}
|
||||
return nkey;
|
||||
};
|
||||
|
||||
var copy = function (el) {
|
||||
if (typeof (el) !== "object") { return el; }
|
||||
return JSON.parse(JSON.stringify(el));
|
||||
};
|
||||
|
||||
var deduplicate = function (array) {
|
||||
var a = array.slice();
|
||||
for(var i=0; i<a.length; i++) {
|
||||
for(var j=i+1; j<a.length; j++) {
|
||||
if(a[i] === a[j] || (
|
||||
typeof(a[i]) === "object" && Sortify(a[i]) === Sortify(a[j]))) {
|
||||
a.splice(j--, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
// Merge obj2 into obj1
|
||||
// If keepOld is true, obj1 values are kept in case of conflicti
|
||||
// Not used ATM
|
||||
var merge = function (obj1, obj2, keepOld) {
|
||||
if (typeof (obj1) !== "object" || typeof (obj2) !== "object") { return; }
|
||||
Object.keys(obj2).forEach(function (k) {
|
||||
var v = obj2[k];
|
||||
// If one of them is not an object or if we have a map and a array, don't override, create a new key
|
||||
if (!obj1[k] || typeof(obj1[k]) !== "object" || typeof(obj2[k]) !== "object" ||
|
||||
(getType(obj1[k]) !== getType(obj2[k]))) {
|
||||
// We don't want to override the values in the object (username, preferences)
|
||||
// These values should be the ones stored in the first object
|
||||
if (keepOld) { return; }
|
||||
if (obj1[k] === obj2[k]) { return; }
|
||||
var nkey = findAvailableKey(obj1, k);
|
||||
obj1[nkey] = copy(obj2[k]);
|
||||
return;
|
||||
}
|
||||
// Else, they're both maps or both arrays
|
||||
if (getType(obj1[k]) === "array" && getType(obj2[k]) === "array") {
|
||||
var c = obj1[k].concat(obj2[k]);
|
||||
obj1[k] = deduplicate(c);
|
||||
return;
|
||||
}
|
||||
merge(obj1[k], obj2[k], keepOld);
|
||||
});
|
||||
};
|
||||
|
||||
var createFromPath = function (proxy, oldFo, path, href) {
|
||||
var root = proxy.drive;
|
||||
|
||||
var error = function (msg) {
|
||||
console.error(msg || "Unable to find that path", path);
|
||||
};
|
||||
|
||||
if (path[0] === FO.TRASH && path.length === 4) {
|
||||
href = oldFo.getTrashElementData(path);
|
||||
path.pop();
|
||||
}
|
||||
|
||||
var p, next, nextRoot;
|
||||
path.forEach(function (p, i) {
|
||||
if (!root) { return; }
|
||||
if (typeof(p) === "string") {
|
||||
if (getType(root) !== "object") { root = undefined; error(); return; }
|
||||
if (i === path.length - 1) {
|
||||
root[findAvailableKey(root, p)] = href;
|
||||
return;
|
||||
}
|
||||
next = getType(path[i+1]);
|
||||
nextRoot = getType(root[p]);
|
||||
if (nextRoot !== "undefined") {
|
||||
if (next === "string" && nextRoot === "object" || next === "number" && nextRoot === "array") {
|
||||
root = root[p];
|
||||
return;
|
||||
}
|
||||
p = findAvailableKey(root, p);
|
||||
}
|
||||
if (next === "number") {
|
||||
root[p] = [];
|
||||
root = root[p];
|
||||
return;
|
||||
}
|
||||
root[p] = {};
|
||||
root = root[p];
|
||||
return;
|
||||
}
|
||||
// Path contains a non-string element: it's an array index
|
||||
if (typeof(p) !== "number") { root = undefined; error(); return; }
|
||||
if (getType(root) !== "array") { root = undefined; error(); return; }
|
||||
if (i === path.length - 1) {
|
||||
if (root.indexOf(href) === -1) { root.push(href); }
|
||||
return;
|
||||
}
|
||||
next = getType(path[i+1]);
|
||||
if (next === "number") {
|
||||
error('2 consecutives arrays in the user object');
|
||||
root = undefined;
|
||||
//root.push([]);
|
||||
//root = root[root.length - 1];
|
||||
return;
|
||||
}
|
||||
root.push({});
|
||||
root = root[root.length - 1];
|
||||
return;
|
||||
});
|
||||
};
|
||||
|
||||
var mergeAnonDrive = exp.anonDriveIntoUser = function (proxy, cb) {
|
||||
// Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
|
||||
if (!localStorage.FS_hash || !Cryptpad.isLoggedIn()) {
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
}
|
||||
// Get the content of FS_hash and then merge the objects, remove the migration key and cb
|
||||
var todo = function (err, doc) {
|
||||
if (err) { console.error("Cannot migrate recent pads", err); return; }
|
||||
var parsed;
|
||||
if (!doc) {
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
return;
|
||||
}
|
||||
try { parsed = JSON.parse(doc); } catch (e) {
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
console.error("Cannot parsed recent pads", e);
|
||||
return;
|
||||
}
|
||||
if (parsed) {
|
||||
//merge(proxy, parsed, true);
|
||||
var oldFo = FO.init(parsed.drive, {
|
||||
Cryptpad: Cryptpad
|
||||
});
|
||||
var newData = Cryptpad.getStore().getProxy();
|
||||
var newFo = newData.fo;
|
||||
var newRecentPads = proxy.drive[Cryptpad.storageKey];
|
||||
var newFiles = newFo.getFilesDataFiles();
|
||||
var oldFiles = oldFo.getFilesDataFiles();
|
||||
oldFiles.forEach(function (href) {
|
||||
// Do not migrate a pad if we already have it, it would create a duplicate in the drive
|
||||
if (newFiles.indexOf(href) !== -1) { return; }
|
||||
// If we have a stronger version, do not add the current href
|
||||
if (Cryptpad.findStronger(href, newRecentPads)) { return; }
|
||||
// If we have a weaker version, replace the href by the new one
|
||||
// NOTE: if that weaker version is in the trash, the strong one will be put in unsorted
|
||||
var weaker = Cryptpad.findWeaker(href, newRecentPads);
|
||||
if (weaker) {
|
||||
// Update RECENTPADS
|
||||
newRecentPads.some(function (pad) {
|
||||
if (pad.href === weaker) {
|
||||
pad.href = href;
|
||||
return true;
|
||||
}
|
||||
return;
|
||||
});
|
||||
// Update the file in the drive
|
||||
newFo.replaceHref(weaker, href);
|
||||
return;
|
||||
}
|
||||
// Here it means we have a new href, so we should add it to the drive at its old location
|
||||
var paths = oldFo.findFile(href);
|
||||
if (paths.length === 0) { return; }
|
||||
createFromPath(proxy, oldFo, paths[0], href);
|
||||
// Also, push the file data in our array
|
||||
var data = oldFo.getFileData(href);
|
||||
if (data) {
|
||||
newRecentPads.push(data);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
};
|
||||
Crypt.get(localStorage.FS_hash, todo);
|
||||
};
|
||||
|
||||
return exp;
|
||||
});
|
|
@ -123,16 +123,89 @@ define([
|
|||
|
||||
// Share button
|
||||
if (config.displayed.indexOf('share') !== -1) {
|
||||
var $shareIcon = $('<span>', {'class': 'fa fa-share-alt'});
|
||||
var $span = $('<span>', {'class': 'large'}).append(' ' +Messages.shareButton);
|
||||
var dropdownConfigShare = {
|
||||
text: $('<div>').append($shareIcon).append($span).html(),
|
||||
options: []
|
||||
};
|
||||
var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare);
|
||||
$shareBlock.find('button').attr('id', 'shareButton');
|
||||
$shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS);
|
||||
$userlistElement.append($shareBlock);
|
||||
var secret = Cryptpad.find(config, ['share', 'secret']);
|
||||
var channel = Cryptpad.find(config, ['share', 'channel']);
|
||||
if (!secret || !channel) {
|
||||
throw new Error("Unable to display the share button: share.secret and share.channel required");
|
||||
}
|
||||
Cryptpad.getRecentPads(function (err, recent) {
|
||||
var $shareIcon = $('<span>', {'class': 'fa fa-share-alt'});
|
||||
var $span = $('<span>', {'class': 'large'}).append(' ' +Messages.shareButton);
|
||||
var hashes = Cryptpad.getHashes(channel, secret);
|
||||
var options = [];
|
||||
|
||||
// If we have a stronger version in drive, add it and add a redirect button
|
||||
var stronger = recent && Cryptpad.findStronger(null, recent);
|
||||
if (stronger) {
|
||||
var parsed = Cryptpad.parsePadUrl(stronger);
|
||||
hashes.editHash = parsed.hash;
|
||||
}
|
||||
|
||||
if (hashes.editHash) {
|
||||
options.push({
|
||||
tag: 'a',
|
||||
attributes: {title: Messages.editShareTitle, 'class': 'editShare'},
|
||||
content: '<span class="fa fa-users"></span> ' + Messages.editShare
|
||||
});
|
||||
if (stronger) {
|
||||
// We're in view mode, display the "open editing link" button
|
||||
options.push({
|
||||
tag: 'a',
|
||||
attributes: {
|
||||
title: Messages.editOpenTitle,
|
||||
'class': 'editOpen',
|
||||
href: window.location.pathname + '#' + hashes.editHash,
|
||||
target: '_blank'
|
||||
},
|
||||
content: '<span class="fa fa-users"></span> ' + Messages.editOpen
|
||||
});
|
||||
}
|
||||
options.push({tag: 'hr'});
|
||||
}
|
||||
if (hashes.viewHash) {
|
||||
options.push({
|
||||
tag: 'a',
|
||||
attributes: {title: Messages.viewShareTitle, 'class': 'viewShare'},
|
||||
content: '<span class="fa fa-eye"></span> ' + Messages.viewShare
|
||||
});
|
||||
if (hashes.editHash && !stronger) {
|
||||
// We're in edit mode, display the "open readonly" button
|
||||
options.push({
|
||||
tag: 'a',
|
||||
attributes: {
|
||||
title: Messages.viewOpenTitle,
|
||||
'class': 'viewOpen',
|
||||
href: window.location.pathname + '#' + hashes.viewHash,
|
||||
target: '_blank'
|
||||
},
|
||||
content: '<span class="fa fa-eye"></span> ' + Messages.viewOpen
|
||||
});
|
||||
}
|
||||
}
|
||||
var dropdownConfigShare = {
|
||||
text: $('<div>').append($shareIcon).append($span).html(),
|
||||
options: options
|
||||
};
|
||||
var $shareBlock = Cryptpad.createDropdown(dropdownConfigShare);
|
||||
$shareBlock.find('button').attr('id', 'shareButton');
|
||||
$shareBlock.find('.dropdown-bar-content').addClass(SHARE_CLS).addClass(EDITSHARE_CLS).addClass(VIEWSHARE_CLS);
|
||||
$userlistElement.append($shareBlock);
|
||||
|
||||
if (hashes.editHash) {
|
||||
$shareBlock.find('a.editShare').click(function () {
|
||||
var url = window.location.origin + window.location.pathname + '#' + hashes.editHash;
|
||||
var success = Cryptpad.Clipboard.copy(url);
|
||||
if (success) { Cryptpad.log(Messages.shareSuccess); }
|
||||
});
|
||||
}
|
||||
if (hashes.viewHash) {
|
||||
$shareBlock.find('a.viewShare').click(function () {
|
||||
var url = window.location.origin + window.location.pathname + '#' + hashes.viewHash;
|
||||
var success = Cryptpad.Clipboard.copy(url);
|
||||
if (success) { Cryptpad.log(Messages.shareSuccess); }
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -223,7 +296,7 @@ define([
|
|||
}
|
||||
if (anonymous > 0) {
|
||||
var text = anonymous === 1 ? Messages.anonymousUser : Messages.anonymousUsers;
|
||||
$editUsers.push('<span class="anonymous">' + anonymous + ' ' + text + '</span>');
|
||||
$editUsers.append('<span class="anonymous">' + anonymous + ' ' + text + '</span>');
|
||||
}
|
||||
if (numberOfViewUsers > 0) {
|
||||
var viewText = '<span class="viewer">';
|
||||
|
|
|
@ -66,6 +66,7 @@ li {
|
|||
.contextMenu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
}
|
||||
.contextMenu li {
|
||||
padding: 0;
|
||||
|
@ -81,6 +82,10 @@ li {
|
|||
color: #eee;
|
||||
margin: -1px;
|
||||
}
|
||||
.selected .fa-minus-square-o,
|
||||
.selected .fa-plus-square-o {
|
||||
color: #000;
|
||||
}
|
||||
span.fa-folder,
|
||||
span.fa-folder-open {
|
||||
color: #FEDE8B;
|
||||
|
@ -101,17 +106,24 @@ span.fa-folder-open {
|
|||
color: #000;
|
||||
}
|
||||
#tree li {
|
||||
/*cursor: pointer;*/
|
||||
padding: 0 0 0 5px;
|
||||
cursor: auto;
|
||||
}
|
||||
#tree li:hover > span.element {
|
||||
text-decoration: underline;
|
||||
}
|
||||
#tree li.collapsed ul {
|
||||
display: none;
|
||||
}
|
||||
#tree li input {
|
||||
width: calc(70%);
|
||||
width: calc(100% - 30px);
|
||||
}
|
||||
#tree li > span.element-row {
|
||||
width: calc(100% + 5px);
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin-left: -5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
#tree li > span.element-row:not(.selected):hover {
|
||||
background-color: #eee;
|
||||
}
|
||||
#tree span.element {
|
||||
cursor: pointer;
|
||||
|
@ -220,6 +232,9 @@ span.fa-folder-open {
|
|||
#content li:not(.header) *:not(input) {
|
||||
/*pointer-events: none;*/
|
||||
}
|
||||
#content li:not(.header):hover:not(.selected) {
|
||||
background-color: #eee;
|
||||
}
|
||||
#content li:not(.header):hover .name {
|
||||
/*text-decoration: underline;*/
|
||||
}
|
||||
|
@ -233,12 +248,20 @@ span.fa-folder-open {
|
|||
text-align: center;
|
||||
vertical-align: top;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
max-height: 145px;
|
||||
}
|
||||
#content div.grid li:not(.selected) {
|
||||
border: transparent 1px;
|
||||
}
|
||||
#content div.grid li .name {
|
||||
width: 100%;
|
||||
}
|
||||
#content div.grid li input {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
#content div.grid li .fa {
|
||||
display: block;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
@tree-fg: #000;
|
||||
@tree-lines-col: #888;
|
||||
|
||||
@drive-hover: #eee;
|
||||
|
||||
@content-bg: @tree-bg;
|
||||
@content-bg-ro: darken(@content-bg, 10%);
|
||||
@content-fg: @tree-fg;
|
||||
|
@ -93,6 +95,7 @@ li {
|
|||
.contextMenu {
|
||||
display: none;
|
||||
position: absolute;
|
||||
z-index: 50;
|
||||
li {
|
||||
padding: 0;
|
||||
font-size: 16px;
|
||||
|
@ -109,6 +112,9 @@ li {
|
|||
background: #666;
|
||||
color: #eee;
|
||||
margin: -1px;
|
||||
.fa-minus-square-o, .fa-plus-square-o {
|
||||
color: @tree-fg;
|
||||
}
|
||||
}
|
||||
|
||||
span {
|
||||
|
@ -134,16 +140,23 @@ span {
|
|||
padding: 10px 0px;
|
||||
color: @tree-fg;
|
||||
li {
|
||||
/*cursor: pointer;*/
|
||||
padding: 0 0 0 5px;
|
||||
cursor: auto;
|
||||
&:hover > span.element {
|
||||
text-decoration: underline;
|
||||
}
|
||||
&.collapsed ul {
|
||||
display: none;
|
||||
}
|
||||
input {
|
||||
width: calc(100% - 30px);
|
||||
width: ~"calc(100% - 30px)";
|
||||
}
|
||||
& > span.element-row {
|
||||
width: ~"calc(100% + 5px)";
|
||||
display: inline-block;
|
||||
cursor: pointer;
|
||||
margin-left: -5px;
|
||||
padding-left: 5px;
|
||||
}
|
||||
& > span.element-row:not(.selected):hover {
|
||||
background-color: @drive-hover;
|
||||
}
|
||||
}
|
||||
span.element {
|
||||
|
@ -261,6 +274,9 @@ span {
|
|||
/*pointer-events: none;*/
|
||||
}
|
||||
&:hover {
|
||||
&:not(.selected) {
|
||||
background-color: @drive-hover;
|
||||
}
|
||||
.name {
|
||||
/*text-decoration: underline;*/
|
||||
}
|
||||
|
@ -276,12 +292,20 @@ span {
|
|||
text-align: center;
|
||||
vertical-align: top;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
padding-top: 10px;
|
||||
padding-bottom: 5px;
|
||||
max-height: 145px;
|
||||
|
||||
&:not(.selected) {
|
||||
border: transparent 1px;
|
||||
}
|
||||
.name {
|
||||
width: 100%;
|
||||
}
|
||||
input {
|
||||
width: 100%;
|
||||
margin-top: 5px;
|
||||
}
|
||||
.fa {
|
||||
display: block;
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
data-main-favicon="/customize/main-favicon.png"
|
||||
data-alt-favicon="/customize/alt-favicon.png"
|
||||
id="favicon" />
|
||||
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="/customize/main.css" />
|
||||
<script data-bootload="main.js" data-main="/common/boot.js" src="/bower_components/requirejs/require.js"></script>
|
||||
<style>
|
||||
|
@ -33,5 +34,14 @@
|
|||
</head>
|
||||
<body>
|
||||
<iframe id="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||
<div id="loading">
|
||||
<div class="loadingContainer">
|
||||
<img class="cryptofist" src="/customize/cryptofist_small.png" />
|
||||
<div class="spinnerContainer">
|
||||
<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>
|
||||
</div>
|
||||
<p data-localization="loading"></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -8,8 +8,9 @@ define([
|
|||
'/common/fileObject.js',
|
||||
'/common/toolbar.js',
|
||||
'/customize/application_config.js',
|
||||
'/common/cryptget.js'
|
||||
], function (Listmap, Crypto, TextPatcher, JSONSortify, Cryptpad, FO, Toolbar, AppConfig, Get) {
|
||||
'/common/cryptget.js',
|
||||
'/common/mergeDrive.js'
|
||||
], function (Listmap, Crypto, TextPatcher, JSONSortify, Cryptpad, FO, Toolbar, AppConfig, Get, Merge) {
|
||||
var module = window.MODULE = {};
|
||||
|
||||
var Messages = Cryptpad.Messages;
|
||||
|
@ -235,15 +236,25 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
var findDataHolder = function ($el) {
|
||||
return $el.is('.element-row') ? $el : $el.closest('.element-row');
|
||||
};
|
||||
|
||||
var removeSelected = function () {
|
||||
$iframe.find('.selected').removeClass("selected");
|
||||
var $container = $driveToolbar.find('#contextButtonsContainer');
|
||||
if (!$container.length) { return; }
|
||||
$container.html('');
|
||||
};
|
||||
var removeInput = function () {
|
||||
$iframe.find('li > span:hidden').removeAttr('style');
|
||||
$iframe.find('li > input').remove();
|
||||
var removeInput = function (cancel) {
|
||||
if (!cancel && $iframe.find('.element-row > input').length === 1) {
|
||||
var $input = $iframe.find('.element-row > input');
|
||||
filesOp.renameElement($input.data('path'), $input.val(), function () {
|
||||
APP.refresh();
|
||||
});
|
||||
}
|
||||
$iframe.find('.element-row > input').remove();
|
||||
$iframe.find('.element-row > span:hidden').removeAttr('style');
|
||||
};
|
||||
|
||||
var compareDays = function (date1, date2) {
|
||||
|
@ -302,13 +313,17 @@ define([
|
|||
var $input = $('<input>', {
|
||||
placeholder: name,
|
||||
value: name
|
||||
});
|
||||
}).data('path', path);
|
||||
$input.on('keyup', function (e) {
|
||||
if (e.which === 13) {
|
||||
removeInput();
|
||||
removeInput(true);
|
||||
filesOp.renameElement(path, $input.val(), function () {
|
||||
refresh();
|
||||
});
|
||||
return;
|
||||
}
|
||||
if (e.which === 27) {
|
||||
removeInput(true);
|
||||
}
|
||||
});
|
||||
//$element.parent().append($input);
|
||||
|
@ -330,33 +345,53 @@ define([
|
|||
// since it would remove the input
|
||||
$input.on('mousedown', function (e) {
|
||||
e.stopPropagation();
|
||||
$input.parents('li').attr("draggable", false);
|
||||
$input.parents('.element-row').attr("draggable", false);
|
||||
});
|
||||
$input.on('mouseup', function (e) {
|
||||
e.stopPropagation();
|
||||
$input.parents('li').attr("draggable", true);
|
||||
$input.parents('.element-row').attr("draggable", true);
|
||||
});
|
||||
},0);
|
||||
};
|
||||
|
||||
var filterContextMenu = function ($menu, $element) {
|
||||
var path = $element.data('path');
|
||||
var filterContextMenu = function ($menu, paths) {
|
||||
//var path = $element.data('path');
|
||||
|
||||
var hide = [];
|
||||
if (!APP.editable) {
|
||||
hide.push($menu.find('a.editable'));
|
||||
}
|
||||
if (!isOwnDrive()) {
|
||||
hide.push($menu.find('a.own'));
|
||||
}
|
||||
if ($element.is('.file-element')) {
|
||||
hide.push($menu.find('a.newfolder'));
|
||||
} else {
|
||||
hide.push($menu.find('a.open_ro'));
|
||||
}
|
||||
if (path && path.length > 4) {
|
||||
var hasFolder = false;
|
||||
paths.forEach(function (p, i) {
|
||||
var path = p.path;
|
||||
var $element = p.element;
|
||||
if (!APP.editable) {
|
||||
hide.push($menu.find('a.editable'));
|
||||
}
|
||||
if (!isOwnDrive()) {
|
||||
hide.push($menu.find('a.own'));
|
||||
}
|
||||
if ($element.is('.file-element')) {
|
||||
// No folder in files
|
||||
hide.push($menu.find('a.newfolder'));
|
||||
} else {
|
||||
if (hasFolder) {
|
||||
// More than 1 folder selected: cannot create a new subfolder
|
||||
hide.push($menu.find('a.newfolder'));
|
||||
}
|
||||
hasFolder = true;
|
||||
hide.push($menu.find('a.open_ro'));
|
||||
}
|
||||
if (path && path.length > 4) {
|
||||
hide.push($menu.find('a.restore'));
|
||||
hide.push($menu.find('a.properties'));
|
||||
}
|
||||
});
|
||||
if (paths.length > 1) {
|
||||
hide.push($menu.find('a.restore'));
|
||||
hide.push($menu.find('a.properties'));
|
||||
hide.push($menu.find('a.rename'));
|
||||
}
|
||||
if (hasFolder && paths.length > 1) {
|
||||
// Cannot open multiple folders
|
||||
hide.push($menu.find('a.open'));
|
||||
}
|
||||
return hide;
|
||||
};
|
||||
|
@ -370,10 +405,36 @@ define([
|
|||
$driveToolbar.find('.path').css('max-width', 'calc(100vw - '+$tree.width()+'px - '+l+'px)');
|
||||
};
|
||||
|
||||
var getSelectedPaths = function ($element) {
|
||||
var paths = [];
|
||||
if ($iframe.find('.selected').length > 1) {
|
||||
var $selected = $iframe.find('.selected');
|
||||
$selected.each(function (idx, elmt) {
|
||||
var ePath = $(elmt).data('path');
|
||||
if (ePath) {
|
||||
paths.push({
|
||||
path: ePath,
|
||||
element: $(elmt)
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if (!paths.length) {
|
||||
var path = $element.data('path');
|
||||
if (!path) { return false; }
|
||||
paths.push({
|
||||
path: path,
|
||||
element: $element
|
||||
});
|
||||
}
|
||||
return paths;
|
||||
};
|
||||
|
||||
var updateContextButton = function () {
|
||||
var $li = $content.find('.selected');
|
||||
if ($li.length !== 1) {
|
||||
$li = $tree.find('.element.active').closest('li');
|
||||
if ($li.length === 0) {
|
||||
$li = findDataHolder($tree.find('.element.active'));
|
||||
}
|
||||
var $button = $driveToolbar.find('#contextButton');
|
||||
if ($button.length) { // mobile
|
||||
|
@ -398,13 +459,13 @@ define([
|
|||
var $container = $driveToolbar.find('#contextButtonsContainer');
|
||||
if (!$container.length) { return; }
|
||||
$container.html('');
|
||||
var $element = $li;
|
||||
var $element = $li.length === 1 ? $li : $($li[0]);
|
||||
var paths = getSelectedPaths($element);
|
||||
var $menu = $element.data('context');
|
||||
var path = $element.data('path');
|
||||
if (!$menu || !path) { return; }
|
||||
if (!$menu) { return; }
|
||||
var actions = [];
|
||||
var $actions = $menu.find('a');
|
||||
var toHide = filterContextMenu($menu, $element);
|
||||
var toHide = filterContextMenu($menu, paths);
|
||||
$actions = $actions.filter(function (i, el) {
|
||||
for (var j = 0; j < toHide.length; j++) {
|
||||
if ($(el).is(toHide[j])) { return false; }
|
||||
|
@ -419,8 +480,9 @@ define([
|
|||
} else {
|
||||
$a.text($(el).text());
|
||||
}
|
||||
$(el).data('path', path);
|
||||
$(el).data('element', $element);
|
||||
$(el).data('paths', paths);
|
||||
//$(el).data('path', path);
|
||||
//:$(el).data('element', $element);
|
||||
$container.append($a);
|
||||
$a.click(function() { $(el).click(); });
|
||||
});
|
||||
|
@ -434,9 +496,7 @@ define([
|
|||
if (!e || !e.ctrlKey) {
|
||||
removeSelected();
|
||||
}
|
||||
if (!$element.is('li')) {
|
||||
$element = $element.closest('li');
|
||||
}
|
||||
$element = findDataHolder($element);
|
||||
if (!$element.length) {
|
||||
log(Messages.fm_selectError);
|
||||
return;
|
||||
|
@ -448,6 +508,9 @@ define([
|
|||
$element.removeClass("selected");
|
||||
}
|
||||
updateContextButton();
|
||||
if ($iframe.find('.selected').length > 1) {
|
||||
module.hideMenu();
|
||||
}
|
||||
};
|
||||
|
||||
// Open the selected context menu on the closest "li" element
|
||||
|
@ -455,7 +518,7 @@ define([
|
|||
module.hideMenu();
|
||||
e.stopPropagation();
|
||||
|
||||
var $element = $(e.target).closest('li');
|
||||
var $element = findDataHolder($(e.target));
|
||||
if (!$element.length) {
|
||||
logError("Unable to locate the .element tag", e.target);
|
||||
$menu.hide();
|
||||
|
@ -463,10 +526,9 @@ define([
|
|||
return false;
|
||||
}
|
||||
|
||||
var path = $element.data('path');
|
||||
if (!path) { return false; }
|
||||
var paths = getSelectedPaths($element);
|
||||
|
||||
var toHide = filterContextMenu($menu, $element);
|
||||
var toHide = filterContextMenu($menu, paths);
|
||||
toHide.forEach(function ($a) {
|
||||
$a.parent('li').hide();
|
||||
});
|
||||
|
@ -483,10 +545,13 @@ define([
|
|||
return true;
|
||||
}
|
||||
|
||||
onElementClick(undefined, $element);
|
||||
if (paths.length === 1) {
|
||||
onElementClick(undefined, $element);
|
||||
}
|
||||
|
||||
$menu.find('a').data('path', path);
|
||||
$menu.find('a').data('element', $element);
|
||||
$menu.find('a').data('paths', paths);
|
||||
//$menu.find('a').data('path', path);
|
||||
//$menu.find('a').data('element', $element);
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -503,13 +568,14 @@ define([
|
|||
};
|
||||
|
||||
var openTrashTreeContextMenu = function (e) {
|
||||
removeSelected();
|
||||
$trashTreeContextMenu.find('li').show();
|
||||
openContextMenu(e, $trashTreeContextMenu);
|
||||
return false;
|
||||
};
|
||||
|
||||
var openTrashContextMenu = function (e) {
|
||||
var path = $(e.target).closest('li').data('path');
|
||||
var path = findDataHolder($(e.target)).data('path');
|
||||
if (!path) { return; }
|
||||
$trashContextMenu.find('li').show();
|
||||
openContextMenu(e, $trashContextMenu);
|
||||
|
@ -595,6 +661,7 @@ define([
|
|||
msg = Messages._getKey('fm_removeDialog', [name]);
|
||||
}
|
||||
Cryptpad.confirm(msg, function (res) {
|
||||
$(ifrw).focus();
|
||||
if (!res) { return; }
|
||||
andThen();
|
||||
});
|
||||
|
@ -603,7 +670,7 @@ define([
|
|||
// The data transferred is a stringified JSON containing the path of the dragged element
|
||||
var onDrag = function (ev, path) {
|
||||
var paths = [];
|
||||
var $element = $(ev.target).closest('li');
|
||||
var $element = findDataHolder($(ev.target));
|
||||
if ($element.hasClass('selected')) {
|
||||
var $selected = $iframe.find('.selected');
|
||||
$selected.each(function (idx, elmt) {
|
||||
|
@ -659,7 +726,8 @@ define([
|
|||
}
|
||||
});
|
||||
|
||||
var newPath = $(ev.target).data('path') || $(ev.target).parent('li').data('path');
|
||||
var $el = findDataHolder($(ev.target));
|
||||
var newPath = $el.data('path');
|
||||
if (!newPath) { return; }
|
||||
if (movedPaths && movedPaths.length) {
|
||||
moveElements(movedPaths, newPath, null, refresh);
|
||||
|
@ -790,7 +858,8 @@ define([
|
|||
$icon = filesOp.isFolderEmpty(root[key]) ? $folderEmptyIcon.clone() : $folderIcon.clone();
|
||||
}
|
||||
var $element = $('<li>', {
|
||||
draggable: true
|
||||
draggable: true,
|
||||
'class': 'element-row'
|
||||
});
|
||||
if (isFolder) {
|
||||
addFolderData(element, key, $element);
|
||||
|
@ -1159,7 +1228,7 @@ define([
|
|||
var e = useData ? element : filesOp.getFileData(element);
|
||||
if (!e) {
|
||||
e = {
|
||||
href : el,
|
||||
href : element,
|
||||
title : Messages.fm_noname,
|
||||
atime : 0,
|
||||
ctime : 0
|
||||
|
@ -1255,7 +1324,7 @@ define([
|
|||
var idx = files[rootName].indexOf(href);
|
||||
var $icon = getFileIcon(href);
|
||||
var $element = $('<li>', {
|
||||
'class': 'file-element element',
|
||||
'class': 'file-element element element-row',
|
||||
draggable: draggable
|
||||
});
|
||||
addFileData(href, file.title, $element, false);
|
||||
|
@ -1287,7 +1356,7 @@ define([
|
|||
var sortedFiles = sortElements(false, [FILES_DATA], keys, Cryptpad.getLSAttribute(SORT_FILE_BY), !getSortFileDesc(), false, true);
|
||||
sortedFiles.forEach(function (file) {
|
||||
var $icon = getFileIcon(file.href);
|
||||
var $element = $('<li>', { 'class': 'file-element element' });
|
||||
var $element = $('<li>', { 'class': 'file-element element element-row' });
|
||||
addFileData(file.href, file.title, $element, false);
|
||||
$element.data('path', [FILES_DATA, allfiles.indexOf(file)]);
|
||||
$element.data('element', file.href);
|
||||
|
@ -1347,6 +1416,7 @@ define([
|
|||
// NOTE: Elements in the trash are not using the same storage structure as the others
|
||||
// _WORKGROUP_ : do not change the lastOpenedFolder value in localStorage
|
||||
var displayDirectory = module.displayDirectory = function (path, force) {
|
||||
module.hideMenu();
|
||||
if (!APP.editable) { debug("Read-only mode"); }
|
||||
if (!appStatus.isReady && !force) { return; }
|
||||
// Only Trash and Root are available in not-owned files manager
|
||||
|
@ -1408,7 +1478,7 @@ define([
|
|||
e.stopPropagation();
|
||||
var $li = $content.find('.selected');
|
||||
if ($li.length !== 1) {
|
||||
$li = $tree.find('.element.active').closest('li');
|
||||
$li = findDataHolder($tree.find('.element.active'));
|
||||
}
|
||||
// Close if already opened
|
||||
if ($iframe.find('.contextMenu:visible').length) {
|
||||
|
@ -1418,7 +1488,8 @@ define([
|
|||
// Open the menu
|
||||
$iframe.find('.contextMenu').css({
|
||||
top: ($context.offset().top + 32) + 'px',
|
||||
right: '0px'
|
||||
right: '0px',
|
||||
left: ''
|
||||
});
|
||||
$li.contextmenu();
|
||||
});
|
||||
|
@ -1467,7 +1538,7 @@ define([
|
|||
};
|
||||
|
||||
var refreshFilesData = function () {
|
||||
$content.find('li').each(function (i, e) {
|
||||
$content.find('.element-row').each(function (i, e) {
|
||||
var $el = $(e);
|
||||
if ($el.data('path')) {
|
||||
var path = $el.data('path');
|
||||
|
@ -1488,10 +1559,12 @@ define([
|
|||
if (collapsable) {
|
||||
$collapse = $expandIcon.clone();
|
||||
}
|
||||
var $element = $('<li>').append($collapse).append($icon).append($name).click(function (e) {
|
||||
var $elementRow = $('<span>', {'class': 'element-row'}).append($collapse).append($icon).append($name).click(function (e) {
|
||||
e.stopPropagation();
|
||||
module.displayDirectory(path);
|
||||
});
|
||||
if (draggable) { $element.attr('draggable', true); }
|
||||
var $element = $('<li>').append($elementRow);
|
||||
if (draggable) { $elementRow.attr('draggable', true); }
|
||||
if (collapsable) {
|
||||
$element.addClass('collapsed');
|
||||
$collapse.click(function(e) {
|
||||
|
@ -1519,8 +1592,8 @@ define([
|
|||
$collapse.click();
|
||||
}
|
||||
}
|
||||
$element.data('path', path);
|
||||
addDragAndDropHandlers($element, path, true, droppable);
|
||||
$elementRow.data('path', path);
|
||||
addDragAndDropHandlers($elementRow, path, true, droppable);
|
||||
if (active) { $name.addClass('active'); }
|
||||
return $element;
|
||||
};
|
||||
|
@ -1559,7 +1632,7 @@ define([
|
|||
(isCurrentFolder ? $folderOpenedIcon : $folderIcon);
|
||||
var $element = createTreeElement(key, $icon.clone(), newPath, true, true, subfolder, isCurrentFolder);
|
||||
$element.appendTo($list);
|
||||
$element.contextmenu(openDirectoryContextMenu);
|
||||
$element.find('>.element-row').contextmenu(openDirectoryContextMenu);
|
||||
createTree($element, newPath);
|
||||
});
|
||||
};
|
||||
|
@ -1672,61 +1745,76 @@ define([
|
|||
|
||||
$contextMenu.on("click", "a", function(e) {
|
||||
e.stopPropagation();
|
||||
var path = $(this).data('path');
|
||||
var $element = $(this).data('element');
|
||||
if (!$element || !path || path.length < 2) {
|
||||
var paths = $(this).data('paths');
|
||||
//var path = $(this).data('path');
|
||||
//var $element = $(this).data('element');
|
||||
if (paths.length === 0) {
|
||||
log(Messages.fm_forbidden);
|
||||
debug("Directory context menu on a forbidden or unexisting element. ", $element, path);
|
||||
debug("Directory context menu on a forbidden or unexisting element. ", paths);
|
||||
return;
|
||||
}
|
||||
if ($(this).hasClass("rename")) {
|
||||
displayRenameInput($element, path);
|
||||
if (paths.length !== 1) { return; }
|
||||
displayRenameInput(paths[0].element, paths[0].path);
|
||||
}
|
||||
else if($(this).hasClass("delete")) {
|
||||
moveElements([path], [TRASH], false, refresh);
|
||||
var pathsList = [];
|
||||
paths.forEach(function (p) { pathsList.push(p.path); });
|
||||
moveElements(pathsList, [TRASH], false, refresh);
|
||||
}
|
||||
else if ($(this).hasClass('open')) {
|
||||
$element.dblclick();
|
||||
paths.forEach(function (p) {
|
||||
var $element = p.element;
|
||||
$element.click();
|
||||
$element.dblclick();
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('open_ro')) {
|
||||
var el = filesOp.findElement(files, path);
|
||||
if (filesOp.isFolder(el)) { return; }
|
||||
var roUrl = getReadOnlyUrl(el);
|
||||
openFile(roUrl);
|
||||
paths.forEach(function (p) {
|
||||
var el = filesOp.findElement(files, p.path);
|
||||
if (filesOp.isFolder(el)) { return; }
|
||||
var roUrl = getReadOnlyUrl(el);
|
||||
openFile(roUrl, false);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('newfolder')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
var onCreated = function (info) {
|
||||
module.newFolder = info.newPath;
|
||||
module.displayDirectory(path);
|
||||
module.displayDirectory(paths[0].path);
|
||||
};
|
||||
filesOp.createNewFolder(path, null, onCreated);
|
||||
filesOp.createNewFolder(paths[0].path, null, onCreated);
|
||||
}
|
||||
module.hideMenu();
|
||||
});
|
||||
|
||||
$defaultContextMenu.on("click", "a", function(e) {
|
||||
e.stopPropagation();
|
||||
var path = $(this).data('path');
|
||||
var $element = $(this).data('element');
|
||||
if (!$element || !path || path.length < 2) {
|
||||
var paths = $(this).data('paths');
|
||||
if (paths.length === 0) {
|
||||
log(Messages.fm_forbidden);
|
||||
debug("Directory context menu on a forbidden or unexisting element. ", $element, path);
|
||||
debug("Context menu on a forbidden or unexisting element. ", paths);
|
||||
return;
|
||||
}
|
||||
if ($(this).hasClass('open')) {
|
||||
$element.dblclick();
|
||||
paths.forEach(function (p) {
|
||||
var $element = p.element;
|
||||
$element.dblclick();
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('open_ro')) {
|
||||
var el = filesOp.findElement(files, path);
|
||||
if (filesOp.isPathInFilesData(path)) {
|
||||
el = el.href;
|
||||
}
|
||||
if (!el || filesOp.isFolder(el)) { return; }
|
||||
var roUrl = getReadOnlyUrl(el);
|
||||
openFile(roUrl);
|
||||
paths.forEach(function (p) {
|
||||
var el = filesOp.findElement(files, p.path);
|
||||
if (filesOp.isPathInFilesData(p.path)) { el = el.href; }
|
||||
if (!el || filesOp.isFolder(el)) { return; }
|
||||
var roUrl = getReadOnlyUrl(el);
|
||||
openFile(roUrl, false);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('delete')) {
|
||||
moveElements([path], [TRASH], false, refresh);
|
||||
var pathsList = [];
|
||||
paths.forEach(function (p) { pathsList.push(p.path); });
|
||||
moveElements(pathsList, [TRASH], false, refresh);
|
||||
}
|
||||
module.hideMenu();
|
||||
});
|
||||
|
@ -1751,11 +1839,10 @@ define([
|
|||
|
||||
$trashTreeContextMenu.on('click', 'a', function (e) {
|
||||
e.stopPropagation();
|
||||
var path = $(this).data('path');
|
||||
var $element = $(this).data('element');
|
||||
if (!$element || !filesOp.comparePath(path, [TRASH])) {
|
||||
var paths = $(this).data('paths');
|
||||
if (paths.length !== 1 || !paths[0].element || !filesOp.comparePath(paths[0].path, [TRASH])) {
|
||||
log(Messages.fm_forbidden);
|
||||
debug("Trash tree context menu on a forbidden or unexisting element. ", $element, path);
|
||||
debug("Trash tree context menu on a forbidden or unexisting element. ", paths);
|
||||
return;
|
||||
}
|
||||
if ($(this).hasClass("empty")) {
|
||||
|
@ -1769,22 +1856,34 @@ define([
|
|||
|
||||
$trashContextMenu.on('click', 'a', function (e) {
|
||||
e.stopPropagation();
|
||||
var path = $(this).data('path');
|
||||
var $element = $(this).data('element');
|
||||
if (!$element || !path || path.length < 2) {
|
||||
var paths = $(this).data('paths');
|
||||
if (paths.length === 0) {
|
||||
log(Messages.fm_forbidden);
|
||||
debug("Trash context menu on a forbidden or unexisting element. ", $element, path);
|
||||
debug("Trash context menu on a forbidden or unexisting element. ", paths);
|
||||
return;
|
||||
}
|
||||
var name = path[path.length - 1];
|
||||
var path = paths[0].path;
|
||||
var name = paths[0].path[paths[0].path.length - 1];
|
||||
if ($(this).hasClass("remove")) {
|
||||
if (path.length === 4) { name = path[1]; }
|
||||
Cryptpad.confirm(Messages._getKey("fm_removePermanentlyDialog", [name]), function(res) {
|
||||
if (paths.length === 1) {
|
||||
if (path.length === 4) { name = path[1]; }
|
||||
Cryptpad.confirm(Messages._getKey("fm_removePermanentlyDialog", [name]), function(res) {
|
||||
if (!res) { return; }
|
||||
filesOp.removeFromTrash(path, refresh);
|
||||
});
|
||||
return;
|
||||
}
|
||||
var pathsList = [];
|
||||
paths.forEach(function (p) { pathsList.push(p.path); });
|
||||
var msg = Messages._getKey("fm_removeSeveralPermanentlyDialog", [paths.length]);
|
||||
Cryptpad.confirm(msg, function(res) {
|
||||
if (!res) { return; }
|
||||
filesOp.removeFromTrash(path, refresh);
|
||||
filesOp.deletePathsPermanently(pathsList);
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass("restore")) {
|
||||
if (paths.length !== 1) { return; }
|
||||
if (path.length === 4) { name = path[1]; }
|
||||
Cryptpad.confirm(Messages._getKey("fm_restoreDialog", [name]), function(res) {
|
||||
if (!res) { return; }
|
||||
|
@ -1792,6 +1891,7 @@ define([
|
|||
});
|
||||
}
|
||||
else if ($(this).hasClass("properties")) {
|
||||
if (paths.length !== 1) { return; }
|
||||
if (path.length !== 4) { return; }
|
||||
var element = filesOp.getTrashElementData(path);
|
||||
var sPath = stringifyPath(element.path);
|
||||
|
@ -1803,12 +1903,12 @@ define([
|
|||
$(ifrw).on('click', function (e) {
|
||||
if (e.which !== 1) { return ; }
|
||||
removeSelected(e);
|
||||
removeInput(e);
|
||||
removeInput();
|
||||
module.hideMenu(e);
|
||||
hideNewButton();
|
||||
});
|
||||
$(ifrw).on('drag drop', function (e) {
|
||||
removeInput(e);
|
||||
removeInput();
|
||||
module.hideMenu(e);
|
||||
});
|
||||
$(ifrw).on('mouseup drop', function (e) {
|
||||
|
@ -1837,6 +1937,7 @@ define([
|
|||
}
|
||||
|
||||
Cryptpad.confirm(msg, function(res) {
|
||||
$(ifrw).focus();
|
||||
if (!res) { return; }
|
||||
filesOp.deletePathsPermanently(paths);
|
||||
refresh();
|
||||
|
@ -1949,30 +2050,19 @@ define([
|
|||
logError("Couldn't set username", err);
|
||||
return;
|
||||
}
|
||||
if (myUserName === "") {
|
||||
myUserName = Messages.anonymous;
|
||||
}
|
||||
APP.$displayName.text(myUserName);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: move that function and use a more generic API?
|
||||
var migrateAnonDrive = function (proxy, cb) {
|
||||
if (sessionStorage.migrateAnonDrive) {
|
||||
// Make sure we have an FS_hash and we don't use it, otherwise just stop the migration and cb
|
||||
if (!localStorage.FS_hash || !APP.loggedIn) {
|
||||
Merge.anonDriveIntoUser(proxy, function () {
|
||||
delete sessionStorage.migrateAnonDrive;
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
}
|
||||
// Get the content of FS_hash and then merge the objects, remove the migration key and cb
|
||||
var todo = function (err, doc) {
|
||||
if (err) { logError("Cannot migrate recent pads", err); return; }
|
||||
var parsed;
|
||||
try { parsed = JSON.parse(doc); } catch (e) { logError("Cannot parsed recent pads", e); }
|
||||
if (parsed) {
|
||||
$.extend(true, proxy, parsed);
|
||||
}
|
||||
delete sessionStorage.migrateAnonDrive;
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
};
|
||||
Get.get(localStorage.FS_hash, todo);
|
||||
});
|
||||
} else {
|
||||
if (typeof(cb) === "function") { cb(); }
|
||||
}
|
||||
|
|
|
@ -76,18 +76,21 @@ define([
|
|||
if (result.proxy && !result.proxy.login_name) {
|
||||
result.proxy.login_name = result.userName;
|
||||
}
|
||||
Cryptpad.login(result.userHash, result.userName, function () {
|
||||
if (sessionStorage.redirectTo) {
|
||||
var h = sessionStorage.redirectTo;
|
||||
var parser = document.createElement('a');
|
||||
parser.href = h;
|
||||
if (parser.origin === window.location.origin) {
|
||||
delete sessionStorage.redirectTo;
|
||||
window.location.href = h;
|
||||
return;
|
||||
|
||||
Cryptpad.whenRealtimeSyncs(result.realtime, function() {
|
||||
Cryptpad.login(result.userHash, result.userName, function () {
|
||||
if (sessionStorage.redirectTo) {
|
||||
var h = sessionStorage.redirectTo;
|
||||
var parser = document.createElement('a');
|
||||
parser.href = h;
|
||||
if (parser.origin === window.location.origin) {
|
||||
delete sessionStorage.redirectTo;
|
||||
window.location.href = h;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
window.location.href = '/drive/';
|
||||
window.location.href = '/drive/';
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
<title>CryptPad</title>
|
||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
|
||||
<link rel="icon" type="image/png"
|
||||
href="/customize/main-favicon.png"
|
||||
data-main-favicon="/customize/main-favicon.png"
|
||||
|
@ -56,5 +57,14 @@
|
|||
</head>
|
||||
<body>
|
||||
<iframe id="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||
<div id="loading">
|
||||
<div class="loadingContainer">
|
||||
<img class="cryptofist" src="/customize/cryptofist_small.png" />
|
||||
<div class="spinnerContainer">
|
||||
<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>
|
||||
</div>
|
||||
<p data-localization="loading"></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -110,7 +110,7 @@ define([
|
|||
var defaultName = Cryptpad.getDefaultName(parsedHash);
|
||||
|
||||
if (readOnly) {
|
||||
$('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox > .cke_toolbar').hide();
|
||||
$('#pad-iframe')[0].contentWindow.$('#cke_1_toolbox > .cke_toolbox_main').hide();
|
||||
}
|
||||
|
||||
/* add a class to the magicline plugin so we can pick it out more easily */
|
||||
|
@ -164,6 +164,16 @@ define([
|
|||
send scripts over the wire.
|
||||
*/
|
||||
if (['addAttribute', 'modifyAttribute'].indexOf(info.diff.action) !== -1) {
|
||||
if (info.diff.name === 'href') {
|
||||
// console.log(info.diff);
|
||||
var href = info.diff.newValue;
|
||||
|
||||
// TODO normalize HTML entities
|
||||
if (/javascript *: */.test(info.diff.newValue)) {
|
||||
// TODO remove javascript: links
|
||||
}
|
||||
}
|
||||
|
||||
if (/^on/.test(info.diff.name)) {
|
||||
console.log("Rejecting forbidden element attribute with name (%s)", info.diff.name);
|
||||
return true;
|
||||
|
@ -561,6 +571,10 @@ define([
|
|||
userData: userData,
|
||||
readOnly: readOnly,
|
||||
ifrw: ifrw,
|
||||
share: {
|
||||
secret: secret,
|
||||
channel: info.channel
|
||||
},
|
||||
title: {
|
||||
onRename: renameCb,
|
||||
defaultName: defaultName,
|
||||
|
@ -573,8 +587,6 @@ define([
|
|||
|
||||
var $rightside = $bar.find('.' + Toolbar.constants.rightside);
|
||||
var $userBlock = $bar.find('.' + Toolbar.constants.username);
|
||||
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
|
||||
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
|
||||
var $usernameButton = module.$userNameButton = $($bar.find('.' + Toolbar.constants.changeUsername));
|
||||
|
||||
var editHash;
|
||||
|
@ -584,23 +596,24 @@ define([
|
|||
editHash = Cryptpad.getEditHashFromKeys(info.channel, secret.keys);
|
||||
}
|
||||
|
||||
// Expand / collapse the toolbar
|
||||
var $existingButton = $bar.find('#cke_1_toolbar_collapser');
|
||||
var $collapse = Cryptpad.createButton(null, true);
|
||||
$existingButton.hide();
|
||||
$collapse.removeClass('fa-question');
|
||||
var updateIcon = function () {
|
||||
$collapse.removeClass('fa-caret-down').removeClass('fa-caret-up');
|
||||
var isCollapsed = !$bar.find('.cke_toolbox_main').is(':visible');
|
||||
if (isCollapsed) { $collapse.addClass('fa-caret-down'); }
|
||||
else { $collapse.addClass('fa-caret-up'); }
|
||||
};
|
||||
updateIcon();
|
||||
$collapse.click(function () {
|
||||
$existingButton.click();
|
||||
var $existingButton = $bar.find('#cke_1_toolbar_collapser').hide();
|
||||
if (!readOnly) {
|
||||
// Expand / collapse the toolbar
|
||||
var $collapse = Cryptpad.createButton(null, true);
|
||||
$collapse.removeClass('fa-question');
|
||||
var updateIcon = function () {
|
||||
$collapse.removeClass('fa-caret-down').removeClass('fa-caret-up');
|
||||
var isCollapsed = !$bar.find('.cke_toolbox_main').is(':visible');
|
||||
if (isCollapsed) { $collapse.addClass('fa-caret-down'); }
|
||||
else { $collapse.addClass('fa-caret-up'); }
|
||||
};
|
||||
updateIcon();
|
||||
});
|
||||
$rightside.append($collapse);
|
||||
$collapse.click(function () {
|
||||
$existingButton.click();
|
||||
updateIcon();
|
||||
});
|
||||
$rightside.append($collapse);
|
||||
}
|
||||
|
||||
/* add an export button */
|
||||
var $export = Cryptpad.createButton('export', true, {}, exportFile);
|
||||
|
@ -624,20 +637,6 @@ define([
|
|||
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
|
||||
$rightside.append($forgetPad);
|
||||
|
||||
if (!readOnly) {
|
||||
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
|
||||
if (viewHash) {
|
||||
$editShare.append($('<hr>'));
|
||||
}
|
||||
}
|
||||
if (viewHash) {
|
||||
/* add a 'links' button */
|
||||
$viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash}));
|
||||
if (!readOnly) {
|
||||
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash}));
|
||||
}
|
||||
}
|
||||
|
||||
// set the hash
|
||||
if (!readOnly) { Cryptpad.replaceHash(editHash); }
|
||||
|
||||
|
|
|
@ -88,6 +88,7 @@
|
|||
margin: auto;
|
||||
|
||||
min-width: 80%;
|
||||
width: 80%;
|
||||
min-height: 5em;
|
||||
font-size: 20px;
|
||||
font-weight: bold;
|
||||
|
@ -142,3 +143,13 @@
|
|||
<button data-localization-title="poll_commit" id="commit"><span class="fa fa-check"></span></button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="loading">
|
||||
<div class="loadingContainer">
|
||||
<img class="cryptofist" src="/customize/cryptofist_small.png" />
|
||||
<div class="spinnerContainer">
|
||||
<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>
|
||||
</div>
|
||||
<p data-localization="loading"></p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -647,7 +647,7 @@ define([
|
|||
// Update the toolbar list:
|
||||
// Add the current user in the metadata if he has edit rights
|
||||
if (readOnly) { return; }
|
||||
if (typeof(lastName) === 'string' && lastName.length) {
|
||||
if (typeof(lastName) === 'string') {
|
||||
setName(lastName);
|
||||
} else {
|
||||
var myData = {};
|
||||
|
@ -687,6 +687,10 @@ define([
|
|||
displayed: ['useradmin', 'language', 'spinner', 'lag', 'state', 'share', 'userlist', 'newpad'],
|
||||
userData: userData,
|
||||
readOnly: readOnly,
|
||||
share: {
|
||||
secret: secret,
|
||||
channel: info.channel
|
||||
},
|
||||
title: {
|
||||
onRename: renameCb,
|
||||
defaultName: defaultName,
|
||||
|
@ -712,17 +716,6 @@ define([
|
|||
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
|
||||
$rightside.append($forgetPad);
|
||||
|
||||
if (!readOnly) {
|
||||
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
|
||||
}
|
||||
if (viewHash) {
|
||||
/* add a 'links' button */
|
||||
$viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash}));
|
||||
if (!readOnly) {
|
||||
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash}));
|
||||
}
|
||||
}
|
||||
|
||||
// set the hash
|
||||
if (!readOnly) { Cryptpad.replaceHash(editHash); }
|
||||
|
||||
|
|
|
@ -306,6 +306,7 @@ var Renderer = function (Cryptpad) {
|
|||
labelClass += ' yes';
|
||||
}
|
||||
|
||||
// TODO implement Yes/No/Maybe/Undecided
|
||||
return ['TD', {class:"checkbox-cell"}, [
|
||||
['DIV', {class: 'checkbox-contain'}, [
|
||||
['INPUT', attrs, []],
|
||||
|
@ -397,6 +398,7 @@ var Renderer = function (Cryptpad) {
|
|||
info.node.selectionEnd = info.selection[1];
|
||||
}
|
||||
} catch (err) {
|
||||
// FIXME LOL empty try-catch?
|
||||
//console.log(info.node);
|
||||
//console.error(err);
|
||||
}
|
||||
|
|
|
@ -71,9 +71,6 @@
|
|||
<input id="accept-terms" type="checkbox" />
|
||||
<label for="accept-terms" data-localization="register_acceptTerms"></label><br />
|
||||
|
||||
<input id="promise" type="checkbox" />
|
||||
<label for="promise" data-localization="register_rememberPassword"></label><br />
|
||||
|
||||
<button id="register" class="btn btn-primary" data-localization="login_register"></button>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -58,10 +58,28 @@ define([
|
|||
// checkboxes
|
||||
var $checkImport = $('#import-recent');
|
||||
var $checkAcceptTerms = $('#accept-terms');
|
||||
var $checkPromise = $('#promise');
|
||||
|
||||
var $register = $('button#register');
|
||||
|
||||
var logMeIn = function (result) {
|
||||
localStorage.User_hash = result.userHash;
|
||||
Cryptpad.whenRealtimeSyncs(result.realtime, function () {
|
||||
Cryptpad.login(result.userHash, result.userName, function () {
|
||||
if (sessionStorage.redirectTo) {
|
||||
var h = sessionStorage.redirectTo;
|
||||
var parser = document.createElement('a');
|
||||
parser.href = h;
|
||||
if (parser.origin === window.location.origin) {
|
||||
delete sessionStorage.redirectTo;
|
||||
window.location.href = h;
|
||||
return;
|
||||
}
|
||||
}
|
||||
window.location.href = '/drive/';
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
$register.click(function () {
|
||||
var uname = $uname.val();
|
||||
var passwd = $passwd.val();
|
||||
|
@ -69,7 +87,6 @@ define([
|
|||
|
||||
var shouldImport = $checkImport[0].checked;
|
||||
var doesAccept = $checkAcceptTerms[0].checked;
|
||||
var doesPromise = $checkPromise[0].checked;
|
||||
|
||||
/* basic validation */
|
||||
if (passwd !== confirmPassword) { // do their passwords match?
|
||||
|
@ -80,61 +97,69 @@ define([
|
|||
return void Cryptpad.alert(Messages.register_mustAcceptTerms);
|
||||
}
|
||||
|
||||
if (!doesPromise) { // do they promise to remember their password?
|
||||
return void Cryptpad.alert(Messages.register_mustRememberPass);
|
||||
}
|
||||
Cryptpad.confirm("<h2 class='bright'>" + Messages.register_warning + "</h2>",
|
||||
function (yes) {
|
||||
if (!yes) { return; }
|
||||
|
||||
Cryptpad.addLoadingScreen(Messages.login_hashing);
|
||||
Login.loginOrRegister(uname, passwd, true, function (err, result) {
|
||||
if (err) {
|
||||
switch (err) {
|
||||
case 'NO_SUCH_USER':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.alert(Messages.login_noSuchUser);
|
||||
});
|
||||
break;
|
||||
case 'INVAL_USER':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.alert(Messages.login_invalUser);
|
||||
});
|
||||
break;
|
||||
case 'INVAL_PASS':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.alert(Messages.login_invalPass);
|
||||
});
|
||||
break;
|
||||
default: // UNHANDLED ERROR
|
||||
Cryptpad.errorLoadingScreen(Messages.login_unhandledError);
|
||||
}
|
||||
}
|
||||
var proxy = result.proxy;
|
||||
Cryptpad.addLoadingScreen(Messages.login_hashing);
|
||||
Login.loginOrRegister(uname, passwd, true, function (err, result) {
|
||||
if (err) {
|
||||
switch (err) {
|
||||
case 'NO_SUCH_USER':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.alert(Messages.login_noSuchUser);
|
||||
});
|
||||
break;
|
||||
case 'INVAL_USER':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.alert(Messages.login_invalUser);
|
||||
});
|
||||
break;
|
||||
case 'INVAL_PASS':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.alert(Messages.login_invalPass);
|
||||
});
|
||||
break;
|
||||
case 'ALREADY_REGISTERED':
|
||||
Cryptpad.removeLoadingScreen(function () {
|
||||
Cryptpad.confirm(Messages.register_alreadyRegistered, function (yes) {
|
||||
if (!yes) { return; }
|
||||
result.proxy.login_name = uname;
|
||||
|
||||
localStorage.User_hash = result.userHash;
|
||||
|
||||
Cryptpad.eraseTempSessionValues();
|
||||
if (shouldImport) {
|
||||
sessionStorage.migrateAnonDrive = 1;
|
||||
}
|
||||
|
||||
proxy.login_name = uname;
|
||||
proxy[Cryptpad.displayNameKey] = uname;
|
||||
sessionStorage.createReadme = 1;
|
||||
|
||||
Cryptpad.whenRealtimeSyncs(result.realtime, function () {
|
||||
Cryptpad.login(result.userHash, result.userName, function () {
|
||||
if (sessionStorage.redirectTo) {
|
||||
var h = sessionStorage.redirectTo;
|
||||
var parser = document.createElement('a');
|
||||
parser.href = h;
|
||||
if (parser.origin === window.location.origin) {
|
||||
delete sessionStorage.redirectTo;
|
||||
window.location.href = h;
|
||||
return;
|
||||
}
|
||||
if (!result.proxy[Cryptpad.displayNameKey]) {
|
||||
result.proxy[Cryptpad.displayNameKey] = uname;
|
||||
}
|
||||
Cryptpad.eraseTempSessionValues();
|
||||
logMeIn(result);
|
||||
});
|
||||
});
|
||||
break;
|
||||
default: // UNHANDLED ERROR
|
||||
Cryptpad.errorLoadingScreen(Messages.login_unhandledError);
|
||||
}
|
||||
window.location.href = '/drive/';
|
||||
});
|
||||
return;
|
||||
}
|
||||
var proxy = result.proxy;
|
||||
|
||||
Cryptpad.eraseTempSessionValues();
|
||||
if (shouldImport) {
|
||||
sessionStorage.migrateAnonDrive = 1;
|
||||
}
|
||||
|
||||
proxy.login_name = uname;
|
||||
proxy[Cryptpad.displayNameKey] = uname;
|
||||
sessionStorage.createReadme = 1;
|
||||
|
||||
logMeIn(result);
|
||||
});
|
||||
}, {
|
||||
ok: Messages.register_writtenPassword, //'I have written down my password, proceed',
|
||||
cancel: Messages.register_cancel, // 'Go back',
|
||||
cancelClass: 'safe',
|
||||
okClass: 'danger',
|
||||
reverseOrder: true,
|
||||
}, true, function ($dialog) {
|
||||
$dialog.find('> div').addClass('half');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -106,6 +106,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="version-footer">CryptPad v1.2.0 (Chupacabra)</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
define([
|
||||
'/common/cryptpad-common.js',
|
||||
'/common/cryptget.js',
|
||||
'/common/mergeDrive.js',
|
||||
'/bower_components/file-saver/FileSaver.min.js',
|
||||
'/bower_components/jquery/dist/jquery.min.js',
|
||||
], function (Cryptpad, Crypt) {
|
||||
], function (Cryptpad, Crypt, Merge) {
|
||||
var $ = window.jQuery;
|
||||
var saveAs = window.saveAs;
|
||||
|
||||
|
@ -41,7 +42,7 @@ define([
|
|||
var obj = store.proxy;
|
||||
var $div = $('<div>', {'class': 'infoBlock'});
|
||||
|
||||
var accountName = obj.login_name;
|
||||
var accountName = obj.login_name || localStorage[Cryptpad.userNameKey];
|
||||
var $label = $('<span>', {'class': 'label'}).text(Messages.user_accountName + ':');
|
||||
var $name = $('<span>').text(accountName || '');
|
||||
if (!accountName) {
|
||||
|
@ -65,10 +66,9 @@ define([
|
|||
'id': 'displayName',
|
||||
'placeholder': Messages.anonymous}).appendTo($div);
|
||||
var $save = $('<button>', {'class': 'btn btn-primary'}).text(Messages.settings_save).appendTo($div);
|
||||
var $ok = $('<span>', {'class': 'fa fa-check'}).appendTo($div);
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).appendTo($div);
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
|
||||
|
||||
$spinner.hide();
|
||||
var displayName = obj[USERNAME_KEY] || '';
|
||||
$input.val(displayName);
|
||||
|
||||
|
@ -124,7 +124,8 @@ define([
|
|||
|
||||
var exportFile = function () {
|
||||
var sjson = JSON.stringify(obj);
|
||||
var suggestion = obj.login_name + '-' + new Date().toDateString();
|
||||
var name = obj.login_name || obj[USERNAME_KEY] || Messages.anonymous;
|
||||
var suggestion = name + '-' + new Date().toDateString();
|
||||
Cryptpad.prompt(Cryptpad.Messages.exportPrompt,
|
||||
Cryptpad.fixFileName(suggestion) + '.json', function (filename) {
|
||||
if (!(typeof(filename) === 'string' && filename)) { return; }
|
||||
|
@ -134,7 +135,7 @@ define([
|
|||
};
|
||||
var importFile = function (content, file) {
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).appendTo($div);
|
||||
Crypt.put(Cryptpad.getUserHash(), content, function (e) {
|
||||
Crypt.put(Cryptpad.getUserHash() || localStorage[Cryptpad.fileHashKey], content, function (e) {
|
||||
if (e) { console.error(e); }
|
||||
$spinner.remove();
|
||||
});
|
||||
|
@ -164,7 +165,10 @@ define([
|
|||
|
||||
$button.click(function () {
|
||||
Cryptpad.prompt(Messages.settings_resetPrompt, "", function (val) {
|
||||
if (val !== "I love CryptPad") { return; }
|
||||
if (val !== "I love CryptPad") {
|
||||
Cryptpad.alert(Messages.settings_resetError);
|
||||
return;
|
||||
}
|
||||
obj.proxy.drive = Cryptpad.getStore().getEmptyObject();
|
||||
Cryptpad.alert(Messages.settings_resetDone);
|
||||
}, undefined, true);
|
||||
|
@ -183,29 +187,66 @@ define([
|
|||
|
||||
$('<br>').appendTo($div);
|
||||
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
|
||||
|
||||
var $checkbox = $('<input>', {
|
||||
'type': 'checkbox',
|
||||
}).on('change', function () {
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
obj.proxy.allowUserFeedback = $checkbox.is(':checked') || false;
|
||||
// TODO provide feedback to show if this is synced
|
||||
// Cryptpad.whenRealtimeSyncs...
|
||||
Cryptpad.whenRealtimeSyncs(obj.info.realtime, function () {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
});
|
||||
});
|
||||
|
||||
$checkbox.appendTo($div);
|
||||
$label.appendTo($div);
|
||||
|
||||
$ok.hide().appendTo($div);
|
||||
$spinner.hide().appendTo($div);
|
||||
|
||||
if (obj.proxy.allowUserFeedback) {
|
||||
$checkbox[0].checked = true;
|
||||
}
|
||||
return $div;
|
||||
};
|
||||
|
||||
var createImportLocalPads = function (obj) {
|
||||
if (!Cryptpad.isLoggedIn()) { return; }
|
||||
var $div = $('<div>', {'class': 'importLocalPads'});
|
||||
var $label = $('<label>', {'for' : 'importLocalPads'}).text(Messages.settings_importTitle).appendTo($div);
|
||||
$('<br>').appendTo($div);
|
||||
var $button = $('<button>', {'id': 'importLocalPads', 'class': 'btn btn-primary'})
|
||||
.text(Messages.settings_import).appendTo($div);
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved}).hide().appendTo($div);
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}).hide().appendTo($div);
|
||||
|
||||
$button.click(function () {
|
||||
Cryptpad.confirm(Messages.settings_importConfirm, function (yes) {
|
||||
if (!yes) { return; }
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
Merge.anonDriveIntoUser(obj.proxy, function () {
|
||||
$spinner.hide();
|
||||
$ok.show();
|
||||
Cryptpad.alert(Messages.settings_importDone);
|
||||
});
|
||||
}, undefined, true);
|
||||
});
|
||||
|
||||
return $div;
|
||||
};
|
||||
|
||||
var andThen = function (obj) {
|
||||
APP.$container.append(createTitle());
|
||||
APP.$container.append(createInfoBlock(obj));
|
||||
APP.$container.append(createDisplayNameInput(obj));
|
||||
APP.$container.append(createResetTips());
|
||||
APP.$container.append(createBackupDrive(obj));
|
||||
APP.$container.append(createImportLocalPads(obj));
|
||||
APP.$container.append(createResetDrive(obj));
|
||||
APP.$container.append(createUserFeedbackToggle(obj));
|
||||
obj.proxy.on('change', [], refresh);
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
data-main-favicon="/customize/main-favicon.png"
|
||||
data-alt-favicon="/customize/alt-favicon.png"
|
||||
id="favicon" />
|
||||
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
|
||||
<link rel="stylesheet" href="/customize/main.css" />
|
||||
<style>
|
||||
html, body {
|
||||
|
@ -34,19 +35,30 @@
|
|||
}
|
||||
/* We use !important here to override the 96% set to the element in DecorateToolbar.js
|
||||
when we enter fullscreen mode. It allows us to avoid changing the iframe's size in JS */
|
||||
#pad-iframe.fullscreen {
|
||||
body #pad-iframe.fullscreen {
|
||||
top: 0px;
|
||||
height: 100% !important;
|
||||
height: 100%;
|
||||
}
|
||||
#iframe-container.fullscreen {
|
||||
body #iframe-container.fullscreen {
|
||||
top: 0px;
|
||||
height: 100% !important;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="iframe-container">
|
||||
<iframe id="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||
<iframe id="pad-iframe", name="pad-iframe"></iframe><script src="/common/noscriptfix.js"></script>
|
||||
</div>
|
||||
<div id="loading">
|
||||
<div class="loadingContainer">
|
||||
<img class="cryptofist" src="/customize/cryptofist_small.png" />
|
||||
<div class="spinnerContainer">
|
||||
<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>
|
||||
</div>
|
||||
<p data-localization="loading"></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
|
||||
<link rel="stylesheet" href="/customize/main.css">
|
||||
<link rel="stylesheet" href="./slide.css">
|
||||
<link rel="stylesheet" href="/bower_components/components-font-awesome/css/font-awesome.min.css">
|
||||
<script src="/bower_components/jquery/dist/jquery.min.js"></script>
|
||||
<script src="/bower_components/codemirror/lib/codemirror.js"></script>
|
||||
|
@ -34,55 +35,6 @@
|
|||
<script src="/bower_components/codemirror/addon/fold/markdown-fold.js"></script>
|
||||
<script src="/bower_components/codemirror/addon/fold/comment-fold.js"></script>
|
||||
<script src="/bower_components/codemirror/addon/display/placeholder.js"></script>
|
||||
<style>
|
||||
html, body{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
#modal.shown {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 100;
|
||||
background-color: black;
|
||||
color: white;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#content h1, h2, h3, h4, h5, h6 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
h1 { font-size: 40px; }
|
||||
h2 { font-size: 37px; }
|
||||
h3 { font-size: 34px; }
|
||||
h4 { font-size: 31px; }
|
||||
h5 { font-size: 27px; }
|
||||
h6 { font-size: 24px; }
|
||||
|
||||
.CodeMirror {
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-focused .cm-matchhighlight {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
#colorPicker_check {
|
||||
display: block;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="bar"></div>
|
||||
|
@ -98,6 +50,7 @@
|
|||
<div id="button_right" class="button"><span class="fa fa-chevron-right"></span></div>
|
||||
<div id="content"></div>
|
||||
</div>
|
||||
<div id="print"></div>
|
||||
</span>
|
||||
<div id="nope"></div>
|
||||
<div id="colorPicker_check"></div>
|
||||
|
|
|
@ -128,12 +128,15 @@ define([
|
|||
}
|
||||
editor.setOption('theme', theme);
|
||||
}
|
||||
if ($select) { $select.find('.buttonTitle').text(theme || 'Theme'); }
|
||||
if ($select) {
|
||||
$select.setValue(theme || 'Theme');
|
||||
}
|
||||
};
|
||||
}());
|
||||
|
||||
var $modal = $pad.contents().find('#modal');
|
||||
var $content = $pad.contents().find('#content');
|
||||
var $print = $pad.contents().find('#print');
|
||||
|
||||
Slide.setModal($modal, $content, $pad, ifrw, initialState);
|
||||
|
||||
|
@ -409,6 +412,79 @@ define([
|
|||
onLocal();
|
||||
};
|
||||
|
||||
var createPrintDialog = function () {
|
||||
var printOptions = {
|
||||
title: true,
|
||||
slide: true,
|
||||
date: true
|
||||
};
|
||||
|
||||
var $container = $('<div class="alertify">');
|
||||
var $container2 = $('<div class="dialog">').appendTo($container);
|
||||
var $div = $('<div id="printOptions">').appendTo($container2);
|
||||
var $p = $('<p>', {'class': 'msg'}).appendTo($div);
|
||||
$('<b>').text(Messages.printOptions).appendTo($p);
|
||||
$p.append($('<br>'));
|
||||
// Slide number
|
||||
$('<input>', {type: 'checkbox', id: 'checkNumber', checked: 'checked'}).on('change', function () {
|
||||
var c = this.checked;
|
||||
console.log(c);
|
||||
printOptions.slide = c;
|
||||
}).appendTo($p).css('width', 'auto');
|
||||
$('<label>', {'for': 'checkNumber'}).text(Messages.printSlideNumber).appendTo($p);
|
||||
$p.append($('<br>'));
|
||||
// Date
|
||||
$('<input>', {type: 'checkbox', id: 'checkDate', checked: 'checked'}).on('change', function () {
|
||||
var c = this.checked;
|
||||
printOptions.date = c;
|
||||
}).appendTo($p).css('width', 'auto');
|
||||
$('<label>', {'for': 'checkDate'}).text(Messages.printDate).appendTo($p);
|
||||
$p.append($('<br>'));
|
||||
// Title
|
||||
$('<input>', {type: 'checkbox', id: 'checkTitle', checked: 'checked'}).on('change', function () {
|
||||
var c = this.checked;
|
||||
printOptions.title = c;
|
||||
}).appendTo($p).css('width', 'auto');
|
||||
$('<label>', {'for': 'checkTitle'}).text(Messages.printTitle).appendTo($p);
|
||||
$p.append($('<br>'));
|
||||
// CSS
|
||||
$('<label>', {'for': 'cssPrint'}).text(Messages.printCSS).appendTo($p);
|
||||
$p.append($('<br>'));
|
||||
var $textarea = $('<textarea>', {'id':'cssPrint'}).css({'width':'100%', 'height':'100px'}).appendTo($p);
|
||||
|
||||
var fixCSS = function (css) {
|
||||
var append = '.cp #print ';
|
||||
return css.replace(/(\n*)([^\n]+)\s*\{/g, '$1' + append + '$2 {');
|
||||
};
|
||||
|
||||
var todo = function () {
|
||||
var $style = $('<style>').text(fixCSS($textarea.val()));
|
||||
$print.prepend($style);
|
||||
var length = $print.find('.slide-frame').length;
|
||||
$print.find('.slide-frame').each(function (i, el) {
|
||||
if (printOptions.slide) {
|
||||
$('<div>', {'class': 'slideNumber'}).text((i+1)+'/'+length).appendTo($(el));
|
||||
}
|
||||
if (printOptions.date) {
|
||||
$('<div>', {'class': 'slideDate'}).text(new Date().toLocaleDateString()).appendTo($(el));
|
||||
}
|
||||
if (printOptions.title) {
|
||||
$('<div>', {'class': 'slideTitle'}).text(APP.title).appendTo($(el));
|
||||
}
|
||||
});
|
||||
window.frames["pad-iframe"].focus();
|
||||
window.frames["pad-iframe"].print();
|
||||
$container.remove();
|
||||
};
|
||||
|
||||
var $nav = $('<nav>').appendTo($div);
|
||||
var $ok = $('<button>', {'class': 'ok'}).text(Messages.printButton).appendTo($nav).click(todo);
|
||||
var $cancel = $('<button>', {'class': 'cancel'}).text(Messages.cancel).appendTo($nav).click(function () {
|
||||
$container.remove();
|
||||
});
|
||||
return $container;
|
||||
};
|
||||
|
||||
var onInit = config.onInit = function (info) {
|
||||
userList = info.userList;
|
||||
|
||||
|
@ -417,6 +493,10 @@ define([
|
|||
userData: userData,
|
||||
readOnly: readOnly,
|
||||
ifrw: ifrw,
|
||||
share: {
|
||||
secret: secret,
|
||||
channel: info.channel
|
||||
},
|
||||
title: {
|
||||
onRename: renameCb,
|
||||
defaultName: defaultName,
|
||||
|
@ -429,8 +509,6 @@ define([
|
|||
|
||||
var $rightside = $bar.find('.' + Toolbar.constants.rightside);
|
||||
var $userBlock = $bar.find('.' + Toolbar.constants.username);
|
||||
var $editShare = $bar.find('.' + Toolbar.constants.editShare);
|
||||
var $viewShare = $bar.find('.' + Toolbar.constants.viewShare);
|
||||
var $usernameButton = module.$userNameButton = $($bar.find('.' + Toolbar.constants.changeUsername));
|
||||
|
||||
var editHash;
|
||||
|
@ -462,16 +540,15 @@ define([
|
|||
var $forgetPad = Cryptpad.createButton('forget', true, {}, forgetCb);
|
||||
$rightside.append($forgetPad);
|
||||
|
||||
if (!readOnly) {
|
||||
$editShare.append(Cryptpad.createButton('editshare', false, {editHash: editHash}));
|
||||
}
|
||||
if (viewHash) {
|
||||
/* add a 'links' button */
|
||||
$viewShare.append(Cryptpad.createButton('viewshare', false, {viewHash: viewHash + '/present'}));
|
||||
if (!readOnly) {
|
||||
$viewShare.append(Cryptpad.createButton('viewopen', false, {viewHash: viewHash + '/present'}));
|
||||
}
|
||||
}
|
||||
var $printButton = $('<button>', {
|
||||
title: Messages.printButtonTitle,
|
||||
'class': 'rightside-button fa fa-print',
|
||||
style: 'font-size: 17px'
|
||||
}).click(function () {
|
||||
$print.html($content.html());
|
||||
$('body').append(createPrintDialog());
|
||||
});
|
||||
$rightside.append($printButton);
|
||||
|
||||
var $present = Cryptpad.createButton('present', true)
|
||||
.click(function () {
|
||||
|
@ -509,6 +586,8 @@ define([
|
|||
text: 'Theme', // Button initial text
|
||||
options: options, // Entries displayed in the menu
|
||||
left: true, // Open to the left of the button
|
||||
isSelect: true,
|
||||
initialValue: lastTheme
|
||||
};
|
||||
var $block = module.$theme = Cryptpad.createDropdown(dropdownConfig);
|
||||
var $button = $block.find('.buttonTitle');
|
||||
|
@ -518,7 +597,6 @@ define([
|
|||
$block.find('a').click(function (e) {
|
||||
var theme = $(this).attr('data-value');
|
||||
setTheme(theme, $block);
|
||||
$button.text($(this).text());
|
||||
localStorage.setItem(themeKey, theme);
|
||||
});
|
||||
|
||||
|
@ -530,13 +608,13 @@ define([
|
|||
id: SLIDE_BACKCOLOR_ID,
|
||||
'class': 'fa fa-square rightside-button',
|
||||
'style': 'font-family: FontAwesome; color: #000;',
|
||||
title: Messages.backgroundButton + '\n' + Messages.backgroundButtonTitle
|
||||
title: Messages.backgroundButtonTitle
|
||||
});
|
||||
var $text = $('<button>', {
|
||||
id: SLIDE_COLOR_ID,
|
||||
'class': 'fa fa-i-cursor rightside-button',
|
||||
'style': 'font-family: FontAwesome; font-weight: bold; color: #fff; background: #000;',
|
||||
title: Messages.colorButton + '\n' + Messages.colorButtonTitle
|
||||
title: Messages.colorButtonTitle
|
||||
});
|
||||
var $testColor = $('<input>', { type: 'color', value: '!' });
|
||||
var $check = $pad.contents().find("#colorPicker_check");
|
||||
|
@ -634,7 +712,8 @@ define([
|
|||
updateMetadata(userDoc);
|
||||
|
||||
editor.setValue(newDoc || initialState);
|
||||
Slide.update(newDoc);
|
||||
Slide.update(newDoc, true);
|
||||
Slide.draw();
|
||||
|
||||
if (Cryptpad.initialName && APP.title === defaultName) {
|
||||
updateTitle(Cryptpad.initialName);
|
||||
|
|
|
@ -0,0 +1,322 @@
|
|||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
h1 {
|
||||
font-size: 40px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 37px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 34px;
|
||||
}
|
||||
h4 {
|
||||
font-size: 31px;
|
||||
}
|
||||
h5 {
|
||||
font-size: 27px;
|
||||
}
|
||||
h6 {
|
||||
font-size: 24px;
|
||||
}
|
||||
body .CodeMirror {
|
||||
height: 100%;
|
||||
}
|
||||
body .CodeMirror-focused .cm-matchhighlight {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
#colorPicker_check {
|
||||
display: block;
|
||||
}
|
||||
@media print {
|
||||
@page {
|
||||
margin: 0;
|
||||
size: auto;
|
||||
}
|
||||
body {
|
||||
display: block;
|
||||
}
|
||||
body .CodeMirror,
|
||||
body #cme_toolbox {
|
||||
display: none;
|
||||
}
|
||||
body * {
|
||||
visibility: hidden;
|
||||
height: auto;
|
||||
max-height: none;
|
||||
}
|
||||
html,
|
||||
body {
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
html #print {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
}
|
||||
html #print * {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
#print {
|
||||
position: relative;
|
||||
display: none;
|
||||
}
|
||||
#print .slide-frame {
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-flow: column;
|
||||
padding: 5vh 0;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
page-break-after: always;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
#print .slide-frame li {
|
||||
min-width: 50vw;
|
||||
}
|
||||
#print .slide-frame h1 {
|
||||
padding-top: 0;
|
||||
}
|
||||
#print .slide-frame .slideNumber {
|
||||
position: absolute;
|
||||
right: 5vh;
|
||||
bottom: 5vh;
|
||||
}
|
||||
#print .slide-frame .slideDate {
|
||||
position: absolute;
|
||||
left: 5vh;
|
||||
bottom: 5vh;
|
||||
}
|
||||
#print .slide-frame .slideTitle {
|
||||
position: absolute;
|
||||
top: 5vh;
|
||||
left: 0px;
|
||||
right: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
.cp.slide #modal .button {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
opacity: 0.6;
|
||||
display: none;
|
||||
}
|
||||
.cp.slide #modal .button:hover {
|
||||
opacity: 1;
|
||||
display: block !important;
|
||||
}
|
||||
.cp.slide #modal #button_exit {
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
z-index: 9001;
|
||||
}
|
||||
.cp.slide #modal #button_left {
|
||||
left: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
.cp.slide #modal #button_right {
|
||||
right: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
.cp.slide #modal #content h1,
|
||||
.cp.slide #modal #content h2,
|
||||
.cp.slide #modal #content h3,
|
||||
.cp.slide #modal #content h4,
|
||||
.cp.slide #modal #content h5,
|
||||
.cp.slide #modal #content h6 {
|
||||
text-align: center;
|
||||
}
|
||||
.cp.slide #modal.shown {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 100;
|
||||
background-color: black;
|
||||
color: white;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
.cp.slide #modal #content p,
|
||||
.cp.slide #modal #content ul,
|
||||
.cp.slide #modal #content ol {
|
||||
font-size: 26px;
|
||||
}
|
||||
.cp.slide #modal #content img {
|
||||
position: relative;
|
||||
min-width: 1%;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
.cp div.modal,
|
||||
.cp div#modal {
|
||||
box-sizing: border-box;
|
||||
z-index: 9001;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: none;
|
||||
background-color: #000;
|
||||
}
|
||||
.cp div.modal #content,
|
||||
.cp div#modal #content {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid white;
|
||||
vertical-align: middle;
|
||||
padding: 2.5vw;
|
||||
/* center things as much as possible
|
||||
|
||||
margin-top: 50vh;
|
||||
margin-bottom: 50vh;
|
||||
transform: translateY(-50%);
|
||||
|
||||
*/
|
||||
width: 100vw;
|
||||
height: 56.25vw;
|
||||
max-height: 100vh;
|
||||
max-width: 177.78vh;
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.cp div.modal #content p,
|
||||
.cp div#modal #content p,
|
||||
.cp div.modal #content li,
|
||||
.cp div#modal #content li,
|
||||
.cp div.modal #content pre,
|
||||
.cp div#modal #content pre,
|
||||
.cp div.modal #content code,
|
||||
.cp div#modal #content code {
|
||||
font-size: 2.75vw;
|
||||
line-height: 3.025vw;
|
||||
}
|
||||
.cp div.modal #content h1,
|
||||
.cp div#modal #content h1 {
|
||||
font-size: 5vw;
|
||||
line-height: 5.5vw;
|
||||
}
|
||||
.cp div.modal #content h2,
|
||||
.cp div#modal #content h2 {
|
||||
font-size: 4.2vw;
|
||||
line-height: 4.62vw;
|
||||
}
|
||||
.cp div.modal #content h3,
|
||||
.cp div#modal #content h3 {
|
||||
font-size: 3.6vw;
|
||||
line-height: 3.96vw;
|
||||
}
|
||||
.cp div.modal #content h4,
|
||||
.cp div#modal #content h4 {
|
||||
font-size: 3vw;
|
||||
line-height: 3.3vw;
|
||||
}
|
||||
.cp div.modal #content h5,
|
||||
.cp div#modal #content h5 {
|
||||
font-size: 2.2vw;
|
||||
line-height: 2.42vw;
|
||||
}
|
||||
.cp div.modal #content h6,
|
||||
.cp div#modal #content h6 {
|
||||
font-size: 1.6vw;
|
||||
line-height: 1.76vw;
|
||||
}
|
||||
.cp div.modal #content h1,
|
||||
.cp div#modal #content h1,
|
||||
.cp div.modal #content h2,
|
||||
.cp div#modal #content h2,
|
||||
.cp div.modal #content h3,
|
||||
.cp div#modal #content h3,
|
||||
.cp div.modal #content h4,
|
||||
.cp div#modal #content h4,
|
||||
.cp div.modal #content h5,
|
||||
.cp div#modal #content h5,
|
||||
.cp div.modal #content h6,
|
||||
.cp div#modal #content h6 {
|
||||
color: inherit;
|
||||
text-align: center;
|
||||
}
|
||||
.cp div.modal #content pre > code,
|
||||
.cp div#modal #content pre > code {
|
||||
display: block;
|
||||
position: relative;
|
||||
border: 1px solid #333;
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
padding-left: .25vw;
|
||||
}
|
||||
.cp div.modal #content ul,
|
||||
.cp div#modal #content ul,
|
||||
.cp div.modal #content ol,
|
||||
.cp div#modal #content ol {
|
||||
min-width: 50%;
|
||||
max-width: 100%;
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
.cp div.modal .center,
|
||||
.cp div#modal .center {
|
||||
position: relative;
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: auto;
|
||||
border: 1px solid #ffffff;
|
||||
text-align: center;
|
||||
}
|
||||
.cp div.modal.shown,
|
||||
.cp div#modal.shown {
|
||||
display: block;
|
||||
}
|
||||
.cp div.modal table,
|
||||
.cp div#modal table {
|
||||
margin: 30px;
|
||||
border-collapse: collapse;
|
||||
}
|
||||
.cp div.modal table input,
|
||||
.cp div#modal table input {
|
||||
height: 100%;
|
||||
width: 90%;
|
||||
border: 3px solid #fff;
|
||||
}
|
||||
.cp div.modal table tfoot tr td,
|
||||
.cp div#modal table tfoot tr td {
|
||||
z-index: 4000;
|
||||
cursor: pointer;
|
||||
}
|
||||
.cp div.modal #addtime,
|
||||
.cp div#modal #addtime,
|
||||
.cp div.modal #adddate,
|
||||
.cp div#modal #adddate {
|
||||
color: #46E981;
|
||||
border: 1px solid #46E981;
|
||||
padding: 15px;
|
||||
}
|
||||
.cp div.modal #adddate,
|
||||
.cp div#modal #adddate {
|
||||
border-top-left-radius: 5px;
|
||||
}
|
||||
.cp div.modal #addtime,
|
||||
.cp div#modal #addtime {
|
||||
border-bottom-left-radius: 5px;
|
||||
}
|
|
@ -19,6 +19,9 @@ define([
|
|||
var $content;
|
||||
var $pad;
|
||||
var placeholder;
|
||||
var separator = '<hr data-pewpew="pezpez">';
|
||||
var separatorReg = /<hr data\-pewpew="pezpez">/g;
|
||||
var slideClass = 'slide-frame';
|
||||
|
||||
Slide.onChange = function (f) {
|
||||
if (typeof(f) === 'function') {
|
||||
|
@ -26,11 +29,15 @@ define([
|
|||
}
|
||||
};
|
||||
|
||||
var getNumberOfSlides = Slide.getNumberOfSlides = function () {
|
||||
return $content.find('.' + slideClass).length;
|
||||
};
|
||||
|
||||
var change = function (oldIndex, newIndex) {
|
||||
if (Slide.changeHandlers.length) {
|
||||
Slide.changeHandlers.some(function (f, i) {
|
||||
// HERE
|
||||
f(oldIndex, newIndex, Slide.content.length);
|
||||
f(oldIndex, newIndex, getNumberOfSlides());
|
||||
});
|
||||
}
|
||||
};
|
||||
|
@ -76,7 +83,7 @@ define([
|
|||
var Err;
|
||||
var Els = [A, B].map(function (frag) {
|
||||
if (typeof(frag) === 'object') {
|
||||
if (!frag && frag.body) {
|
||||
if (!frag || (frag && !frag.body)) {
|
||||
Err = "No body";
|
||||
return;
|
||||
}
|
||||
|
@ -108,19 +115,23 @@ define([
|
|||
};
|
||||
|
||||
var draw = Slide.draw = function (i) {
|
||||
console.log("Trying to draw slide #%s", i);
|
||||
if (typeof(Slide.content[i]) !== 'string') { return; }
|
||||
i = i || 0;
|
||||
if (typeof(Slide.content) !== 'string') { return; }
|
||||
|
||||
var c = Slide.content[i];
|
||||
var Dom = domFromHTML('<div id="content">' + Marked(c) + '</div>');
|
||||
var c = Slide.content;
|
||||
var m = '<span class="'+slideClass+'">'+Marked(c).replace(separatorReg, '</span><span class="'+slideClass+'">')+'</span>';
|
||||
|
||||
var Dom = domFromHTML('<div id="content">' + m + '</div>');
|
||||
removeListeners(Dom.body);
|
||||
var patch = makeDiff(domFromHTML($content[0].outerHTML), Dom);
|
||||
|
||||
if (typeof(patch) === 'string') {
|
||||
$content.html(Marked(c));
|
||||
$content.html(m);
|
||||
} else {
|
||||
DD.apply($content[0], patch);
|
||||
}
|
||||
$content.find('.' + slideClass).hide();
|
||||
$content.find('.' + slideClass + ':eq( ' + i + ' )').show();
|
||||
change(Slide.lastIndex, Slide.index);
|
||||
};
|
||||
|
||||
|
@ -159,13 +170,13 @@ define([
|
|||
$modal.removeClass('shown');
|
||||
};
|
||||
|
||||
var update = Slide.update = function (content) {
|
||||
if (!Slide.shown) { return; }
|
||||
if (!content) { content = placeholder; }
|
||||
var old = Slide.content[Slide.index];
|
||||
Slide.content = content.split(/\n\s*\-\-\-\s*\n/).filter(truthy);
|
||||
if (old !== Slide.content[Slide.index]) {
|
||||
draw(Slide.index);
|
||||
var update = Slide.update = function (content, init) {
|
||||
if (!Slide.shown && !init) { return; }
|
||||
if (!content) { content = ''; }
|
||||
var old = Slide.content;
|
||||
Slide.content = content.replace(/\n\s*\-\-\-\s*\n/g, '\n\n'+separator+'\n\n');
|
||||
if (old !== Slide.content) {
|
||||
draw();
|
||||
return;
|
||||
}
|
||||
change(Slide.lastIndex, Slide.index);
|
||||
|
@ -183,7 +194,7 @@ define([
|
|||
console.log('right');
|
||||
Slide.lastIndex = Slide.index;
|
||||
|
||||
var i = Slide.index = Math.min(Slide.content.length -1, Slide.index + 1);
|
||||
var i = Slide.index = Math.min(getNumberOfSlides() -1, Slide.index + 1);
|
||||
Slide.draw(i);
|
||||
};
|
||||
|
||||
|
@ -199,7 +210,7 @@ define([
|
|||
console.log('end');
|
||||
Slide.lastIndex = Slide.index;
|
||||
|
||||
var i = Slide.index = Slide.content.length - 1;
|
||||
var i = Slide.index = getNumberOfSlides() - 1;
|
||||
Slide.draw(i);
|
||||
};
|
||||
|
||||
|
|
|
@ -0,0 +1,314 @@
|
|||
@import "../../customize.dist/src/less/variables.less";
|
||||
@import "../../customize.dist/src/less/mixins.less";
|
||||
|
||||
// used for slides
|
||||
.viewportRatio (@x, @y, @p: 100) {
|
||||
width: @p * 100vw;
|
||||
height: @y * (@p * 100vw) / @x;
|
||||
max-width: @x / @y * (@p * 100vh);
|
||||
max-height: (@p * 100vh);
|
||||
}
|
||||
|
||||
html, body{
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
padding: 0px;
|
||||
margin: 0px;
|
||||
overflow: hidden;
|
||||
box-sizing: border-box;
|
||||
position: relative;
|
||||
}
|
||||
body {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
}
|
||||
|
||||
//.cp {
|
||||
h1 { font-size: 40px; }
|
||||
h2 { font-size: 37px; }
|
||||
h3 { font-size: 34px; }
|
||||
h4 { font-size: 31px; }
|
||||
h5 { font-size: 27px; }
|
||||
h6 { font-size: 24px; }
|
||||
|
||||
body {
|
||||
.CodeMirror {
|
||||
height: 100%;
|
||||
}
|
||||
.CodeMirror-focused .cm-matchhighlight {
|
||||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0kAAAAFklEQVQI12NgYGBgkKzc8x9CMDAwAAAmhwSbidEoSQAAAABJRU5ErkJggg==);
|
||||
background-position: bottom;
|
||||
background-repeat: repeat-x;
|
||||
}
|
||||
}
|
||||
#colorPicker_check {
|
||||
display: block;
|
||||
}
|
||||
|
||||
@media print {
|
||||
@page {
|
||||
margin: 0;
|
||||
size: auto;
|
||||
}
|
||||
body {
|
||||
.CodeMirror, #cme_toolbox {
|
||||
display: none;
|
||||
}
|
||||
* {
|
||||
visibility: hidden;
|
||||
height: auto;
|
||||
max-height: none;
|
||||
}
|
||||
display:block;
|
||||
}
|
||||
html, body {
|
||||
max-height: none;
|
||||
overflow: visible;
|
||||
}
|
||||
html {
|
||||
#print {
|
||||
display: block;
|
||||
visibility: visible;
|
||||
* {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#print {
|
||||
position: relative;
|
||||
display: none;
|
||||
.slide-frame {
|
||||
display: flex !important;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
flex-flow: column;
|
||||
padding: 5vh 0;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
page-break-after: always;
|
||||
position: relative;
|
||||
box-sizing: border-box;
|
||||
li {
|
||||
min-width: 50vw;
|
||||
}
|
||||
h1 {
|
||||
padding-top: 0;
|
||||
}
|
||||
.slideNumber {
|
||||
position: absolute;
|
||||
right: 5vh;
|
||||
bottom: 5vh;
|
||||
}
|
||||
.slideDate {
|
||||
position: absolute;
|
||||
left: 5vh;
|
||||
bottom: 5vh;
|
||||
}
|
||||
.slideTitle {
|
||||
position: absolute;
|
||||
top: 5vh;
|
||||
left: 0px; right: 0px;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.cp {
|
||||
|
||||
&.slide {
|
||||
#modal {
|
||||
.button {
|
||||
position: absolute;
|
||||
cursor: pointer;
|
||||
font-size: 30px;
|
||||
opacity: 0.6;
|
||||
display: none;
|
||||
}
|
||||
.button:hover {
|
||||
opacity: 1;
|
||||
display: block !important;
|
||||
}
|
||||
#button_exit {
|
||||
left: 20px;
|
||||
top: 20px;
|
||||
z-index: 9001;
|
||||
}
|
||||
#button_left {
|
||||
left: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
#button_right {
|
||||
right: 6vw;
|
||||
bottom: 10vh;
|
||||
}
|
||||
#content {
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
}
|
||||
&.shown {
|
||||
display: block;
|
||||
position: fixed;
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
z-index: 100;
|
||||
background-color: black;
|
||||
color: white;
|
||||
height: 100vh;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
#modal #content {
|
||||
p, ul, ol { font-size: 26px; }
|
||||
|
||||
img {
|
||||
position: relative;
|
||||
min-width: 1%;
|
||||
max-width: 90%;
|
||||
max-height: 90%;
|
||||
margin: auto;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
div.modal, div#modal {
|
||||
display: none;
|
||||
|
||||
#content {
|
||||
box-sizing: border-box;
|
||||
border: 1px solid white;
|
||||
|
||||
vertical-align: middle;
|
||||
padding: 2.5vw;
|
||||
|
||||
/* center things as much as possible
|
||||
|
||||
margin-top: 50vh;
|
||||
margin-bottom: 50vh;
|
||||
transform: translateY(-50%);
|
||||
|
||||
*/
|
||||
|
||||
width: 100vw;
|
||||
height: 56.25vw; // height:width ratio = 9/16 = .5625
|
||||
max-height: 100vh;
|
||||
max-width: 177.78vh; // 16/9 = 1.778
|
||||
margin: auto;
|
||||
position: absolute;
|
||||
top:0;bottom:0; // vertical center
|
||||
left:0;right:0; // horizontal center
|
||||
|
||||
p, li, pre, code {
|
||||
.size(2.75);
|
||||
}
|
||||
|
||||
h1 { .size(5); }
|
||||
h2 { .size(4.2); }
|
||||
h3 { .size(3.6); }
|
||||
h4 { .size (3); }
|
||||
h5 { .size(2.2); }
|
||||
h6 { .size(1.6); }
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: inherit;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
pre > code {
|
||||
display: block;
|
||||
position: relative;
|
||||
border: 1px solid #333;
|
||||
width: 90%;
|
||||
margin: auto;
|
||||
padding-left: .25vw;
|
||||
}
|
||||
|
||||
ul, ol {
|
||||
min-width: 50%;
|
||||
max-width: 100%;
|
||||
display: table;
|
||||
margin: 0 auto;
|
||||
}
|
||||
}
|
||||
|
||||
box-sizing: border-box;
|
||||
z-index: 9001;
|
||||
position: fixed;
|
||||
|
||||
top: 0px;
|
||||
left: 0px;
|
||||
|
||||
width: 100%;
|
||||
height: 100vh;
|
||||
display: none;
|
||||
|
||||
background-color: @slide-default-bg;
|
||||
|
||||
.center {
|
||||
position: relative;
|
||||
|
||||
width: 80%;
|
||||
height: 80%;
|
||||
margin: auto;
|
||||
border: 1px solid @light-base;
|
||||
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
&.shown {
|
||||
display: block;
|
||||
}
|
||||
|
||||
table {
|
||||
margin: 30px;
|
||||
|
||||
border-collapse: collapse;
|
||||
tr {
|
||||
td {
|
||||
}
|
||||
}
|
||||
|
||||
input {
|
||||
height: 100%;
|
||||
width: 90%;
|
||||
border: 3px solid @base;
|
||||
}
|
||||
|
||||
thead {
|
||||
tr {
|
||||
th {
|
||||
span.remove {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
tbody {
|
||||
tr {
|
||||
td {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
tfoot {
|
||||
tr {
|
||||
td {
|
||||
z-index: 4000;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#addtime,
|
||||
#adddate {
|
||||
color: @cp-green;
|
||||
border: 1px solid @cp-green;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
#adddate { .top-left; }
|
||||
#addtime { .bottom-left; }
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue