Merge branch 'coati' into kanban
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
node_modules/
|
node_modules/
|
||||||
www/bower_components/
|
www/bower_components/
|
||||||
www/common/pdfjs/
|
www/common/pdfjs/
|
||||||
|
www/common/tippy/
|
||||||
|
www/common/jquery-ui/
|
||||||
|
|
||||||
server.js
|
server.js
|
||||||
www/common/media-tag.js
|
www/common/media-tag.js
|
||||||
@@ -8,7 +10,6 @@ www/scratch
|
|||||||
|
|
||||||
www/common/toolbar.js
|
www/common/toolbar.js
|
||||||
www/common/hyperscript.js
|
www/common/hyperscript.js
|
||||||
www/common/tippy.min.js
|
|
||||||
|
|
||||||
www/pad/wysiwygarea-plugin.js
|
www/pad/wysiwygarea-plugin.js
|
||||||
www/pad/mediatag-plugin.js
|
www/pad/mediatag-plugin.js
|
||||||
|
|||||||
47
CHANGELOG.md
Normal file
47
CHANGELOG.md
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
# 1.29.0
|
||||||
|
|
||||||
|
**Goals**
|
||||||
|
|
||||||
|
For this release we wanted to direct our effort towards improving user experience issues surrounding user accounts.
|
||||||
|
|
||||||
|
**Update notes**
|
||||||
|
|
||||||
|
This release features breaking changes to some clientside dependencies. Administrators must make sure to deploy the
|
||||||
|
latest server with npm update before updating your clientside dependencies with bower update.
|
||||||
|
|
||||||
|
**What's new**
|
||||||
|
|
||||||
|
* newly registered users are now able to delete their accounts automatically, along with any personal
|
||||||
|
information which had been created:
|
||||||
|
* ToDo list data is automatically deleted, along with user profiles
|
||||||
|
* all of a user's owned pads are also removed immediately in their account deletion process
|
||||||
|
* users who predate account deletion will not benefit from automatic account deletion, since the server
|
||||||
|
does not have sufficient knowledge to guarantee that the information they could request to have deleted is strictly
|
||||||
|
their own. For this reason, we've started working on scripts for validating user requests, so as to enable manual
|
||||||
|
deletion by the server administrator.
|
||||||
|
* the script can be found in cryptpad/check-account-deletion.js, and it will be a part of an ongoing
|
||||||
|
effort to improve administrator tooling for situations like this
|
||||||
|
* users who have not logged in, but wish to use their drive now see a ghost icon which they can use to create pads.
|
||||||
|
We hope this makes it easier to get started as a new user.
|
||||||
|
* registered users who have saved templates in their drives can now use those templates at any time, rather than only
|
||||||
|
using them to create new pads
|
||||||
|
* we've updated our file encryption code such that it does not interfere with other scripts which may be running at
|
||||||
|
the same time (synchronous blocking, for those who are interested)
|
||||||
|
* we now validate message signatures clientside, except when they are coming from the history keeper because clients
|
||||||
|
trust that the server has already validated those signatures
|
||||||
|
|
||||||
|
**Bug fixes**
|
||||||
|
* we've removed some dependencies from our home page that were introduced when we updated to use bootstrap4
|
||||||
|
* we now import fontawesome as css, and not less, which saves processing time and saves room in our localStorage cache
|
||||||
|
* templates which do not have a 'type' attribute set are migrated such that the pads which are created with their
|
||||||
|
content are valid
|
||||||
|
* thumbnail creation for pads is now disabled by default, due to poor performance
|
||||||
|
* users can enable thumbnail creation in their settings page
|
||||||
|
* we've fixed a significant bug in how our server handles checkpoints (special patches in history which contain the
|
||||||
|
entire pads content)
|
||||||
|
* it was possible for two users to independently create checkpoints in close proximity while the document was in a
|
||||||
|
forked state. New users joining while the session was in this state would get stuck on one side of the fork,
|
||||||
|
and could lose data if the users on the opposing fork overrode their changes
|
||||||
|
* we've updated our tests, which have been failing for some time because their success conditions were no longer valid
|
||||||
|
* while trying to register a previously registered user, users could cancel the prompt to login as that user.
|
||||||
|
If they did so, the registration form remained locked. This has been fixed.
|
||||||
11
bower.json
11
bower.json
@@ -29,10 +29,10 @@
|
|||||||
"json.sortify": "~2.1.0",
|
"json.sortify": "~2.1.0",
|
||||||
"secure-fabric.js": "secure-v1.7.9",
|
"secure-fabric.js": "secure-v1.7.9",
|
||||||
"hyperjson": "~1.4.0",
|
"hyperjson": "~1.4.0",
|
||||||
"chainpad-crypto": "^0.1.3",
|
"chainpad-crypto": "^0.2.0",
|
||||||
"chainpad-listmap": "^0.4.2",
|
"chainpad-listmap": "^0.5.0",
|
||||||
"chainpad": "^5.0.0",
|
"chainpad": "^5.1.0",
|
||||||
"chainpad-netflux": "^0.6.1",
|
"chainpad-netflux": "^0.7.0",
|
||||||
"file-saver": "1.3.1",
|
"file-saver": "1.3.1",
|
||||||
"alertifyjs": "1.0.11",
|
"alertifyjs": "1.0.11",
|
||||||
"scrypt-async": "1.2.0",
|
"scrypt-async": "1.2.0",
|
||||||
@@ -46,7 +46,8 @@
|
|||||||
"localforage": "^1.5.2",
|
"localforage": "^1.5.2",
|
||||||
"html2canvas": "^0.4.1",
|
"html2canvas": "^0.4.1",
|
||||||
"croppie": "^2.5.0",
|
"croppie": "^2.5.0",
|
||||||
"sortablejs": "#^1.6.0"
|
"sortablejs": "#^1.6.0",
|
||||||
|
"saferphore": "^0.0.1"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"bootstrap": "^v4.0.0"
|
"bootstrap": "^v4.0.0"
|
||||||
|
|||||||
76
check-account-deletion.js
Normal file
76
check-account-deletion.js
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
/* jshint esversion: 6, node: true */
|
||||||
|
const Fs = require('fs');
|
||||||
|
const nThen = require('nthen');
|
||||||
|
const Pinned = require('./pinned');
|
||||||
|
const Nacl = require('tweetnacl');
|
||||||
|
|
||||||
|
const hashesFromPinFile = (pinFile, fileName) => {
|
||||||
|
var pins = {};
|
||||||
|
pinFile.split('\n').filter((x)=>(x)).map((l) => JSON.parse(l)).forEach((l) => {
|
||||||
|
switch (l[0]) {
|
||||||
|
case 'RESET': {
|
||||||
|
pins = {};
|
||||||
|
if (l[1] && l[1].length) { l[1].forEach((x) => { pins[x] = 1; }); }
|
||||||
|
//jshint -W086
|
||||||
|
// fallthrough
|
||||||
|
}
|
||||||
|
case 'PIN': {
|
||||||
|
l[1].forEach((x) => { pins[x] = 1; });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'UNPIN': {
|
||||||
|
l[1].forEach((x) => { delete pins[x]; });
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: throw new Error(JSON.stringify(l) + ' ' + fileName);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
return Object.keys(pins);
|
||||||
|
};
|
||||||
|
|
||||||
|
var escapeKeyCharacters = function (key) {
|
||||||
|
return key && key.replace && key.replace(/\//g, '-');
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
const dataIdx = process.argv.indexOf('--data');
|
||||||
|
let edPublic;
|
||||||
|
if (dataIdx === -1) {
|
||||||
|
const hasEdPublic = process.argv.indexOf('--ed');
|
||||||
|
if (hasEdPublic === -1) { return void console.error("Missing ed argument"); }
|
||||||
|
edPublic = escapeKeyCharacters(process.argv[hasEdPublic+1]);
|
||||||
|
} else {
|
||||||
|
const deleteData = JSON.parse(process.argv[dataIdx+1]);
|
||||||
|
if (!deleteData.toSign || !deleteData.proof) { return void console.error("Invalid arguments"); }
|
||||||
|
// Check sig
|
||||||
|
const ed = Nacl.util.decodeBase64(deleteData.toSign.edPublic);
|
||||||
|
const signed = Nacl.util.decodeUTF8(JSON.stringify(deleteData.toSign));
|
||||||
|
const proof = Nacl.util.decodeBase64(deleteData.proof);
|
||||||
|
if (!Nacl.sign.detached.verify(signed, proof, ed)) { return void console.error("Invalid signature"); }
|
||||||
|
edPublic = escapeKeyCharacters(deleteData.toSign.edPublic);
|
||||||
|
}
|
||||||
|
|
||||||
|
let data = [];
|
||||||
|
let pinned = [];
|
||||||
|
|
||||||
|
nThen((waitFor) => {
|
||||||
|
let f = './pins/' + edPublic.slice(0, 2) + '/' + edPublic + '.ndjson';
|
||||||
|
Fs.readFile(f, waitFor((err, content) => {
|
||||||
|
if (err) { throw err; }
|
||||||
|
pinned = hashesFromPinFile(content.toString('utf8'), f);
|
||||||
|
}));
|
||||||
|
}).nThen((waitFor) => {
|
||||||
|
Pinned.load(waitFor((d) => {
|
||||||
|
data = Object.keys(d);
|
||||||
|
}), {
|
||||||
|
exclude: [edPublic + '.ndjson']
|
||||||
|
});
|
||||||
|
}).nThen(() => {
|
||||||
|
console.log('Pads pinned by this user and not pinned by anybody else:');
|
||||||
|
pinned.forEach((p) => {
|
||||||
|
if (data.indexOf(p) === -1) {
|
||||||
|
console.log(p);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
/*
|
/*
|
||||||
globals module
|
globals module
|
||||||
*/
|
*/
|
||||||
var domain = ' http://localhost:3000/';
|
var domain = 'http://localhost:3000/';
|
||||||
|
|
||||||
// You can `kill -USR2` the node process and it will write out a heap dump.
|
// You can `kill -USR2` the node process and it will write out a heap dump.
|
||||||
// If your system doesn't support dumping, comment this out and install with
|
// If your system doesn't support dumping, comment this out and install with
|
||||||
@@ -12,6 +12,10 @@ var domain = ' http://localhost:3000/';
|
|||||||
// to enable this feature, uncomment the line below:
|
// to enable this feature, uncomment the line below:
|
||||||
// require('heapdump');
|
// require('heapdump');
|
||||||
|
|
||||||
|
|
||||||
|
// we prepend a space because every usage expects it
|
||||||
|
// requiring admins to preserve it is unnecessarily confusing
|
||||||
|
domain = ' ' + domain;
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|
||||||
// the address you want to bind to, :: means all ipv4 and ipv6 addresses
|
// the address you want to bind to, :: means all ipv4 and ipv6 addresses
|
||||||
|
|||||||
BIN
customize.dist/loading-logo.png
Normal file
BIN
customize.dist/loading-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 23 KiB |
201
customize.dist/loading.js
Normal file
201
customize.dist/loading.js
Normal file
@@ -0,0 +1,201 @@
|
|||||||
|
// dark #326599
|
||||||
|
// light #4591c4
|
||||||
|
define([], function () {
|
||||||
|
var loadingStyle = (function(){/*
|
||||||
|
#cp-loading {
|
||||||
|
transition: opacity 0.75s, visibility 0s 0.75s;
|
||||||
|
visibility: visible;
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10000000;
|
||||||
|
top: 0px;
|
||||||
|
bottom: 0px;
|
||||||
|
left: 0px;
|
||||||
|
right: 0px;
|
||||||
|
background: linear-gradient(to right, #326599 0%, #326599 50%, #4591c4 50%, #4591c4 100%);
|
||||||
|
color: #fafafa;
|
||||||
|
font-size: 1.5em;
|
||||||
|
opacity: 1;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
#cp-loading.cp-loading-hidden {
|
||||||
|
opacity: 0;
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
|
#cp-loading .cp-loading-logo {
|
||||||
|
height: 300px;
|
||||||
|
width: 300px;
|
||||||
|
margin-top: 50px;
|
||||||
|
flex: 0 1 auto;
|
||||||
|
min-height: 0;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
#cp-loading .cp-loading-logo img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
#cp-loading .cp-loading-container {
|
||||||
|
width: 700px;
|
||||||
|
max-width: 90vw;
|
||||||
|
height: 500px;
|
||||||
|
max-height: calc(100vh - 20px);
|
||||||
|
margin: 50px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
justify-content: center;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
@media screen and (max-height: 800px) {
|
||||||
|
#cp-loading .cp-loading-container {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@media screen and (max-width: 600px) {
|
||||||
|
#cp-loading .cp-loading-container {
|
||||||
|
height: auto;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#cp-loading .cp-loading-cryptofist {
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
//height: 300px;
|
||||||
|
max-width: 90vw;
|
||||||
|
max-height: 300px;
|
||||||
|
width: auto;
|
||||||
|
height: auto;
|
||||||
|
margin-bottom: 2em;
|
||||||
|
}
|
||||||
|
@media screen and (max-height: 500px) {
|
||||||
|
#cp-loading .cp-loading-logo {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#cp-loading-message {
|
||||||
|
background: #FFF;
|
||||||
|
padding: 20px;
|
||||||
|
width: 100%;
|
||||||
|
color: #000;
|
||||||
|
text-align: center;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt {
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-error {
|
||||||
|
color: white;
|
||||||
|
background: #9e0000;
|
||||||
|
padding: 5px;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-info {
|
||||||
|
text-align: left;
|
||||||
|
margin-bottom: 15px;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-form {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-around;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-form button,
|
||||||
|
#cp-loading-password-prompt .cp-password-form .cp-password-input {
|
||||||
|
background-color: #4591c4;
|
||||||
|
color: white;
|
||||||
|
border: 1px solid #4591c4;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-form .cp-password-container {
|
||||||
|
flex-shrink: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-form input {
|
||||||
|
flex: 1;
|
||||||
|
padding: 0 5px;
|
||||||
|
min-width: 0;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
#cp-loading-password-prompt .cp-password-form button:hover {
|
||||||
|
background-color: #326599;
|
||||||
|
}
|
||||||
|
#cp-loading .cp-loading-spinner-container {
|
||||||
|
position: relative;
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
#cp-loading .cp-loading-spinner-container > div {
|
||||||
|
height: 100px;
|
||||||
|
}
|
||||||
|
#cp-loading-tip {
|
||||||
|
position: fixed;
|
||||||
|
z-index: 10000000;
|
||||||
|
top: 80%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
text-align: center;
|
||||||
|
transition: opacity 750ms;
|
||||||
|
transition-delay: 3000ms;
|
||||||
|
}
|
||||||
|
@media screen and (max-height: 600px) {
|
||||||
|
#cp-loading-tip {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#cp-loading-tip span {
|
||||||
|
background: #222;
|
||||||
|
color: #fafafa;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 1.5em;
|
||||||
|
opacity: 0.7;
|
||||||
|
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
|
||||||
|
padding: 15px;
|
||||||
|
max-width: 60%;
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
|
.cp-loading-progress {
|
||||||
|
width: 100%;
|
||||||
|
margin: 20px;
|
||||||
|
}
|
||||||
|
.cp-loading-progress p {
|
||||||
|
margin: 5px;
|
||||||
|
overflow: hidden;
|
||||||
|
white-space: nowrap;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
}
|
||||||
|
.cp-loading-progress-bar {
|
||||||
|
height: 24px;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
.cp-loading-progress-bar-value {
|
||||||
|
height: 100%;
|
||||||
|
background: #5cb85c;
|
||||||
|
}
|
||||||
|
*/}).toString().slice(14, -3);
|
||||||
|
var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; });
|
||||||
|
var elem = document.createElement('div');
|
||||||
|
elem.setAttribute('id', 'cp-loading');
|
||||||
|
elem.innerHTML = [
|
||||||
|
'<style>',
|
||||||
|
loadingStyle,
|
||||||
|
'</style>',
|
||||||
|
'<div class="cp-loading-logo">',
|
||||||
|
'<img class="cp-loading-cryptofist" src="/customize/loading-logo.png?' + urlArgs + '">',
|
||||||
|
'</div>',
|
||||||
|
'<div class="cp-loading-container">',
|
||||||
|
'<div class="cp-loading-spinner-container">',
|
||||||
|
'<span class="fa fa-circle-o-notch fa-spin fa-4x fa-fw"></span>',
|
||||||
|
'</div>',
|
||||||
|
'<p id="cp-loading-message"></p>',
|
||||||
|
'</div>'
|
||||||
|
].join('');
|
||||||
|
return function () {
|
||||||
|
var intr;
|
||||||
|
var append = function () {
|
||||||
|
if (!document.body) { return; }
|
||||||
|
clearInterval(intr);
|
||||||
|
document.body.appendChild(elem);
|
||||||
|
};
|
||||||
|
intr = setInterval(append, 100);
|
||||||
|
append();
|
||||||
|
};
|
||||||
|
});
|
||||||
@@ -154,6 +154,7 @@ define([
|
|||||||
proxy.login_name = uname;
|
proxy.login_name = uname;
|
||||||
proxy[Constants.displayNameKey] = uname;
|
proxy[Constants.displayNameKey] = uname;
|
||||||
sessionStorage.createReadme = 1;
|
sessionStorage.createReadme = 1;
|
||||||
|
if (!shouldImport) { proxy.version = 6; }
|
||||||
Feedback.send('REGISTRATION', true);
|
Feedback.send('REGISTRATION', true);
|
||||||
} else {
|
} else {
|
||||||
Feedback.send('LOGIN', true);
|
Feedback.send('LOGIN', true);
|
||||||
@@ -212,6 +213,7 @@ define([
|
|||||||
loadingText: Messages.login_hashing,
|
loadingText: Messages.login_hashing,
|
||||||
hideTips: true,
|
hideTips: true,
|
||||||
});
|
});
|
||||||
|
|
||||||
// We need a setTimeout(cb, 0) otherwise the loading screen is only displayed
|
// We need a setTimeout(cb, 0) otherwise the loading screen is only displayed
|
||||||
// after hashing the password
|
// after hashing the password
|
||||||
window.setTimeout(function () {
|
window.setTimeout(function () {
|
||||||
@@ -256,7 +258,10 @@ define([
|
|||||||
// logMeIn should reset registering = false
|
// logMeIn should reset registering = false
|
||||||
UI.removeLoadingScreen(function () {
|
UI.removeLoadingScreen(function () {
|
||||||
UI.confirm(Messages.register_alreadyRegistered, function (yes) {
|
UI.confirm(Messages.register_alreadyRegistered, function (yes) {
|
||||||
if (!yes) { return; }
|
if (!yes) {
|
||||||
|
hashing = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
proxy.login_name = uname;
|
proxy.login_name = uname;
|
||||||
|
|
||||||
if (!proxy[Constants.displayNameKey]) {
|
if (!proxy[Constants.displayNameKey]) {
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ define([
|
|||||||
])
|
])
|
||||||
])
|
])
|
||||||
]),
|
]),
|
||||||
h('div.cp-version-footer', "CryptPad v1.28.0 (toString)")
|
h('div.cp-version-footer', "CryptPad v2.0.0 (Alpaca)")
|
||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -93,16 +93,25 @@ define([
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var button = h('button.navbar-toggler', {
|
||||||
|
'type':'button',
|
||||||
|
/*'data-toggle':'collapse',
|
||||||
|
'data-target':'#menuCollapse',
|
||||||
|
'aria-controls': 'menuCollapse',
|
||||||
|
'aria-expanded':'false',
|
||||||
|
'aria-label':'Toggle navigation'*/
|
||||||
|
}, h('i.fa.fa-bars '));
|
||||||
|
|
||||||
|
$(button).click(function () {
|
||||||
|
if ($('#menuCollapse').is(':visible')) {
|
||||||
|
return void $('#menuCollapse').slideUp();
|
||||||
|
}
|
||||||
|
$('#menuCollapse').slideDown();
|
||||||
|
});
|
||||||
|
|
||||||
return h('nav.navbar.navbar-expand-lg',
|
return h('nav.navbar.navbar-expand-lg',
|
||||||
h('a.navbar-brand', { href: '/index.html'}),
|
h('a.navbar-brand', { href: '/index.html'}),
|
||||||
h('button.navbar-toggler', {
|
button,
|
||||||
'type':'button',
|
|
||||||
'data-toggle':'collapse',
|
|
||||||
'data-target':'#menuCollapse',
|
|
||||||
'aria-controls': 'menuCollapse',
|
|
||||||
'aria-expanded':'false',
|
|
||||||
'aria-label':'Toggle navigation'
|
|
||||||
}, h('i.fa.fa-bars ')),
|
|
||||||
h('div.collapse.navbar-collapse.justify-content-end#menuCollapse', [
|
h('div.collapse.navbar-collapse.justify-content-end#menuCollapse', [
|
||||||
//h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.topbar_whatIsCryptpad), // Moved the FAQ
|
//h('a.nav-item.nav-link', { href: '/what-is-cryptpad.html'}, Msg.topbar_whatIsCryptpad), // Moved the FAQ
|
||||||
h('a.nav-item.nav-link', { href: '/faq.html'}, Msg.faq_link),
|
h('a.nav-item.nav-link', { href: '/faq.html'}, Msg.faq_link),
|
||||||
@@ -619,23 +628,87 @@ define([
|
|||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
var loadingScreen = Pages.loadingScreen = function () {
|
Pages.createCheckbox = function (id, labelTxt, checked, opts) {
|
||||||
return h('div#cp-loading',
|
opts = opts|| {};
|
||||||
h('div.cp-loading-container', [
|
// Input properties
|
||||||
h('img.cp-loading-cryptofist', {
|
var inputOpts = {
|
||||||
src: '/customize/cryptpad-new-logo-colors-logoonly.png?' + urlArgs
|
type: 'checkbox',
|
||||||
}),
|
id: id
|
||||||
h('div.cp-loading-spinner-container',
|
};
|
||||||
h('span.fa.fa-circle-o-notch.fa-spin.fa-4x.fa-fw')),
|
if (checked) { inputOpts.checked = 'checked'; }
|
||||||
h('p'),
|
$.extend(inputOpts, opts.input || {});
|
||||||
])
|
|
||||||
);
|
// Label properties
|
||||||
|
var labelOpts = {};
|
||||||
|
$.extend(labelOpts, opts.label || {});
|
||||||
|
if (labelOpts.class) { labelOpts.class += ' cp-checkmark'; }
|
||||||
|
|
||||||
|
// Mark properties
|
||||||
|
var markOpts = { tabindex: 0 };
|
||||||
|
$.extend(markOpts, opts.mark || {});
|
||||||
|
|
||||||
|
var input = h('input', inputOpts);
|
||||||
|
var mark = h('span.cp-checkmark-mark', markOpts);
|
||||||
|
var label = h('span.cp-checkmark-label', labelTxt);
|
||||||
|
|
||||||
|
$(mark).keydown(function (e) {
|
||||||
|
if (e.which === 32) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
$(input).prop('checked', !$(input).is(':checked'));
|
||||||
|
$(input).change();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(input).change(function () { $(mark).focus(); });
|
||||||
|
|
||||||
|
return h('label.cp-checkmark', labelOpts, [
|
||||||
|
input,
|
||||||
|
mark,
|
||||||
|
label
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
var hiddenLoader = function () {
|
Pages.createRadio = function (name, id, labelTxt, checked, opts) {
|
||||||
var loader = loadingScreen();
|
opts = opts|| {};
|
||||||
loader.style.display = 'none';
|
// Input properties
|
||||||
return loader;
|
var inputOpts = {
|
||||||
|
type: 'radio',
|
||||||
|
id: id,
|
||||||
|
name: name
|
||||||
|
};
|
||||||
|
if (checked) { inputOpts.checked = 'checked'; }
|
||||||
|
$.extend(inputOpts, opts.input || {});
|
||||||
|
|
||||||
|
// Label properties
|
||||||
|
var labelOpts = {};
|
||||||
|
$.extend(labelOpts, opts.label || {});
|
||||||
|
if (labelOpts.class) { labelOpts.class += ' cp-checkmark'; }
|
||||||
|
|
||||||
|
// Mark properties
|
||||||
|
var markOpts = { tabindex: 0 };
|
||||||
|
$.extend(markOpts, opts.mark || {});
|
||||||
|
|
||||||
|
var input = h('input', inputOpts);
|
||||||
|
var mark = h('span.cp-radio-mark', markOpts);
|
||||||
|
var label = h('span.cp-checkmark-label', labelTxt);
|
||||||
|
|
||||||
|
$(mark).keydown(function (e) {
|
||||||
|
if (e.which === 32) {
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
$(input).prop('checked', !$(input).is(':checked'));
|
||||||
|
$(input).change();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
$(input).change(function () { $(mark).focus(); });
|
||||||
|
|
||||||
|
return h('label.cp-radio', labelOpts, [
|
||||||
|
input,
|
||||||
|
mark,
|
||||||
|
label
|
||||||
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
Pages['/user/'] = Pages['/user/index.html'] = function () {
|
Pages['/user/'] = Pages['/user/index.html'] = function () {
|
||||||
@@ -681,27 +754,10 @@ define([
|
|||||||
placeholder: Msg.login_confirm,
|
placeholder: Msg.login_confirm,
|
||||||
}),
|
}),
|
||||||
h('div.checkbox-container', [
|
h('div.checkbox-container', [
|
||||||
h('input#import-recent', {
|
Pages.createCheckbox('import-recent', Msg.register_importRecent, true)
|
||||||
name: 'import-recent',
|
|
||||||
type: 'checkbox',
|
|
||||||
checked: true
|
|
||||||
}),
|
|
||||||
// hscript doesn't generate for on label for some
|
|
||||||
// reason... use jquery as a temporary fallback
|
|
||||||
setHTML($('<label for="import-recent"></label>')[0], Msg.register_importRecent)
|
|
||||||
/*h('label', {
|
|
||||||
'for': 'import-recent',
|
|
||||||
}, Msg.register_importRecent),*/
|
|
||||||
]),
|
]),
|
||||||
h('div.checkbox-container', [
|
h('div.checkbox-container', [
|
||||||
h('input#accept-terms', {
|
$(Pages.createCheckbox('accept-terms')).find('.cp-checkmark-label').append(Msg.register_acceptTerms).parent()[0]
|
||||||
name: 'accept-terms',
|
|
||||||
type: 'checkbox'
|
|
||||||
}),
|
|
||||||
setHTML($('<label for="accept-terms"></label>')[0], Msg.register_acceptTerms)
|
|
||||||
/*setHTML(h('label', {
|
|
||||||
'for': 'accept-terms',
|
|
||||||
}), Msg.register_acceptTerms),*/
|
|
||||||
]),
|
]),
|
||||||
h('button#register.btn.cp-login-register', Msg.login_register)
|
h('button#register.btn.cp-login-register', Msg.login_register)
|
||||||
])
|
])
|
||||||
@@ -716,7 +772,6 @@ define([
|
|||||||
]),
|
]),
|
||||||
|
|
||||||
infopageFooter(),
|
infopageFooter(),
|
||||||
hiddenLoader(),
|
|
||||||
])];
|
])];
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -743,17 +798,7 @@ define([
|
|||||||
placeholder: Msg.login_password,
|
placeholder: Msg.login_password,
|
||||||
}),
|
}),
|
||||||
h('div.checkbox-container', [
|
h('div.checkbox-container', [
|
||||||
h('input#import-recent', {
|
Pages.createCheckbox('import-recent', Msg.register_importRecent, true),
|
||||||
name: 'import-recent',
|
|
||||||
type: 'checkbox',
|
|
||||||
checked: true
|
|
||||||
}),
|
|
||||||
// hscript doesn't generate for on label for some
|
|
||||||
// reason... use jquery as a temporary fallback
|
|
||||||
setHTML($('<label for="import-recent"></label>')[0], Msg.register_importRecent)
|
|
||||||
/*h('label', {
|
|
||||||
'for': 'import-recent',
|
|
||||||
}, Msg.register_importRecent),*/
|
|
||||||
]),
|
]),
|
||||||
h('div.extra', [
|
h('div.extra', [
|
||||||
h('button.login.first.btn', Msg.login_login)
|
h('button.login.first.btn', Msg.login_login)
|
||||||
@@ -762,7 +807,6 @@ define([
|
|||||||
]),
|
]),
|
||||||
]),
|
]),
|
||||||
infopageFooter(),
|
infopageFooter(),
|
||||||
hiddenLoader(),
|
|
||||||
])];
|
])];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -12,14 +12,11 @@
|
|||||||
|
|
||||||
@alertify-btn-fg: @alertify-fore;
|
@alertify-btn-fg: @alertify-fore;
|
||||||
|
|
||||||
@alertify-btn-bg: rgba(200, 200, 200, 0.1);
|
|
||||||
@alertify-btn-bg-hover: rgba(200, 200, 200, .3);
|
|
||||||
|
|
||||||
@alertify-bg: @colortheme_modal-dim;
|
@alertify-bg: @colortheme_modal-dim;
|
||||||
@alertify-fg: @alertify-fore;
|
@alertify-fg: @alertify-fore;
|
||||||
|
|
||||||
@alertify-input-bg: @colortheme_modal-input;
|
@alertify-input-bg: @colortheme_modal-input;
|
||||||
@alertify-input-fg: @colortheme_modal-fg;
|
@alertify-input-fg: @colortheme_modal-input-fg;
|
||||||
|
|
||||||
@alertify_padding-base: @variables_padding;
|
@alertify_padding-base: @variables_padding;
|
||||||
@alertify_box-shadow: @variables_shadow;
|
@alertify_box-shadow: @variables_shadow;
|
||||||
@@ -34,7 +31,7 @@
|
|||||||
}
|
}
|
||||||
> * {
|
> * {
|
||||||
padding: @alertify_padding-base @alertify_padding-base * 4;
|
padding: @alertify_padding-base @alertify_padding-base * 4;
|
||||||
color: @alertify-fore;
|
color: @colortheme_notification-color;
|
||||||
|
|
||||||
font-family: @colortheme_font;
|
font-family: @colortheme_font;
|
||||||
font-size: large;
|
font-size: large;
|
||||||
@@ -65,6 +62,8 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
z-index: 100000; // alertify container
|
z-index: 100000; // alertify container
|
||||||
|
font: @colortheme_app-font;
|
||||||
|
|
||||||
&.forefront {
|
&.forefront {
|
||||||
z-index: @max-z-index; // alertify max forefront
|
z-index: @max-z-index; // alertify max forefront
|
||||||
}
|
}
|
||||||
@@ -112,10 +111,6 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
.dialog, .alert {
|
.dialog, .alert {
|
||||||
.bright {
|
|
||||||
color: @colortheme_light-base;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
background-color: @alertify-dialog-bg;
|
background-color: @alertify-dialog-bg;
|
||||||
&.half {
|
&.half {
|
||||||
@@ -227,7 +222,7 @@
|
|||||||
|
|
||||||
button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button) {
|
button:not(.btn):not(.pure-button):not(.md-button):not(.mdl-button) {
|
||||||
|
|
||||||
background-color: @alertify-btn-bg;
|
background-color: @colortheme_alertify-cancel;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
@@ -247,7 +242,7 @@
|
|||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
color: @alertify-btn-fg;
|
color: @alertify-btn-fg;
|
||||||
border: 1px solid transparent;
|
border: 1px solid @colortheme_alertify-cancel-border;
|
||||||
|
|
||||||
&.safe, &.danger {
|
&.safe, &.danger {
|
||||||
color: @colortheme_old-base;
|
color: @colortheme_old-base;
|
||||||
@@ -256,32 +251,40 @@
|
|||||||
}
|
}
|
||||||
&.danger {
|
&.danger {
|
||||||
background-color: @colortheme_alertify-red;
|
background-color: @colortheme_alertify-red;
|
||||||
|
border-color: @colortheme_alertify-red-border;
|
||||||
|
color: @colortheme_alertify-red-color;
|
||||||
&:hover, &:active {
|
&:hover, &:active {
|
||||||
background-color: lighten(@colortheme_alertify-red, 5%);
|
background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-red, 10%), lighten(@colortheme_alertify-red, 10%));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.safe {
|
&.safe {
|
||||||
background-color: @colortheme_alertify-green;
|
background-color: @colortheme_alertify-green;
|
||||||
|
border-color: @colortheme_alertify-green-border;
|
||||||
|
color: @colortheme_alertify-green-color;
|
||||||
&:hover, &:active {
|
&:hover, &:active {
|
||||||
background-color: lighten(@colortheme_alertify-green, 10%);
|
background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-green, 10%), lighten(@colortheme_alertify-green, 10%));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&.primary {
|
&.primary {
|
||||||
background-color: @colortheme_alertify-primary;
|
background-color: @colortheme_alertify-primary;
|
||||||
color: @colortheme_alertify-primary-text;
|
color: @colortheme_alertify-primary-text;
|
||||||
|
border-color: @colortheme_alertify-primary-border;
|
||||||
|
font-weight: bold;
|
||||||
&:hover, &:active {
|
&:hover, &:active {
|
||||||
background-color: darken(@colortheme_alertify-primary, 10%);
|
background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-primary, 10%), lighten(@colortheme_alertify-primary, 10%));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:hover, &:active {
|
&:hover, &:active {
|
||||||
background-color: @alertify-btn-bg-hover;
|
background-color: contrast(@colortheme_modal-bg, darken(@colortheme_alertify-cancel, 10%), lighten(@colortheme_alertify-cancel, 10%));
|
||||||
}
|
}
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
border: 1px dotted @alertify-base;
|
//border: 1px dotted @alertify-base;
|
||||||
|
box-shadow: 0px 0px 5px @colortheme_alertify-primary;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
&::-moz-focus-inner {
|
&::-moz-focus-inner {
|
||||||
border: 0;
|
border: 0;
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
border: 0;
|
||||||
body {
|
body {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -15,6 +16,7 @@
|
|||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
position: relative;
|
position: relative;
|
||||||
|
border: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,7 @@
|
|||||||
@width: round(@size / 8);
|
@width: round(@size / 8);
|
||||||
@dim1: round(@size / 3);
|
@dim1: round(@size / 3);
|
||||||
@dim2: round(2 * @size / 3);
|
@dim2: round(2 * @size / 3);
|
||||||
@top: round(@size / 12);
|
@top: round(@size / 12) - 1;
|
||||||
// <label.cp-checkmark><input><span.cp-checkmark-mark></span>Text</label>
|
// <label.cp-checkmark><input><span.cp-checkmark-mark></span>Text</label>
|
||||||
.cp-checkmark {
|
.cp-checkmark {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@@ -17,6 +17,10 @@
|
|||||||
-ms-user-select: none;
|
-ms-user-select: none;
|
||||||
user-select: none;
|
user-select: none;
|
||||||
|
|
||||||
|
& > a {
|
||||||
|
margin-left: 0.25em;
|
||||||
|
}
|
||||||
|
|
||||||
&.cp-checkmark-secondary {
|
&.cp-checkmark-secondary {
|
||||||
.cp-checkmark-mark {
|
.cp-checkmark-mark {
|
||||||
&:after {
|
&:after {
|
||||||
@@ -26,6 +30,7 @@
|
|||||||
input {
|
input {
|
||||||
&:checked ~ .cp-checkmark-mark {
|
&:checked ~ .cp-checkmark-mark {
|
||||||
background-color: @colortheme_checkmark-back2;
|
background-color: @colortheme_checkmark-back2;
|
||||||
|
border-color: @colortheme_checkmark-back2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -37,12 +42,19 @@
|
|||||||
display: none;
|
display: none;
|
||||||
&:checked ~ .cp-checkmark-mark {
|
&:checked ~ .cp-checkmark-mark {
|
||||||
background-color: @colortheme_checkmark-back1;
|
background-color: @colortheme_checkmark-back1;
|
||||||
|
border-color: @colortheme_checkmark-back1;
|
||||||
&:after {
|
&:after {
|
||||||
display: block;
|
display: block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cp-checkmark-label {
|
||||||
|
cursor: default;
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
.cp-checkmark-mark {
|
.cp-checkmark-mark {
|
||||||
margin-right: 10px;
|
margin-right: 10px;
|
||||||
position: relative;
|
position: relative;
|
||||||
@@ -51,6 +63,8 @@
|
|||||||
background-color: @colortheme_checkmark-back0;
|
background-color: @colortheme_checkmark-back0;
|
||||||
display: flex;
|
display: flex;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
border: 1px solid @colortheme_form-border;
|
||||||
|
flex-shrink: 0;
|
||||||
&:after {
|
&:after {
|
||||||
content: "";
|
content: "";
|
||||||
display: none;
|
display: none;
|
||||||
@@ -60,6 +74,90 @@
|
|||||||
transform: rotate(45deg);
|
transform: rotate(45deg);
|
||||||
border: solid @colortheme_checkmark-col1;
|
border: solid @colortheme_checkmark-col1;
|
||||||
border-width: 0 @width @width 0;
|
border-width: 0 @width @width 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
//border-color: #FF007C !important;
|
||||||
|
box-shadow: 0px 0px 5px @colortheme_checkmark-back1;
|
||||||
|
outline: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-radio {
|
||||||
|
margin: 0;
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
position: relative;
|
||||||
|
-webkit-user-select: none;
|
||||||
|
-moz-user-select: none;
|
||||||
|
-ms-user-select: none;
|
||||||
|
user-select: none;
|
||||||
|
|
||||||
|
&.cp-radio-secondary {
|
||||||
|
.cp-radio-mark {
|
||||||
|
&:after {
|
||||||
|
border-color: @colortheme_checkmark-col2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
input {
|
||||||
|
&:checked ~ .cp-radio-mark {
|
||||||
|
background-color: @colortheme_checkmark-back2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&:hover .cp-radio-mark {
|
||||||
|
background-color: @colortheme_checkmark-back0-active;
|
||||||
|
}
|
||||||
|
|
||||||
|
input {
|
||||||
|
display: none;
|
||||||
|
&:checked ~ .cp-radio-mark {
|
||||||
|
background-color: @colortheme_checkmark-back1;
|
||||||
|
border-color: @colortheme_checkmark-back1;
|
||||||
|
&:after {
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-checkmark-label {
|
||||||
|
cursor: default;
|
||||||
|
&:empty {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@radio-size: @dim1 * 3;
|
||||||
|
.cp-radio-mark {
|
||||||
|
margin-right: 10px;
|
||||||
|
position: relative;
|
||||||
|
height: @radio-size;
|
||||||
|
width: @radio-size;
|
||||||
|
background-color: @colortheme_checkmark-back0;
|
||||||
|
border-radius: 50%;
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
border: 1px solid @colortheme_form-border;
|
||||||
|
flex-shrink: 0;
|
||||||
|
&:after {
|
||||||
|
display: none;
|
||||||
|
content: "";
|
||||||
|
border-radius: 50%;
|
||||||
|
background: white;
|
||||||
|
width: @dim1;
|
||||||
|
height: @dim1;
|
||||||
|
|
||||||
|
//transform: rotate(45deg);
|
||||||
|
//border: solid @colortheme_checkmark-col1;
|
||||||
|
//border-width: 0 @width @width 0;
|
||||||
|
}
|
||||||
|
&:focus {
|
||||||
|
//border-color: #FF007C !important;
|
||||||
|
box-shadow: 0px 0px 5px @colortheme_checkmark-back1;
|
||||||
|
outline: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
@colortheme_app-font-size: 16px;
|
@colortheme_app-font-size: 16px;
|
||||||
@colortheme_app-font: @colortheme_app-font-size @colortheme_font;
|
@colortheme_app-font: @colortheme_app-font-size @colortheme_font;
|
||||||
|
|
||||||
|
@colortheme_logo-1: #326599;
|
||||||
|
@colortheme_logo-2: #4591c4;
|
||||||
|
|
||||||
@colortheme_link-color: #0275D8;
|
@colortheme_link-color: #0275D8;
|
||||||
@colortheme_link-color-visited: #005999;
|
@colortheme_link-color-visited: #005999;
|
||||||
@colortheme_info-background: #fafafa;
|
@colortheme_info-background: #fafafa;
|
||||||
@@ -15,23 +18,42 @@
|
|||||||
@colortheme_cp-red: #FA5858; // remove red
|
@colortheme_cp-red: #FA5858; // remove red
|
||||||
@colortheme_cp-green: #46E981;
|
@colortheme_cp-green: #46E981;
|
||||||
|
|
||||||
@colortheme_modal-bg: #222;
|
@colortheme_form-border: #bbbbbb;
|
||||||
@colortheme_modal-fg: #fff;
|
@colortheme_form-bg: @colortheme_logo-2;
|
||||||
@colortheme_modal-link: #eee;
|
@colortheme_form-color: #ffffff;
|
||||||
@colortheme_modal-link-visited: lighten(@colortheme_modal-link, 10%);
|
@colortheme_form-bg-alt: #ffffff;
|
||||||
@colortheme_modal-dim: rgba(0, 0, 0, 0.4);
|
@colortheme_form-color-alt: @colortheme_logo-1;
|
||||||
|
@colortheme_form-warning: #f49842;
|
||||||
|
@colortheme_form-warning-hov: darken(@colortheme_form-warning, 5%);
|
||||||
|
|
||||||
@colortheme_loading-bg: #222;
|
@colortheme_modal-bg: @colortheme_form-bg-alt; // TODO Modals bg
|
||||||
|
@colortheme_modal-fg: @colortheme_form-color-alt;
|
||||||
|
@colortheme_modal-link: @colortheme_link-color;
|
||||||
|
@colortheme_modal-link-visited: lighten(@colortheme_modal-link, 10%);
|
||||||
|
@colortheme_modal-dim: fade(@colortheme_logo-2, 50%); // TODO transparent background behind modals
|
||||||
|
@colortheme_modal-input: @colortheme_form-bg;
|
||||||
|
@colortheme_modal-input-fg: @colortheme_form-color;
|
||||||
|
|
||||||
|
@colortheme_loading-bg: @colortheme_logo-1;
|
||||||
|
@colortheme_loading-bg-alt: @colortheme_logo-2;
|
||||||
@colortheme_loading-color: @colortheme_old-fore;
|
@colortheme_loading-color: @colortheme_old-fore;
|
||||||
|
|
||||||
@colortheme_modal-input: #111;
|
|
||||||
|
|
||||||
|
// TODO modals buttons
|
||||||
@colortheme_alertify-red: #E55236;
|
@colortheme_alertify-red: #E55236;
|
||||||
|
@colortheme_alertify-red-color: #FFF;
|
||||||
|
@colortheme_alertify-red-border: transparent;
|
||||||
@colortheme_alertify-green: #77C825;
|
@colortheme_alertify-green: #77C825;
|
||||||
@colortheme_alertify-primary: #fff;
|
@colortheme_alertify-green-color: #FFF;
|
||||||
@colortheme_alertify-primary-text: #000;
|
@colortheme_alertify-green-border: transparent;
|
||||||
|
@colortheme_alertify-primary: @colortheme_form-bg;
|
||||||
|
@colortheme_alertify-primary-text: @colortheme_form-color;
|
||||||
|
@colortheme_alertify-primary-border: transparent;
|
||||||
|
@colortheme_alertify-cancel: @colortheme_modal-bg;
|
||||||
|
@colortheme_alertify-cancel-border: #ccc;
|
||||||
|
|
||||||
@colortheme_notification-log: rgba(0, 0, 0, 0.8);
|
@colortheme_notification-log: fade(@colortheme_logo-1, 90%);
|
||||||
|
@colortheme_notification-color: #fff;;
|
||||||
@colortheme_notification-warn: rgba(205, 37, 50, 0.8);
|
@colortheme_notification-warn: rgba(205, 37, 50, 0.8);
|
||||||
|
|
||||||
@colortheme_dropdown-bg: #f9f9f9;
|
@colortheme_dropdown-bg: #f9f9f9;
|
||||||
@@ -117,9 +139,9 @@
|
|||||||
@cryptpad_header_col: #1E1F1F;
|
@cryptpad_header_col: #1E1F1F;
|
||||||
@cryptpad_text_col: #3F4141;
|
@cryptpad_text_col: #3F4141;
|
||||||
|
|
||||||
@colortheme_checkmark-back0: #ffffff;
|
@colortheme_checkmark-back0: @colortheme_form-bg-alt;
|
||||||
@colortheme_checkmark-back0-active: #bbbbbb;
|
@colortheme_checkmark-back0-active: @colortheme_form-border;
|
||||||
@colortheme_checkmark-back1: #FF0073;
|
@colortheme_checkmark-back1: @colortheme_form-bg;
|
||||||
@colortheme_checkmark-col1: #ffffff;
|
@colortheme_checkmark-col1: @colortheme_form-color;
|
||||||
@colortheme_checkmark-back2: #FFFFFF;
|
@colortheme_checkmark-back2: @colortheme_form-bg-alt;
|
||||||
@colortheme_checkmark-col2: #000000;
|
@colortheme_checkmark-col2: @colortheme_form-color-alt;
|
||||||
|
|||||||
@@ -1,47 +1,78 @@
|
|||||||
@import (once) "./colortheme-all.less";
|
@import (once) "./colortheme-all.less";
|
||||||
@import (once) "./tools.less";
|
@import (once) "./tools.less";
|
||||||
@import (once) "./checkmark.less";
|
|
||||||
@import (once) './icon-colors.less';
|
@import (once) './icon-colors.less';
|
||||||
|
|
||||||
.creation_main() {
|
.creation_main(
|
||||||
.tippy-popper {
|
@color: @colortheme_default-color, // Color of the text for the toolbar
|
||||||
z-index: 100000001 !important;
|
@bg-color: @colortheme_default-bg, // color of the toolbar background
|
||||||
}
|
@warn-color: @colortheme_default-warn, // color of the warning text in the toolbar
|
||||||
|
) {
|
||||||
|
@colortheme_creation-modal-bg: #fff;
|
||||||
|
@colortheme_creation-modal: #666;
|
||||||
|
@colortheme_creation-modal-title: @colortheme_loading-bg;
|
||||||
|
|
||||||
#cp-creation-container {
|
#cp-creation-container {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 100000000; // #loading * 10
|
z-index: 100000000; // #loading * 10
|
||||||
top: 0px;
|
top: 0px;
|
||||||
background: @colortheme_loading-bg;
|
//background: @colortheme_loading-bg;
|
||||||
|
background: linear-gradient(to right, @colortheme_loading-bg 0%, @colortheme_loading-bg 50%, @colortheme_loading-bg-alt 50%, @colortheme_loading-bg-alt 100%);
|
||||||
color: @colortheme_loading-color;
|
color: @colortheme_loading-color;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column; /* we need column so that the child can shrink vertically */
|
flex-flow: column; /* we need column so that the child can shrink vertically */
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
|
.cp-creation-logo {
|
||||||
|
height: 300px;
|
||||||
|
width: 300px;
|
||||||
|
margin-top: 50px;
|
||||||
|
flex: 0 1 auto; /* allows shrink */
|
||||||
|
min-height: 0;
|
||||||
|
text-align: center;
|
||||||
|
img {
|
||||||
|
max-width: 100%;
|
||||||
|
max-height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#cp-creation {
|
#cp-creation {
|
||||||
flex: 0 1 auto; /* allows shrink */
|
|
||||||
min-height: 0;
|
|
||||||
overflow: auto;
|
overflow: auto;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
|
background: @colortheme_creation-modal-bg;
|
||||||
|
color: @colortheme_creation-modal;
|
||||||
font: @colortheme_app-font;
|
font: @colortheme_app-font;
|
||||||
width: 100%;
|
|
||||||
outline: none;
|
outline: none;
|
||||||
|
width: 700px;
|
||||||
|
max-width: 90vw;
|
||||||
|
height: 500px;
|
||||||
|
max-height: calc(~"100vh - 20px");
|
||||||
|
margin: 50px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
|
||||||
& > div {
|
& > div {
|
||||||
width: 60vw;
|
width: 100%;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
margin: 40px auto;
|
margin: auto;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
}
|
}
|
||||||
|
|
||||||
.cp-creation-create, .cp-creation-settings {
|
.cp-creation-title {
|
||||||
|
color: @colortheme_creation-modal-title;
|
||||||
|
font-weight: bold;
|
||||||
|
margin: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cp-creation-create {
|
||||||
margin-top: 0px;
|
margin-top: 0px;
|
||||||
@creation-button: #30B239;
|
|
||||||
button {
|
button {
|
||||||
.tools_unselectable();
|
.tools_unselectable();
|
||||||
padding: 15px;
|
padding: 15px;
|
||||||
background: @creation-button;
|
background: linear-gradient(to right, @colortheme_logo-2, @colortheme_logo-1);
|
||||||
color: #FFF;
|
color: #FFF;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
margin: 3px 10px;
|
margin: 3px 10px;
|
||||||
@@ -50,15 +81,16 @@
|
|||||||
outline: none;
|
outline: none;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
&:hover {
|
&:hover {
|
||||||
|
background: linear-gradient(to right, lighten(@colortheme_logo-2, 5%), lighten(@colortheme_logo-1, 5%));
|
||||||
//background: darken(@creation-button, 5%);
|
//background: darken(@creation-button, 5%);
|
||||||
background: lighten(@creation-button, 5%);
|
//background: lighten(@creation-button, 5%);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-creation-create {
|
.cp-creation-create {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin: auto;
|
//margin: auto;
|
||||||
margin-top: 20px;
|
//margin-top: 20px;
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
button {
|
button {
|
||||||
@@ -70,6 +102,8 @@
|
|||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
|
flex: 1 0 auto;
|
||||||
|
justify-content: space-evenly;
|
||||||
& > div {
|
& > div {
|
||||||
width: 400px;
|
width: 400px;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
@@ -77,7 +111,9 @@
|
|||||||
align-items: center;
|
align-items: center;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
font-size: 16px;
|
font-size: 16px;
|
||||||
margin: 10px 0;
|
//margin: 10px 0;
|
||||||
|
min-height: 28px;
|
||||||
|
line-height: 28px;
|
||||||
label {
|
label {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
@@ -88,31 +124,68 @@
|
|||||||
padding: 0 10px;
|
padding: 0 10px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-creation-help {
|
}
|
||||||
font-size: 18px;
|
.cp-creation-help, .cp-creation-warning {
|
||||||
color: white;
|
font-size: 18px;
|
||||||
&:hover {
|
color: @colortheme_form-warning;
|
||||||
color: #AAA;
|
&:hover {
|
||||||
text-decoration: none;
|
color: @colortheme_form-warning-hov;
|
||||||
}
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-creation-slider {
|
.cp-creation-slider {
|
||||||
display: block;
|
display: block;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
max-height: 0px;
|
max-height: 0px;
|
||||||
transition: max-height 0.5s ease-in-out;
|
max-width: 0px;
|
||||||
width: 100%;
|
//margin-top: 10px;
|
||||||
margin-top: 10px;
|
|
||||||
&.active {
|
&.active {
|
||||||
max-height: 40px;
|
transition: max-height 0.5s ease-in-out;
|
||||||
|
max-width: unset;
|
||||||
|
max-height: 100px;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
input, select {
|
||||||
|
font-size: 14px;
|
||||||
|
border: 1px solid @colortheme_form-border;
|
||||||
|
height: 26px;
|
||||||
|
background-color: @colortheme_form-bg;
|
||||||
|
color: @colortheme_form-color;
|
||||||
|
}
|
||||||
|
|
||||||
.cp-creation-expire {
|
.cp-creation-expire {
|
||||||
.cp-creation-expire-picker {
|
.cp-creation-expire-picker {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
input {
|
input {
|
||||||
width: 100px;
|
width: 50px;
|
||||||
|
margin: 0 5px;
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
margin-right: 5px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
&.active {
|
||||||
|
label {
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
|
.cp-creation-slider {
|
||||||
|
flex: 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.cp-creation-password {
|
||||||
|
.cp-creation-password-picker {
|
||||||
|
text-align: center;
|
||||||
|
width: 100%;
|
||||||
|
.cp-password-container {
|
||||||
|
input {
|
||||||
|
width: 150px;
|
||||||
|
padding: 0 5px;
|
||||||
|
}
|
||||||
|
label {
|
||||||
|
flex: unset;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -125,31 +198,51 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
div.cp-creation-remember {
|
div.cp-creation-remember {
|
||||||
margin-top: 30px;
|
|
||||||
.cp-creation-remember-help {
|
.cp-creation-remember-help {
|
||||||
font-style: italic;
|
width: 100%;
|
||||||
|
//font-style: italic;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
color: @colortheme_form-bg;
|
||||||
|
line-height: 20px;
|
||||||
|
.fa {
|
||||||
|
margin-right: 10px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
div.cp-creation-template {
|
div.cp-creation-template {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background-color: darken(@colortheme_modal-bg, 3%);
|
//flex: 1 0 auto;
|
||||||
padding: 20px;
|
flex-wrap: nowrap;
|
||||||
margin: 30px 0;
|
.cp-creation-template-more {
|
||||||
.cp-creation-title {
|
font-size: 30px;
|
||||||
padding: 0 0 10px 10px;
|
cursor: pointer;
|
||||||
margin: auto;
|
margin: 0 5px;
|
||||||
|
text-align: center;
|
||||||
|
&:first-child {
|
||||||
|
left: 5px;
|
||||||
|
}
|
||||||
|
&:last-child {
|
||||||
|
right: 5px;
|
||||||
|
}
|
||||||
|
&:hover {
|
||||||
|
color: #888;
|
||||||
|
}
|
||||||
|
&.hidden {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-creation-template-container {
|
.cp-creation-template-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
|
flex: 1;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-wrap: wrap;
|
flex-wrap: wrap;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
overflow-y: auto;
|
//overflow-y: auto;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
.cp-creation-template-element {
|
.cp-creation-template-element {
|
||||||
@darker: darken(@colortheme_modal-fg, 30%);
|
box-shadow: 2px 2px 7px @colortheme_form-border;
|
||||||
|
|
||||||
width: 135px;
|
width: 135px;
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
@@ -162,19 +255,23 @@
|
|||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
background-color: #111;
|
color: black;
|
||||||
color: @darker;
|
|
||||||
border: 1px solid transparent;
|
border: 1px solid transparent;
|
||||||
|
|
||||||
&.cp-creation-template-selected {
|
&.cp-creation-template-selected {
|
||||||
border: 1px solid white;
|
color: @color !important;
|
||||||
background-color: #222;
|
background-color: @bg-color !important;
|
||||||
|
.fa {
|
||||||
|
color: @color;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
transition: all 0.1s;
|
transition: all 0.1s;
|
||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
color: @colortheme_modal-fg;
|
//color: @colortheme_modal-fg;
|
||||||
|
background-color: @colortheme_form-border;
|
||||||
|
box-shadow: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
align-items: center;
|
align-items: center;
|
||||||
@@ -196,6 +293,7 @@
|
|||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
}
|
}
|
||||||
.fa {
|
.fa {
|
||||||
|
color: @bg-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
width: 100px;
|
width: 100px;
|
||||||
height: 100px;
|
height: 100px;
|
||||||
@@ -210,52 +308,78 @@
|
|||||||
.cp-creation-deleted-container {
|
.cp-creation-deleted-container {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
.cp-creation-deleted {
|
.cp-creation-deleted {
|
||||||
background: #111;
|
margin: 0 10px;
|
||||||
|
background: @colortheme_loading-bg;
|
||||||
|
color: @colortheme_loading-color;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-weight: bold;
|
font-weight: bold;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.checkmark_main(30px);
|
@media screen and (max-height: 700px) {
|
||||||
|
#cp-creation-container {
|
||||||
@media screen and (max-width: @browser_media-narrow-screen) {
|
.cp-creation-logo {
|
||||||
& > div {
|
//flex-shrink: 0;
|
||||||
width: 95%;
|
display: none;
|
||||||
margin: 10px auto;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media screen and (max-width: @browser_media-medium-screen) {
|
@media screen and (max-width: 500px) {
|
||||||
#cp-creation-form {
|
#cp-creation {
|
||||||
div.cp-creation-template {
|
#cp-creation-form {
|
||||||
margin: 0;
|
& > div {
|
||||||
padding: 5px;
|
width: 95%;
|
||||||
.cp-creation-template-container {
|
margin: 10px auto;
|
||||||
.cp-creation-template-element {
|
}
|
||||||
flex-flow: row;
|
.cp-creation-expire {
|
||||||
margin: 1px;
|
&.active {
|
||||||
padding: 5px;
|
label {
|
||||||
width: 155px;
|
flex: 1;
|
||||||
img {
|
|
||||||
display: none;
|
|
||||||
}
|
}
|
||||||
.fa {
|
.cp-creation-slider {
|
||||||
font-size: 18px;
|
flex: unset;
|
||||||
width: 20px;
|
order: 10;
|
||||||
height: 20px;
|
width: 100%;
|
||||||
line-height: 20px;
|
}
|
||||||
display: inline !important;
|
}
|
||||||
}
|
}
|
||||||
.cp-creation-template-element-name {
|
}
|
||||||
margin: 0;
|
}
|
||||||
margin-left: 5px;
|
}
|
||||||
|
@media screen and (max-width: @browser_media-medium-screen) {
|
||||||
|
#cp-creation {
|
||||||
|
height: auto;
|
||||||
|
#cp-creation-form {
|
||||||
|
div.cp-creation-template {
|
||||||
|
margin: 0;
|
||||||
|
padding: 5px;
|
||||||
|
.cp-creation-template-container {
|
||||||
|
.cp-creation-template-element {
|
||||||
|
flex-flow: row;
|
||||||
|
margin: 1px;
|
||||||
|
padding: 5px;
|
||||||
|
width: 155px;
|
||||||
|
img {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
.fa {
|
||||||
|
font-size: 18px;
|
||||||
|
width: 20px;
|
||||||
|
height: 20px;
|
||||||
|
line-height: 20px;
|
||||||
|
display: inline !important;
|
||||||
|
}
|
||||||
|
.cp-creation-template-element-name {
|
||||||
|
margin: 0;
|
||||||
|
margin-left: 5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,9 +55,23 @@
|
|||||||
user-select: none;
|
user-select: none;
|
||||||
float: none;
|
float: none;
|
||||||
text-align: left;
|
text-align: left;
|
||||||
font: @dropdown_font;
|
|
||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
&:not(.fa) {
|
||||||
|
font: @dropdown_font;
|
||||||
|
}
|
||||||
|
&.fa {
|
||||||
|
font-size: 18px;
|
||||||
|
&::before {
|
||||||
|
width: 40px;
|
||||||
|
margin-left: -10px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
* {
|
||||||
|
font: @dropdown_font;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.fa {
|
.fa {
|
||||||
width: 20px;
|
width: 20px;
|
||||||
|
|||||||
@@ -1,8 +1,12 @@
|
|||||||
|
@import (once) "./colortheme-all.less";
|
||||||
@import (once) "./toolbar.less";
|
@import (once) "./toolbar.less";
|
||||||
@import (once) './fileupload.less';
|
@import (once) './fileupload.less';
|
||||||
@import (once) './alertify.less';
|
@import (once) './alertify.less';
|
||||||
@import (once) './tokenfield.less';
|
@import (once) './tokenfield.less';
|
||||||
@import (once) './creation.less';
|
@import (once) './creation.less';
|
||||||
|
@import (once) './tippy.less';
|
||||||
|
@import (once) "./checkmark.less";
|
||||||
|
@import (once) "./password-input.less";
|
||||||
|
|
||||||
.framework_main(@bg-color, @warn-color, @color) {
|
.framework_main(@bg-color, @warn-color, @color) {
|
||||||
.toolbar_main(
|
.toolbar_main(
|
||||||
@@ -13,6 +17,33 @@
|
|||||||
.fileupload_main();
|
.fileupload_main();
|
||||||
.alertify_main();
|
.alertify_main();
|
||||||
.tokenfield_main();
|
.tokenfield_main();
|
||||||
.creation_main();
|
.tippy_main();
|
||||||
|
.checkmark_main(20px);
|
||||||
|
.password_main();
|
||||||
|
.creation_main(
|
||||||
|
@bg-color: @bg-color,
|
||||||
|
@warn-color: @warn-color,
|
||||||
|
@color: @color
|
||||||
|
);
|
||||||
|
font: @colortheme_app-font;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.framework_min_main(
|
||||||
|
@color: @colortheme_default-color, // Color of the text for the toolbar
|
||||||
|
@bg-color: @colortheme_default-bg, // color of the toolbar background
|
||||||
|
@warn-color: @colortheme_default-warn, // color of the warning text in the toolbar
|
||||||
|
) {
|
||||||
|
.toolbar_main(
|
||||||
|
@bg-color: @bg-color,
|
||||||
|
@warn-color: @warn-color,
|
||||||
|
@color: @color
|
||||||
|
);
|
||||||
|
.fileupload_main();
|
||||||
|
.alertify_main();
|
||||||
|
.tippy_main();
|
||||||
|
.checkmark_main(20px);
|
||||||
|
.password_main();
|
||||||
|
font: @colortheme_app-font;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,6 @@
|
|||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
padding-top: 5px;
|
padding-top: 5px;
|
||||||
padding-bottom: 5px;
|
padding-bottom: 5px;
|
||||||
border: 1px solid white;
|
|
||||||
|
|
||||||
.cp-icons-name {
|
.cp-icons-name {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
@@ -26,7 +25,7 @@
|
|||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
}
|
}
|
||||||
&.cp-icons-element-selected {
|
&.cp-icons-element-selected {
|
||||||
background-color: white;
|
background-color: rgba(0,0,0,0.2);
|
||||||
color: #666;
|
color: #666;
|
||||||
}
|
}
|
||||||
.fa {
|
.fa {
|
||||||
|
|||||||
@@ -161,6 +161,7 @@
|
|||||||
background-size: contain;
|
background-size: contain;
|
||||||
height: 50px;
|
height: 50px;
|
||||||
width: 250px;
|
width: 250px;
|
||||||
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
a {
|
a {
|
||||||
border: 2px solid transparent;
|
border: 2px solid transparent;
|
||||||
@@ -169,7 +170,8 @@
|
|||||||
.nav-link {
|
.nav-link {
|
||||||
padding: 0.5em 0.7em;
|
padding: 0.5em 0.7em;
|
||||||
&:hover {
|
&:hover {
|
||||||
transform: scale(1.05);
|
font-size: 1.05em;
|
||||||
|
//transform: scale(1.05);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
.cp-register-btn {
|
.cp-register-btn {
|
||||||
@@ -184,9 +186,18 @@
|
|||||||
color: #4591C4;
|
color: #4591C4;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@media (max-width: 991px) {
|
@media (max-width: 1000px) {
|
||||||
#menuCollapse {
|
#menuCollapse {
|
||||||
text-align: right;
|
text-align: right;
|
||||||
|
/* @media (min-width: 576px) {
|
||||||
|
top: 100%;
|
||||||
|
background: rgba(255,255,255,0.8);
|
||||||
|
position: absolute;
|
||||||
|
right: 0px;
|
||||||
|
padding: 0 20px;
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
.navbar-nav a {
|
.navbar-nav a {
|
||||||
text-align: right !important;
|
text-align: right !important;
|
||||||
@@ -194,7 +205,7 @@
|
|||||||
.cp-register-btn {
|
.cp-register-btn {
|
||||||
margin-right: 13px;
|
margin-right: 13px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//footer general styles
|
//footer general styles
|
||||||
|
|||||||
@@ -57,7 +57,7 @@
|
|||||||
|
|
||||||
input {
|
input {
|
||||||
background-color: @colortheme_modal-input;
|
background-color: @colortheme_modal-input;
|
||||||
color: @colortheme_modal-fg;
|
color: @colortheme_modal-input-fg;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 8px 12px;
|
padding: 8px 12px;
|
||||||
margin: 1em;
|
margin: 1em;
|
||||||
|
|||||||
13
customize.dist/src/less2/include/password-input.less
Normal file
13
customize.dist/src/less2/include/password-input.less
Normal file
@@ -0,0 +1,13 @@
|
|||||||
|
.password_main() {
|
||||||
|
.cp-password-container {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
input {
|
||||||
|
flex: 1;
|
||||||
|
min-width: 0;
|
||||||
|
}
|
||||||
|
label, .fa {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -52,6 +52,12 @@
|
|||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
label.noTitle {
|
||||||
|
display: inline-flex;
|
||||||
|
.fa {
|
||||||
|
margin-left: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
margin-bottom: 20px;
|
margin-bottom: 20px;
|
||||||
}
|
}
|
||||||
[type="text"], button {
|
[type="text"], button {
|
||||||
|
|||||||
14
customize.dist/src/less2/include/tippy.less
Normal file
14
customize.dist/src/less2/include/tippy.less
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
@import (once) './colortheme-all.less';
|
||||||
|
|
||||||
|
.tippy_main() {
|
||||||
|
.tippy-tooltip.cryptpad-theme {
|
||||||
|
/* Your styling here. Example: */
|
||||||
|
background-color: white;
|
||||||
|
box-shadow: 2px 2px 10px #000;
|
||||||
|
font-weight: bold;
|
||||||
|
color: #333;
|
||||||
|
[x-circle] {
|
||||||
|
background-color: unset;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,25 +1,31 @@
|
|||||||
@import (once) "./tools.less";
|
@import (once) "./tools.less";
|
||||||
|
|
||||||
.tokenfield_main () {
|
.tokenfield_main () {
|
||||||
|
.ui-autocomplete {
|
||||||
|
z-index: 100001; // alertify + 1
|
||||||
|
}
|
||||||
.tokenfield {
|
.tokenfield {
|
||||||
.tools_unselectable();
|
.tools_unselectable();
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
justify-content: space-evenly;
|
||||||
height: auto;
|
height: auto;
|
||||||
min-height: 34px;
|
min-height: 34px;
|
||||||
padding-bottom: 0px;
|
padding-bottom: 0px;
|
||||||
background-color: unset;
|
background-color: unset;
|
||||||
border: none;
|
border: none;
|
||||||
display: flex;
|
margin: 0 10px;
|
||||||
flex-wrap: wrap;
|
padding: 0;
|
||||||
align-items: center;
|
width: ~"calc(100% - 20px)";
|
||||||
padding: 0 10px;
|
|
||||||
.token {
|
.token {
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
border-radius: 3px;
|
border-radius: 3px;
|
||||||
display: inline-block;
|
display: inline-flex;
|
||||||
|
align-items: center;
|
||||||
border: 1px solid #d9d9d9;
|
border: 1px solid #d9d9d9;
|
||||||
background-color: #ededed;
|
background-color: #ededed;
|
||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
margin: 10px 5px;
|
margin: 2px 0;
|
||||||
height: 24px;
|
height: 24px;
|
||||||
vertical-align: middle;
|
vertical-align: middle;
|
||||||
cursor: default;
|
cursor: default;
|
||||||
@@ -50,7 +56,7 @@
|
|||||||
.close {
|
.close {
|
||||||
font-family: Arial;
|
font-family: Arial;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
line-height: 24px;
|
line-height: 1.49em;
|
||||||
font-size: 1.1em;
|
font-size: 1.1em;
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
float: none;
|
float: none;
|
||||||
@@ -73,6 +79,8 @@
|
|||||||
margin: 0 !important; // Override alertify
|
margin: 0 !important; // Override alertify
|
||||||
box-shadow: none;
|
box-shadow: none;
|
||||||
max-width: 100%;
|
max-width: 100%;
|
||||||
|
width: 100%;
|
||||||
|
min-width: 100% !important;
|
||||||
&:focus {
|
&:focus {
|
||||||
border-color: transparent;
|
border-color: transparent;
|
||||||
outline: 0;
|
outline: 0;
|
||||||
|
|||||||
@@ -183,8 +183,13 @@
|
|||||||
#cp-app-toolbar-creation-dialog.cp-modal-container {
|
#cp-app-toolbar-creation-dialog.cp-modal-container {
|
||||||
.icons_main();
|
.icons_main();
|
||||||
|
|
||||||
li:hover {
|
li {
|
||||||
border: 1px solid white;
|
border: 1px solid @colortheme_modal-fg;
|
||||||
|
&:hover {
|
||||||
|
//border: 1px solid @colortheme_modal-fg;
|
||||||
|
background: @colortheme_modal-fg;
|
||||||
|
color: @colortheme_modal-bg;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
.cp-modal {
|
.cp-modal {
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|||||||
@@ -1,73 +0,0 @@
|
|||||||
/*
|
|
||||||
WARNING: THIS FILE DOES NOTHING
|
|
||||||
It exists only as a proposal of what CSS you should use in loading.js
|
|
||||||
The CSS inside of loading.js is precompiled in order to save 200ish milliseconds to the loading screen.
|
|
||||||
*/
|
|
||||||
@import (once) "./include/colortheme-all.less";
|
|
||||||
@import (once) "./include/browser.less";
|
|
||||||
|
|
||||||
#cp-loading {
|
|
||||||
transition: opacity 0.75s, visibility 0s 0.75s;
|
|
||||||
visibility: visible;
|
|
||||||
opacity: 1;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 10000000; // #loading
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
background: @colortheme_loading-bg;
|
|
||||||
color: @colortheme_loading-color;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.5em;
|
|
||||||
.cp-loading-container {
|
|
||||||
margin-top: 50vh;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
.cp-loading-cryptofist {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
height: 300px;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
@media screen and (max-height: @browser_media-short-screen) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.cp-loading-spinner-container {
|
|
||||||
position: relative;
|
|
||||||
height: 100px;
|
|
||||||
> div {
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.cp-loading-hidden {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#cp-loading-tip {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 10000000; // loading tip
|
|
||||||
top: 80%;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
text-align: center;
|
|
||||||
|
|
||||||
transition: opacity 750ms;
|
|
||||||
transition-delay: 3000ms;
|
|
||||||
@media screen and (max-height: @browser_media-medium-screen) {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
span {
|
|
||||||
background: @colortheme_loading-bg;
|
|
||||||
color: @colortheme_loading-color;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.5em;
|
|
||||||
opacity: 0.7;
|
|
||||||
font-family: @colortheme_font;
|
|
||||||
padding: 15px;
|
|
||||||
max-width: 60%;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@@ -1,11 +1,12 @@
|
|||||||
@import (once) "../include/infopages.less";
|
@import (once) "../include/infopages.less";
|
||||||
@import (once) "../include/colortheme-all.less";
|
@import (once) "../include/colortheme-all.less";
|
||||||
@import (once) "../include/alertify.less";
|
@import (once) "../include/alertify.less";
|
||||||
@import (once) "../loading.less";
|
@import (once) "../include/checkmark.less";
|
||||||
|
|
||||||
.infopages_main();
|
.infopages_main();
|
||||||
.infopages_topbar();
|
.infopages_topbar();
|
||||||
.alertify_main();
|
.alertify_main();
|
||||||
|
.checkmark_main(20px);
|
||||||
|
|
||||||
.form-group {
|
.form-group {
|
||||||
.extra {
|
.extra {
|
||||||
|
|||||||
@@ -1,11 +1,12 @@
|
|||||||
@import (once) "../include/infopages.less";
|
@import (once) "../include/infopages.less";
|
||||||
@import (once) "../include/colortheme-all.less";
|
@import (once) "../include/colortheme-all.less";
|
||||||
@import (once) "../include/alertify.less";
|
@import (once) "../include/alertify.less";
|
||||||
@import (once) "../loading.less";
|
@import (once) "../include/checkmark.less";
|
||||||
|
|
||||||
.infopages_main();
|
.infopages_main();
|
||||||
.infopages_topbar();
|
.infopages_topbar();
|
||||||
.alertify_main();
|
.alertify_main();
|
||||||
|
.checkmark_main(20px);
|
||||||
|
|
||||||
.cp-container {
|
.cp-container {
|
||||||
.form-group {
|
.form-group {
|
||||||
@@ -23,11 +24,7 @@
|
|||||||
}
|
}
|
||||||
margin-top: 16px;
|
margin-top: 16px;
|
||||||
font-size: 1.25em;
|
font-size: 1.25em;
|
||||||
min-width: 30%; // conflict?
|
min-width: 30%;
|
||||||
width: 30%;
|
|
||||||
@media (max-width: 500px) {
|
|
||||||
width: 45%;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
padding-bottom: 3em;
|
padding-bottom: 3em;
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ define([
|
|||||||
'/common/hyperscript.js',
|
'/common/hyperscript.js',
|
||||||
'/customize/pages.js',
|
'/customize/pages.js',
|
||||||
|
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
], function ($, h, Pages) {
|
], function ($, h, Pages) {
|
||||||
$(function () {
|
$(function () {
|
||||||
var $body = $('body');
|
var $body = $('body');
|
||||||
@@ -27,8 +27,7 @@ $(function () {
|
|||||||
window.Tether = function () {};
|
window.Tether = function () {};
|
||||||
require([
|
require([
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css'
|
||||||
'/bower_components/bootstrap/dist/js/bootstrap.bundle.min.js'
|
|
||||||
], function () {
|
], function () {
|
||||||
$body.append($main);
|
$body.append($main);
|
||||||
|
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -31,7 +31,7 @@ define(function () {
|
|||||||
|
|
||||||
out.websocketError = 'Αδυναμία σύνδεσης στον διακομιστή...';
|
out.websocketError = 'Αδυναμία σύνδεσης στον διακομιστή...';
|
||||||
out.typeError = "Αυτό το pad δεν είναι συμβατό με την επιλεγμένη εφαρμογή";
|
out.typeError = "Αυτό το pad δεν είναι συμβατό με την επιλεγμένη εφαρμογή";
|
||||||
out.onLogout = 'Έχετε αποσυνδεθεί, <a href="/" target="_blank">κάντε "κλικ" εδώ</a> για να συνδεθείτε<br>ή πατήστε <em>Escape</em> για να προσπελάσετε το έγγραφο σε λειτουργία ανάγνωσης μόνο.';
|
out.onLogout = 'Έχετε αποσυνδεθεί, {0}κάντε "κλικ" εδώ{1} για να συνδεθείτε<br>ή πατήστε <em>Escape</em> για να προσπελάσετε το έγγραφο σε λειτουργία ανάγνωσης μόνο.';
|
||||||
out.wrongApp = "Αδυναμία προβολής του περιεχομένου αυτής της συνεδρίας στον περιηγητή σας. Παρακαλώ δοκιμάστε επαναφόρτωση της σελίδας.";
|
out.wrongApp = "Αδυναμία προβολής του περιεχομένου αυτής της συνεδρίας στον περιηγητή σας. Παρακαλώ δοκιμάστε επαναφόρτωση της σελίδας.";
|
||||||
|
|
||||||
out.loading = "Φόρτωση...";
|
out.loading = "Φόρτωση...";
|
||||||
|
|||||||
@@ -152,7 +152,7 @@ define(function () {
|
|||||||
|
|
||||||
out.websocketError = "Error al conectarse al servidor WebSocket";
|
out.websocketError = "Error al conectarse al servidor WebSocket";
|
||||||
out.typeError = "Este documento no es compatible con la aplicación seleccionada";
|
out.typeError = "Este documento no es compatible con la aplicación seleccionada";
|
||||||
out.onLogout = "Tu sesión está cerrada, <a href=\"/\" target=\"_blank\">haz clic aquí</a> para iniciar sesión<br>o pulsa <em>Escape</em> para acceder al documento en modo sólo lectura.";
|
out.onLogout = "Tu sesión está cerrada, {0}haz clic aquí{1} para iniciar sesión<br>o pulsa <em>Escape</em> para acceder al documento en modo sólo lectura.";
|
||||||
out.loading = "Cargando...";
|
out.loading = "Cargando...";
|
||||||
out.error = "Error";
|
out.error = "Error";
|
||||||
out.language = "Idioma";
|
out.language = "Idioma";
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ define(function () {
|
|||||||
|
|
||||||
out.websocketError = 'Impossible de se connecter au serveur WebSocket...';
|
out.websocketError = 'Impossible de se connecter au serveur WebSocket...';
|
||||||
out.typeError = "Ce pad n'est pas compatible avec l'application sélectionnée";
|
out.typeError = "Ce pad n'est pas compatible avec l'application sélectionnée";
|
||||||
out.onLogout = 'Vous êtes déconnecté de votre compte utilisateur, <a href="/" target="_blank">cliquez ici</a> pour vous authentifier<br>ou appuyez sur <em>Échap</em> pour accéder au pad en mode lecture seule.';
|
out.onLogout = 'Vous êtes déconnecté de votre compte utilisateur, {0}cliquez ici{1} pour vous authentifier<br>ou appuyez sur <em>Échap</em> pour accéder au pad en mode lecture seule.';
|
||||||
out.wrongApp = "Impossible d'afficher le contenu de ce document temps-réel dans votre navigateur. Vous pouvez essayer de recharger la page.";
|
out.wrongApp = "Impossible d'afficher le contenu de ce document temps-réel dans votre navigateur. Vous pouvez essayer de recharger la page.";
|
||||||
out.padNotPinned = 'Ce pad va expirer après 3 mois d\'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.';
|
out.padNotPinned = 'Ce pad va expirer après 3 mois d\'inactivité, {0}connectez-vous{1} ou {2}enregistrez-vous{3} pour le préserver.';
|
||||||
out.anonymousStoreDisabled = "L'administrateur de cette instance de CryptPad a désactivé le drive pour les utilisateurs non enregistrés. Vous devez vous connecter pour pouvoir utiliser CryptDrive.";
|
out.anonymousStoreDisabled = "L'administrateur de cette instance de CryptPad a désactivé le drive pour les utilisateurs non enregistrés. Vous devez vous connecter pour pouvoir utiliser CryptDrive.";
|
||||||
@@ -37,6 +37,7 @@ define(function () {
|
|||||||
out.chainpadError = 'Une erreur critique est survenue lors de la mise à jour du contenu. Le pad est désormais en mode lecture seule afin de s\'assurer que vous ne perdiez pas davantage de données.<br>' +
|
out.chainpadError = 'Une erreur critique est survenue lors de la mise à jour du contenu. Le pad est désormais en mode lecture seule afin de s\'assurer que vous ne perdiez pas davantage de données.<br>' +
|
||||||
'Appuyez sur <em>Échap</em> pour voir le pad ou rechargez la page pour pouvoir le modifier à nouveau.';
|
'Appuyez sur <em>Échap</em> pour voir le pad ou rechargez la page pour pouvoir le modifier à nouveau.';
|
||||||
out.errorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur <em>Échap</em>.<br> Dés que vous aurez quitté la page, il sera impossible de le récupérer.';
|
out.errorCopy = ' Vous pouvez toujours copier son contenu ailleurs en appuyant sur <em>Échap</em>.<br> Dés que vous aurez quitté la page, il sera impossible de le récupérer.';
|
||||||
|
out.errorRedirectToHome = 'Appuyez sur <em>Échap</em> pour retourner vers votre CryptDrive.';
|
||||||
|
|
||||||
out.loading = "Chargement...";
|
out.loading = "Chargement...";
|
||||||
out.error = "Erreur";
|
out.error = "Erreur";
|
||||||
@@ -145,6 +146,8 @@ define(function () {
|
|||||||
out.useTemplate = "Commencer avec un modèle?";
|
out.useTemplate = "Commencer avec un modèle?";
|
||||||
out.useTemplateOK = 'Choisir un modèle (Entrée)';
|
out.useTemplateOK = 'Choisir un modèle (Entrée)';
|
||||||
out.useTemplateCancel = 'Document vierge (Échap)';
|
out.useTemplateCancel = 'Document vierge (Échap)';
|
||||||
|
out.template_import = "Importer un modèle";
|
||||||
|
out.template_empty = "Aucun modèle disponible";
|
||||||
|
|
||||||
out.previewButtonTitle = "Afficher ou cacher la prévisualisation de Markdown";
|
out.previewButtonTitle = "Afficher ou cacher la prévisualisation de Markdown";
|
||||||
|
|
||||||
@@ -364,6 +367,7 @@ define(function () {
|
|||||||
out.fm_searchName = "Recherche";
|
out.fm_searchName = "Recherche";
|
||||||
out.fm_recentPadsName = "Pads récents";
|
out.fm_recentPadsName = "Pads récents";
|
||||||
out.fm_ownedPadsName = "Pads en votre possession";
|
out.fm_ownedPadsName = "Pads en votre possession";
|
||||||
|
out.fm_tagsName = "Mots-clés";
|
||||||
out.fm_searchPlaceholder = "Rechercher...";
|
out.fm_searchPlaceholder = "Rechercher...";
|
||||||
out.fm_newButton = "Nouveau";
|
out.fm_newButton = "Nouveau";
|
||||||
out.fm_newButtonTitle = "Créer un nouveau pad ou un dossier, importer un fichier dans le dossier courant";
|
out.fm_newButtonTitle = "Créer un nouveau pad ou un dossier, importer un fichier dans le dossier courant";
|
||||||
@@ -426,6 +430,8 @@ define(function () {
|
|||||||
out.fm_padIsOwned = "Vous êtes le propriétaire de ce pad";
|
out.fm_padIsOwned = "Vous êtes le propriétaire de ce pad";
|
||||||
out.fm_padIsOwnedOther = "Ce pad est la propriété d'un autre utilisateur";
|
out.fm_padIsOwnedOther = "Ce pad est la propriété d'un autre utilisateur";
|
||||||
out.fm_deletedPads = "Ces pads n'existent plus sur le serveur, ils ont été supprimés de votre CryptDrive: {0}";
|
out.fm_deletedPads = "Ces pads n'existent plus sur le serveur, ils ont été supprimés de votre CryptDrive: {0}";
|
||||||
|
out.fm_tags_name = "Mot-clé";
|
||||||
|
out.fm_tags_used = "Nombre d'utilisations";
|
||||||
// File - Context menu
|
// File - Context menu
|
||||||
out.fc_newfolder = "Nouveau dossier";
|
out.fc_newfolder = "Nouveau dossier";
|
||||||
out.fc_rename = "Renommer";
|
out.fc_rename = "Renommer";
|
||||||
@@ -546,6 +552,8 @@ define(function () {
|
|||||||
out.settings_deleteHint = "La suppression de votre compte utilisateur est permanente. Votre CryptDrive et votre liste de pads seront supprimés du serveur. Le reste de vos pads sera supprimé après 90 jours d'inactivité si personne ne les a stockés dans leur CryptDrive.";
|
out.settings_deleteHint = "La suppression de votre compte utilisateur est permanente. Votre CryptDrive et votre liste de pads seront supprimés du serveur. Le reste de vos pads sera supprimé après 90 jours d'inactivité si personne ne les a stockés dans leur CryptDrive.";
|
||||||
out.settings_deleteButton = "Supprimer votre compte";
|
out.settings_deleteButton = "Supprimer votre compte";
|
||||||
out.settings_deleteModal = "Veuillez envoyer les informations suivantes à votre administrateur CryptPad afin que vos données soient supprimées du serveur.";
|
out.settings_deleteModal = "Veuillez envoyer les informations suivantes à votre administrateur CryptPad afin que vos données soient supprimées du serveur.";
|
||||||
|
out.settings_deleteConfirm = "Êtes-vous sûr de vouloir supprimer votre compte utilisateur ? Cette action est irréversible.";
|
||||||
|
out.settings_deleted = "Votre compte utilisateur a été supprimé. Appuyez sur OK pour être rédirigé(e) vers la page d'accueil.";
|
||||||
|
|
||||||
out.settings_anonymous = "Vous n'êtes pas connecté. Ces préférences seront utilisées pour ce navigateur.";
|
out.settings_anonymous = "Vous n'êtes pas connecté. Ces préférences seront utilisées pour ce navigateur.";
|
||||||
out.settings_publicSigningKey = "Clé publique de signature";
|
out.settings_publicSigningKey = "Clé publique de signature";
|
||||||
@@ -609,9 +617,6 @@ define(function () {
|
|||||||
out.pad_showToolbar = "Afficher la barre d'outils";
|
out.pad_showToolbar = "Afficher la barre d'outils";
|
||||||
out.pad_hideToolbar = "Cacher la barre d'outils";
|
out.pad_hideToolbar = "Cacher la barre d'outils";
|
||||||
|
|
||||||
// general warnings
|
|
||||||
out.warn_notPinned = "Ce pad n'est stocké dans aucun CryptDrive. Il va expirer après 3 mois d'inactivité. <a href='/about.html#pinning'>En savoir plus...</a>";
|
|
||||||
|
|
||||||
// markdown toolbar
|
// markdown toolbar
|
||||||
out.mdToolbar_button = "Afficher ou cacher la barre d'outils Markdown";
|
out.mdToolbar_button = "Afficher ou cacher la barre d'outils Markdown";
|
||||||
out.mdToolbar_defaultText = "Votre texte ici";
|
out.mdToolbar_defaultText = "Votre texte ici";
|
||||||
@@ -950,8 +955,6 @@ define(function () {
|
|||||||
|
|
||||||
// Header.html
|
// Header.html
|
||||||
|
|
||||||
out.header_france = '<a href="http://www.xwiki.com/fr" target="_blank" rel="noopener noreferrer">Fait avec <img class="bottom-bar-heart" src="/customize/heart.png" alt="amour" /> en <img class="bottom-bar-fr" title="France" alt="France" src="/customize/fr.png" /> par <img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>';
|
|
||||||
out.header_support = '<a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
|
|
||||||
out.updated_0_header_logoTitle = 'Retourner vers votre CryptDrive';
|
out.updated_0_header_logoTitle = 'Retourner vers votre CryptDrive';
|
||||||
out.header_logoTitle = out.updated_0_header_logoTitle;
|
out.header_logoTitle = out.updated_0_header_logoTitle;
|
||||||
out.header_homeTitle = "Aller sur la page d'accueil";
|
out.header_homeTitle = "Aller sur la page d'accueil";
|
||||||
@@ -1051,7 +1054,7 @@ define(function () {
|
|||||||
out.tips = {};
|
out.tips = {};
|
||||||
out.tips.shortcuts = "`ctrl+b`, `ctrl+i` et `ctrl+u` sont des raccourcis rapides pour mettre en gras, en italique ou souligner.";
|
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.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.store = "Dès que vous ouvrez un nouveau pad, il est automatiquement stocké dans votre CryptDrive si vous êtes connectés.";
|
out.tips.store = "Dès que vous ouvrez un nouveau pad, il est automatiquement stocké dans votre CryptDrive si vous êtes connecté.";
|
||||||
out.tips.marker = "Vous pouvez surligner du texte dans un pad en utilisant l'option \"marker\" dans le menu déroulant des styles.";
|
out.tips.marker = "Vous pouvez surligner du texte dans un pad en utilisant l'option \"marker\" dans le menu déroulant des styles.";
|
||||||
out.tips.driveUpload = "Les utilisateurs enregistrés peuvent importer des fichiers en les faisant glisser et en les déposant dans leur CryptDrive.";
|
out.tips.driveUpload = "Les utilisateurs enregistrés peuvent importer des fichiers en les faisant glisser et en les déposant dans leur CryptDrive.";
|
||||||
out.tips.filenames = "Vous pouvez renommer les fichiers de votre CryptDrive, ce nom ne sera visible que par vous.";
|
out.tips.filenames = "Vous pouvez renommer les fichiers de votre CryptDrive, ce nom ne sera visible que par vous.";
|
||||||
@@ -1081,6 +1084,7 @@ define(function () {
|
|||||||
out.creation_expireMonths = "Mois";
|
out.creation_expireMonths = "Mois";
|
||||||
out.creation_expire1 = "Un pad <b>illimité</b> ne sera pas supprimé du serveur à moins que son propriétaire ne le décide.";
|
out.creation_expire1 = "Un pad <b>illimité</b> ne sera pas supprimé du serveur à moins que son propriétaire ne le décide.";
|
||||||
out.creation_expire2 = "Un pad <b>à durée de vie</b> sera supprimé automatiquement du serveur et du CryptDrive des utilisateurs lorsque cette durée sera dépassée.";
|
out.creation_expire2 = "Un pad <b>à durée de vie</b> sera supprimé automatiquement du serveur et du CryptDrive des utilisateurs lorsque cette durée sera dépassée.";
|
||||||
|
out.creation_password = "Ajouter un mot de passe";
|
||||||
out.creation_noTemplate = "Pas de modèle";
|
out.creation_noTemplate = "Pas de modèle";
|
||||||
out.creation_newTemplate = "Nouveau modèle";
|
out.creation_newTemplate = "Nouveau modèle";
|
||||||
out.creation_create = "Créer";
|
out.creation_create = "Créer";
|
||||||
@@ -1092,12 +1096,20 @@ define(function () {
|
|||||||
out.creation_ownedByOther = "Appartient à un autre utilisateur";
|
out.creation_ownedByOther = "Appartient à un autre utilisateur";
|
||||||
out.creation_noOwner = "Pas de propriétaire";
|
out.creation_noOwner = "Pas de propriétaire";
|
||||||
out.creation_expiration = "Date d'expiration";
|
out.creation_expiration = "Date d'expiration";
|
||||||
|
out.creation_passwordValue = "Mot de passe";
|
||||||
out.creation_propertiesTitle = "Disponibilité";
|
out.creation_propertiesTitle = "Disponibilité";
|
||||||
out.creation_appMenuName = "Mode avancé (Ctrl + E)";
|
out.creation_appMenuName = "Mode avancé (Ctrl + E)";
|
||||||
out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez aussi appuyer sur <b>Tab</b> pour sélectionner un type et appuyer sur <b>Entrée</b> pour valider.";
|
out.creation_newPadModalDescription = "Cliquez sur un type de pad pour le créer. Vous pouvez aussi appuyer sur <b>Tab</b> pour sélectionner un type et appuyer sur <b>Entrée</b> pour valider.";
|
||||||
out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads avec propriétaire ou à durée de vie). Vous pouvez appuyer sur <b>Espace</b> pour changer sa valeur.";
|
out.creation_newPadModalDescriptionAdvanced = "Cochez la case si vous souhaitez voir l'écran de création de pads (pour les pads avec propriétaire ou à durée de vie). Vous pouvez appuyer sur <b>Espace</b> pour changer sa valeur.";
|
||||||
out.creation_newPadModalAdvanced = "Afficher l'écran de création de pads";
|
out.creation_newPadModalAdvanced = "Afficher l'écran de création de pads";
|
||||||
|
|
||||||
|
// Password prompt on the loadind screen
|
||||||
|
out.password_info = "Le pad auquel vous essayez d'accéder est protégé par un mot de passe. Entrez le bon mot de passe pour accéder à son contenu.";
|
||||||
|
out.password_error = "Pad introuvable !<br>Cette erreur peut provenir de deux facteurs. Soit le mot de passe est faux, soit le pad a été supprimé du serveur.";
|
||||||
|
out.password_placeholder = "Tapez le mot de passe ici...";
|
||||||
|
out.password_submit = "Valider";
|
||||||
|
out.password_show = "Afficher";
|
||||||
|
|
||||||
// New share modal
|
// New share modal
|
||||||
out.share_linkCategory = "Partage";
|
out.share_linkCategory = "Partage";
|
||||||
out.share_linkAccess = "Droits d'accès";
|
out.share_linkAccess = "Droits d'accès";
|
||||||
@@ -1111,5 +1123,12 @@ define(function () {
|
|||||||
out.share_embedCategory = "Intégration";
|
out.share_embedCategory = "Intégration";
|
||||||
out.share_mediatagCopy = "Copier le mediatag";
|
out.share_mediatagCopy = "Copier le mediatag";
|
||||||
|
|
||||||
|
// Loading info
|
||||||
|
out.loading_pad_1 = "Initialisation du pad";
|
||||||
|
out.loading_pad_2 = "Chargement du contenu du pad";
|
||||||
|
out.loading_drive_1 = "Chargement des données";
|
||||||
|
out.loading_drive_2 = "Mise à jour du format des données";
|
||||||
|
out.loading_drive_3 = "Vérification de l'intégrité des données";
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ define(function () {
|
|||||||
|
|
||||||
out.websocketError = 'Unable to connect to the websocket server...';
|
out.websocketError = 'Unable to connect to the websocket server...';
|
||||||
out.typeError = "This pad is not compatible with the selected application";
|
out.typeError = "This pad is not compatible with the selected application";
|
||||||
out.onLogout = 'You are logged out, <a href="/" target="_blank">click here</a> to log in<br>or press <em>Escape</em> to access your pad in read-only mode.';
|
out.onLogout = 'You are logged out, {0}click here{1} to log in<br>or press <em>Escape</em> to access your pad in read-only mode.';
|
||||||
out.wrongApp = "Unable to display the content of that realtime session in your browser. Please try to reload that page.";
|
out.wrongApp = "Unable to display the content of that realtime session in your browser. Please try to reload that page.";
|
||||||
out.padNotPinned = 'This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.';
|
out.padNotPinned = 'This pad will expire after 3 months of inactivity, {0}login{1} or {2}register{3} to preserve it.';
|
||||||
out.anonymousStoreDisabled = "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive.";
|
out.anonymousStoreDisabled = "The webmaster of this CryptPad instance has disabled the store for anonymous users. You have to log in to be able to use CryptDrive.";
|
||||||
@@ -40,6 +40,7 @@ define(function () {
|
|||||||
out.chainpadError = 'A critical error occurred when updating your content. This page is in read-only mode to make sure you won\'t lose your work.<br>' +
|
out.chainpadError = 'A critical error occurred when updating your content. This page is in read-only mode to make sure you won\'t lose your work.<br>' +
|
||||||
'Hit <em>Esc</em> to continue to view this pad, or reload to try editing again.';
|
'Hit <em>Esc</em> to continue to view this pad, or reload to try editing again.';
|
||||||
out.errorCopy = ' You can still copy the content to another location by pressing <em>Esc</em>.<br>Once you leave this page, it will disappear forever!';
|
out.errorCopy = ' You can still copy the content to another location by pressing <em>Esc</em>.<br>Once you leave this page, it will disappear forever!';
|
||||||
|
out.errorRedirectToHome = 'Press <em>Esc</em> to be redirected to your CryptDrive.';
|
||||||
|
|
||||||
out.loading = "Loading...";
|
out.loading = "Loading...";
|
||||||
out.error = "Error";
|
out.error = "Error";
|
||||||
@@ -148,6 +149,8 @@ define(function () {
|
|||||||
out.useTemplate = "Start with a template?"; //Would you like to "You have available templates for this type of pad. Do you want to use one?";
|
out.useTemplate = "Start with a template?"; //Would you like to "You have available templates for this type of pad. Do you want to use one?";
|
||||||
out.useTemplateOK = 'Pick a template (Enter)';
|
out.useTemplateOK = 'Pick a template (Enter)';
|
||||||
out.useTemplateCancel = 'Start fresh (Esc)';
|
out.useTemplateCancel = 'Start fresh (Esc)';
|
||||||
|
out.template_import = "Import a template";
|
||||||
|
out.template_empty = "No template available";
|
||||||
|
|
||||||
out.previewButtonTitle = "Display or hide the Markdown preview mode";
|
out.previewButtonTitle = "Display or hide the Markdown preview mode";
|
||||||
|
|
||||||
@@ -370,6 +373,7 @@ define(function () {
|
|||||||
out.fm_searchName = "Search";
|
out.fm_searchName = "Search";
|
||||||
out.fm_recentPadsName = "Recent pads";
|
out.fm_recentPadsName = "Recent pads";
|
||||||
out.fm_ownedPadsName = "Owned";
|
out.fm_ownedPadsName = "Owned";
|
||||||
|
out.fm_tagsName = "Tags";
|
||||||
out.fm_searchPlaceholder = "Search...";
|
out.fm_searchPlaceholder = "Search...";
|
||||||
out.fm_newButton = "New";
|
out.fm_newButton = "New";
|
||||||
out.fm_newButtonTitle = "Create a new pad or folder, import a file in the current folder";
|
out.fm_newButtonTitle = "Create a new pad or folder, import a file in the current folder";
|
||||||
@@ -432,6 +436,8 @@ define(function () {
|
|||||||
out.fm_padIsOwned = "You are the owner of this pad";
|
out.fm_padIsOwned = "You are the owner of this pad";
|
||||||
out.fm_padIsOwnedOther = "This pad is owned by another user";
|
out.fm_padIsOwnedOther = "This pad is owned by another user";
|
||||||
out.fm_deletedPads = "These pads no longer exist on the server, they've been removed from your CryptDrive: {0}";
|
out.fm_deletedPads = "These pads no longer exist on the server, they've been removed from your CryptDrive: {0}";
|
||||||
|
out.fm_tags_name = "Tag name";
|
||||||
|
out.fm_tags_used = "Number of uses";
|
||||||
// File - Context menu
|
// File - Context menu
|
||||||
out.fc_newfolder = "New folder";
|
out.fc_newfolder = "New folder";
|
||||||
out.fc_rename = "Rename";
|
out.fc_rename = "Rename";
|
||||||
@@ -555,6 +561,8 @@ define(function () {
|
|||||||
out.settings_deleteHint = "Account deletion is permanent. Your CryptDrive and your list of pads will be deleted from the server. The rest of your pads will be deleted in 90 days if nobody else has stored them in their CryptDrive.";
|
out.settings_deleteHint = "Account deletion is permanent. Your CryptDrive and your list of pads will be deleted from the server. The rest of your pads will be deleted in 90 days if nobody else has stored them in their CryptDrive.";
|
||||||
out.settings_deleteButton = "Delete your account";
|
out.settings_deleteButton = "Delete your account";
|
||||||
out.settings_deleteModal = "Share the following information with your CryptPad administrator in order to have your data removed from their server.";
|
out.settings_deleteModal = "Share the following information with your CryptPad administrator in order to have your data removed from their server.";
|
||||||
|
out.settings_deleteConfirm = "Clicking OK will delete your account permanently. Are you sure?";
|
||||||
|
out.settings_deleted = "Your user account is now deleted. Press OK to go to the home page.";
|
||||||
|
|
||||||
out.settings_anonymous = "You are not logged in. Settings here are specific to this browser.";
|
out.settings_anonymous = "You are not logged in. Settings here are specific to this browser.";
|
||||||
out.settings_publicSigningKey = "Public Signing Key";
|
out.settings_publicSigningKey = "Public Signing Key";
|
||||||
@@ -618,9 +626,6 @@ define(function () {
|
|||||||
out.pad_showToolbar = "Show toolbar";
|
out.pad_showToolbar = "Show toolbar";
|
||||||
out.pad_hideToolbar = "Hide toolbar";
|
out.pad_hideToolbar = "Hide toolbar";
|
||||||
|
|
||||||
// general warnings
|
|
||||||
out.warn_notPinned = "This pad is not in anyone's CryptDrive. It will expire after 3 months. <a href='/about.html#pinning'>Learn more...</a>";
|
|
||||||
|
|
||||||
// markdown toolbar
|
// markdown toolbar
|
||||||
out.mdToolbar_button = "Show or hide the Markdown toolbar";
|
out.mdToolbar_button = "Show or hide the Markdown toolbar";
|
||||||
out.mdToolbar_defaultText = "Your text here";
|
out.mdToolbar_defaultText = "Your text here";
|
||||||
@@ -999,9 +1004,6 @@ define(function () {
|
|||||||
|
|
||||||
// Header.html
|
// Header.html
|
||||||
|
|
||||||
out.header_france = '<a href="http://www.xwiki.com/" target="_blank" rel="noopener noreferrer">With <img class="bottom-bar-heart" src="/customize/heart.png" alt="love" /> from <img class="bottom-bar-fr" src="/customize/fr.png" title="France" alt="France"/> by <img src="/customize/logo-xwiki.png" alt="XWiki SAS" class="bottom-bar-xwiki"/></a>';
|
|
||||||
|
|
||||||
out.header_support = '<a href="http://ng.open-paas.org/" title="OpenPaaS::ng" target="_blank" rel="noopener noreferrer"> <img src="/customize/openpaasng.png" alt="OpenPaaS-ng" class="bottom-bar-openpaas" /></a>';
|
|
||||||
out.updated_0_header_logoTitle = 'Go to your CryptDrive';
|
out.updated_0_header_logoTitle = 'Go to your CryptDrive';
|
||||||
out.header_logoTitle = out.updated_0_header_logoTitle;
|
out.header_logoTitle = out.updated_0_header_logoTitle;
|
||||||
out.header_homeTitle = 'Go to CryptPad homepage';
|
out.header_homeTitle = 'Go to CryptPad homepage';
|
||||||
@@ -1133,6 +1135,7 @@ define(function () {
|
|||||||
out.creation_expireMonths = "Month(s)";
|
out.creation_expireMonths = "Month(s)";
|
||||||
out.creation_expire1 = "An <b>unlimited</b> pad will not be removed from the server until its owner deletes it.";
|
out.creation_expire1 = "An <b>unlimited</b> pad will not be removed from the server until its owner deletes it.";
|
||||||
out.creation_expire2 = "An <b>expiring</b> pad has a set lifetime, after which it will be automatically removed from the server and other users' CryptDrives.";
|
out.creation_expire2 = "An <b>expiring</b> pad has a set lifetime, after which it will be automatically removed from the server and other users' CryptDrives.";
|
||||||
|
out.creation_password = "Add a password";
|
||||||
out.creation_noTemplate = "No template";
|
out.creation_noTemplate = "No template";
|
||||||
out.creation_newTemplate = "New template";
|
out.creation_newTemplate = "New template";
|
||||||
out.creation_create = "Create";
|
out.creation_create = "Create";
|
||||||
@@ -1144,12 +1147,20 @@ define(function () {
|
|||||||
out.creation_ownedByOther = "Owned by another user";
|
out.creation_ownedByOther = "Owned by another user";
|
||||||
out.creation_noOwner = "No owner";
|
out.creation_noOwner = "No owner";
|
||||||
out.creation_expiration = "Expiration time";
|
out.creation_expiration = "Expiration time";
|
||||||
|
out.creation_passwordValue = "Password";
|
||||||
out.creation_propertiesTitle = "Availability";
|
out.creation_propertiesTitle = "Availability";
|
||||||
out.creation_appMenuName = "Advanced mode (Ctrl + E)";
|
out.creation_appMenuName = "Advanced mode (Ctrl + E)";
|
||||||
out.creation_newPadModalDescription = "Click on a pad type to create it. You can also press <b>Tab</b> to select the type and press <b>Enter</b> to confirm.";
|
out.creation_newPadModalDescription = "Click on a pad type to create it. You can also press <b>Tab</b> to select the type and press <b>Enter</b> to confirm.";
|
||||||
out.creation_newPadModalDescriptionAdvanced = "You can check the box (or press <b>Space</b> to change its value) if you want to display the pad creation screen (for owned pads, expiring pads, etc.).";
|
out.creation_newPadModalDescriptionAdvanced = "You can check the box (or press <b>Space</b> to change its value) if you want to display the pad creation screen (for owned pads, expiring pads, etc.).";
|
||||||
out.creation_newPadModalAdvanced = "Display the pad creation screen";
|
out.creation_newPadModalAdvanced = "Display the pad creation screen";
|
||||||
|
|
||||||
|
// Password prompt on the loadind screen
|
||||||
|
out.password_info = "The pad you're tyring to open is protected with a password. Enter the correct password to access its content.";
|
||||||
|
out.password_error = "Pad not found!<br>This error can be caused by two factors: either the password in invalid, or the pad has been deleted from the server.";
|
||||||
|
out.password_placeholder = "Type the password here...";
|
||||||
|
out.password_submit = "Submit";
|
||||||
|
out.password_show = "Show";
|
||||||
|
|
||||||
// New share modal
|
// New share modal
|
||||||
out.share_linkCategory = "Share link";
|
out.share_linkCategory = "Share link";
|
||||||
out.share_linkAccess = "Access rights";
|
out.share_linkAccess = "Access rights";
|
||||||
@@ -1163,6 +1174,12 @@ define(function () {
|
|||||||
out.share_embedCategory = "Embed";
|
out.share_embedCategory = "Embed";
|
||||||
out.share_mediatagCopy = "Copy mediatag to clipboard";
|
out.share_mediatagCopy = "Copy mediatag to clipboard";
|
||||||
|
|
||||||
|
// Loading info
|
||||||
|
out.loading_pad_1 = "Initializing pad";
|
||||||
|
out.loading_pad_2 = "Loading pad content";
|
||||||
|
out.loading_drive_1 = "Loading data";
|
||||||
|
out.loading_drive_2 = "Updating data format";
|
||||||
|
out.loading_drive_3 = "Verifying data integrity";
|
||||||
|
|
||||||
return out;
|
return out;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ define(function () {
|
|||||||
|
|
||||||
out.websocketError = 'Incapaz de se conectar com o servidor websocket...';
|
out.websocketError = 'Incapaz de se conectar com o servidor websocket...';
|
||||||
out.typeError = "Este bloco não é compatível com a aplicação selecionada";
|
out.typeError = "Este bloco não é compatível com a aplicação selecionada";
|
||||||
out.onLogout = 'você foi desconectado, <a href="/" target="_blank">clique aqui</a> para se conectar, <br>ou pressione <em>ESC</em> para acessar seu bloco em modo somente leitura.';
|
out.onLogout = 'você foi desconectado, {0}clique aqui{1} para se conectar, <br>ou pressione <em>ESC</em> para acessar seu bloco em modo somente leitura.';
|
||||||
out.wrongApp = "Incapaz de mostrar o conteúdo em tempo real no seu navegador. Por favor tente recarregar a página.";
|
out.wrongApp = "Incapaz de mostrar o conteúdo em tempo real no seu navegador. Por favor tente recarregar a página.";
|
||||||
|
|
||||||
out.loading = "Carregando...";
|
out.loading = "Carregando...";
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ define(function () {
|
|||||||
out.common_connectionLost = out.updated_0_common_connectionLost;
|
out.common_connectionLost = out.updated_0_common_connectionLost;
|
||||||
out.websocketError = "Conexiune inexistentă către serverul websocket...";
|
out.websocketError = "Conexiune inexistentă către serverul websocket...";
|
||||||
out.typeError = "Această filă nu este compatibilă cu aplicația aleasă";
|
out.typeError = "Această filă nu este compatibilă cu aplicația aleasă";
|
||||||
out.onLogout = "Nu mai ești autentificat, <a href=\"/\" target=\"_blank\">apasă aici</a> să te autentifici<br>sau apasă <em>Escape</em>să accesezi fila în modul citire.";
|
out.onLogout = "Nu mai ești autentificat, {0}apasă aici{1} să te autentifici<br>sau apasă <em>Escape</em>să accesezi fila în modul citire.";
|
||||||
out.wrongApp = "Momentan nu putem arăta conținutul sesiunii în timp real în fereastra ta. Te rugăm reîncarcă pagina.";
|
out.wrongApp = "Momentan nu putem arăta conținutul sesiunii în timp real în fereastra ta. Te rugăm reîncarcă pagina.";
|
||||||
out.loading = "Încarcă...";
|
out.loading = "Încarcă...";
|
||||||
out.error = "Eroare";
|
out.error = "Eroare";
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ define(function () {
|
|||||||
|
|
||||||
out.websocketError = '無法連結上 websocket 伺服器...';
|
out.websocketError = '無法連結上 websocket 伺服器...';
|
||||||
out.typeError = "這個編輯檔與所選的應用程式並不相容";
|
out.typeError = "這個編輯檔與所選的應用程式並不相容";
|
||||||
out.onLogout = '你已登出, <a href="/" target="_blank">點擊這裏</a> 來登入<br>或按<em>Escape</em> 來以唯讀模型使用你的編輯檔案';
|
out.onLogout = '你已登出, {0}點擊這裏{1} 來登入<br>或按<em>Escape</em> 來以唯讀模型使用你的編輯檔案';
|
||||||
out.wrongApp = "無法在瀏覽器顯示即時期間的內容,請試著再重新載入本頁。";
|
out.wrongApp = "無法在瀏覽器顯示即時期間的內容,請試著再重新載入本頁。";
|
||||||
|
|
||||||
out.loading = "載入中...";
|
out.loading = "載入中...";
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ nThen(function (waitFor) {
|
|||||||
sem.take(function (give) {
|
sem.take(function (give) {
|
||||||
Fs.unlink(f.filename, give(function (err) {
|
Fs.unlink(f.filename, give(function (err) {
|
||||||
if (err) { return void console.error(err + " " + f.filename); }
|
if (err) { return void console.error(err + " " + f.filename); }
|
||||||
console.log(f.filename + " " + f.size + " " + (+f.atime) + " " + (+new Date()));
|
console.log(f.filename + " " + f.size + " " + (+f.mtime) + " " + (+new Date()));
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -75,6 +75,12 @@ server {
|
|||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /blob/ {
|
location ^~ /blob/ {
|
||||||
|
add_header Cache-Control max-age=31536000;
|
||||||
|
try_files $uri =404;
|
||||||
|
}
|
||||||
|
|
||||||
|
location ^~ /datastore/ {
|
||||||
|
add_header Cache-Control max-age=0;
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "cryptpad",
|
"name": "cryptpad",
|
||||||
"description": "realtime collaborative visual editor with zero knowlege server",
|
"description": "realtime collaborative visual editor with zero knowlege server",
|
||||||
"version": "1.28.0",
|
"version": "2.0.0",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chainpad-server": "^2.0.0",
|
"chainpad-server": "^2.0.0",
|
||||||
|
|||||||
10
pinned.js
10
pinned.js
@@ -15,6 +15,7 @@ const hashesFromPinFile = (pinFile, fileName) => {
|
|||||||
switch (l[0]) {
|
switch (l[0]) {
|
||||||
case 'RESET': {
|
case 'RESET': {
|
||||||
pins = {};
|
pins = {};
|
||||||
|
if (l[1] && l[1].length) { l[1].forEach((x) => { pins[x] = 1; }); }
|
||||||
//jshint -W086
|
//jshint -W086
|
||||||
// fallthrough
|
// fallthrough
|
||||||
}
|
}
|
||||||
@@ -32,7 +33,7 @@ const hashesFromPinFile = (pinFile, fileName) => {
|
|||||||
return Object.keys(pins);
|
return Object.keys(pins);
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports.load = function (cb) {
|
module.exports.load = function (cb, config) {
|
||||||
nThen((waitFor) => {
|
nThen((waitFor) => {
|
||||||
Fs.readdir('./pins', waitFor((err, list) => {
|
Fs.readdir('./pins', waitFor((err, list) => {
|
||||||
if (err) {
|
if (err) {
|
||||||
@@ -49,7 +50,10 @@ module.exports.load = function (cb) {
|
|||||||
sema.take((returnAfter) => {
|
sema.take((returnAfter) => {
|
||||||
Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => {
|
Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); });
|
list2.forEach((ff) => {
|
||||||
|
if (config && config.exclude && config.exclude.indexOf(ff) > -1) { return; }
|
||||||
|
fileList.push('./pins/' + f + '/' + ff);
|
||||||
|
});
|
||||||
})));
|
})));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -76,4 +80,4 @@ if (!module.parent) {
|
|||||||
console.log(x + ' ' + JSON.stringify(data[x]));
|
console.log(x + ' ' + JSON.stringify(data[x]));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
146
pinneddata.js
146
pinneddata.js
@@ -3,14 +3,21 @@ const Fs = require('fs');
|
|||||||
const Semaphore = require('saferphore');
|
const Semaphore = require('saferphore');
|
||||||
const nThen = require('nthen');
|
const nThen = require('nthen');
|
||||||
|
|
||||||
|
/*
|
||||||
|
takes contents of a pinFile (UTF8 string)
|
||||||
|
and the pin file's name
|
||||||
|
returns an array of of channel ids which are pinned
|
||||||
|
|
||||||
|
throw errors on pin logs with invalid pin data
|
||||||
|
*/
|
||||||
const hashesFromPinFile = (pinFile, fileName) => {
|
const hashesFromPinFile = (pinFile, fileName) => {
|
||||||
var pins = {};
|
var pins = {};
|
||||||
pinFile.split('\n').filter((x)=>(x)).map((l) => JSON.parse(l)).forEach((l) => {
|
pinFile.split('\n').filter((x)=>(x)).map((l) => JSON.parse(l)).forEach((l) => {
|
||||||
switch (l[0]) {
|
switch (l[0]) {
|
||||||
case 'RESET': {
|
case 'RESET': {
|
||||||
pins = {};
|
pins = {};
|
||||||
//jshint -W086
|
if (l[1] && l[1].length) { l[1].forEach((x) => { pins[x] = 1; }); }
|
||||||
// fallthrough
|
break;
|
||||||
}
|
}
|
||||||
case 'PIN': {
|
case 'PIN': {
|
||||||
l[1].forEach((x) => { pins[x] = 1; });
|
l[1].forEach((x) => { pins[x] = 1; });
|
||||||
@@ -26,6 +33,11 @@ const hashesFromPinFile = (pinFile, fileName) => {
|
|||||||
return Object.keys(pins);
|
return Object.keys(pins);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
takes an array of pinned file names
|
||||||
|
and a global map of stats indexed by public keys
|
||||||
|
returns the sum of the size of those pinned files
|
||||||
|
*/
|
||||||
const sizeForHashes = (hashes, dsFileStats) => {
|
const sizeForHashes = (hashes, dsFileStats) => {
|
||||||
let sum = 0;
|
let sum = 0;
|
||||||
hashes.forEach((h) => {
|
hashes.forEach((h) => {
|
||||||
@@ -39,23 +51,31 @@ const sizeForHashes = (hashes, dsFileStats) => {
|
|||||||
return sum;
|
return sum;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// do twenty things at a time
|
||||||
const sema = Semaphore.create(20);
|
const sema = Semaphore.create(20);
|
||||||
|
|
||||||
let dirList;
|
let dirList;
|
||||||
const fileList = [];
|
const fileList = []; // array which we reuse for a lot of things
|
||||||
const dsFileStats = {};
|
const dsFileStats = {}; // map of stats
|
||||||
const out = [];
|
const out = []; // what we return at the end
|
||||||
const pinned = {};
|
const pinned = {}; // map of pinned files
|
||||||
|
|
||||||
|
// define a function: 'load' which takes a config
|
||||||
|
// and a callback
|
||||||
module.exports.load = function (config, cb) {
|
module.exports.load = function (config, cb) {
|
||||||
nThen((waitFor) => {
|
nThen((waitFor) => {
|
||||||
|
// read the subdirectories in the datastore
|
||||||
Fs.readdir('./datastore', waitFor((err, list) => {
|
Fs.readdir('./datastore', waitFor((err, list) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
dirList = list;
|
dirList = list;
|
||||||
}));
|
}));
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// iterate over all subdirectories
|
||||||
dirList.forEach((f) => {
|
dirList.forEach((f) => {
|
||||||
|
// process twenty subdirectories simultaneously
|
||||||
sema.take((returnAfter) => {
|
sema.take((returnAfter) => {
|
||||||
|
// get the list of files in every subdirectory
|
||||||
|
// and push them to 'fileList'
|
||||||
Fs.readdir('./datastore/' + f, waitFor(returnAfter((err, list2) => {
|
Fs.readdir('./datastore/' + f, waitFor(returnAfter((err, list2) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
list2.forEach((ff) => { fileList.push('./datastore/' + f + '/' + ff); });
|
list2.forEach((ff) => { fileList.push('./datastore/' + f + '/' + ff); });
|
||||||
@@ -63,14 +83,19 @@ module.exports.load = function (config, cb) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// read the subdirectories in 'blob'
|
||||||
Fs.readdir('./blob', waitFor((err, list) => {
|
Fs.readdir('./blob', waitFor((err, list) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
|
// overwrite dirList
|
||||||
dirList = list;
|
dirList = list;
|
||||||
}));
|
}));
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// iterate over all subdirectories
|
||||||
dirList.forEach((f) => {
|
dirList.forEach((f) => {
|
||||||
|
// process twenty subdirectories simultaneously
|
||||||
sema.take((returnAfter) => {
|
sema.take((returnAfter) => {
|
||||||
|
// get the list of files in every subdirectory
|
||||||
|
// and push them to 'fileList'
|
||||||
Fs.readdir('./blob/' + f, waitFor(returnAfter((err, list2) => {
|
Fs.readdir('./blob/' + f, waitFor(returnAfter((err, list2) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
list2.forEach((ff) => { fileList.push('./blob/' + f + '/' + ff); });
|
list2.forEach((ff) => { fileList.push('./blob/' + f + '/' + ff); });
|
||||||
@@ -78,24 +103,34 @@ module.exports.load = function (config, cb) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// iterate over the fileList
|
||||||
fileList.forEach((f) => {
|
fileList.forEach((f) => {
|
||||||
|
// process twenty files simultaneously
|
||||||
sema.take((returnAfter) => {
|
sema.take((returnAfter) => {
|
||||||
|
// get the stats of each files
|
||||||
Fs.stat(f, waitFor(returnAfter((err, st) => {
|
Fs.stat(f, waitFor(returnAfter((err, st) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
st.filename = f;
|
st.filename = f;
|
||||||
|
// push them to a big map of stats
|
||||||
dsFileStats[f.replace(/^.*\/([^\/\.]*)(\.ndjson)?$/, (all, a) => (a))] = st;
|
dsFileStats[f.replace(/^.*\/([^\/\.]*)(\.ndjson)?$/, (all, a) => (a))] = st;
|
||||||
})));
|
})));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// read the subdirectories in the pinstore
|
||||||
Fs.readdir('./pins', waitFor((err, list) => {
|
Fs.readdir('./pins', waitFor((err, list) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
dirList = list;
|
dirList = list;
|
||||||
}));
|
}));
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// set file list to an empty array
|
||||||
|
// fileList = [] ??
|
||||||
fileList.splice(0, fileList.length);
|
fileList.splice(0, fileList.length);
|
||||||
dirList.forEach((f) => {
|
dirList.forEach((f) => {
|
||||||
|
// process twenty directories at a time
|
||||||
sema.take((returnAfter) => {
|
sema.take((returnAfter) => {
|
||||||
|
// get the list of files in every subdirectory
|
||||||
|
// and push them to 'fileList' (which is empty because we keep reusing it)
|
||||||
Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => {
|
Fs.readdir('./pins/' + f, waitFor(returnAfter((err, list2) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); });
|
list2.forEach((ff) => { fileList.push('./pins/' + f + '/' + ff); });
|
||||||
@@ -103,70 +138,147 @@ module.exports.load = function (config, cb) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).nThen((waitFor) => {
|
}).nThen((waitFor) => {
|
||||||
|
// iterate over the list of pin logs
|
||||||
fileList.forEach((f) => {
|
fileList.forEach((f) => {
|
||||||
|
// twenty at a time
|
||||||
sema.take((returnAfter) => {
|
sema.take((returnAfter) => {
|
||||||
|
// read the full content
|
||||||
Fs.readFile(f, waitFor(returnAfter((err, content) => {
|
Fs.readFile(f, waitFor(returnAfter((err, content) => {
|
||||||
if (err) { throw err; }
|
if (err) { throw err; }
|
||||||
|
// get the list of channels pinned by this log
|
||||||
const hashes = hashesFromPinFile(content.toString('utf8'), f);
|
const hashes = hashesFromPinFile(content.toString('utf8'), f);
|
||||||
const size = sizeForHashes(hashes, dsFileStats);
|
|
||||||
if (config.unpinned) {
|
if (config.unpinned) {
|
||||||
hashes.forEach((x) => { pinned[x] = 1; });
|
hashes.forEach((x) => { pinned[x] = 1; });
|
||||||
} else {
|
} else {
|
||||||
|
// get the size of files pinned by this log
|
||||||
|
// but only if we're gonna use it
|
||||||
|
let size = sizeForHashes(hashes, dsFileStats);
|
||||||
|
// we will return a list of values
|
||||||
|
// [user_public_key, size_of_files_they_have_pinned]
|
||||||
out.push([f, Math.floor(size / (1024 * 1024))]);
|
out.push([f, Math.floor(size / (1024 * 1024))]);
|
||||||
}
|
}
|
||||||
})));
|
})));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}).nThen(() => {
|
}).nThen(() => {
|
||||||
|
// handle all the information you've processed so far
|
||||||
if (config.unpinned) {
|
if (config.unpinned) {
|
||||||
|
// the user wants data about what has not been pinned
|
||||||
|
|
||||||
|
// by default we concern ourselves with pads and files older than infinity (everything)
|
||||||
let before = Infinity;
|
let before = Infinity;
|
||||||
|
|
||||||
|
// but you can override this with config
|
||||||
if (config.olderthan) {
|
if (config.olderthan) {
|
||||||
before = config.olderthan;
|
before = config.olderthan;
|
||||||
if (isNaN(before)) {
|
// FIXME validate inputs before doing the heavy lifting
|
||||||
|
if (isNaN(before)) { // make sure the supplied value is a number
|
||||||
return void cb('--olderthan error [' + config.olderthan + '] not a valid date');
|
return void cb('--olderthan error [' + config.olderthan + '] not a valid date');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// you can specify a different time for blobs...
|
||||||
let blobsbefore = before;
|
let blobsbefore = before;
|
||||||
if (config.blobsolderthan) {
|
if (config.blobsolderthan) {
|
||||||
|
// use the supplied date if it exists
|
||||||
blobsbefore = config.blobsolderthan;
|
blobsbefore = config.blobsolderthan;
|
||||||
if (isNaN(blobsbefore)) {
|
if (isNaN(blobsbefore)) {
|
||||||
return void cb('--blobsolderthan error [' + config.blobsolderthan + '] not a valid date');
|
return void cb('--blobsolderthan error [' + config.blobsolderthan + '] not a valid date');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let files = [];
|
let files = [];
|
||||||
|
// iterate over all the stats that you've saved
|
||||||
Object.keys(dsFileStats).forEach((f) => {
|
Object.keys(dsFileStats).forEach((f) => {
|
||||||
|
// we only care about files which are not in the pin map
|
||||||
if (!(f in pinned)) {
|
if (!(f in pinned)) {
|
||||||
|
// check if it's a blob or a 'pad'
|
||||||
const isBlob = dsFileStats[f].filename.indexOf('.ndjson') === -1;
|
const isBlob = dsFileStats[f].filename.indexOf('.ndjson') === -1;
|
||||||
if ((+dsFileStats[f].atime) >= ((isBlob) ? blobsbefore : before)) { return; }
|
|
||||||
|
// if the mtime is newer than the specified value for its file type, ignore this file
|
||||||
|
|
||||||
|
if ((+dsFileStats[f].mtime) >= ((isBlob) ? blobsbefore : before)) { return; }
|
||||||
|
|
||||||
|
// otherwise push it to the list of files, with its filename, size, and mtime
|
||||||
files.push({
|
files.push({
|
||||||
filename: dsFileStats[f].filename,
|
filename: dsFileStats[f].filename,
|
||||||
size: dsFileStats[f].size,
|
size: dsFileStats[f].size,
|
||||||
atime: dsFileStats[f].atime
|
mtime: dsFileStats[f].mtime
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// return the list of files
|
||||||
cb(null, files);
|
cb(null, files);
|
||||||
} else {
|
} else {
|
||||||
|
// if you're not in 'unpinned' mode, sort by size (ascending)
|
||||||
out.sort((a,b) => (a[1] - b[1]));
|
out.sort((a,b) => (a[1] - b[1]));
|
||||||
|
// and return the sorted data
|
||||||
cb(null, out.slice());
|
cb(null, out.slice());
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
// This script can be called directly on its own
|
||||||
|
// or required as part of another script
|
||||||
if (!module.parent) {
|
if (!module.parent) {
|
||||||
let config = {};
|
// if no parent, it is being invoked directly
|
||||||
|
let config = {}; // build the config from command line arguments...
|
||||||
|
|
||||||
|
// --unpinned gets the list of unpinned files
|
||||||
|
// if you don't pass this, it will list the size of pinned data per user
|
||||||
if (process.argv.indexOf('--unpinned') > -1) { config.unpinned = true; }
|
if (process.argv.indexOf('--unpinned') > -1) { config.unpinned = true; }
|
||||||
|
|
||||||
|
// '--olderthan' must be used in conjunction with '--unpinned'
|
||||||
|
// if you pass '--olderthan' with a string date or number, it will limit
|
||||||
|
// results only to pads older than the supplied time
|
||||||
|
// it defaults to 'infinity', or no filter at all
|
||||||
const ot = process.argv.indexOf('--olderthan');
|
const ot = process.argv.indexOf('--olderthan');
|
||||||
config.olderthan = ot > -1 && new Date(process.argv[ot+1]);
|
if (ot > -1) {
|
||||||
|
config.olderthan = Number(process.argv[ot+1]) ? new Date(Number(process.argv[ot+1]))
|
||||||
|
: new Date(process.argv[ot+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// '--blobsolderthan' must be used in conjunction with '--unpinned'
|
||||||
|
// if you pass '--blobsolderthan with a string date or number, it will limit
|
||||||
|
// results only to blobs older than the supplied time
|
||||||
|
// it defaults to using the same value passed '--olderthan'
|
||||||
const bot = process.argv.indexOf('--blobsolderthan');
|
const bot = process.argv.indexOf('--blobsolderthan');
|
||||||
config.blobsolderthan = bot > -1 && new Date(process.argv[bot+1]);
|
if (bot > -1) {
|
||||||
|
config.blobsolderthan = Number(process.argv[bot+1]) ? new Date(Number(process.argv[bot+1]))
|
||||||
|
: new Date(process.argv[bot+1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// call our big function directly
|
||||||
|
// pass our constructed configuration and a callback
|
||||||
module.exports.load(config, function (err, data) {
|
module.exports.load(config, function (err, data) {
|
||||||
if (err) { throw new Error(err); }
|
if (err) { throw new Error(err); } // throw errors
|
||||||
if (!Array.isArray(data)) { return; }
|
if (!Array.isArray(data)) { return; } // if the returned value is not an array, you're done
|
||||||
if (config.unpinned) {
|
if (config.unpinned) {
|
||||||
data.forEach((f) => { console.log(f.filename + " " + f.size + " " + (+f.atime)); });
|
// display the list of unpinned files with their size and mtime
|
||||||
|
data.forEach((f) => { console.log(f.filename + " " + f.size + " " + (+f.mtime)); });
|
||||||
} else {
|
} else {
|
||||||
|
// display the list of public keys and the size of the data they have pinned in megabytes
|
||||||
data.forEach((x) => { console.log(x[0] + ' ' + x[1] + ' MB'); });
|
data.forEach((x) => { console.log(x[0] + ' ' + x[1] + ' MB'); });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Example usage of this script...
|
||||||
|
|
||||||
|
# display the list of public keys and the size of the data the have pinned in megabytes
|
||||||
|
node pinneddata.js
|
||||||
|
|
||||||
|
# display the list of unpinned pads and blobs with their size and mtime
|
||||||
|
node pinneddata.js --unpinned
|
||||||
|
|
||||||
|
# display the list of unpinned pads and blobs older than 12345 with their size and mtime
|
||||||
|
node pinneddata.js --unpinned --olderthan 12345
|
||||||
|
|
||||||
|
|
||||||
|
# display the list of unpinned pads older than 12345 and unpinned blobs older than 123
|
||||||
|
# each with their size and mtime
|
||||||
|
node pinneddata.js --unpinned --olderthan 12345 --blobsolderthan 123
|
||||||
|
|
||||||
|
*/
|
||||||
|
|||||||
31
rpc.js
31
rpc.js
@@ -326,6 +326,24 @@ var getFileSize = function (Env, channel, cb) {
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var getMetadata = function (Env, channel, cb) {
|
||||||
|
if (!isValidId(channel)) { return void cb('INVALID_CHAN'); }
|
||||||
|
|
||||||
|
if (channel.length === 32) {
|
||||||
|
if (typeof(Env.msgStore.getChannelMetadata) !== 'function') {
|
||||||
|
return cb('GET_CHANNEL_METADATA_UNSUPPORTED');
|
||||||
|
}
|
||||||
|
|
||||||
|
return void Env.msgStore.getChannelMetadata(channel, function (e, data) {
|
||||||
|
if (e) {
|
||||||
|
if (e.code === 'INVALID_METADATA') { return void cb(void 0, {}); }
|
||||||
|
return void cb(e.code);
|
||||||
|
}
|
||||||
|
cb(void 0, data);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
var getMultipleFileSize = function (Env, channels, cb) {
|
var getMultipleFileSize = function (Env, channels, cb) {
|
||||||
if (!Array.isArray(channels)) { return cb('INVALID_PIN_LIST'); }
|
if (!Array.isArray(channels)) { return cb('INVALID_PIN_LIST'); }
|
||||||
if (typeof(Env.msgStore.getChannelSize) !== 'function') {
|
if (typeof(Env.msgStore.getChannelSize) !== 'function') {
|
||||||
@@ -1139,6 +1157,7 @@ var isNewChannel = function (Env, channel, cb) {
|
|||||||
var isUnauthenticatedCall = function (call) {
|
var isUnauthenticatedCall = function (call) {
|
||||||
return [
|
return [
|
||||||
'GET_FILE_SIZE',
|
'GET_FILE_SIZE',
|
||||||
|
'GET_METADATA',
|
||||||
'GET_MULTIPLE_FILE_SIZE',
|
'GET_MULTIPLE_FILE_SIZE',
|
||||||
'IS_CHANNEL_PINNED',
|
'IS_CHANNEL_PINNED',
|
||||||
'IS_NEW_CHANNEL',
|
'IS_NEW_CHANNEL',
|
||||||
@@ -1260,12 +1279,14 @@ RPC.create = function (
|
|||||||
}
|
}
|
||||||
case 'GET_FILE_SIZE':
|
case 'GET_FILE_SIZE':
|
||||||
return void getFileSize(Env, msg[1], function (e, size) {
|
return void getFileSize(Env, msg[1], function (e, size) {
|
||||||
if (e) {
|
|
||||||
console.error(e);
|
|
||||||
}
|
|
||||||
WARN(e, msg[1]);
|
WARN(e, msg[1]);
|
||||||
respond(e, [null, size, null]);
|
respond(e, [null, size, null]);
|
||||||
});
|
});
|
||||||
|
case 'GET_METADATA':
|
||||||
|
return void getMetadata(Env, msg[1], function (e, data) {
|
||||||
|
WARN(e, msg[1]);
|
||||||
|
respond(e, [null, data, null]);
|
||||||
|
});
|
||||||
case 'GET_MULTIPLE_FILE_SIZE':
|
case 'GET_MULTIPLE_FILE_SIZE':
|
||||||
return void getMultipleFileSize(Env, msg[1], function (e, dict) {
|
return void getMultipleFileSize(Env, msg[1], function (e, dict) {
|
||||||
if (e) {
|
if (e) {
|
||||||
@@ -1458,9 +1479,9 @@ RPC.create = function (
|
|||||||
Respond(void 0, "OK");
|
Respond(void 0, "OK");
|
||||||
});
|
});
|
||||||
case 'REMOVE_PINS':
|
case 'REMOVE_PINS':
|
||||||
return void removePins(Env, safeKey, function (e, response) {
|
return void removePins(Env, safeKey, function (e) {
|
||||||
if (e) { return void Respond(e); }
|
if (e) { return void Respond(e); }
|
||||||
Respond(void 0, response);
|
Respond(void 0, "OK");
|
||||||
});
|
});
|
||||||
// restricted to privileged users...
|
// restricted to privileged users...
|
||||||
case 'UPLOAD':
|
case 'UPLOAD':
|
||||||
|
|||||||
@@ -123,6 +123,9 @@ app.get(mainPagePattern, Express.static(__dirname + '/customize.dist'));
|
|||||||
app.use("/blob", Express.static(Path.join(__dirname, (config.blobPath || './blob')), {
|
app.use("/blob", Express.static(Path.join(__dirname, (config.blobPath || './blob')), {
|
||||||
maxAge: DEV_MODE? "0d": "365d"
|
maxAge: DEV_MODE? "0d": "365d"
|
||||||
}));
|
}));
|
||||||
|
app.use("/datastore", Express.static(Path.join(__dirname, (config.filePath || './datastore')), {
|
||||||
|
maxAge: "0d"
|
||||||
|
}));
|
||||||
|
|
||||||
app.use("/customize", Express.static(__dirname + '/customize'));
|
app.use("/customize", Express.static(__dirname + '/customize'));
|
||||||
app.use("/customize", Express.static(__dirname + '/customize.dist'));
|
app.use("/customize", Express.static(__dirname + '/customize.dist'));
|
||||||
@@ -188,6 +191,7 @@ var custom_four04_path = Path.resolve(__dirname + '/customize/404.html');
|
|||||||
var send404 = function (res, path) {
|
var send404 = function (res, path) {
|
||||||
if (!path && path !== four04_path) { path = four04_path; }
|
if (!path && path !== four04_path) { path = four04_path; }
|
||||||
Fs.exists(path, function (exists) {
|
Fs.exists(path, function (exists) {
|
||||||
|
res.setHeader('Content-Type', 'text/html; charset=utf-8');
|
||||||
if (exists) { return Fs.createReadStream(path).pipe(res); }
|
if (exists) { return Fs.createReadStream(path).pipe(res); }
|
||||||
send404(res);
|
send404(res);
|
||||||
});
|
});
|
||||||
@@ -250,4 +254,4 @@ var nt = nThen(function (w) {
|
|||||||
|
|
||||||
if (config.debugReplName) {
|
if (config.debugReplName) {
|
||||||
require('replify')({ name: config.debugReplName, app: debuggableStore });
|
require('replify')({ name: config.debugReplName, app: debuggableStore });
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -223,6 +223,33 @@ define([
|
|||||||
hd.type === 'invite');
|
hd.type === 'invite');
|
||||||
}, "test support for invite urls");
|
}, "test support for invite urls");
|
||||||
|
|
||||||
|
// test support for V2
|
||||||
|
assert(function (cb) {
|
||||||
|
var parsed = Hash.parsePadUrl('/pad/#/2/pad/edit/oRE0oLCtEXusRDyin7GyLGcS/');
|
||||||
|
var secret = Hash.getSecrets('pad', '/2/pad/edit/oRE0oLCtEXusRDyin7GyLGcS/');
|
||||||
|
return cb(parsed.hashData.version === 2 &&
|
||||||
|
parsed.hashData.mode === "edit" &&
|
||||||
|
parsed.hashData.type === "pad" &&
|
||||||
|
parsed.hashData.key === "oRE0oLCtEXusRDyin7GyLGcS" &&
|
||||||
|
secret.channel === "d8d51b4aea863f3f050f47f8ad261753" &&
|
||||||
|
window.nacl.util.encodeBase64(secret.keys.cryptKey) === "0Ts1M6VVEozErV2Nx/LTv6Im5SCD7io2LlhasyyBPQo=" &&
|
||||||
|
secret.keys.validateKey === "f5A1FM9Gp55tnOcM75RyHD1oxBG9ZPh9WDA7qe2Fvps=" &&
|
||||||
|
!parsed.hashData.present);
|
||||||
|
}, "test support for version 2 hash failed to parse");
|
||||||
|
assert(function (cb) {
|
||||||
|
var parsed = Hash.parsePadUrl('/pad/#/2/pad/edit/HGu0tK2od-2BBnwAz2ZNS-t4/p/embed');
|
||||||
|
var secret = Hash.getSecrets('pad', '/2/pad/edit/HGu0tK2od-2BBnwAz2ZNS-t4/p/embed', 'pewpew');
|
||||||
|
return cb(parsed.hashData.version === 2 &&
|
||||||
|
parsed.hashData.mode === "edit" &&
|
||||||
|
parsed.hashData.type === "pad" &&
|
||||||
|
parsed.hashData.key === "HGu0tK2od-2BBnwAz2ZNS-t4" &&
|
||||||
|
secret.channel === "3fb6dc93807d903aff390b5f798c92c9" &&
|
||||||
|
window.nacl.util.encodeBase64(secret.keys.cryptKey) === "EeCkGJra8eJgVu7v4Yl2Hc3yUjrgpKpxr0Lcc3bSWVs=" &&
|
||||||
|
secret.keys.validateKey === "WGkBczJf2V6vQZfAScz8V1KY6jKdoxUCckrD+E75gGE=" &&
|
||||||
|
parsed.hashData.embed &&
|
||||||
|
parsed.hashData.password);
|
||||||
|
}, "test support for password in version 2 hash failed to parse");
|
||||||
|
|
||||||
assert(function (cb) {
|
assert(function (cb) {
|
||||||
var url = '/pad/?utm_campaign=new_comment&utm_medium=email&utm_source=thread_mailer#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI/';
|
var url = '/pad/?utm_campaign=new_comment&utm_medium=email&utm_source=thread_mailer#/1/edit/3Ujt4F2Sjnjbis6CoYWpoQ/usn4+9CqVja8Q7RZOGTfRgqI/';
|
||||||
var secret = Hash.parsePadUrl(url);
|
var secret = Hash.parsePadUrl(url);
|
||||||
|
|||||||
@@ -334,6 +334,7 @@ define([
|
|||||||
//var cursor = editor.getCursor();
|
//var cursor = editor.getCursor();
|
||||||
//var cleanName = data.name.replace(/[\[\]]/g, '');
|
//var cleanName = data.name.replace(/[\[\]]/g, '');
|
||||||
//var text = '';
|
//var text = '';
|
||||||
|
// PASSWORD_FILES
|
||||||
var parsed = Hash.parsePadUrl(data.url);
|
var parsed = Hash.parsePadUrl(data.url);
|
||||||
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
||||||
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ define([
|
|||||||
url: '/common/feedback.html?NO_LOCALSTORAGE=' + (+new Date()),
|
url: '/common/feedback.html?NO_LOCALSTORAGE=' + (+new Date()),
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
window.alert("CryptPad needs localStorage to work, try a different browser");
|
window.alert("CryptPad needs localStorage to work. Try changing your cookie permissions, or using a different browser");
|
||||||
};
|
};
|
||||||
|
|
||||||
window.onerror = function (e) {
|
window.onerror = function (e) {
|
||||||
|
|||||||
@@ -19,7 +19,50 @@ define([
|
|||||||
.decodeUTF8(JSON.stringify(list))));
|
.decodeUTF8(JSON.stringify(list))));
|
||||||
};
|
};
|
||||||
|
|
||||||
var getEditHashFromKeys = Hash.getEditHashFromKeys = function (chanKey, keys) {
|
var getEditHashFromKeys = Hash.getEditHashFromKeys = function (secret) {
|
||||||
|
var version = secret.version;
|
||||||
|
var data = secret.keys;
|
||||||
|
if (version === 0) {
|
||||||
|
return secret.channel + secret.key;
|
||||||
|
}
|
||||||
|
if (version === 1) {
|
||||||
|
if (!data.editKeyStr) { return; }
|
||||||
|
return '/1/edit/' + hexToBase64(secret.channel) +
|
||||||
|
'/' + Crypto.b64RemoveSlashes(data.editKeyStr) + '/';
|
||||||
|
}
|
||||||
|
if (version === 2) {
|
||||||
|
if (!data.editKeyStr) { return; }
|
||||||
|
var pass = secret.password ? 'p/' : '';
|
||||||
|
return '/2/' + secret.type + '/edit/' + Crypto.b64RemoveSlashes(data.editKeyStr) + '/' + pass;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var getViewHashFromKeys = Hash.getViewHashFromKeys = function (secret) {
|
||||||
|
var version = secret.version;
|
||||||
|
var data = secret.keys;
|
||||||
|
if (version === 0) { return; }
|
||||||
|
if (version === 1) {
|
||||||
|
if (!data.viewKeyStr) { return; }
|
||||||
|
return '/1/view/' + hexToBase64(secret.channel) +
|
||||||
|
'/'+Crypto.b64RemoveSlashes(data.viewKeyStr)+'/';
|
||||||
|
}
|
||||||
|
if (version === 2) {
|
||||||
|
if (!data.viewKeyStr) { return; }
|
||||||
|
var pass = secret.password ? 'p/' : '';
|
||||||
|
return '/2/' + secret.type + '/view/' + Crypto.b64RemoveSlashes(data.viewKeyStr) + '/' + pass;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var getFileHashFromKeys = Hash.getFileHashFromKeys = function (secret) {
|
||||||
|
var version = secret.version;
|
||||||
|
var data = secret.keys;
|
||||||
|
if (version === 0) { return; }
|
||||||
|
if (version === 1) {
|
||||||
|
return '/1/' + hexToBase64(secret.channel) + '/' +
|
||||||
|
Crypto.b64RemoveSlashes(data.fileKeyStr) + '/';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// V1
|
||||||
|
/*var getEditHashFromKeys = Hash.getEditHashFromKeys = function (chanKey, keys) {
|
||||||
if (typeof keys === 'string') {
|
if (typeof keys === 'string') {
|
||||||
return chanKey + keys;
|
return chanKey + keys;
|
||||||
}
|
}
|
||||||
@@ -34,7 +77,7 @@ define([
|
|||||||
};
|
};
|
||||||
var getFileHashFromKeys = Hash.getFileHashFromKeys = function (fileKey, cryptKey) {
|
var getFileHashFromKeys = Hash.getFileHashFromKeys = function (fileKey, cryptKey) {
|
||||||
return '/1/' + hexToBase64(fileKey) + '/' + Crypto.b64RemoveSlashes(cryptKey) + '/';
|
return '/1/' + hexToBase64(fileKey) + '/' + Crypto.b64RemoveSlashes(cryptKey) + '/';
|
||||||
};
|
};*/
|
||||||
Hash.getUserHrefFromKeys = function (origin, username, pubkey) {
|
Hash.getUserHrefFromKeys = function (origin, username, pubkey) {
|
||||||
return origin + '/user/#/1/' + username + '/' + pubkey.replace(/\//g, '-');
|
return origin + '/user/#/1/' + username + '/' + pubkey.replace(/\//g, '-');
|
||||||
};
|
};
|
||||||
@@ -43,6 +86,24 @@ define([
|
|||||||
return s.replace(/\/+/g, '/');
|
return s.replace(/\/+/g, '/');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Hash.createChannelId = function () {
|
||||||
|
var id = uint8ArrayToHex(Crypto.Nacl.randomBytes(16));
|
||||||
|
if (id.length !== 32 || /[^a-f0-9]/.test(id)) {
|
||||||
|
throw new Error('channel ids must consist of 32 hex characters');
|
||||||
|
}
|
||||||
|
return id;
|
||||||
|
};
|
||||||
|
|
||||||
|
Hash.createRandomHash = function (type, password) {
|
||||||
|
var cryptor = Crypto.createEditCryptor2(void 0, void 0, password);
|
||||||
|
return getEditHashFromKeys({
|
||||||
|
password: Boolean(password),
|
||||||
|
version: 2,
|
||||||
|
type: type,
|
||||||
|
keys: { editKeyStr: cryptor.editKeyStr }
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Version 0
|
Version 0
|
||||||
/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy
|
/pad/#67b8385b07352be53e40746d2be6ccd7XAYSuJYYqa9NfmInyHci7LNy
|
||||||
@@ -56,25 +117,56 @@ Version 1
|
|||||||
var hashArr = fixDuplicateSlashes(hash).split('/');
|
var hashArr = fixDuplicateSlashes(hash).split('/');
|
||||||
if (['media', 'file', 'user', 'invite'].indexOf(type) === -1) {
|
if (['media', 'file', 'user', 'invite'].indexOf(type) === -1) {
|
||||||
parsed.type = 'pad';
|
parsed.type = 'pad';
|
||||||
if (hash.slice(0,1) !== '/' && hash.length >= 56) {
|
if (hash.slice(0,1) !== '/' && hash.length >= 56) { // Version 0
|
||||||
// Old hash
|
// Old hash
|
||||||
parsed.channel = hash.slice(0, 32);
|
parsed.channel = hash.slice(0, 32);
|
||||||
parsed.key = hash.slice(32, 56);
|
parsed.key = hash.slice(32, 56);
|
||||||
parsed.version = 0;
|
parsed.version = 0;
|
||||||
|
parsed.getHash = function () { return hash; };
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
if (hashArr[1] && hashArr[1] === '1') {
|
var options;
|
||||||
|
if (hashArr[1] && hashArr[1] === '1') { // Version 1
|
||||||
parsed.version = 1;
|
parsed.version = 1;
|
||||||
parsed.mode = hashArr[2];
|
parsed.mode = hashArr[2];
|
||||||
parsed.channel = hashArr[3];
|
parsed.channel = hashArr[3];
|
||||||
parsed.key = hashArr[4].replace(/-/g, '/');
|
parsed.key = Crypto.b64AddSlashes(hashArr[4]);
|
||||||
var options = hashArr.slice(5);
|
|
||||||
|
options = hashArr.slice(5);
|
||||||
parsed.present = options.indexOf('present') !== -1;
|
parsed.present = options.indexOf('present') !== -1;
|
||||||
parsed.embed = options.indexOf('embed') !== -1;
|
parsed.embed = options.indexOf('embed') !== -1;
|
||||||
|
|
||||||
|
parsed.getHash = function (opts) {
|
||||||
|
var hash = hashArr.slice(0, 5).join('/') + '/';
|
||||||
|
if (opts.embed) { hash += 'embed/'; }
|
||||||
|
if (opts.present) { hash += 'present/'; }
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
|
return parsed;
|
||||||
|
}
|
||||||
|
if (hashArr[1] && hashArr[1] === '2') { // Version 2
|
||||||
|
parsed.version = 2;
|
||||||
|
parsed.app = hashArr[2];
|
||||||
|
parsed.mode = hashArr[3];
|
||||||
|
parsed.key = hashArr[4];
|
||||||
|
|
||||||
|
options = hashArr.slice(5);
|
||||||
|
parsed.password = options.indexOf('p') !== -1;
|
||||||
|
parsed.present = options.indexOf('present') !== -1;
|
||||||
|
parsed.embed = options.indexOf('embed') !== -1;
|
||||||
|
|
||||||
|
parsed.getHash = function (opts) {
|
||||||
|
var hash = hashArr.slice(0, 5).join('/') + '/';
|
||||||
|
if (parsed.password) { hash += 'p/'; }
|
||||||
|
if (opts.embed) { hash += 'embed/'; }
|
||||||
|
if (opts.present) { hash += 'present/'; }
|
||||||
|
return hash;
|
||||||
|
};
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
return parsed;
|
return parsed;
|
||||||
}
|
}
|
||||||
|
parsed.getHash = function () { return hashArr.join('/'); };
|
||||||
if (['media', 'file'].indexOf(type) !== -1) {
|
if (['media', 'file'].indexOf(type) !== -1) {
|
||||||
parsed.type = 'file';
|
parsed.type = 'file';
|
||||||
if (hashArr[1] && hashArr[1] === '1') {
|
if (hashArr[1] && hashArr[1] === '1') {
|
||||||
@@ -125,17 +217,9 @@ Version 1
|
|||||||
url += ret.type + '/';
|
url += ret.type + '/';
|
||||||
if (!ret.hashData) { return url; }
|
if (!ret.hashData) { return url; }
|
||||||
if (ret.hashData.type !== 'pad') { return url + '#' + ret.hash; }
|
if (ret.hashData.type !== 'pad') { return url + '#' + ret.hash; }
|
||||||
if (ret.hashData.version !== 1) { return url + '#' + ret.hash; }
|
if (ret.hashData.version === 0) { return url + '#' + ret.hash; }
|
||||||
url += '#/' + ret.hashData.version +
|
var hash = ret.hashData.getHash(options);
|
||||||
'/' + ret.hashData.mode +
|
url += '#' + hash;
|
||||||
'/' + ret.hashData.channel.replace(/\//g, '-') +
|
|
||||||
'/' + ret.hashData.key.replace(/\//g, '-') +'/';
|
|
||||||
if (options.embed) {
|
|
||||||
url += 'embed/';
|
|
||||||
}
|
|
||||||
if (options.present) {
|
|
||||||
url += 'present/';
|
|
||||||
}
|
|
||||||
return url;
|
return url;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -153,12 +237,13 @@ Version 1
|
|||||||
return '';
|
return '';
|
||||||
});
|
});
|
||||||
idx = href.indexOf('/#');
|
idx = href.indexOf('/#');
|
||||||
|
if (idx === -1) { return ret; }
|
||||||
ret.hash = href.slice(idx + 2);
|
ret.hash = href.slice(idx + 2);
|
||||||
ret.hashData = parseTypeHash(ret.type, ret.hash);
|
ret.hashData = parseTypeHash(ret.type, ret.hash);
|
||||||
return ret;
|
return ret;
|
||||||
};
|
};
|
||||||
|
|
||||||
var getRelativeHref = Hash.getRelativeHref = function (href) {
|
Hash.getRelativeHref = function (href) {
|
||||||
if (!href) { return; }
|
if (!href) { return; }
|
||||||
if (href.indexOf('#') === -1) { return; }
|
if (href.indexOf('#') === -1) { return; }
|
||||||
var parsed = parsePadUrl(href);
|
var parsed = parsePadUrl(href);
|
||||||
@@ -170,11 +255,13 @@ Version 1
|
|||||||
* - no argument: use the URL hash or create one if it doesn't exist
|
* - no argument: use the URL hash or create one if it doesn't exist
|
||||||
* - secretHash provided: use secretHash to find the keys
|
* - secretHash provided: use secretHash to find the keys
|
||||||
*/
|
*/
|
||||||
Hash.getSecrets = function (type, secretHash) {
|
Hash.getSecrets = function (type, secretHash, password) {
|
||||||
var secret = {};
|
var secret = {};
|
||||||
var generate = function () {
|
var generate = function () {
|
||||||
secret.keys = Crypto.createEditCryptor();
|
secret.keys = Crypto.createEditCryptor2(void 0, void 0, password);
|
||||||
secret.key = Crypto.createEditCryptor().editKeyStr;
|
secret.channel = base64ToHex(secret.keys.chanId);
|
||||||
|
secret.version = 2;
|
||||||
|
secret.type = type;
|
||||||
};
|
};
|
||||||
if (!secretHash && !window.location.hash) { //!/#/.test(window.location.href)) {
|
if (!secretHash && !window.location.hash) { //!/#/.test(window.location.href)) {
|
||||||
generate();
|
generate();
|
||||||
@@ -191,7 +278,6 @@ Version 1
|
|||||||
parsed = pHref.hashData;
|
parsed = pHref.hashData;
|
||||||
hash = pHref.hash;
|
hash = pHref.hash;
|
||||||
}
|
}
|
||||||
//var parsed = parsePadUrl(window.location.href);
|
|
||||||
//var hash = secretHash || window.location.hash.slice(1);
|
//var hash = secretHash || window.location.hash.slice(1);
|
||||||
if (hash.length === 0) {
|
if (hash.length === 0) {
|
||||||
generate();
|
generate();
|
||||||
@@ -203,9 +289,10 @@ Version 1
|
|||||||
// Old hash
|
// Old hash
|
||||||
secret.channel = parsed.channel;
|
secret.channel = parsed.channel;
|
||||||
secret.key = parsed.key;
|
secret.key = parsed.key;
|
||||||
}
|
secret.version = 0;
|
||||||
else if (parsed.version === 1) {
|
} else if (parsed.version === 1) {
|
||||||
// New hash
|
// New hash
|
||||||
|
secret.version = 1;
|
||||||
if (parsed.type === "pad") {
|
if (parsed.type === "pad") {
|
||||||
secret.channel = base64ToHex(parsed.channel);
|
secret.channel = base64ToHex(parsed.channel);
|
||||||
if (parsed.mode === 'edit') {
|
if (parsed.mode === 'edit') {
|
||||||
@@ -229,49 +316,63 @@ Version 1
|
|||||||
// version 2 hashes are to be used for encrypted blobs
|
// version 2 hashes are to be used for encrypted blobs
|
||||||
throw new Error("User hashes can't be opened (yet)");
|
throw new Error("User hashes can't be opened (yet)");
|
||||||
}
|
}
|
||||||
|
} else if (parsed.version === 2) {
|
||||||
|
// New hash
|
||||||
|
secret.version = 2;
|
||||||
|
secret.type = type;
|
||||||
|
secret.password = password;
|
||||||
|
if (parsed.type === "pad") {
|
||||||
|
if (parsed.mode === 'edit') {
|
||||||
|
secret.keys = Crypto.createEditCryptor2(parsed.key, void 0, password);
|
||||||
|
secret.channel = base64ToHex(secret.keys.chanId);
|
||||||
|
secret.key = secret.keys.editKeyStr;
|
||||||
|
if (secret.channel.length !== 32 || secret.key.length !== 24) {
|
||||||
|
throw new Error("The channel key and/or the encryption key is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (parsed.mode === 'view') {
|
||||||
|
secret.keys = Crypto.createViewCryptor2(parsed.key, password);
|
||||||
|
secret.channel = base64ToHex(secret.keys.chanId);
|
||||||
|
if (secret.channel.length !== 32) {
|
||||||
|
throw new Error("The channel key is invalid");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (parsed.type === "file") {
|
||||||
|
throw new Error("File hashes should be version 1");
|
||||||
|
} else if (parsed.type === "user") {
|
||||||
|
throw new Error("User hashes can't be opened (yet)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return secret;
|
return secret;
|
||||||
};
|
};
|
||||||
|
|
||||||
Hash.getHashes = function (channel, secret) {
|
Hash.getHashes = function (secret) {
|
||||||
var hashes = {};
|
var hashes = {};
|
||||||
if (!secret.keys) {
|
secret = JSON.parse(JSON.stringify(secret));
|
||||||
|
|
||||||
|
if (!secret.keys && !secret.key) {
|
||||||
console.error('e');
|
console.error('e');
|
||||||
return hashes;
|
return hashes;
|
||||||
|
} else if (!secret.keys) {
|
||||||
|
secret.keys = {};
|
||||||
}
|
}
|
||||||
if (secret.keys.editKeyStr) {
|
|
||||||
hashes.editHash = getEditHashFromKeys(channel, secret.keys);
|
if (secret.keys.editKeyStr || (secret.version === 0 && secret.key)) {
|
||||||
|
hashes.editHash = getEditHashFromKeys(secret);
|
||||||
}
|
}
|
||||||
if (secret.keys.viewKeyStr) {
|
if (secret.keys.viewKeyStr) {
|
||||||
hashes.viewHash = getViewHashFromKeys(channel, secret.keys);
|
hashes.viewHash = getViewHashFromKeys(secret);
|
||||||
}
|
}
|
||||||
if (secret.keys.fileKeyStr) {
|
if (secret.keys.fileKeyStr) {
|
||||||
hashes.fileHash = getFileHashFromKeys(channel, secret.keys.fileKeyStr);
|
hashes.fileHash = getFileHashFromKeys(secret);
|
||||||
}
|
}
|
||||||
return hashes;
|
return hashes;
|
||||||
};
|
};
|
||||||
|
|
||||||
var createChannelId = Hash.createChannelId = function () {
|
|
||||||
var id = uint8ArrayToHex(Crypto.Nacl.randomBytes(16));
|
|
||||||
if (id.length !== 32 || /[^a-f0-9]/.test(id)) {
|
|
||||||
throw new Error('channel ids must consist of 32 hex characters');
|
|
||||||
}
|
|
||||||
return id;
|
|
||||||
};
|
|
||||||
|
|
||||||
Hash.createRandomHash = function () {
|
|
||||||
// 16 byte channel Id
|
|
||||||
var channelId = Util.hexToBase64(createChannelId());
|
|
||||||
// 18 byte encryption key
|
|
||||||
var key = Crypto.b64RemoveSlashes(Crypto.rand64(18));
|
|
||||||
return '/1/edit/' + [channelId, key].join('/') + '/';
|
|
||||||
};
|
|
||||||
|
|
||||||
// STORAGE
|
// STORAGE
|
||||||
Hash.findWeaker = function (href, recents) {
|
Hash.findWeaker = function (href, channel, recents) {
|
||||||
var rHref = href || getRelativeHref(window.location.href);
|
var parsed = parsePadUrl(href);
|
||||||
var parsed = parsePadUrl(rHref);
|
|
||||||
if (!parsed.hash) { return false; }
|
if (!parsed.hash) { return false; }
|
||||||
var weaker;
|
var weaker;
|
||||||
Object.keys(recents).some(function (id) {
|
Object.keys(recents).some(function (id) {
|
||||||
@@ -279,6 +380,8 @@ Version 1
|
|||||||
var p = parsePadUrl(pad.href);
|
var p = parsePadUrl(pad.href);
|
||||||
if (p.type !== parsed.type) { return; } // Not the same type
|
if (p.type !== parsed.type) { return; } // Not the same type
|
||||||
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
||||||
|
if (channel !== pad.channel) { return; } // Not the same channel
|
||||||
|
|
||||||
var pHash = p.hashData;
|
var pHash = p.hashData;
|
||||||
var parsedHash = parsed.hashData;
|
var parsedHash = parsed.hashData;
|
||||||
if (!parsedHash || !pHash) { return; }
|
if (!parsedHash || !pHash) { return; }
|
||||||
@@ -287,18 +390,16 @@ Version 1
|
|||||||
if (pHash.type !== 'pad' && parsedHash.type !== 'pad') { return; }
|
if (pHash.type !== 'pad' && parsedHash.type !== 'pad') { return; }
|
||||||
|
|
||||||
if (pHash.version !== parsedHash.version) { return; }
|
if (pHash.version !== parsedHash.version) { return; }
|
||||||
if (pHash.channel !== parsedHash.channel) { return; }
|
|
||||||
if (pHash.mode === 'view' && parsedHash.mode === 'edit') {
|
if (pHash.mode === 'view' && parsedHash.mode === 'edit') {
|
||||||
weaker = pad.href;
|
weaker = pad;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
return weaker;
|
return weaker;
|
||||||
};
|
};
|
||||||
var findStronger = Hash.findStronger = function (href, recents) {
|
Hash.findStronger = function (href, channel, recents) {
|
||||||
var rHref = href || getRelativeHref(window.location.href);
|
var parsed = parsePadUrl(href);
|
||||||
var parsed = parsePadUrl(rHref);
|
|
||||||
if (!parsed.hash) { return false; }
|
if (!parsed.hash) { return false; }
|
||||||
// We can't have a stronger hash if we're already in edit mode
|
// We can't have a stronger hash if we're already in edit mode
|
||||||
if (parsed.hashData && parsed.hashData.mode === 'edit') { return; }
|
if (parsed.hashData && parsed.hashData.mode === 'edit') { return; }
|
||||||
@@ -308,6 +409,8 @@ Version 1
|
|||||||
var p = parsePadUrl(pad.href);
|
var p = parsePadUrl(pad.href);
|
||||||
if (p.type !== parsed.type) { return; } // Not the same type
|
if (p.type !== parsed.type) { return; } // Not the same type
|
||||||
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
if (p.hash === parsed.hash) { return; } // Same hash, not stronger
|
||||||
|
if (channel !== pad.channel) { return; } // Not the same channel
|
||||||
|
|
||||||
var pHash = p.hashData;
|
var pHash = p.hashData;
|
||||||
var parsedHash = parsed.hashData;
|
var parsedHash = parsed.hashData;
|
||||||
if (!parsedHash || !pHash) { return; }
|
if (!parsedHash || !pHash) { return; }
|
||||||
@@ -316,37 +419,20 @@ Version 1
|
|||||||
if (pHash.type !== 'pad' && parsedHash.type !== 'pad') { return; }
|
if (pHash.type !== 'pad' && parsedHash.type !== 'pad') { return; }
|
||||||
|
|
||||||
if (pHash.version !== parsedHash.version) { return; }
|
if (pHash.version !== parsedHash.version) { return; }
|
||||||
if (pHash.channel !== parsedHash.channel) { return; }
|
|
||||||
if (pHash.mode === 'edit' && parsedHash.mode === 'view') {
|
if (pHash.mode === 'edit' && parsedHash.mode === 'view') {
|
||||||
stronger = pad.href;
|
stronger = pad;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
return stronger;
|
return stronger;
|
||||||
};
|
};
|
||||||
Hash.isNotStrongestStored = function (href, recents) {
|
|
||||||
return findStronger(href, recents);
|
|
||||||
};
|
|
||||||
|
|
||||||
Hash.hrefToHexChannelId = function (href) {
|
Hash.hrefToHexChannelId = function (href, password) {
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
if (!parsed || !parsed.hash) { return; }
|
if (!parsed || !parsed.hash) { return; }
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, password);
|
||||||
parsed = parsed.hashData;
|
return secret.channel;
|
||||||
if (parsed.version === 0) {
|
|
||||||
return parsed.channel;
|
|
||||||
} else if (parsed.version !== 1 && parsed.version !== 2) {
|
|
||||||
console.error("parsed href had no version");
|
|
||||||
console.error(parsed);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var channel = parsed.channel;
|
|
||||||
if (!channel) { return; }
|
|
||||||
|
|
||||||
var hex = base64ToHex(channel);
|
|
||||||
return hex;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Hash.getBlobPathFromHex = function (id) {
|
Hash.getBlobPathFromHex = function (id) {
|
||||||
|
|||||||
@@ -6,15 +6,18 @@ define([
|
|||||||
'/common/common-notifier.js',
|
'/common/common-notifier.js',
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/bower_components/alertifyjs/dist/js/alertify.js',
|
'/bower_components/alertifyjs/dist/js/alertify.js',
|
||||||
'/common/tippy.min.js',
|
'/common/tippy/tippy.min.js',
|
||||||
'/customize/pages.js',
|
'/customize/pages.js',
|
||||||
'/common/hyperscript.js',
|
'/common/hyperscript.js',
|
||||||
|
'/customize/loading.js',
|
||||||
'/common/test.js',
|
'/common/test.js',
|
||||||
|
|
||||||
|
'/common/jquery-ui/jquery-ui.min.js',
|
||||||
'/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.js',
|
'/bower_components/bootstrap-tokenfield/dist/bootstrap-tokenfield.js',
|
||||||
'css!/common/tippy.css',
|
'css!/common/tippy/tippy.css',
|
||||||
|
'css!/common/jquery-ui/jquery-ui.min.css'
|
||||||
], function ($, Messages, Util, Hash, Notifier, AppConfig,
|
], function ($, Messages, Util, Hash, Notifier, AppConfig,
|
||||||
Alertify, Tippy, Pages, h, Test) {
|
Alertify, Tippy, Pages, h, Loading, Test) {
|
||||||
var UI = {};
|
var UI = {};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -182,11 +185,17 @@ define([
|
|||||||
]);
|
]);
|
||||||
};
|
};
|
||||||
|
|
||||||
UI.tokenField = function (target) {
|
UI.tokenField = function (target, autocomplete) {
|
||||||
var t = {
|
var t = {
|
||||||
element: target || h('input'),
|
element: target || h('input'),
|
||||||
};
|
};
|
||||||
var $t = t.tokenfield = $(t.element).tokenfield();
|
var $t = t.tokenfield = $(t.element).tokenfield({
|
||||||
|
autocomplete: {
|
||||||
|
source: autocomplete,
|
||||||
|
delay: 100
|
||||||
|
},
|
||||||
|
showAutocompleteOnFocus: false
|
||||||
|
});
|
||||||
|
|
||||||
t.getTokens = function (ignorePending) {
|
t.getTokens = function (ignorePending) {
|
||||||
var tokens = $t.tokenfield('getTokens').map(function (token) {
|
var tokens = $t.tokenfield('getTokens').map(function (token) {
|
||||||
@@ -209,10 +218,17 @@ define([
|
|||||||
|
|
||||||
t.preventDuplicates = function (cb) {
|
t.preventDuplicates = function (cb) {
|
||||||
$t.on('tokenfield:createtoken', function (ev) {
|
$t.on('tokenfield:createtoken', function (ev) {
|
||||||
|
// Close the suggest list when a token is added because we're going to wipe the input
|
||||||
|
var $input = $t.closest('.tokenfield').find('.token-input');
|
||||||
|
$input.autocomplete('close');
|
||||||
|
|
||||||
var val;
|
var val;
|
||||||
ev.attrs.value = ev.attrs.value.toLowerCase();
|
ev.attrs.value = ev.attrs.value.toLowerCase();
|
||||||
if (t.getTokens(true).some(function (t) {
|
if (t.getTokens(true).some(function (t) {
|
||||||
if (t === ev.attrs.value) { return ((val = t)); }
|
if (t === ev.attrs.value) {
|
||||||
|
ev.preventDefault();
|
||||||
|
return ((val = t));
|
||||||
|
}
|
||||||
})) {
|
})) {
|
||||||
ev.preventDefault();
|
ev.preventDefault();
|
||||||
if (typeof(cb) === 'function') { cb(val); }
|
if (typeof(cb) === 'function') { cb(val); }
|
||||||
@@ -240,7 +256,7 @@ define([
|
|||||||
return t;
|
return t;
|
||||||
};
|
};
|
||||||
|
|
||||||
dialog.tagPrompt = function (tags, cb) {
|
dialog.tagPrompt = function (tags, existing, cb) {
|
||||||
var input = dialog.textInput();
|
var input = dialog.textInput();
|
||||||
|
|
||||||
var tagger = dialog.frame([
|
var tagger = dialog.frame([
|
||||||
@@ -254,7 +270,7 @@ define([
|
|||||||
dialog.nav(),
|
dialog.nav(),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var field = UI.tokenField(input).preventDuplicates(function (val) {
|
var field = UI.tokenField(input, existing).preventDuplicates(function (val) {
|
||||||
UI.warn(Messages._getKey('tags_duplicate', [val]));
|
UI.warn(Messages._getKey('tags_duplicate', [val]));
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -395,7 +411,7 @@ define([
|
|||||||
stopListening(listener);
|
stopListening(listener);
|
||||||
cb();
|
cb();
|
||||||
});
|
});
|
||||||
listener = listenForKeys(close, close, ok);
|
listener = listenForKeys(close, close);
|
||||||
var $ok = $(ok).click(close);
|
var $ok = $(ok).click(close);
|
||||||
|
|
||||||
document.body.appendChild(frame);
|
document.body.appendChild(frame);
|
||||||
@@ -512,6 +528,50 @@ define([
|
|||||||
Alertify.error(Util.fixHTML(msg));
|
Alertify.error(Util.fixHTML(msg));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UI.passwordInput = function (opts, displayEye) {
|
||||||
|
opts = opts || {};
|
||||||
|
var attributes = merge({
|
||||||
|
type: 'password'
|
||||||
|
}, opts);
|
||||||
|
|
||||||
|
var input = h('input.cp-password-input', attributes);
|
||||||
|
var reveal = UI.createCheckbox('cp-password-reveal', Messages.password_show);
|
||||||
|
var eye = h('span.fa.fa-eye.cp-password-reveal');
|
||||||
|
|
||||||
|
$(reveal).find('input').on('change', function () {
|
||||||
|
if($(this).is(':checked')) {
|
||||||
|
$(input).prop('type', 'text');
|
||||||
|
$(input).focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$(input).prop('type', 'password');
|
||||||
|
$(input).focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
$(eye).mousedown(function () {
|
||||||
|
$(input).prop('type', 'text');
|
||||||
|
$(input).focus();
|
||||||
|
}).mouseup(function(){
|
||||||
|
$(input).prop('type', 'password');
|
||||||
|
$(input).focus();
|
||||||
|
}).mouseout(function(){
|
||||||
|
$(input).prop('type', 'password');
|
||||||
|
$(input).focus();
|
||||||
|
});
|
||||||
|
if (displayEye) {
|
||||||
|
$(reveal).hide();
|
||||||
|
} else {
|
||||||
|
$(eye).hide();
|
||||||
|
}
|
||||||
|
|
||||||
|
return h('span.cp-password-container', [
|
||||||
|
input,
|
||||||
|
reveal,
|
||||||
|
eye
|
||||||
|
]);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* spinner
|
* spinner
|
||||||
*/
|
*/
|
||||||
@@ -539,48 +599,99 @@ define([
|
|||||||
|
|
||||||
var LOADING = 'cp-loading';
|
var LOADING = 'cp-loading';
|
||||||
|
|
||||||
var getRandomTip = function () {
|
/*var getRandomTip = function () {
|
||||||
if (!Messages.tips || !Object.keys(Messages.tips).length) { return ''; }
|
if (!Messages.tips || !Object.keys(Messages.tips).length) { return ''; }
|
||||||
var keys = Object.keys(Messages.tips);
|
var keys = Object.keys(Messages.tips);
|
||||||
var rdm = Math.floor(Math.random() * keys.length);
|
var rdm = Math.floor(Math.random() * keys.length);
|
||||||
return Messages.tips[keys[rdm]];
|
return Messages.tips[keys[rdm]];
|
||||||
|
};*/
|
||||||
|
var loading = {
|
||||||
|
error: false,
|
||||||
|
driveState: 0,
|
||||||
|
padState: 0
|
||||||
};
|
};
|
||||||
UI.addLoadingScreen = function (config) {
|
UI.addLoadingScreen = function (config) {
|
||||||
config = config || {};
|
config = config || {};
|
||||||
var loadingText = config.loadingText;
|
var loadingText = config.loadingText;
|
||||||
var hideTips = config.hideTips || AppConfig.hideLoadingScreenTips;
|
var todo = function () {
|
||||||
var hideLogo = config.hideLogo;
|
var $loading = $('#' + LOADING); //.show();
|
||||||
var $loading, $container;
|
|
||||||
if ($('#' + LOADING).length) {
|
|
||||||
$loading = $('#' + LOADING); //.show();
|
|
||||||
$loading.css('display', '');
|
$loading.css('display', '');
|
||||||
$loading.removeClass('cp-loading-hidden');
|
$loading.removeClass('cp-loading-hidden');
|
||||||
$('.cp-loading-spinner-container').show();
|
$('.cp-loading-spinner-container').show();
|
||||||
|
if (!config.noProgress && !$loading.find('.cp-loading-progress').length) {
|
||||||
|
var progress = h('div.cp-loading-progress', [
|
||||||
|
h('p.cp-loading-progress-drive'),
|
||||||
|
h('p.cp-loading-progress-pad')
|
||||||
|
]);
|
||||||
|
$loading.find('.cp-loading-container').append(progress);
|
||||||
|
} else if (config.noProgress) {
|
||||||
|
$loading.find('.cp-loading-progress').remove();
|
||||||
|
}
|
||||||
if (loadingText) {
|
if (loadingText) {
|
||||||
$('#' + LOADING).find('p').text(loadingText);
|
$('#' + LOADING).find('#cp-loading-message').show().text(loadingText);
|
||||||
} else {
|
} else {
|
||||||
$('#' + LOADING).find('p').text('');
|
$('#' + LOADING).find('#cp-loading-message').hide().text('');
|
||||||
}
|
}
|
||||||
$container = $loading.find('.cp-loading-container');
|
loading.error = false;
|
||||||
|
};
|
||||||
|
if ($('#' + LOADING).length) {
|
||||||
|
todo();
|
||||||
} else {
|
} else {
|
||||||
$loading = $(Pages.loadingScreen());
|
Loading();
|
||||||
$container = $loading.find('.cp-loading-container');
|
todo();
|
||||||
if (hideLogo) {
|
|
||||||
$loading.find('img').hide();
|
|
||||||
} else {
|
|
||||||
$loading.find('img').show();
|
|
||||||
}
|
|
||||||
var $spinner = $loading.find('.cp-loading-spinner-container');
|
|
||||||
$spinner.show();
|
|
||||||
$('body').append($loading);
|
|
||||||
}
|
}
|
||||||
if (Messages.tips && !hideTips) {
|
};
|
||||||
var $loadingTip = $('<div>', {'id': 'cp-loading-tip'});
|
UI.updateLoadingProgress = function (data, isDrive) {
|
||||||
$('<span>', {'class': 'tips'}).text(getRandomTip()).appendTo($loadingTip);
|
var $loading = $('#' + LOADING);
|
||||||
$loadingTip.css({
|
if (!$loading.length || loading.error) { return; }
|
||||||
'bottom': $('body').height()/2 - $container.height()/2 + 20 + 'px'
|
var $progress;
|
||||||
});
|
if (isDrive) {
|
||||||
$('body').append($loadingTip);
|
console.log(data);
|
||||||
|
// Drive state
|
||||||
|
if (loading.driveState === -1) { return; } // Already loaded
|
||||||
|
$progress = $loading.find('.cp-loading-progress-drive');
|
||||||
|
if (!$progress.length) { return; } // Can't find the box to display data
|
||||||
|
|
||||||
|
// If state is -1, remove the box, drive is loaded
|
||||||
|
if (data.state === -1) {
|
||||||
|
loading.driveState = -1;
|
||||||
|
$progress.remove();
|
||||||
|
} else {
|
||||||
|
if (data.state < loading.driveState) { return; } // We should not display old data
|
||||||
|
// Update the current state
|
||||||
|
loading.driveState = data.state;
|
||||||
|
data.progress = data.progress || 100;
|
||||||
|
data.msg = Messages['loading_drive_'+data.state] || '';
|
||||||
|
$progress.html(data.msg);
|
||||||
|
if (data.progress) {
|
||||||
|
$progress.append(h('div.cp-loading-progress-bar', [
|
||||||
|
h('div.cp-loading-progress-bar-value', {style: 'width:'+data.progress+'%;'})
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Pad state
|
||||||
|
if (loading.padState === -1) { return; } // Already loaded
|
||||||
|
$progress = $loading.find('.cp-loading-progress-pad');
|
||||||
|
if (!$progress.length) { return; } // Can't find the box to display data
|
||||||
|
|
||||||
|
// If state is -1, remove the box, pad is loaded
|
||||||
|
if (data.state === -1) {
|
||||||
|
loading.padState = -1;
|
||||||
|
$progress.remove();
|
||||||
|
} else {
|
||||||
|
if (data.state < loading.padState) { return; } // We should not display old data
|
||||||
|
// Update the current state
|
||||||
|
loading.padState = data.state;
|
||||||
|
data.progress = data.progress || 100;
|
||||||
|
data.msg = Messages['loading_pad_'+data.state] || '';
|
||||||
|
$progress.html(data.msg);
|
||||||
|
if (data.progress) {
|
||||||
|
$progress.append(h('div.cp-loading-progress-bar', [
|
||||||
|
h('div.cp-loading-progress-bar-value', {style: 'width:'+data.progress+'%;'})
|
||||||
|
]));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
UI.removeLoadingScreen = function (cb) {
|
UI.removeLoadingScreen = function (cb) {
|
||||||
@@ -591,7 +702,7 @@ define([
|
|||||||
|
|
||||||
$('#' + LOADING).addClass("cp-loading-hidden");
|
$('#' + LOADING).addClass("cp-loading-hidden");
|
||||||
setTimeout(cb, 750);
|
setTimeout(cb, 750);
|
||||||
//$('#' + LOADING).fadeOut(750, cb);
|
loading.error = false;
|
||||||
var $tip = $('#cp-loading-tip').css('top', '')
|
var $tip = $('#cp-loading-tip').css('top', '')
|
||||||
// loading.less sets transition-delay: $wait-time
|
// loading.less sets transition-delay: $wait-time
|
||||||
// and transition: opacity $fadeout-time
|
// and transition: opacity $fadeout-time
|
||||||
@@ -605,18 +716,27 @@ define([
|
|||||||
// jquery.fadeout can get stuck
|
// jquery.fadeout can get stuck
|
||||||
};
|
};
|
||||||
UI.errorLoadingScreen = function (error, transparent, exitable) {
|
UI.errorLoadingScreen = function (error, transparent, exitable) {
|
||||||
if (!$('#' + LOADING).is(':visible') || $('#' + LOADING).hasClass('cp-loading-hidden')) {
|
var $loading = $('#' + LOADING);
|
||||||
|
if (!$loading.is(':visible') || $loading.hasClass('cp-loading-hidden')) {
|
||||||
UI.addLoadingScreen({hideTips: true});
|
UI.addLoadingScreen({hideTips: true});
|
||||||
}
|
}
|
||||||
|
loading.error = true;
|
||||||
|
$loading.find('.cp-loading-progress').remove();
|
||||||
$('.cp-loading-spinner-container').hide();
|
$('.cp-loading-spinner-container').hide();
|
||||||
$('#cp-loading-tip').remove();
|
$('#cp-loading-tip').remove();
|
||||||
if (transparent) { $('#' + LOADING).css('opacity', 0.8); }
|
if (transparent) { $loading.css('opacity', 0.9); }
|
||||||
$('#' + LOADING).find('p').html(error || Messages.error);
|
var $error = $loading.find('#cp-loading-message').show();
|
||||||
|
if (error instanceof Element) {
|
||||||
|
$error.html('').append(error);
|
||||||
|
} else {
|
||||||
|
$error.html(error || Messages.error);
|
||||||
|
}
|
||||||
if (exitable) {
|
if (exitable) {
|
||||||
$(window).focus();
|
$(window).focus();
|
||||||
$(window).keydown(function (e) {
|
$(window).keydown(function (e) {
|
||||||
if (e.which === 27) {
|
if (e.which === 27) {
|
||||||
$('#' + LOADING).hide();
|
$loading.hide();
|
||||||
|
loading.error = false;
|
||||||
if (typeof(exitable) === "function") { exitable(); }
|
if (typeof(exitable) === "function") { exitable(); }
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -660,18 +780,40 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var delay = typeof(AppConfig.tooltipDelay) === "number" ? AppConfig.tooltipDelay : 500;
|
||||||
|
$.extend(true, Tippy.defaults, {
|
||||||
|
placement: 'bottom',
|
||||||
|
performance: true,
|
||||||
|
delay: [delay, 0],
|
||||||
|
//sticky: true,
|
||||||
|
theme: 'cryptpad',
|
||||||
|
arrow: true,
|
||||||
|
maxWidth: '200px',
|
||||||
|
flip: true,
|
||||||
|
popperOptions: {
|
||||||
|
modifiers: {
|
||||||
|
preventOverflow: { boundariesElement: 'window' }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
//arrowType: 'round',
|
||||||
|
dynamicTitle: true,
|
||||||
|
arrowTransform: 'scale(2)',
|
||||||
|
zIndex: 100000001
|
||||||
|
});
|
||||||
UI.addTooltips = function () {
|
UI.addTooltips = function () {
|
||||||
var MutationObserver = window.MutationObserver;
|
var MutationObserver = window.MutationObserver;
|
||||||
var delay = typeof(AppConfig.tooltipDelay) === "number" ? AppConfig.tooltipDelay : 500;
|
|
||||||
var addTippy = function (i, el) {
|
var addTippy = function (i, el) {
|
||||||
|
if (el._tippy) { return; }
|
||||||
if (el.nodeName === 'IFRAME') { return; }
|
if (el.nodeName === 'IFRAME') { return; }
|
||||||
Tippy(el, {
|
var opts = {
|
||||||
position: 'bottom',
|
distance: 15
|
||||||
distance: 0,
|
};
|
||||||
performance: true,
|
Array.prototype.slice.apply(el.attributes).filter(function (obj) {
|
||||||
delay: [delay, 0],
|
return /^data-tippy-/.test(obj.name);
|
||||||
sticky: true
|
}).forEach(function (obj) {
|
||||||
|
opts[obj.name.slice(11)] = obj.value;
|
||||||
});
|
});
|
||||||
|
Tippy(el, opts);
|
||||||
};
|
};
|
||||||
// This is the robust solution to remove dangling tooltips
|
// This is the robust solution to remove dangling tooltips
|
||||||
// The mutation observer does not always find removed nodes.
|
// The mutation observer does not always find removed nodes.
|
||||||
@@ -720,5 +862,9 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UI.createCheckbox = Pages.createCheckbox;
|
||||||
|
|
||||||
|
UI.createRadio = Pages.createRadio;
|
||||||
|
|
||||||
return UI;
|
return UI;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -99,7 +99,7 @@ define([
|
|||||||
try {
|
try {
|
||||||
var parsed = Hash.parsePadUrl(window.location.href);
|
var parsed = Hash.parsePadUrl(window.location.href);
|
||||||
if (!parsed.hashData) { return; }
|
if (!parsed.hashData) { return; }
|
||||||
var chan = parsed.hashData.channel;
|
var chan = Hash.hrefToHexChannelId(window.location.href);
|
||||||
// Decrypt
|
// Decrypt
|
||||||
var keyStr = parsed.hashData.key;
|
var keyStr = parsed.hashData.key;
|
||||||
var cryptor = Crypto.createEditCryptor(keyStr);
|
var cryptor = Crypto.createEditCryptor(keyStr);
|
||||||
@@ -113,7 +113,7 @@ define([
|
|||||||
if (!decryptMsg) { return; }
|
if (!decryptMsg) { return; }
|
||||||
// Parse
|
// Parse
|
||||||
msg = JSON.parse(decryptMsg);
|
msg = JSON.parse(decryptMsg);
|
||||||
if (msg[1] !== parsed.hashData.channel) { return; }
|
if (msg[1] !== chan) { return; }
|
||||||
var msgData = msg[2];
|
var msgData = msg[2];
|
||||||
var msgStr;
|
var msgStr;
|
||||||
if (msg[0] === "FRIEND_REQ") {
|
if (msg[0] === "FRIEND_REQ") {
|
||||||
@@ -199,7 +199,7 @@ define([
|
|||||||
var parsed = Hash.parsePadUrl(data.href);
|
var parsed = Hash.parsePadUrl(data.href);
|
||||||
if (!parsed.hashData) { return; }
|
if (!parsed.hashData) { return; }
|
||||||
// Message
|
// Message
|
||||||
var chan = parsed.hashData.channel;
|
var chan = Hash.hrefToHexChannelId(data.href);
|
||||||
var myData = createData(cfg.proxy);
|
var myData = createData(cfg.proxy);
|
||||||
var msg = ["FRIEND_REQ", chan, myData];
|
var msg = ["FRIEND_REQ", chan, myData];
|
||||||
// Encryption
|
// Encryption
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ define([
|
|||||||
if (content === oldThumbnailState) { return; }
|
if (content === oldThumbnailState) { return; }
|
||||||
oldThumbnailState = content;
|
oldThumbnailState = content;
|
||||||
Thumb.fromDOM(opts, function (err, b64) {
|
Thumb.fromDOM(opts, function (err, b64) {
|
||||||
Thumb.setPadThumbnail(common, opts.href, b64);
|
Thumb.setPadThumbnail(common, opts.href, null, b64);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
var nafa = Util.notAgainForAnother(mkThumbnail, Thumb.UPDATE_INTERVAL);
|
var nafa = Util.notAgainForAnother(mkThumbnail, Thumb.UPDATE_INTERVAL);
|
||||||
@@ -240,20 +240,22 @@ define([
|
|||||||
Thumb.addThumbnail = function(thumb, $span, cb) {
|
Thumb.addThumbnail = function(thumb, $span, cb) {
|
||||||
return addThumbnail(null, thumb, $span, cb);
|
return addThumbnail(null, thumb, $span, cb);
|
||||||
};
|
};
|
||||||
var getKey = function (href) {
|
var getKey = function (type, channel) {
|
||||||
var parsed = Hash.parsePadUrl(href);
|
return 'thumbnail-' + type + '-' + channel;
|
||||||
return 'thumbnail-' + parsed.type + '-' + parsed.hashData.channel;
|
|
||||||
};
|
};
|
||||||
Thumb.setPadThumbnail = function (common, href, b64, cb) {
|
Thumb.setPadThumbnail = function (common, href, channel, b64, cb) {
|
||||||
cb = cb || function () {};
|
cb = cb || function () {};
|
||||||
var k = getKey(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
channel = channel || common.getMetadataMgr().getPrivateData().channel;
|
||||||
|
var k = getKey(parsed.type, channel);
|
||||||
common.setThumbnail(k, b64, cb);
|
common.setThumbnail(k, b64, cb);
|
||||||
};
|
};
|
||||||
Thumb.displayThumbnail = function (common, href, $container, cb) {
|
Thumb.displayThumbnail = function (common, href, channel, $container, cb) {
|
||||||
cb = cb || function () {};
|
cb = cb || function () {};
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
var k = getKey(href);
|
var k = getKey(parsed.type, channel);
|
||||||
var whenNewThumb = function () {
|
var whenNewThumb = function () {
|
||||||
|
// PASSWORD_FILES
|
||||||
var secret = Hash.getSecrets('file', parsed.hash);
|
var secret = Hash.getSecrets('file', parsed.hash);
|
||||||
var hexFileName = Util.base64ToHex(secret.channel);
|
var hexFileName = Util.base64ToHex(secret.channel);
|
||||||
var src = Hash.getBlobPathFromHex(hexFileName);
|
var src = Hash.getBlobPathFromHex(hexFileName);
|
||||||
@@ -270,7 +272,7 @@ define([
|
|||||||
if (!v) {
|
if (!v) {
|
||||||
v = 'EMPTY';
|
v = 'EMPTY';
|
||||||
}
|
}
|
||||||
Thumb.setPadThumbnail(common, href, v, function (err) {
|
Thumb.setPadThumbnail(common, href, hexFileName, v, function (err) {
|
||||||
if (!metadata.thumbnail) { return; }
|
if (!metadata.thumbnail) { return; }
|
||||||
addThumbnail(err, metadata.thumbnail, $container, cb);
|
addThumbnail(err, metadata.thumbnail, $container, cb);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -13,8 +13,6 @@ define([
|
|||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
'/customize/application_config.js',
|
'/customize/application_config.js',
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
|
|
||||||
'css!/common/tippy.css',
|
|
||||||
], function ($, Config, Util, Hash, Language, UI, Constants, Feedback, h, MediaTag, Clipboard,
|
], function ($, Config, Util, Hash, Language, UI, Constants, Feedback, h, MediaTag, Clipboard,
|
||||||
Messages, AppConfig, NThen) {
|
Messages, AppConfig, NThen) {
|
||||||
var UIElements = {};
|
var UIElements = {};
|
||||||
@@ -25,20 +23,27 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
UIElements.updateTags = function (common, href) {
|
UIElements.updateTags = function (common, href) {
|
||||||
var sframeChan = common.getSframeChannel();
|
var existing, tags;
|
||||||
sframeChan.query('Q_TAGS_GET', href || null, function (err, res) {
|
NThen(function(waitFor) {
|
||||||
if (err || res.error) {
|
common.getSframeChannel().query("Q_GET_ALL_TAGS", null, waitFor(function(err, res) {
|
||||||
if (res.error === 'NO_ENTRY') {
|
if (err || res.error) { return void console.error(err || res.error); }
|
||||||
UI.alert(Messages.tags_noentry);
|
existing = Object.keys(res.tags).sort();
|
||||||
|
}));
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
common.getPadAttribute('tags', waitFor(function (err, res) {
|
||||||
|
if (err) {
|
||||||
|
if (err === 'NO_ENTRY') {
|
||||||
|
UI.alert(Messages.tags_noentry);
|
||||||
|
}
|
||||||
|
waitFor.abort();
|
||||||
|
return void console.error(err);
|
||||||
}
|
}
|
||||||
return void console.error(err || res.error);
|
tags = res || [];
|
||||||
}
|
}), href);
|
||||||
UI.dialog.tagPrompt(res.data, function (tags) {
|
}).nThen(function () {
|
||||||
if (!Array.isArray(tags)) { return; }
|
UI.dialog.tagPrompt(tags, existing, function (newTags) {
|
||||||
sframeChan.event('EV_TAGS_SET', {
|
if (!Array.isArray(newTags)) { return; }
|
||||||
tags: tags,
|
common.setPadAttribute('tags', newTags, null, href);
|
||||||
href: href,
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -62,6 +67,10 @@ define([
|
|||||||
var getPropertiesData = function (common, cb) {
|
var getPropertiesData = function (common, cb) {
|
||||||
var data = {};
|
var data = {};
|
||||||
NThen(function (waitFor) {
|
NThen(function (waitFor) {
|
||||||
|
common.getPadAttribute('password', waitFor(function (err, val) {
|
||||||
|
data.password = val;
|
||||||
|
}));
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
common.getPadAttribute('href', waitFor(function (err, val) {
|
common.getPadAttribute('href', waitFor(function (err, val) {
|
||||||
var base = common.getMetadataMgr().getPrivateData().origin;
|
var base = common.getMetadataMgr().getPrivateData().origin;
|
||||||
|
|
||||||
@@ -73,15 +82,19 @@ define([
|
|||||||
|
|
||||||
// We're not in a read-only pad
|
// We're not in a read-only pad
|
||||||
data.href = base + val;
|
data.href = base + val;
|
||||||
|
|
||||||
// Get Read-only href
|
// Get Read-only href
|
||||||
if (parsed.hashData.type !== "pad") { return; }
|
if (parsed.hashData.type !== "pad") { return; }
|
||||||
var i = data.href.indexOf('#') + 1;
|
var i = data.href.indexOf('#') + 1;
|
||||||
var hBase = data.href.slice(0, i);
|
var hBase = data.href.slice(0, i);
|
||||||
var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash);
|
var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
||||||
if (!hrefsecret.keys) { return; }
|
if (!hrefsecret.keys) { return; }
|
||||||
var viewHash = Hash.getViewHashFromKeys(hrefsecret.channel, hrefsecret.keys);
|
var viewHash = Hash.getViewHashFromKeys(hrefsecret);
|
||||||
data.roHref = hBase + viewHash;
|
data.roHref = hBase + viewHash;
|
||||||
}));
|
}));
|
||||||
|
common.getPadAttribute('channel', waitFor(function (err, val) {
|
||||||
|
data.channel = val;
|
||||||
|
}));
|
||||||
common.getPadAttribute('atime', waitFor(function (err, val) {
|
common.getPadAttribute('atime', waitFor(function (err, val) {
|
||||||
data.atime = val;
|
data.atime = val;
|
||||||
}));
|
}));
|
||||||
@@ -137,6 +150,22 @@ define([
|
|||||||
$d.append(UI.dialog.selectable(expire, {
|
$d.append(UI.dialog.selectable(expire, {
|
||||||
id: 'cp-app-prop-expire',
|
id: 'cp-app-prop-expire',
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
if (typeof data.password !== "undefined") {
|
||||||
|
$('<label>', {'for': 'cp-app-prop-password'}).text(Messages.creation_passwordValue)
|
||||||
|
.appendTo($d);
|
||||||
|
var password = UI.passwordInput({
|
||||||
|
id: 'cp-app-prop-expire',
|
||||||
|
readonly: 'readonly'
|
||||||
|
});
|
||||||
|
var $pwInput = $(password).find('.cp-password-input');
|
||||||
|
$pwInput.val(data.password).click(function () {
|
||||||
|
$pwInput[0].select();
|
||||||
|
});
|
||||||
|
$(password).find('.cp-checkmark').css('margin-bottom', '15px');
|
||||||
|
$d.append(password);
|
||||||
|
}
|
||||||
|
|
||||||
cb(void 0, $d);
|
cb(void 0, $d);
|
||||||
};
|
};
|
||||||
var getPadProperties = function (common, data, cb) {
|
var getPadProperties = function (common, data, cb) {
|
||||||
@@ -178,7 +207,7 @@ define([
|
|||||||
|
|
||||||
if (common.isLoggedIn() && AppConfig.enablePinning) {
|
if (common.isLoggedIn() && AppConfig.enablePinning) {
|
||||||
// check the size of this file...
|
// check the size of this file...
|
||||||
common.getFileSize(data.href, function (e, bytes) {
|
common.getFileSize(data.channel, function (e, bytes) {
|
||||||
if (e) {
|
if (e) {
|
||||||
// there was a problem with the RPC
|
// there was a problem with the RPC
|
||||||
console.error(e);
|
console.error(e);
|
||||||
@@ -237,7 +266,11 @@ define([
|
|||||||
var link = h('div.cp-share-modal', [
|
var link = h('div.cp-share-modal', [
|
||||||
h('label', Messages.share_linkAccess),
|
h('label', Messages.share_linkAccess),
|
||||||
h('br'),
|
h('br'),
|
||||||
h('input#cp-share-editable-true.cp-share-editable-value', {
|
UI.createRadio('cp-share-editable', 'cp-share-editable-true',
|
||||||
|
Messages.share_linkEdit, true, { mark: {tabindex:1} }),
|
||||||
|
UI.createRadio('cp-share-editable', 'cp-share-editable-false',
|
||||||
|
Messages.share_linkView, false, { mark: {tabindex:1} }),
|
||||||
|
/*h('input#cp-share-editable-true.cp-share-editable-value', {
|
||||||
type: 'radio',
|
type: 'radio',
|
||||||
name: 'cp-share-editable',
|
name: 'cp-share-editable',
|
||||||
value: 1,
|
value: 1,
|
||||||
@@ -248,25 +281,14 @@ define([
|
|||||||
name: 'cp-share-editable',
|
name: 'cp-share-editable',
|
||||||
value: 0
|
value: 0
|
||||||
}),
|
}),
|
||||||
h('label', { 'for': 'cp-share-editable-false' }, Messages.share_linkView),
|
h('label', { 'for': 'cp-share-editable-false' }, Messages.share_linkView),*/
|
||||||
h('br'),
|
|
||||||
h('br'),
|
h('br'),
|
||||||
h('label', Messages.share_linkOptions),
|
h('label', Messages.share_linkOptions),
|
||||||
h('br'),
|
h('br'),
|
||||||
h('input#cp-share-embed', {
|
UI.createCheckbox('cp-share-embed', Messages.share_linkEmbed, false, { mark: {tabindex:1} }),
|
||||||
type: 'checkbox',
|
UI.createCheckbox('cp-share-present', Messages.share_linkPresent, false, { mark: {tabindex:1} }),
|
||||||
name: 'cp-share-embed'
|
|
||||||
}),
|
|
||||||
h('label', { 'for': 'cp-share-embed' }, Messages.share_linkEmbed),
|
|
||||||
h('br'),
|
h('br'),
|
||||||
h('input#cp-share-present', {
|
UI.dialog.selectable('', { id: 'cp-share-link-preview', tabindex: 1 })
|
||||||
type: 'checkbox',
|
|
||||||
name: 'cp-share-present'
|
|
||||||
}),
|
|
||||||
h('label', { 'for': 'cp-share-present' }, Messages.share_linkPresent),
|
|
||||||
h('br'),
|
|
||||||
h('br'),
|
|
||||||
UI.dialog.selectable('', { id: 'cp-share-link-preview' })
|
|
||||||
]);
|
]);
|
||||||
if (!hashes.editHash) {
|
if (!hashes.editHash) {
|
||||||
$(link).find('#cp-share-editable-false').attr('checked', true);
|
$(link).find('#cp-share-editable-false').attr('checked', true);
|
||||||
@@ -482,13 +504,44 @@ define([
|
|||||||
'class': 'fa fa-upload cp-toolbar-icon-import',
|
'class': 'fa fa-upload cp-toolbar-icon-import',
|
||||||
title: Messages.importButtonTitle,
|
title: Messages.importButtonTitle,
|
||||||
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton));
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.importButton));
|
||||||
if (callback) {
|
/*if (data.types) {
|
||||||
|
// New import button in the toolbar
|
||||||
|
var importFunction = {
|
||||||
|
template: function () {
|
||||||
|
UIElements.openTemplatePicker(common, true);
|
||||||
|
},
|
||||||
|
file: function (cb) {
|
||||||
|
importContent('text/plain', function (content, file) {
|
||||||
|
cb(content, file);
|
||||||
|
}, {accept: data ? data.accept : undefined})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var toImport = [];
|
||||||
|
Object.keys(data.types).forEach(function (importType) {
|
||||||
|
if (!importFunction[importType] || !data.types[importType]) { return; }
|
||||||
|
var option = h('button', importType);
|
||||||
|
$(option).click(function () {
|
||||||
|
importFunction[importType](data.types[importType]);
|
||||||
|
});
|
||||||
|
toImport.push(options);
|
||||||
|
});
|
||||||
|
|
||||||
|
button.click(common.prepareFeedback(type));
|
||||||
|
|
||||||
|
if (toImport.length === 1) {
|
||||||
|
button.click(function () { $(toImport[0]).click(); });
|
||||||
|
} else {
|
||||||
|
Cryptpad.alert(h('p.cp-import-container', toImport));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (callback) {*/
|
||||||
|
// Old import button, used in settings
|
||||||
button
|
button
|
||||||
.click(common.prepareFeedback(type))
|
.click(common.prepareFeedback(type))
|
||||||
.click(importContent('text/plain', function (content, file) {
|
.click(importContent('text/plain', function (content, file) {
|
||||||
callback(content, file);
|
callback(content, file);
|
||||||
}, {accept: data ? data.accept : undefined}));
|
}, {accept: data ? data.accept : undefined}));
|
||||||
}
|
//}
|
||||||
break;
|
break;
|
||||||
case 'upload':
|
case 'upload':
|
||||||
button = $('<button>', {
|
button = $('<button>', {
|
||||||
@@ -520,6 +573,19 @@ define([
|
|||||||
if (data.accept) { $input.attr('accept', data.accept); }
|
if (data.accept) { $input.attr('accept', data.accept); }
|
||||||
button.click(function () { $input.click(); });
|
button.click(function () { $input.click(); });
|
||||||
break;
|
break;
|
||||||
|
case 'importtemplate':
|
||||||
|
if (!AppConfig.enableTemplates) { return; }
|
||||||
|
if (!common.isLoggedIn()) { return; }
|
||||||
|
button = $('<button>', {
|
||||||
|
'class': 'fa fa-upload cp-toolbar-icon-import',
|
||||||
|
title: Messages.template_import,
|
||||||
|
}).append($('<span>', {'class': 'cp-toolbar-drawer-element'}).text(Messages.template_import));
|
||||||
|
button
|
||||||
|
.click(common.prepareFeedback(type))
|
||||||
|
.click(function () {
|
||||||
|
UIElements.openTemplatePicker(common, true);
|
||||||
|
});
|
||||||
|
break;
|
||||||
case 'template':
|
case 'template':
|
||||||
if (!AppConfig.enableTemplates) { return; }
|
if (!AppConfig.enableTemplates) { return; }
|
||||||
if (!common.isLoggedIn()) { return; }
|
if (!common.isLoggedIn()) { return; }
|
||||||
@@ -584,7 +650,8 @@ define([
|
|||||||
sframeChan.query('Q_MOVE_TO_TRASH', null, function (err) {
|
sframeChan.query('Q_MOVE_TO_TRASH', null, function (err) {
|
||||||
if (err) { return void callback(err); }
|
if (err) { return void callback(err); }
|
||||||
var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted;
|
var cMsg = common.isLoggedIn() ? Messages.movedToTrash : Messages.deleted;
|
||||||
UI.alert(cMsg, undefined, true);
|
var msg = common.fixLinks($('<div>').html(cMsg));
|
||||||
|
UI.alert(msg);
|
||||||
callback();
|
callback();
|
||||||
return;
|
return;
|
||||||
});
|
});
|
||||||
@@ -890,14 +957,14 @@ define([
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var setHTML = function (e, html) {
|
||||||
|
e.innerHTML = html;
|
||||||
|
return e;
|
||||||
|
};
|
||||||
|
|
||||||
UIElements.createHelpMenu = function (common, categories) {
|
UIElements.createHelpMenu = function (common, categories) {
|
||||||
var type = common.getMetadataMgr().getMetadata().type || 'pad';
|
var type = common.getMetadataMgr().getMetadata().type || 'pad';
|
||||||
|
|
||||||
var setHTML = function (e, html) {
|
|
||||||
e.innerHTML = html;
|
|
||||||
return e;
|
|
||||||
};
|
|
||||||
|
|
||||||
var elements = [];
|
var elements = [];
|
||||||
if (Messages.help && Messages.help.generic) {
|
if (Messages.help && Messages.help.generic) {
|
||||||
Object.keys(Messages.help.generic).forEach(function (el) {
|
Object.keys(Messages.help.generic).forEach(function (el) {
|
||||||
@@ -920,18 +987,7 @@ define([
|
|||||||
h('ul', elements)
|
h('ul', elements)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var origin = common.getMetadataMgr().getPrivateData().origin || '';
|
common.fixLinks(text);
|
||||||
$(text).find('a').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
e.stopPropagation();
|
|
||||||
var href = $(this).attr('href');
|
|
||||||
var absolute = /^https?:\/\//i;
|
|
||||||
if (!absolute.test(href)) {
|
|
||||||
if (href.slice(0,1) !== '/') { href = '/' + href; }
|
|
||||||
href = origin + href;
|
|
||||||
}
|
|
||||||
common.openUnsafeURL(href);
|
|
||||||
});
|
|
||||||
|
|
||||||
var closeButton = h('span.cp-help-close.fa.fa-window-close');
|
var closeButton = h('span.cp-help-close.fa.fa-window-close');
|
||||||
var $toolbarButton = common.createButton('', true, {
|
var $toolbarButton = common.createButton('', true, {
|
||||||
@@ -1110,12 +1166,13 @@ define([
|
|||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
// No password for avatars
|
||||||
var secret = Hash.getSecrets('file', parsed.hash);
|
var secret = Hash.getSecrets('file', parsed.hash);
|
||||||
if (secret.keys && secret.channel) {
|
if (secret.keys && secret.channel) {
|
||||||
var cryptKey = secret.keys && secret.keys.fileKeyStr;
|
var cryptKey = secret.keys && secret.keys.fileKeyStr;
|
||||||
var hexFileName = Util.base64ToHex(secret.channel);
|
var hexFileName = Util.base64ToHex(secret.channel);
|
||||||
var src = Hash.getBlobPathFromHex(hexFileName);
|
var src = Hash.getBlobPathFromHex(hexFileName);
|
||||||
Common.getFileSize(href, function (e, data) {
|
Common.getFileSize(hexFileName, function (e, data) {
|
||||||
if (e) {
|
if (e) {
|
||||||
displayDefault();
|
displayDefault();
|
||||||
return void console.error(e);
|
return void console.error(e);
|
||||||
@@ -1148,7 +1205,7 @@ define([
|
|||||||
// so we can just use those and only check for errors
|
// so we can just use those and only check for errors
|
||||||
var $container = $('<span>', {'class':'cp-limit-container'});
|
var $container = $('<span>', {'class':'cp-limit-container'});
|
||||||
var todo = function (err, data) {
|
var todo = function (err, data) {
|
||||||
if (err) { return void console.error(err); }
|
if (err || !data) { return void console.error(err || 'No data'); }
|
||||||
|
|
||||||
var usage = data.usage;
|
var usage = data.usage;
|
||||||
var limit = data.limit;
|
var limit = data.limit;
|
||||||
@@ -1422,50 +1479,51 @@ define([
|
|||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {
|
attributes: {
|
||||||
'target': '_blank',
|
'target': '_blank',
|
||||||
'href': origin+'/drive/'
|
'href': origin+'/drive/',
|
||||||
|
'class': 'fa fa-hdd-o'
|
||||||
},
|
},
|
||||||
content: Messages.login_accessDrive
|
content: h('span', Messages.login_accessDrive)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add the change display name button if not in read only mode
|
// Add the change display name button if not in read only mode
|
||||||
if (config.changeNameButtonCls && config.displayChangeName && !AppConfig.disableProfile) {
|
if (config.changeNameButtonCls && config.displayChangeName && !AppConfig.disableProfile) {
|
||||||
options.push({
|
options.push({
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {'class': config.changeNameButtonCls},
|
attributes: {'class': config.changeNameButtonCls + ' fa fa-user'},
|
||||||
content: Messages.user_rename
|
content: h('span', Messages.user_rename)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (accountName && !AppConfig.disableProfile) {
|
if (accountName && !AppConfig.disableProfile) {
|
||||||
options.push({
|
options.push({
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {'class': 'cp-toolbar-menu-profile'},
|
attributes: {'class': 'cp-toolbar-menu-profile fa fa-user-circle'},
|
||||||
content: Messages.profileButton
|
content: h('span', Messages.profileButton)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (padType !== 'settings') {
|
if (padType !== 'settings') {
|
||||||
options.push({
|
options.push({
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {'class': 'cp-toolbar-menu-settings'},
|
attributes: {'class': 'cp-toolbar-menu-settings fa fa-cog'},
|
||||||
content: Messages.settingsButton
|
content: h('span', Messages.settingsButton)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
// Add login or logout button depending on the current status
|
// Add login or logout button depending on the current status
|
||||||
if (accountName) {
|
if (accountName) {
|
||||||
options.push({
|
options.push({
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {'class': 'cp-toolbar-menu-logout'},
|
attributes: {'class': 'cp-toolbar-menu-logout fa fa-sign-out'},
|
||||||
content: Messages.logoutButton
|
content: h('span', Messages.logoutButton)
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
options.push({
|
options.push({
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {'class': 'cp-toolbar-menu-login'},
|
attributes: {'class': 'cp-toolbar-menu-login fa fa-sign-in'},
|
||||||
content: Messages.login_login
|
content: h('span', Messages.login_login)
|
||||||
});
|
});
|
||||||
options.push({
|
options.push({
|
||||||
tag: 'a',
|
tag: 'a',
|
||||||
attributes: {'class': 'cp-toolbar-menu-register'},
|
attributes: {'class': 'cp-toolbar-menu-register fa fa-user-plus'},
|
||||||
content: Messages.login_register
|
content: h('span', Messages.login_register)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
var $icon = $('<span>', {'class': 'fa fa-user-secret'});
|
var $icon = $('<span>', {'class': 'fa fa-user-secret'});
|
||||||
@@ -1521,9 +1579,8 @@ define([
|
|||||||
UIElements.displayAvatar(Common, $avatar, url,
|
UIElements.displayAvatar(Common, $avatar, url,
|
||||||
newName || Messages.anonymous, function ($img) {
|
newName || Messages.anonymous, function ($img) {
|
||||||
oldUrl = url;
|
oldUrl = url;
|
||||||
if ($img) {
|
$userAdmin.find('> button').removeClass('cp-avatar');
|
||||||
$userAdmin.find('> button').addClass('cp-avatar');
|
if ($img) { $userAdmin.find('> button').addClass('cp-avatar'); }
|
||||||
}
|
|
||||||
loadingAvatar = false;
|
loadingAvatar = false;
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
@@ -1651,14 +1708,10 @@ define([
|
|||||||
var priv = common.getMetadataMgr().getPrivateData();
|
var priv = common.getMetadataMgr().getPrivateData();
|
||||||
var c = (priv.settings.general && priv.settings.general.creation) || {};
|
var c = (priv.settings.general && priv.settings.general.creation) || {};
|
||||||
if (AppConfig.displayCreationScreen && common.isLoggedIn() && c.skip) {
|
if (AppConfig.displayCreationScreen && common.isLoggedIn() && c.skip) {
|
||||||
$advanced = $('<input>', {
|
var $cboxLabel = $(UI.createCheckbox('cp-app-toolbar-creation-advanced',
|
||||||
type: 'checkbox',
|
Messages.creation_newPadModalAdvanced, true))
|
||||||
checked: 'checked',
|
.appendTo($advancedContainer);
|
||||||
id: 'cp-app-toolbar-creation-advanced'
|
$advanced = $cboxLabel.find('input');
|
||||||
}).appendTo($advancedContainer);
|
|
||||||
$('<label>', {
|
|
||||||
for: 'cp-app-toolbar-creation-advanced'
|
|
||||||
}).text(Messages.creation_newPadModalAdvanced).appendTo($advancedContainer);
|
|
||||||
$description.append('<br>');
|
$description.append('<br>');
|
||||||
$description.append(Messages.creation_newPadModalDescriptionAdvanced);
|
$description.append(Messages.creation_newPadModalDescriptionAdvanced);
|
||||||
}
|
}
|
||||||
@@ -1742,17 +1795,21 @@ define([
|
|||||||
sframeChan.event("EV_FILE_PICKER_OPEN", types);
|
sframeChan.event("EV_FILE_PICKER_OPEN", types);
|
||||||
};
|
};
|
||||||
|
|
||||||
UIElements.openTemplatePicker = function (common) {
|
UIElements.openTemplatePicker = function (common, force) {
|
||||||
var metadataMgr = common.getMetadataMgr();
|
var metadataMgr = common.getMetadataMgr();
|
||||||
var type = metadataMgr.getMetadataLazy().type;
|
var type = metadataMgr.getMetadataLazy().type;
|
||||||
var sframeChan = common.getSframeChannel();
|
var sframeChan = common.getSframeChannel();
|
||||||
var focus;
|
var focus;
|
||||||
|
|
||||||
var pickerCfg = {
|
var pickerCfgInit = {
|
||||||
types: [type],
|
types: [type],
|
||||||
where: ['template'],
|
where: ['template'],
|
||||||
hidden: true
|
hidden: true
|
||||||
};
|
};
|
||||||
|
var pickerCfg = {
|
||||||
|
types: [type],
|
||||||
|
where: ['template'],
|
||||||
|
};
|
||||||
var onConfirm = function (yes) {
|
var onConfirm = function (yes) {
|
||||||
if (!yes) {
|
if (!yes) {
|
||||||
if (focus) { focus.focus(); }
|
if (focus) { focus.focus(); }
|
||||||
@@ -1780,12 +1837,15 @@ define([
|
|||||||
|
|
||||||
sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) {
|
sframeChan.query("Q_TEMPLATE_EXIST", type, function (err, data) {
|
||||||
if (data) {
|
if (data) {
|
||||||
common.openFilePicker(pickerCfg);
|
common.openFilePicker(pickerCfgInit);
|
||||||
focus = document.activeElement;
|
focus = document.activeElement;
|
||||||
|
if (force) { return void onConfirm(true); }
|
||||||
UI.confirm(Messages.useTemplate, onConfirm, {
|
UI.confirm(Messages.useTemplate, onConfirm, {
|
||||||
ok: Messages.useTemplateOK,
|
ok: Messages.useTemplateOK,
|
||||||
cancel: Messages.useTemplateCancel,
|
cancel: Messages.useTemplateCancel,
|
||||||
});
|
});
|
||||||
|
} else if (force) {
|
||||||
|
UI.alert(Messages.template_empty);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -1821,11 +1881,15 @@ define([
|
|||||||
|
|
||||||
var $body = $('body');
|
var $body = $('body');
|
||||||
var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body);
|
var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body);
|
||||||
|
var urlArgs = (Config.requireConf && Config.requireConf.urlArgs) || '';
|
||||||
|
var l = h('div.cp-creation-logo', h('img', { src: '/customize/loading-logo.png?' + urlArgs }));
|
||||||
|
$(l).appendTo($creationContainer);
|
||||||
var $creation = $('<div>', { id: 'cp-creation', tabindex: 1 }).appendTo($creationContainer);
|
var $creation = $('<div>', { id: 'cp-creation', tabindex: 1 }).appendTo($creationContainer);
|
||||||
|
|
||||||
// Title
|
// Title
|
||||||
var colorClass = 'cp-icon-color-'+type;
|
//var colorClass = 'cp-icon-color-'+type;
|
||||||
$creation.append(h('h2.cp-creation-title', Messages.newButtonTitle));
|
//$creation.append(h('h2.cp-creation-title', Messages.newButtonTitle));
|
||||||
|
$creation.append(h('h3.cp-creation-title', Messages['button_new'+type]));
|
||||||
//$creation.append(h('h2.cp-creation-title.'+colorClass, Messages.newButtonTitle));
|
//$creation.append(h('h2.cp-creation-title.'+colorClass, Messages.newButtonTitle));
|
||||||
|
|
||||||
// Deleted pad warning
|
// Deleted pad warning
|
||||||
@@ -1837,10 +1901,11 @@ define([
|
|||||||
|
|
||||||
var origin = common.getMetadataMgr().getPrivateData().origin;
|
var origin = common.getMetadataMgr().getPrivateData().origin;
|
||||||
var createHelper = function (href, text) {
|
var createHelper = function (href, text) {
|
||||||
var q = h('a.cp-creation-help.fa.fa-question', {
|
var q = h('a.cp-creation-help.fa.fa-question-circle', {
|
||||||
title: text,
|
title: text,
|
||||||
href: origin + href,
|
href: origin + href,
|
||||||
target: "_blank"
|
target: "_blank",
|
||||||
|
'data-tippy-placement': "right"
|
||||||
});
|
});
|
||||||
return q;
|
return q;
|
||||||
};
|
};
|
||||||
@@ -1848,30 +1913,14 @@ define([
|
|||||||
// Owned pads
|
// Owned pads
|
||||||
// Default is Owned pad
|
// Default is Owned pad
|
||||||
var owned = h('div.cp-creation-owned', [
|
var owned = h('div.cp-creation-owned', [
|
||||||
h('label.cp-checkmark', [
|
UI.createCheckbox('cp-creation-owned', Messages.creation_owned, true),
|
||||||
h('input', {
|
|
||||||
type: 'checkbox',
|
|
||||||
id: 'cp-creation-owned',
|
|
||||||
checked: 'checked'
|
|
||||||
}),
|
|
||||||
h('span.cp-checkmark-mark'),
|
|
||||||
Messages.creation_owned
|
|
||||||
]),
|
|
||||||
createHelper('/faq.html#keywords-owned', Messages.creation_owned1)
|
createHelper('/faq.html#keywords-owned', Messages.creation_owned1)
|
||||||
]);
|
]);
|
||||||
|
|
||||||
// Life time
|
// Life time
|
||||||
var expire = h('div.cp-creation-expire', [
|
var expire = h('div.cp-creation-expire', [
|
||||||
h('label.cp-checkmark', [
|
UI.createCheckbox('cp-creation-expire', Messages.creation_expire, false),
|
||||||
h('input', {
|
h('span.cp-creation-expire-picker.cp-creation-slider', [
|
||||||
type: 'checkbox',
|
|
||||||
id: 'cp-creation-expire'
|
|
||||||
}),
|
|
||||||
h('span.cp-checkmark-mark'),
|
|
||||||
Messages.creation_expire
|
|
||||||
]),
|
|
||||||
createHelper('/faq.html#keywords-expiring', Messages.creation_expire2),
|
|
||||||
h('div.cp-creation-expire-picker.cp-creation-slider', [
|
|
||||||
h('input#cp-creation-expire-val', {
|
h('input#cp-creation-expire-val', {
|
||||||
type: "number",
|
type: "number",
|
||||||
min: 1,
|
min: 1,
|
||||||
@@ -1886,106 +1935,168 @@ define([
|
|||||||
selected: 'selected'
|
selected: 'selected'
|
||||||
}, Messages.creation_expireMonths)
|
}, Messages.creation_expireMonths)
|
||||||
])
|
])
|
||||||
|
]),
|
||||||
|
createHelper('/faq.html#keywords-expiring', Messages.creation_expire2),
|
||||||
|
]);
|
||||||
|
|
||||||
|
// Password
|
||||||
|
var password = h('div.cp-creation-password', [
|
||||||
|
UI.createCheckbox('cp-creation-password', Messages.creation_password, false),
|
||||||
|
h('span.cp-creation-password-picker.cp-creation-slider', [
|
||||||
|
UI.passwordInput({id: 'cp-creation-password-val'})
|
||||||
|
/*h('input#cp-creation-password-val', {
|
||||||
|
type: "text" // TODO type password with click to show
|
||||||
|
}),*/
|
||||||
|
]),
|
||||||
|
//createHelper('#', "TODO: password protection adds another layer of security ........") // TODO
|
||||||
|
]);
|
||||||
|
|
||||||
|
var right = h('span.fa.fa-chevron-right.cp-creation-template-more');
|
||||||
|
var left = h('span.fa.fa-chevron-left.cp-creation-template-more');
|
||||||
|
var templates = h('div.cp-creation-template', [
|
||||||
|
left,
|
||||||
|
h('div.cp-creation-template-container', [
|
||||||
|
h('span.fa.fa-circle-o-notch.fa-spin.fa-4x.fa-fw')
|
||||||
|
]),
|
||||||
|
right
|
||||||
|
]);
|
||||||
|
|
||||||
|
var settings = h('div.cp-creation-remember', [
|
||||||
|
UI.createCheckbox('cp-creation-remember', Messages.creation_saveSettings, false),
|
||||||
|
createHelper('/settings/#creation', Messages.creation_settings),
|
||||||
|
h('div.cp-creation-remember-help.cp-creation-slider', [
|
||||||
|
h('span.fa.fa-exclamation-circle.cp-creation-warning'),
|
||||||
|
Messages.creation_rememberHelp
|
||||||
])
|
])
|
||||||
]);
|
]);
|
||||||
|
|
||||||
var createDiv = h('div.cp-creation-create');
|
var createDiv = h('div.cp-creation-create');
|
||||||
var $create = $(createDiv);
|
var $create = $(createDiv);
|
||||||
|
|
||||||
var templates = h('div.cp-creation-template', [
|
|
||||||
h('h3.cp-creation-title.'+colorClass, Messages['button_new'+type]),
|
|
||||||
h('div.cp-creation-template-container', [
|
|
||||||
h('span.fa.fa-circle-o-notch.fa-spin.fa-4x.fa-fw')
|
|
||||||
]),
|
|
||||||
createDiv
|
|
||||||
]);
|
|
||||||
|
|
||||||
var settings = h('div.cp-creation-remember', [
|
|
||||||
h('label.cp-checkmark', [
|
|
||||||
h('input', {
|
|
||||||
type: 'checkbox',
|
|
||||||
id: 'cp-creation-remember'
|
|
||||||
}),
|
|
||||||
h('span.cp-checkmark-mark'),
|
|
||||||
Messages.creation_saveSettings
|
|
||||||
]),
|
|
||||||
createHelper('/settings/#creation', Messages.creation_settings),
|
|
||||||
h('div.cp-creation-remember-help.cp-creation-slider', Messages.creation_rememberHelp)
|
|
||||||
]);
|
|
||||||
|
|
||||||
$(h('div#cp-creation-form', [
|
$(h('div#cp-creation-form', [
|
||||||
owned,
|
owned,
|
||||||
expire,
|
expire,
|
||||||
|
password,
|
||||||
settings,
|
settings,
|
||||||
templates
|
templates,
|
||||||
|
createDiv
|
||||||
])).appendTo($creation);
|
])).appendTo($creation);
|
||||||
|
|
||||||
// Display templates
|
// Display templates
|
||||||
var selected = 0;
|
|
||||||
|
var selected = 0; // Selected template in the list (highlighted)
|
||||||
|
var TEMPLATES_DISPLAYED = 4; // Max templates displayed per page
|
||||||
|
var next = function () {}; // Function called when pressing tab to highlight the next template
|
||||||
|
var i = 0; // Index of the first template displayed in the current page
|
||||||
sframeChan.query("Q_CREATE_TEMPLATES", type, function (err, res) {
|
sframeChan.query("Q_CREATE_TEMPLATES", type, function (err, res) {
|
||||||
if (!res.data || !Array.isArray(res.data)) {
|
if (!res.data || !Array.isArray(res.data)) {
|
||||||
return void console.error("Error: get the templates list");
|
return void console.error("Error: get the templates list");
|
||||||
}
|
}
|
||||||
var data = res.data.slice().sort(function (a, b) {
|
var allData = res.data.slice().sort(function (a, b) {
|
||||||
if (a.name === b.name) { return 0; }
|
if (a.used === b.used) {
|
||||||
return a.name < b.name ? -1 : 1;
|
// Sort by name
|
||||||
|
if (a.name === b.name) { return 0; }
|
||||||
|
return a.name < b.name ? -1 : 1;
|
||||||
|
}
|
||||||
|
return b.used - a.used;
|
||||||
});
|
});
|
||||||
data.unshift({
|
allData.unshift({
|
||||||
name: Messages.creation_noTemplate,
|
|
||||||
id: 0,
|
|
||||||
icon: h('span.fa.fa-file')
|
|
||||||
});
|
|
||||||
data.push({
|
|
||||||
name: Messages.creation_newTemplate,
|
name: Messages.creation_newTemplate,
|
||||||
id: -1,
|
id: -1,
|
||||||
icon: h('span.fa.fa-bookmark')
|
icon: h('span.fa.fa-bookmark')
|
||||||
});
|
});
|
||||||
var $container = $(templates).find('.cp-creation-template-container').html('');
|
allData.unshift({
|
||||||
data.forEach(function (obj, idx) {
|
name: Messages.creation_noTemplate,
|
||||||
var name = obj.name;
|
id: 0,
|
||||||
var $span = $('<span>', {
|
icon: h('span.fa.fa-file')
|
||||||
'class': 'cp-creation-template-element',
|
|
||||||
'title': name,
|
|
||||||
}).appendTo($container);
|
|
||||||
$span.data('id', obj.id);
|
|
||||||
if (idx === 0) { $span.addClass('cp-creation-template-selected'); }
|
|
||||||
$span.append(obj.icon || UI.getFileIcon({type: type}));
|
|
||||||
$('<span>', {'class': 'cp-creation-template-element-name'}).text(name)
|
|
||||||
.appendTo($span);
|
|
||||||
$span.click(function () {
|
|
||||||
$container.find('.cp-creation-template-selected')
|
|
||||||
.removeClass('cp-creation-template-selected');
|
|
||||||
$span.addClass('cp-creation-template-selected');
|
|
||||||
selected = idx;
|
|
||||||
});
|
|
||||||
|
|
||||||
// Add thumbnail if it exists
|
|
||||||
if (obj.thumbnail) {
|
|
||||||
common.addThumbnail(obj.thumbnail, $span, function () {});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
});
|
var redraw = function (index) {
|
||||||
// Change template selection when Tab is pressed
|
if (index < 0) { i = 0; }
|
||||||
var next = function (revert) {
|
else if (index > allData.length - 1) { return; }
|
||||||
var max = $creation.find('.cp-creation-template-element').length;
|
else { i = index; }
|
||||||
selected = revert ?
|
var data = allData.slice(i, i + TEMPLATES_DISPLAYED);
|
||||||
(--selected < 0 ? max-1 : selected) :
|
var $container = $(templates).find('.cp-creation-template-container').html('');
|
||||||
++selected % max;
|
data.forEach(function (obj, idx) {
|
||||||
$creation.find('.cp-creation-template-element')
|
var name = obj.name;
|
||||||
.removeClass('cp-creation-template-selected');
|
var $span = $('<span>', {
|
||||||
$($creation.find('.cp-creation-template-element').get(selected))
|
'class': 'cp-creation-template-element',
|
||||||
.addClass('cp-creation-template-selected');
|
'title': name,
|
||||||
};
|
}).appendTo($container);
|
||||||
|
$span.data('id', obj.id);
|
||||||
|
if (idx === selected) { $span.addClass('cp-creation-template-selected'); }
|
||||||
|
$span.append(obj.icon || UI.getFileIcon({type: type}));
|
||||||
|
$('<span>', {'class': 'cp-creation-template-element-name'}).text(name)
|
||||||
|
.appendTo($span);
|
||||||
|
$span.click(function () {
|
||||||
|
$container.find('.cp-creation-template-selected')
|
||||||
|
.removeClass('cp-creation-template-selected');
|
||||||
|
$span.addClass('cp-creation-template-selected');
|
||||||
|
selected = idx;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Add thumbnail if it exists
|
||||||
|
if (obj.thumbnail) {
|
||||||
|
common.addThumbnail(obj.thumbnail, $span, function () {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
$(right).off('click').removeClass('hidden').click(function () {
|
||||||
|
selected = 0;
|
||||||
|
redraw(i + TEMPLATES_DISPLAYED);
|
||||||
|
});
|
||||||
|
if (i >= allData.length - TEMPLATES_DISPLAYED ) { $(right).addClass('hidden'); }
|
||||||
|
$(left).off('click').removeClass('hidden').click(function () {
|
||||||
|
selected = TEMPLATES_DISPLAYED - 1;
|
||||||
|
redraw(i - TEMPLATES_DISPLAYED);
|
||||||
|
});
|
||||||
|
if (i < TEMPLATES_DISPLAYED) { $(left).addClass('hidden'); }
|
||||||
|
};
|
||||||
|
redraw(0);
|
||||||
|
|
||||||
|
// Change template selection when Tab is pressed
|
||||||
|
next = function (revert) {
|
||||||
|
var max = $creation.find('.cp-creation-template-element').length;
|
||||||
|
if (selected + 1 === max && !revert) {
|
||||||
|
selected = i + TEMPLATES_DISPLAYED < allData.length ? 0 : max;
|
||||||
|
return void redraw(i + TEMPLATES_DISPLAYED);
|
||||||
|
}
|
||||||
|
if (selected === 0 && revert) {
|
||||||
|
selected = i - TEMPLATES_DISPLAYED >= 0 ? TEMPLATES_DISPLAYED - 1 : 0;
|
||||||
|
return void redraw(i - TEMPLATES_DISPLAYED);
|
||||||
|
}
|
||||||
|
selected = revert ?
|
||||||
|
(--selected < 0 ? 0 : selected) :
|
||||||
|
++selected >= max ? max-1 : selected;
|
||||||
|
$creation.find('.cp-creation-template-element')
|
||||||
|
.removeClass('cp-creation-template-selected');
|
||||||
|
$($creation.find('.cp-creation-template-element').get(selected))
|
||||||
|
.addClass('cp-creation-template-selected');
|
||||||
|
};
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
// Display expiration form when checkbox checked
|
// Display expiration form when checkbox checked
|
||||||
$creation.find('#cp-creation-expire').on('change', function () {
|
$creation.find('#cp-creation-expire').on('change', function () {
|
||||||
if ($(this).is(':checked')) {
|
if ($(this).is(':checked')) {
|
||||||
$creation.find('.cp-creation-expire-picker:not(.active)').addClass('active');
|
$creation.find('.cp-creation-expire-picker:not(.active)').addClass('active');
|
||||||
|
$creation.find('.cp-creation-expire:not(.active)').addClass('active');
|
||||||
$creation.find('#cp-creation-expire-val').focus();
|
$creation.find('#cp-creation-expire-val').focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$creation.find('.cp-creation-expire-picker').removeClass('active');
|
$creation.find('.cp-creation-expire-picker').removeClass('active');
|
||||||
|
$creation.find('.cp-creation-expire').removeClass('active');
|
||||||
|
$creation.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
// Display expiration form when checkbox checked
|
||||||
|
$creation.find('#cp-creation-password').on('change', function () {
|
||||||
|
if ($(this).is(':checked')) {
|
||||||
|
$creation.find('.cp-creation-password-picker:not(.active)').addClass('active');
|
||||||
|
$creation.find('.cp-creation-password:not(.active)').addClass('active');
|
||||||
|
$creation.find('#cp-creation-password-val').focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
$creation.find('.cp-creation-password-picker').removeClass('active');
|
||||||
|
$creation.find('.cp-creation-password').removeClass('active');
|
||||||
$creation.focus();
|
$creation.focus();
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -2037,12 +2148,16 @@ define([
|
|||||||
}
|
}
|
||||||
expireVal = ($('#cp-creation-expire-val').val() || 0) * unit;
|
expireVal = ($('#cp-creation-expire-val').val() || 0) * unit;
|
||||||
}
|
}
|
||||||
|
// Password
|
||||||
|
var passwordVal = $('#cp-creation-password').is(':checked') ?
|
||||||
|
$('#cp-creation-password-val').val() : undefined;
|
||||||
|
|
||||||
var $template = $creation.find('.cp-creation-template-selected');
|
var $template = $creation.find('.cp-creation-template-selected');
|
||||||
var templateId = $template.data('id') || undefined;
|
var templateId = $template.data('id') || undefined;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
owned: ownedVal,
|
owned: ownedVal,
|
||||||
|
password: passwordVal,
|
||||||
expire: expireVal,
|
expire: expireVal,
|
||||||
templateId: templateId
|
templateId: templateId
|
||||||
};
|
};
|
||||||
@@ -2112,5 +2227,38 @@ define([
|
|||||||
(cb || function () {})();
|
(cb || function () {})();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
UIElements.displayPasswordPrompt = function (common, isError) {
|
||||||
|
var error;
|
||||||
|
if (isError) { error = setHTML(h('p.cp-password-error'), Messages.password_error); }
|
||||||
|
var info = h('p.cp-password-info', Messages.password_info);
|
||||||
|
var password = UI.passwordInput({placeholder: Messages.password_placeholder});
|
||||||
|
var button = h('button', Messages.password_submit);
|
||||||
|
|
||||||
|
var submit = function () {
|
||||||
|
var value = $(password).find('.cp-password-input').val();
|
||||||
|
UI.addLoadingScreen();
|
||||||
|
common.getSframeChannel().query('Q_PAD_PASSWORD_VALUE', value, function (err, data) {
|
||||||
|
if (!data) {
|
||||||
|
UIElements.displayPasswordPrompt(common, true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
$(password).find('.cp-password-input').on('keydown', function (e) { if (e.which === 13) { submit(); } });
|
||||||
|
$(button).on('click', function () { submit(); });
|
||||||
|
|
||||||
|
|
||||||
|
var block = h('div#cp-loading-password-prompt', [
|
||||||
|
error,
|
||||||
|
info,
|
||||||
|
h('p.cp-password-form', [
|
||||||
|
password,
|
||||||
|
button
|
||||||
|
])
|
||||||
|
]);
|
||||||
|
UI.errorLoadingScreen(block);
|
||||||
|
|
||||||
|
$(password).find('.cp-password-input').focus();
|
||||||
|
};
|
||||||
|
|
||||||
return UIElements;
|
return UIElements;
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
var makeConfig = function (hash) {
|
var makeConfig = function (hash, password) {
|
||||||
// We can't use cryptget with a file or a user so we can use 'pad' as hash type
|
// We can't use cryptget with a file or a user so we can use 'pad' as hash type
|
||||||
var secret = Hash.getSecrets('pad', hash);
|
var secret = Hash.getSecrets('pad', hash, password);
|
||||||
if (!secret.keys) { secret.keys = secret.key; } // support old hashses
|
if (!secret.keys) { secret.keys = secret.key; } // support old hashses
|
||||||
var config = {
|
var config = {
|
||||||
websocketURL: NetConfig.getWebsocketURL(),
|
websocketURL: NetConfig.getWebsocketURL(),
|
||||||
@@ -47,8 +47,10 @@ define([
|
|||||||
if (typeof(cb) !== 'function') {
|
if (typeof(cb) !== 'function') {
|
||||||
throw new Error('Cryptget expects a callback');
|
throw new Error('Cryptget expects a callback');
|
||||||
}
|
}
|
||||||
|
opt = opt || {};
|
||||||
|
|
||||||
|
var config = makeConfig(hash, opt.password);
|
||||||
var Session = { cb: cb, };
|
var Session = { cb: cb, };
|
||||||
var config = makeConfig(hash);
|
|
||||||
|
|
||||||
config.onReady = function (info) {
|
config.onReady = function (info) {
|
||||||
var rt = Session.session = info.realtime;
|
var rt = Session.session = info.realtime;
|
||||||
@@ -64,9 +66,11 @@ define([
|
|||||||
if (typeof(cb) !== 'function') {
|
if (typeof(cb) !== 'function') {
|
||||||
throw new Error('Cryptput expects a callback');
|
throw new Error('Cryptput expects a callback');
|
||||||
}
|
}
|
||||||
|
opt = opt || {};
|
||||||
|
|
||||||
var config = makeConfig(hash);
|
var config = makeConfig(hash, opt.password);
|
||||||
var Session = { cb: cb, };
|
var Session = { cb: cb, };
|
||||||
|
|
||||||
config.onReady = function (info) {
|
config.onReady = function (info) {
|
||||||
var realtime = Session.session = info.realtime;
|
var realtime = Session.session = info.realtime;
|
||||||
Session.network = info.network;
|
Session.network = info.network;
|
||||||
|
|||||||
@@ -246,8 +246,8 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
common.getFileSize = function (href, cb) {
|
common.getFileSize = function (href, password, cb) {
|
||||||
postMessage("GET_FILE_SIZE", {href: href}, function (obj) {
|
postMessage("GET_FILE_SIZE", {href: href, password: password}, function (obj) {
|
||||||
if (obj && obj.error) { return void cb(obj.error); }
|
if (obj && obj.error) { return void cb(obj.error); }
|
||||||
cb(undefined, obj.size);
|
cb(undefined, obj.size);
|
||||||
});
|
});
|
||||||
@@ -260,8 +260,8 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
common.isNewChannel = function (href, cb) {
|
common.isNewChannel = function (href, password, cb) {
|
||||||
postMessage('IS_NEW_CHANNEL', {href: href}, function (obj) {
|
postMessage('IS_NEW_CHANNEL', {href: href, password: password}, function (obj) {
|
||||||
if (obj.error) { return void cb(obj.error); }
|
if (obj.error) { return void cb(obj.error); }
|
||||||
if (!obj) { return void cb('INVALID_RESPONSE'); }
|
if (!obj) { return void cb('INVALID_RESPONSE'); }
|
||||||
cb(undefined, obj.isNew);
|
cb(undefined, obj.isNew);
|
||||||
@@ -395,8 +395,10 @@ define([
|
|||||||
common.saveAsTemplate = function (Cryptput, data, cb) {
|
common.saveAsTemplate = function (Cryptput, data, cb) {
|
||||||
var p = Hash.parsePadUrl(window.location.href);
|
var p = Hash.parsePadUrl(window.location.href);
|
||||||
if (!p.type) { return; }
|
if (!p.type) { return; }
|
||||||
var hash = Hash.createRandomHash();
|
// PPP: password for the new template?
|
||||||
|
var hash = Hash.createRandomHash(p.type);
|
||||||
var href = '/' + p.type + '/#' + hash;
|
var href = '/' + p.type + '/#' + hash;
|
||||||
|
// PPP: add password as cryptput option
|
||||||
Cryptput(hash, data.toSave, function (e) {
|
Cryptput(hash, data.toSave, function (e) {
|
||||||
if (e) { throw new Error(e); }
|
if (e) { throw new Error(e); }
|
||||||
postMessage("ADD_PAD", {
|
postMessage("ADD_PAD", {
|
||||||
@@ -419,15 +421,33 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
common.useTemplate = function (href, Crypt, cb, opts) {
|
common.useTemplate = function (href, Crypt, cb, optsPut) {
|
||||||
// opts is used to overrides options for chainpad-netflux in cryptput
|
// opts is used to overrides options for chainpad-netflux in cryptput
|
||||||
// it allows us to add owners and expiration time if it is a new file
|
// it allows us to add owners and expiration time if it is a new file
|
||||||
|
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
|
var parsed2 = Hash.parsePadUrl(window.location.href);
|
||||||
if(!parsed) { throw new Error("Cannot get template hash"); }
|
if(!parsed) { throw new Error("Cannot get template hash"); }
|
||||||
Crypt.get(parsed.hash, function (err, val) {
|
postMessage("INCREMENT_TEMPLATE_USE", href);
|
||||||
if (err) { throw new Error(err); }
|
|
||||||
var p = Hash.parsePadUrl(window.location.href);
|
optsPut = optsPut || {};
|
||||||
Crypt.put(p.hash, val, cb, opts);
|
var optsGet = {};
|
||||||
|
Nthen(function (waitFor) {
|
||||||
|
if (parsed.hashData && parsed.hashData.password) {
|
||||||
|
common.getPadAttribute('password', waitFor(function (err, password) {
|
||||||
|
optsGet.password = password;
|
||||||
|
}), href);
|
||||||
|
}
|
||||||
|
if (parsed2.hashData && parsed2.hashData.password) {
|
||||||
|
common.getPadAttribute('password', waitFor(function (err, password) {
|
||||||
|
optsPut.password = password;
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}).nThen(function () {
|
||||||
|
Crypt.get(parsed.hash, function (err, val) {
|
||||||
|
if (err) { throw new Error(err); }
|
||||||
|
Crypt.put(parsed2.hash, val, cb, optsPut);
|
||||||
|
}, optsGet);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -438,20 +458,18 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
// When opening a new pad or renaming it, store the new title
|
// When opening a new pad or renaming it, store the new title
|
||||||
common.setPadTitle = function (title, padHref, path, cb) {
|
common.setPadTitle = function (data, cb) {
|
||||||
var href = padHref || window.location.href;
|
if (!data || typeof (data) !== "object") { return cb ('Data is not an object'); }
|
||||||
|
|
||||||
|
var href = data.href || window.location.href;
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
if (!parsed.hash) { return; }
|
if (!parsed.hash) { return cb ('Invalid hash'); }
|
||||||
href = parsed.getUrl({present: parsed.present});
|
data.href = parsed.getUrl({present: parsed.present});
|
||||||
|
|
||||||
if (title === null) { return; }
|
if (typeof (data.title) !== "string") { return cb('Missing title'); }
|
||||||
if (title.trim() === "") { title = Hash.getDefaultName(parsed); }
|
if (data.title.trim() === "") { data.title = Hash.getDefaultName(parsed); }
|
||||||
|
|
||||||
postMessage("SET_PAD_TITLE", {
|
postMessage("SET_PAD_TITLE", data, function (obj) {
|
||||||
href: href,
|
|
||||||
title: title,
|
|
||||||
path: path
|
|
||||||
}, function (obj) {
|
|
||||||
if (obj && obj.error) {
|
if (obj && obj.error) {
|
||||||
console.log("unable to set pad title");
|
console.log("unable to set pad title");
|
||||||
return void cb(obj.error);
|
return void cb(obj.error);
|
||||||
@@ -472,10 +490,6 @@ define([
|
|||||||
cb(void 0, data);
|
cb(void 0, data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
// Set initial path when creating a pad from pad creation screen
|
|
||||||
common.setInitialPath = function (path) {
|
|
||||||
postMessage("SET_INITIAL_PATH", path);
|
|
||||||
};
|
|
||||||
|
|
||||||
// Messaging (manage friends from the userlist)
|
// Messaging (manage friends from the userlist)
|
||||||
common.inviteFromUserlist = function (netfluxId, cb) {
|
common.inviteFromUserlist = function (netfluxId, cb) {
|
||||||
@@ -548,6 +562,10 @@ define([
|
|||||||
pad.onDisconnectEvent = Util.mkEvent();
|
pad.onDisconnectEvent = Util.mkEvent();
|
||||||
pad.onErrorEvent = Util.mkEvent();
|
pad.onErrorEvent = Util.mkEvent();
|
||||||
|
|
||||||
|
// Loading events
|
||||||
|
common.loading = {};
|
||||||
|
common.loading.onDriveEvent = Util.mkEvent();
|
||||||
|
|
||||||
common.getFullHistory = function (data, cb) {
|
common.getFullHistory = function (data, cb) {
|
||||||
postMessage("GET_FULL_HISTORY", data, cb);
|
postMessage("GET_FULL_HISTORY", data, cb);
|
||||||
};
|
};
|
||||||
@@ -555,15 +573,15 @@ define([
|
|||||||
common.getShareHashes = function (secret, cb) {
|
common.getShareHashes = function (secret, cb) {
|
||||||
var hashes;
|
var hashes;
|
||||||
if (!window.location.hash) {
|
if (!window.location.hash) {
|
||||||
hashes = Hash.getHashes(secret.channel, secret);
|
hashes = Hash.getHashes(secret);
|
||||||
return void cb(null, hashes);
|
return void cb(null, hashes);
|
||||||
}
|
}
|
||||||
var parsed = Hash.parsePadUrl(window.location.href);
|
var parsed = Hash.parsePadUrl(window.location.href);
|
||||||
if (!parsed.type || !parsed.hashData) { return void cb('E_INVALID_HREF'); }
|
if (!parsed.type || !parsed.hashData) { return void cb('E_INVALID_HREF'); }
|
||||||
if (parsed.type === 'file') { secret.channel = Util.base64ToHex(secret.channel); }
|
if (parsed.type === 'file') { secret.channel = Util.base64ToHex(secret.channel); }
|
||||||
hashes = Hash.getHashes(secret.channel, secret);
|
hashes = Hash.getHashes(secret);
|
||||||
|
|
||||||
if (!hashes.editHash && !hashes.viewHash && parsed.hashData && !parsed.hashData.mode) {
|
if (secret.version === 0) {
|
||||||
// It means we're using an old hash
|
// It means we're using an old hash
|
||||||
hashes.editHash = window.location.hash.slice(1);
|
hashes.editHash = window.location.hash.slice(1);
|
||||||
return void cb(null, hashes);
|
return void cb(null, hashes);
|
||||||
@@ -575,7 +593,8 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
postMessage("GET_STRONGER_HASH", {
|
postMessage("GET_STRONGER_HASH", {
|
||||||
href: window.location.href
|
href: window.location.href,
|
||||||
|
password: secret.password
|
||||||
}, function (hash) {
|
}, function (hash) {
|
||||||
if (hash) { hashes.editHash = hash; }
|
if (hash) { hashes.editHash = hash; }
|
||||||
cb(null, hashes);
|
cb(null, hashes);
|
||||||
@@ -622,6 +641,12 @@ define([
|
|||||||
window.location.href = '/login/';
|
window.location.href = '/login/';
|
||||||
};
|
};
|
||||||
|
|
||||||
|
common.startAccountDeletion = function (cb) {
|
||||||
|
// Logout other tabs
|
||||||
|
LocalStore.logout(null, true);
|
||||||
|
cb();
|
||||||
|
};
|
||||||
|
|
||||||
var onMessage = function (cmd, data, cb) {
|
var onMessage = function (cmd, data, cb) {
|
||||||
cb = cb || function () {};
|
cb = cb || function () {};
|
||||||
switch (cmd) {
|
switch (cmd) {
|
||||||
@@ -701,6 +726,14 @@ define([
|
|||||||
case 'DRIVE_REMOVE': {
|
case 'DRIVE_REMOVE': {
|
||||||
common.drive.onRemove.fire(data); break;
|
common.drive.onRemove.fire(data); break;
|
||||||
}
|
}
|
||||||
|
// Account deletion
|
||||||
|
case 'DELETE_ACCOUNT': {
|
||||||
|
common.startAccountDeletion(cb); break;
|
||||||
|
}
|
||||||
|
// Loading
|
||||||
|
case 'LOADING_DRIVE': {
|
||||||
|
common.loading.onDriveEvent.fire(data); break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -779,11 +812,11 @@ define([
|
|||||||
|
|
||||||
if (data.anonHash && !cfg.userHash) { LocalStore.setFSHash(data.anonHash); }
|
if (data.anonHash && !cfg.userHash) { LocalStore.setFSHash(data.anonHash); }
|
||||||
|
|
||||||
if (cfg.userHash && sessionStorage) {
|
/*if (cfg.userHash && sessionStorage) {
|
||||||
// copy User_hash into sessionStorage because cross-domain iframes
|
// copy User_hash into sessionStorage because cross-domain iframes
|
||||||
// on safari replaces localStorage with sessionStorage or something
|
// on safari replaces localStorage with sessionStorage or something
|
||||||
sessionStorage.setItem(Constants.userHashKey, cfg.userHash);
|
sessionStorage.setItem(Constants.userHashKey, cfg.userHash);
|
||||||
}
|
}*/
|
||||||
|
|
||||||
if (cfg.userHash) {
|
if (cfg.userHash) {
|
||||||
var localToken = tryParsing(localStorage.getItem(Constants.tokenKey));
|
var localToken = tryParsing(localStorage.getItem(Constants.tokenKey));
|
||||||
@@ -802,18 +835,18 @@ define([
|
|||||||
window.onhashchange = function (ev) {
|
window.onhashchange = function (ev) {
|
||||||
if (ev && ev.reset) { oldHref = document.location.href; return; }
|
if (ev && ev.reset) { oldHref = document.location.href; return; }
|
||||||
var newHref = document.location.href;
|
var newHref = document.location.href;
|
||||||
var parsedOld = Hash.parsePadUrl(oldHref).hashData;
|
|
||||||
var parsedNew = Hash.parsePadUrl(newHref).hashData;
|
// Compare the URLs without /embed and /present
|
||||||
if (parsedOld && parsedNew && (
|
var parsedOld = Hash.parsePadUrl(oldHref);
|
||||||
parsedOld.type !== parsedNew.type
|
var parsedNew = Hash.parsePadUrl(newHref);
|
||||||
|| parsedOld.channel !== parsedNew.channel
|
if (parsedOld.hashData && parsedNew.hashData &&
|
||||||
|| parsedOld.mode !== parsedNew.mode
|
parsedOld.getUrl() !== parsedNew.getUrl()) {
|
||||||
|| parsedOld.key !== parsedNew.key)) {
|
if (!parsedOld.hashData.key) { oldHref = newHref; return; }
|
||||||
if (!parsedOld.channel) { oldHref = newHref; return; }
|
// If different, reload
|
||||||
document.location.reload();
|
document.location.reload();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (parsedNew) { oldHref = newHref; }
|
if (parsedNew.hashData) { oldHref = newHref; }
|
||||||
};
|
};
|
||||||
// Listen for login/logout in other tabs
|
// Listen for login/logout in other tabs
|
||||||
window.addEventListener('storage', function (e) {
|
window.addEventListener('storage', function (e) {
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ define([
|
|||||||
};
|
};
|
||||||
renderer.image = function (href, title, text) {
|
renderer.image = function (href, title, text) {
|
||||||
if (href.slice(0,6) === '/file/') {
|
if (href.slice(0,6) === '/file/') {
|
||||||
|
// PASSWORD_FILES
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
||||||
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
||||||
|
|||||||
7
www/common/jquery-ui/jquery-ui.min.css
vendored
Normal file
7
www/common/jquery-ui/jquery-ui.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
6
www/common/jquery-ui/jquery-ui.min.js
vendored
Normal file
6
www/common/jquery-ui/jquery-ui.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -1,94 +1,3 @@
|
|||||||
define([], function () {
|
require(['/customize/loading.js'], function (Loading) {
|
||||||
var loadingStyle = (function(){/*
|
Loading();
|
||||||
#cp-loading {
|
|
||||||
transition: opacity 0.75s, visibility 0s 0.75s;
|
|
||||||
visibility: visible;
|
|
||||||
position: fixed;
|
|
||||||
z-index: 10000000;
|
|
||||||
top: 0px;
|
|
||||||
bottom: 0px;
|
|
||||||
left: 0px;
|
|
||||||
right: 0px;
|
|
||||||
background: #222;
|
|
||||||
color: #fafafa;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.5em;
|
|
||||||
opacity: 1;
|
|
||||||
}
|
|
||||||
#cp-loading.cp-loading-hidden {
|
|
||||||
opacity: 0;
|
|
||||||
visibility: hidden;
|
|
||||||
}
|
|
||||||
#cp-loading .cp-loading-container {
|
|
||||||
margin-top: 50vh;
|
|
||||||
transform: translateY(-50%);
|
|
||||||
}
|
|
||||||
#cp-loading .cp-loading-cryptofist {
|
|
||||||
margin-left: auto;
|
|
||||||
margin-right: auto;
|
|
||||||
height: 300px;
|
|
||||||
margin-bottom: 2em;
|
|
||||||
}
|
|
||||||
@media screen and (max-height: 450px) {
|
|
||||||
#cp-loading .cp-loading-cryptofist {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#cp-loading .cp-loading-spinner-container {
|
|
||||||
position: relative;
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
#cp-loading .cp-loading-spinner-container > div {
|
|
||||||
height: 100px;
|
|
||||||
}
|
|
||||||
#cp-loading-tip {
|
|
||||||
position: fixed;
|
|
||||||
z-index: 10000000;
|
|
||||||
top: 80%;
|
|
||||||
left: 0;
|
|
||||||
right: 0;
|
|
||||||
text-align: center;
|
|
||||||
transition: opacity 750ms;
|
|
||||||
transition-delay: 3000ms;
|
|
||||||
}
|
|
||||||
@media screen and (max-height: 600px) {
|
|
||||||
#cp-loading-tip {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#cp-loading-tip span {
|
|
||||||
background: #222;
|
|
||||||
color: #fafafa;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 1.5em;
|
|
||||||
opacity: 0.7;
|
|
||||||
font-family: 'Open Sans', 'Helvetica Neue', sans-serif;
|
|
||||||
padding: 15px;
|
|
||||||
max-width: 60%;
|
|
||||||
display: inline-block;
|
|
||||||
}
|
|
||||||
*/}).toString().slice(14, -3);
|
|
||||||
var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; });
|
|
||||||
var elem = document.createElement('div');
|
|
||||||
elem.setAttribute('id', 'cp-loading');
|
|
||||||
elem.innerHTML = [
|
|
||||||
'<style>',
|
|
||||||
loadingStyle,
|
|
||||||
'</style>',
|
|
||||||
'<div class="cp-loading-container">',
|
|
||||||
'<img class="cp-loading-cryptofist" src="/customize/cryptpad-new-logo-colors-logoonly.png?' + urlArgs + '">',
|
|
||||||
'<div class="cp-loading-spinner-container">',
|
|
||||||
'<span class="fa fa-circle-o-notch fa-spin fa-4x fa-fw"></span>',
|
|
||||||
'</div>',
|
|
||||||
'<p id="cp-loading-message"></p>',
|
|
||||||
'</div>'
|
|
||||||
].join('');
|
|
||||||
var intr;
|
|
||||||
var append = function () {
|
|
||||||
if (!document.body) { return; }
|
|
||||||
clearInterval(intr);
|
|
||||||
document.body.appendChild(elem);
|
|
||||||
};
|
|
||||||
intr = setInterval(append, 100);
|
|
||||||
append();
|
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -122,21 +122,15 @@ define([
|
|||||||
// Do not migrate a pad if we already have it, it would create a duplicate in the drive
|
// Do not migrate a pad if we already have it, it would create a duplicate in the drive
|
||||||
if (newHrefs.indexOf(href) !== -1) { return; }
|
if (newHrefs.indexOf(href) !== -1) { return; }
|
||||||
// If we have a stronger version, do not add the current href
|
// If we have a stronger version, do not add the current href
|
||||||
if (Hash.findStronger(href, newRecentPads)) { return; }
|
if (Hash.findStronger(href, oldRecentPads[id].channel, newRecentPads)) { return; }
|
||||||
// If we have a weaker version, replace the href by the new one
|
// 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
|
// NOTE: if that weaker version is in the trash, the strong one will be put in unsorted
|
||||||
var weaker = Hash.findWeaker(href, newRecentPads);
|
var weaker = Hash.findWeaker(href, oldRecentPads[id].channel, newRecentPads);
|
||||||
if (weaker) {
|
if (weaker) {
|
||||||
// Update RECENTPADS
|
// Update RECENTPADS
|
||||||
newRecentPads.some(function (pad) {
|
weaker.href = href;
|
||||||
if (pad.href === weaker) {
|
|
||||||
pad.href = href;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
});
|
|
||||||
// Update the file in the drive
|
// Update the file in the drive
|
||||||
newFo.replace(weaker, href);
|
newFo.replace(weaker.href, href);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// Here it means we have a new href, so we should add it to the drive at its old location
|
// Here it means we have a new href, so we should add it to the drive at its old location
|
||||||
|
|||||||
@@ -34,6 +34,10 @@ define(['json.sortify'], function (Sortify) {
|
|||||||
}
|
}
|
||||||
if (!metadataObj.users) { metadataObj.users = {}; }
|
if (!metadataObj.users) { metadataObj.users = {}; }
|
||||||
if (!metadataLazyObj.users) { metadataLazyObj.users = {}; }
|
if (!metadataLazyObj.users) { metadataLazyObj.users = {}; }
|
||||||
|
|
||||||
|
if (!metadataObj.type) { metadataObj.type = meta.doc.type; }
|
||||||
|
if (!metadataLazyObj.type) { metadataLazyObj.type = meta.doc.type; }
|
||||||
|
|
||||||
var mdo = {};
|
var mdo = {};
|
||||||
// We don't want to add our user data to the object multiple times.
|
// We don't want to add our user data to the object multiple times.
|
||||||
//var containsYou = false;
|
//var containsYou = false;
|
||||||
|
|||||||
@@ -1,106 +1,152 @@
|
|||||||
define(['/common/common-feedback.js'], function (Feedback) {
|
define([
|
||||||
|
'/common/common-feedback.js',
|
||||||
|
'/common/common-hash.js',
|
||||||
|
'/common/common-util.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
], function (Feedback, Hash, Util, nThen) {
|
||||||
// Start migration check
|
// Start migration check
|
||||||
// Versions:
|
// Versions:
|
||||||
// 1: migrate pad attributes
|
// 1: migrate pad attributes
|
||||||
// 2: migrate indent settings (codemirror)
|
// 2: migrate indent settings (codemirror)
|
||||||
|
|
||||||
return function (userObject) {
|
return function (userObject, cb, progress) {
|
||||||
var version = userObject.version || 0;
|
var version = userObject.version || 0;
|
||||||
|
|
||||||
// DEPRECATED
|
nThen(function () {
|
||||||
// Migration 1: pad attributes moved to filesData
|
// DEPRECATED
|
||||||
var migratePadAttributesToData = function () {
|
// Migration 1: pad attributes moved to filesData
|
||||||
return true;
|
var migratePadAttributesToData = function () {
|
||||||
};
|
return true;
|
||||||
if (version < 1) {
|
};
|
||||||
migratePadAttributesToData();
|
if (version < 1) {
|
||||||
}
|
migratePadAttributesToData();
|
||||||
|
|
||||||
// Migration 2: global attributes from root to 'settings' subobjects
|
|
||||||
var migrateAttributes = function () {
|
|
||||||
var drawer = 'cryptpad.userlist-drawer';
|
|
||||||
var polls = 'cryptpad.hide_poll_text';
|
|
||||||
var indentKey = 'cryptpad.indentUnit';
|
|
||||||
var useTabsKey = 'cryptpad.indentWithTabs';
|
|
||||||
var settings = userObject.settings = userObject.settings || {};
|
|
||||||
if (typeof(userObject[indentKey]) !== "undefined") {
|
|
||||||
settings.codemirror = settings.codemirror || {};
|
|
||||||
settings.codemirror.indentUnit = userObject[indentKey];
|
|
||||||
delete userObject[indentKey];
|
|
||||||
}
|
}
|
||||||
if (typeof(userObject[useTabsKey]) !== "undefined") {
|
}).nThen(function () {
|
||||||
settings.codemirror = settings.codemirror || {};
|
// Migration 2: global attributes from root to 'settings' subobjects
|
||||||
settings.codemirror.indentWithTabs = userObject[useTabsKey];
|
var migrateAttributes = function () {
|
||||||
delete userObject[useTabsKey];
|
var drawer = 'cryptpad.userlist-drawer';
|
||||||
|
var polls = 'cryptpad.hide_poll_text';
|
||||||
|
var indentKey = 'cryptpad.indentUnit';
|
||||||
|
var useTabsKey = 'cryptpad.indentWithTabs';
|
||||||
|
var settings = userObject.settings = userObject.settings || {};
|
||||||
|
if (typeof(userObject[indentKey]) !== "undefined") {
|
||||||
|
settings.codemirror = settings.codemirror || {};
|
||||||
|
settings.codemirror.indentUnit = userObject[indentKey];
|
||||||
|
delete userObject[indentKey];
|
||||||
|
}
|
||||||
|
if (typeof(userObject[useTabsKey]) !== "undefined") {
|
||||||
|
settings.codemirror = settings.codemirror || {};
|
||||||
|
settings.codemirror.indentWithTabs = userObject[useTabsKey];
|
||||||
|
delete userObject[useTabsKey];
|
||||||
|
}
|
||||||
|
if (typeof(userObject[drawer]) !== "undefined") {
|
||||||
|
settings.toolbar = settings.toolbar || {};
|
||||||
|
settings.toolbar['userlist-drawer'] = userObject[drawer];
|
||||||
|
delete userObject[drawer];
|
||||||
|
}
|
||||||
|
if (typeof(userObject[polls]) !== "undefined") {
|
||||||
|
settings.poll = settings.poll || {};
|
||||||
|
settings.poll['hide-text'] = userObject[polls];
|
||||||
|
delete userObject[polls];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (version < 2) {
|
||||||
|
migrateAttributes();
|
||||||
|
Feedback.send('Migrate-2', true);
|
||||||
|
userObject.version = version = 2;
|
||||||
}
|
}
|
||||||
if (typeof(userObject[drawer]) !== "undefined") {
|
}).nThen(function () {
|
||||||
settings.toolbar = settings.toolbar || {};
|
// Migration 3: language from localStorage to settings
|
||||||
settings.toolbar['userlist-drawer'] = userObject[drawer];
|
var migrateLanguage = function () {
|
||||||
delete userObject[drawer];
|
if (!localStorage.CRYPTPAD_LANG) { return; }
|
||||||
|
var l = localStorage.CRYPTPAD_LANG;
|
||||||
|
userObject.settings.language = l;
|
||||||
|
};
|
||||||
|
if (version < 3) {
|
||||||
|
migrateLanguage();
|
||||||
|
Feedback.send('Migrate-3', true);
|
||||||
|
userObject.version = version = 3;
|
||||||
}
|
}
|
||||||
if (typeof(userObject[polls]) !== "undefined") {
|
}).nThen(function () {
|
||||||
settings.poll = settings.poll || {};
|
// Migration 4: allowUserFeedback to settings
|
||||||
settings.poll['hide-text'] = userObject[polls];
|
var migrateFeedback = function () {
|
||||||
delete userObject[polls];
|
var settings = userObject.settings = userObject.settings || {};
|
||||||
|
if (typeof(userObject['allowUserFeedback']) !== "undefined") {
|
||||||
|
settings.general = settings.general || {};
|
||||||
|
settings.general.allowUserFeedback = userObject['allowUserFeedback'];
|
||||||
|
delete userObject['allowUserFeedback'];
|
||||||
|
}
|
||||||
|
};
|
||||||
|
if (version < 4) {
|
||||||
|
migrateFeedback();
|
||||||
|
Feedback.send('Migrate-4', true);
|
||||||
|
userObject.version = version = 4;
|
||||||
}
|
}
|
||||||
};
|
}).nThen(function () {
|
||||||
if (version < 2) {
|
// Migration 5: dates to Number
|
||||||
migrateAttributes();
|
var migrateDates = function () {
|
||||||
Feedback.send('Migrate-2', true);
|
var data = userObject.drive && userObject.drive.filesData;
|
||||||
userObject.version = version = 2;
|
if (data) {
|
||||||
}
|
for (var id in data) {
|
||||||
|
if (typeof data[id].ctime !== "number") {
|
||||||
|
data[id].ctime = +new Date(data[id].ctime);
|
||||||
|
}
|
||||||
// Migration 3: language from localStorage to settings
|
if (typeof data[id].atime !== "number") {
|
||||||
var migrateLanguage = function () {
|
data[id].atime = +new Date(data[id].atime);
|
||||||
if (!localStorage.CRYPTPAD_LANG) { return; }
|
}
|
||||||
var l = localStorage.CRYPTPAD_LANG;
|
|
||||||
userObject.settings.language = l;
|
|
||||||
};
|
|
||||||
if (version < 3) {
|
|
||||||
migrateLanguage();
|
|
||||||
Feedback.send('Migrate-3', true);
|
|
||||||
userObject.version = version = 3;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Migration 4: allowUserFeedback to settings
|
|
||||||
var migrateFeedback = function () {
|
|
||||||
var settings = userObject.settings = userObject.settings || {};
|
|
||||||
if (typeof(userObject['allowUserFeedback']) !== "undefined") {
|
|
||||||
settings.general = settings.general || {};
|
|
||||||
settings.general.allowUserFeedback = userObject['allowUserFeedback'];
|
|
||||||
delete userObject['allowUserFeedback'];
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (version < 4) {
|
|
||||||
migrateFeedback();
|
|
||||||
Feedback.send('Migrate-4', true);
|
|
||||||
userObject.version = version = 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Migration 5: dates to Number
|
|
||||||
var migrateDates = function () {
|
|
||||||
var data = userObject.drive && userObject.drive.filesData;
|
|
||||||
if (data) {
|
|
||||||
for (var id in data) {
|
|
||||||
if (typeof data[id].ctime !== "number") {
|
|
||||||
data[id].ctime = +new Date(data[id].ctime);
|
|
||||||
}
|
|
||||||
if (typeof data[id].atime !== "number") {
|
|
||||||
data[id].atime = +new Date(data[id].atime);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
if (version < 5) {
|
||||||
|
migrateDates();
|
||||||
|
Feedback.send('Migrate-5', true);
|
||||||
|
userObject.version = version = 5;
|
||||||
}
|
}
|
||||||
};
|
}).nThen(function (waitFor) {
|
||||||
if (version < 5) {
|
var addChannelId = function () {
|
||||||
migrateDates();
|
var data = userObject.drive.filesData;
|
||||||
Feedback.send('Migrate-5', true);
|
var el, parsed;
|
||||||
userObject.version = version = 5;
|
var n = nThen(function () {});
|
||||||
}
|
var padsLength = Object.keys(data).length;
|
||||||
|
Object.keys(data).forEach(function (k, i) {
|
||||||
|
n = n.nThen(function (w) {
|
||||||
|
setTimeout(w(function () {
|
||||||
|
el = data[k];
|
||||||
|
parsed = Hash.parsePadUrl(el.href);
|
||||||
|
if (!el.href) { return; }
|
||||||
|
if (!el.channel) {
|
||||||
|
if (parsed.hashData && parsed.hashData.type === "file") {
|
||||||
|
// PASSWORD_FILES
|
||||||
|
el.channel = Util.base64ToHex(parsed.hashData.channel);
|
||||||
|
} else {
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
||||||
|
el.channel = secret.channel;
|
||||||
|
}
|
||||||
|
progress(6, Math.round(100*i/padsLength));
|
||||||
|
console.log('Adding missing channel in filesData ', el.channel);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
n.nThen(waitFor());
|
||||||
|
};
|
||||||
|
if (version < 6) {
|
||||||
|
addChannelId();
|
||||||
|
Feedback.send('Migrate-6', true);
|
||||||
|
userObject.version = version = 6;
|
||||||
|
}
|
||||||
|
/*}).nThen(function (waitFor) {
|
||||||
|
// Test progress bar in the loading screen
|
||||||
|
var i = 0;
|
||||||
|
var w = waitFor();
|
||||||
|
var it = setInterval(function () {
|
||||||
|
i += 5;
|
||||||
|
if (i >= 100) { w(); clearInterval(it); i = 100;}
|
||||||
|
progress(0, i);
|
||||||
|
}, 500);
|
||||||
|
progress(0, 0);*/
|
||||||
|
}).nThen(function () {
|
||||||
|
cb();
|
||||||
|
});
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -16,9 +16,11 @@ define([
|
|||||||
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
|
'/bower_components/chainpad-crypto/crypto.js?v=0.1.5',
|
||||||
'/bower_components/chainpad/chainpad.dist.js',
|
'/bower_components/chainpad/chainpad.dist.js',
|
||||||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||||
|
'/bower_components/nthen/index.js',
|
||||||
|
'/bower_components/saferphore/index.js',
|
||||||
], function (Sortify, UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger,
|
], function (Sortify, UserObject, Migrate, Hash, Util, Constants, Feedback, Realtime, Messaging, Messenger,
|
||||||
CpNfWorker, NetConfig, AppConfig,
|
CpNfWorker, NetConfig, AppConfig,
|
||||||
Crypto, ChainPad, Listmap) {
|
Crypto, ChainPad, Listmap, nThen, Saferphore) {
|
||||||
var Store = {};
|
var Store = {};
|
||||||
|
|
||||||
var postMessage = function () {};
|
var postMessage = function () {};
|
||||||
@@ -66,8 +68,9 @@ define([
|
|||||||
var userHash = storeHash;
|
var userHash = storeHash;
|
||||||
if (!userHash) { return null; }
|
if (!userHash) { return null; }
|
||||||
|
|
||||||
var userParsedHash = Hash.parseTypeHash('drive', userHash);
|
// No password for drive
|
||||||
var userChannel = userParsedHash && userParsedHash.channel;
|
var secret = Hash.getSecrets('drive', userHash);
|
||||||
|
var userChannel = secret.channel;
|
||||||
if (!userChannel) { return null; }
|
if (!userChannel) { return null; }
|
||||||
|
|
||||||
// Get the list of pads' channel ID in your drive
|
// Get the list of pads' channel ID in your drive
|
||||||
@@ -79,16 +82,16 @@ define([
|
|||||||
var d = store.userObject.getFileData(id);
|
var d = store.userObject.getFileData(id);
|
||||||
if (d.owners && d.owners.length && edPublic &&
|
if (d.owners && d.owners.length && edPublic &&
|
||||||
d.owners.indexOf(edPublic) === -1) { return; }
|
d.owners.indexOf(edPublic) === -1) { return; }
|
||||||
return Hash.hrefToHexChannelId(d.href);
|
return d.channel;
|
||||||
})
|
})
|
||||||
.filter(function (x) { return x; });
|
.filter(function (x) { return x; });
|
||||||
|
|
||||||
// Get the avatar
|
// Get the avatar
|
||||||
var profile = store.proxy.profile;
|
var profile = store.proxy.profile;
|
||||||
if (profile) {
|
if (profile) {
|
||||||
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit) : null;
|
var profileChan = profile.edit ? Hash.hrefToHexChannelId('/profile/#' + profile.edit, null) : null;
|
||||||
if (profileChan) { list.push(profileChan); }
|
if (profileChan) { list.push(profileChan); }
|
||||||
var avatarChan = profile.avatar ? Hash.hrefToHexChannelId(profile.avatar) : null;
|
var avatarChan = profile.avatar ? Hash.hrefToHexChannelId(profile.avatar, null) : null;
|
||||||
if (avatarChan) { list.push(avatarChan); }
|
if (avatarChan) { list.push(avatarChan); }
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -97,7 +100,7 @@ define([
|
|||||||
list = list.concat(fList);
|
list = list.concat(fList);
|
||||||
}
|
}
|
||||||
|
|
||||||
list.push(Util.base64ToHex(userChannel));
|
list.push(userChannel);
|
||||||
list.sort();
|
list.sort();
|
||||||
|
|
||||||
return list;
|
return list;
|
||||||
@@ -113,7 +116,7 @@ define([
|
|||||||
// because of the expiration time
|
// because of the expiration time
|
||||||
if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) ||
|
if ((data.owners && data.owners.length && data.owners.indexOf(edPublic) === -1) ||
|
||||||
(data.expire && data.expire < (+new Date()))) {
|
(data.expire && data.expire < (+new Date()))) {
|
||||||
list.push(Hash.hrefToHexChannelId(data.href));
|
list.push(data.channel);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return list;
|
return list;
|
||||||
@@ -301,7 +304,7 @@ define([
|
|||||||
Store.getFileSize = function (data, cb) {
|
Store.getFileSize = function (data, cb) {
|
||||||
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||||
|
|
||||||
var channelId = Hash.hrefToHexChannelId(data.href);
|
var channelId = Hash.hrefToHexChannelId(data.href, data.password);
|
||||||
store.anon_rpc.send("GET_FILE_SIZE", channelId, function (e, response) {
|
store.anon_rpc.send("GET_FILE_SIZE", channelId, function (e, response) {
|
||||||
if (e) { return void cb({error: e}); }
|
if (e) { return void cb({error: e}); }
|
||||||
if (response && response.length && typeof(response[0]) === 'number') {
|
if (response && response.length && typeof(response[0]) === 'number') {
|
||||||
@@ -314,7 +317,7 @@ define([
|
|||||||
|
|
||||||
Store.isNewChannel = function (data, cb) {
|
Store.isNewChannel = function (data, cb) {
|
||||||
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
if (!store.anon_rpc) { return void cb({error: 'ANON_RPC_NOT_READY'}); }
|
||||||
var channelId = Hash.hrefToHexChannelId(data.href);
|
var channelId = Hash.hrefToHexChannelId(data.href, data.password);
|
||||||
store.anon_rpc.send("IS_NEW_CHANNEL", channelId, function (e, response) {
|
store.anon_rpc.send("IS_NEW_CHANNEL", channelId, function (e, response) {
|
||||||
if (e) { return void cb({error: e}); }
|
if (e) { return void cb({error: e}); }
|
||||||
if (response && response.length && typeof(response[0]) === 'boolean') {
|
if (response && response.length && typeof(response[0]) === 'boolean') {
|
||||||
@@ -378,6 +381,7 @@ define([
|
|||||||
|
|
||||||
// Get the metadata for sframe-common-outer
|
// Get the metadata for sframe-common-outer
|
||||||
Store.getMetadata = function (data, cb) {
|
Store.getMetadata = function (data, cb) {
|
||||||
|
var disableThumbnails = Util.find(store.proxy, ['settings', 'general', 'disableThumbnails']);
|
||||||
var metadata = {
|
var metadata = {
|
||||||
// "user" is shared with everybody via the userlist
|
// "user" is shared with everybody via the userlist
|
||||||
user: {
|
user: {
|
||||||
@@ -392,7 +396,7 @@ define([
|
|||||||
edPublic: store.proxy.edPublic,
|
edPublic: store.proxy.edPublic,
|
||||||
friends: store.proxy.friends || {},
|
friends: store.proxy.friends || {},
|
||||||
settings: store.proxy.settings,
|
settings: store.proxy.settings,
|
||||||
thumbnails: !Util.find(store.proxy, ['settings', 'general', 'disableThumbnails'])
|
thumbnails: disableThumbnails === false
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
cb(JSON.parse(JSON.stringify(metadata)));
|
cb(JSON.parse(JSON.stringify(metadata)));
|
||||||
@@ -413,6 +417,8 @@ define([
|
|||||||
var pad = makePad(data.href, data.title);
|
var pad = makePad(data.href, data.title);
|
||||||
if (data.owners) { pad.owners = data.owners; }
|
if (data.owners) { pad.owners = data.owners; }
|
||||||
if (data.expire) { pad.expire = data.expire; }
|
if (data.expire) { pad.expire = data.expire; }
|
||||||
|
if (data.password) { pad.password = data.password; }
|
||||||
|
if (data.channel) { pad.channel = data.channel; }
|
||||||
store.userObject.pushData(pad, function (e, id) {
|
store.userObject.pushData(pad, function (e, id) {
|
||||||
if (e) { return void cb({error: "Error while adding a template:"+ e}); }
|
if (e) { return void cb({error: "Error while adding a template:"+ e}); }
|
||||||
var path = data.path || ['root'];
|
var path = data.path || ['root'];
|
||||||
@@ -421,20 +427,98 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var getOwnedPads = function () {
|
||||||
|
var list = [];
|
||||||
|
store.userObject.getFiles([store.userObject.FILES_DATA]).forEach(function (id) {
|
||||||
|
var data = store.userObject.getFileData(id);
|
||||||
|
var edPublic = store.proxy.edPublic;
|
||||||
|
|
||||||
|
// Push channels owned by someone else or channel that should have expired
|
||||||
|
// because of the expiration time
|
||||||
|
if (data.owners && data.owners.length === 1 && data.owners.indexOf(edPublic) !== -1) {
|
||||||
|
list.push(data.channel);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (store.proxy.todo) {
|
||||||
|
// No password for todo
|
||||||
|
list.push(Hash.hrefToHexChannelId('/todo/#' + store.proxy.todo, null));
|
||||||
|
}
|
||||||
|
if (store.proxy.profile && store.proxy.profile.edit) {
|
||||||
|
// No password for profile
|
||||||
|
list.push(Hash.hrefToHexChannelId('/profile/#' + store.proxy.profile.edit, null));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
};
|
||||||
|
var removeOwnedPads = function (waitFor) {
|
||||||
|
// Delete owned pads
|
||||||
|
var ownedPads = getOwnedPads();
|
||||||
|
var sem = Saferphore.create(10);
|
||||||
|
ownedPads.forEach(function (c) {
|
||||||
|
var w = waitFor();
|
||||||
|
sem.take(function (give) {
|
||||||
|
Store.removeOwnedChannel(c, give(function (obj) {
|
||||||
|
if (obj && obj.error) { console.error(obj.error); }
|
||||||
|
w();
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
Store.deleteAccount = function (data, cb) {
|
Store.deleteAccount = function (data, cb) {
|
||||||
var toSign = {
|
var edPublic = store.proxy.edPublic;
|
||||||
intent: 'Please delete my account.'
|
// No password for drive
|
||||||
};
|
|
||||||
var secret = Hash.getSecrets('drive', storeHash);
|
var secret = Hash.getSecrets('drive', storeHash);
|
||||||
toSign.drive = secret.channel;
|
Store.anonRpcMsg({
|
||||||
toSign.edPublic = store.proxy.edPublic;
|
msg: 'GET_METADATA',
|
||||||
var signKey = Crypto.Nacl.util.decodeBase64(secret.keys.signKey);
|
data: secret.channel
|
||||||
console.log(Sortify(toSign));
|
}, function (data) {
|
||||||
var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey);
|
var metadata = data[0];
|
||||||
var proofTxt = Crypto.Nacl.util.encodeBase64(proof);
|
// Owned drive
|
||||||
cb({
|
if (metadata && metadata.owners && metadata.owners.length === 1 &&
|
||||||
proof: proofTxt,
|
metadata.owners.indexOf(edPublic) !== -1) {
|
||||||
toSign: JSON.parse(Sortify(toSign))
|
nThen(function (waitFor) {
|
||||||
|
var token = Math.floor(Math.random()*Number.MAX_SAFE_INTEGER);
|
||||||
|
store.proxy[Constants.tokenKey] = token;
|
||||||
|
postMessage("DELETE_ACCOUNT", token, waitFor());
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
removeOwnedPads(waitFor);
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// Delete Pin Store
|
||||||
|
store.rpc.removePins(waitFor(function (err) {
|
||||||
|
if (err) { console.error(err); }
|
||||||
|
}));
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
// Delete Drive
|
||||||
|
Store.removeOwnedChannel(secret.channel, waitFor());
|
||||||
|
}).nThen(function () {
|
||||||
|
store.network.disconnect();
|
||||||
|
cb({
|
||||||
|
state: true
|
||||||
|
});
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not owned drive
|
||||||
|
var toSign = {
|
||||||
|
intent: 'Please delete my account.'
|
||||||
|
};
|
||||||
|
toSign.drive = secret.channel;
|
||||||
|
toSign.edPublic = edPublic;
|
||||||
|
var signKey = Crypto.Nacl.util.decodeBase64(store.proxy.edPrivate);
|
||||||
|
var proof = Crypto.Nacl.sign.detached(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)), signKey);
|
||||||
|
|
||||||
|
var check = Crypto.Nacl.sign.detached.verify(Crypto.Nacl.util.decodeUTF8(Sortify(toSign)),
|
||||||
|
proof,
|
||||||
|
Crypto.Nacl.util.decodeBase64(edPublic));
|
||||||
|
|
||||||
|
if (!check) { console.error('signed message failed verification'); }
|
||||||
|
|
||||||
|
var proofTxt = Crypto.Nacl.util.encodeBase64(proof);
|
||||||
|
cb({
|
||||||
|
proof: proofTxt,
|
||||||
|
toSign: JSON.parse(Sortify(toSign))
|
||||||
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -446,25 +530,19 @@ define([
|
|||||||
*/
|
*/
|
||||||
Store.createReadme = function (data, cb) {
|
Store.createReadme = function (data, cb) {
|
||||||
require(['/common/cryptget.js'], function (Crypt) {
|
require(['/common/cryptget.js'], function (Crypt) {
|
||||||
var hash = Hash.createRandomHash();
|
var hash = Hash.createRandomHash('pad');
|
||||||
Crypt.put(hash, data.driveReadme, function (e) {
|
Crypt.put(hash, data.driveReadme, function (e) {
|
||||||
if (e) {
|
if (e) {
|
||||||
return void cb({ error: "Error while creating the default pad:"+ e});
|
return void cb({ error: "Error while creating the default pad:"+ e});
|
||||||
}
|
}
|
||||||
var href = '/pad/#' + hash;
|
var href = '/pad/#' + hash;
|
||||||
|
var channel = Hash.hrefToHexChannelId(href, null);
|
||||||
var fileData = {
|
var fileData = {
|
||||||
href: href,
|
href: href,
|
||||||
|
channel: channel,
|
||||||
title: data.driveReadmeTitle,
|
title: data.driveReadmeTitle,
|
||||||
atime: +new Date(),
|
|
||||||
ctime: +new Date()
|
|
||||||
};
|
};
|
||||||
store.userObject.pushData(fileData, function (e, id) {
|
Store.addPad(fileData, cb);
|
||||||
if (e) {
|
|
||||||
return void cb({ error: "Error while creating the default pad:"+ e});
|
|
||||||
}
|
|
||||||
store.userObject.add(id);
|
|
||||||
onSync(cb);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
@@ -515,8 +593,12 @@ define([
|
|||||||
|
|
||||||
// Reset the drive part of the userObject (from settings)
|
// Reset the drive part of the userObject (from settings)
|
||||||
Store.resetDrive = function (data, cb) {
|
Store.resetDrive = function (data, cb) {
|
||||||
store.proxy.drive = store.fo.getStructure();
|
nThen(function (waitFor) {
|
||||||
onSync(cb);
|
removeOwnedPads(waitFor);
|
||||||
|
}).nThen(function () {
|
||||||
|
store.proxy.drive = store.fo.getStructure();
|
||||||
|
onSync(cb);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -554,18 +636,7 @@ define([
|
|||||||
|
|
||||||
// Tags
|
// Tags
|
||||||
Store.listAllTags = function (data, cb) {
|
Store.listAllTags = function (data, cb) {
|
||||||
var all = [];
|
cb(store.userObject.getTagsList());
|
||||||
var files = Util.find(store.proxy, ['drive', 'filesData']);
|
|
||||||
|
|
||||||
if (typeof(files) !== 'object') { return cb({error: 'invalid_drive'}); }
|
|
||||||
Object.keys(files).forEach(function (k) {
|
|
||||||
var file = files[k];
|
|
||||||
if (!Array.isArray(file.tags)) { return; }
|
|
||||||
file.tags.forEach(function (tag) {
|
|
||||||
if (all.indexOf(tag) === -1) { all.push(tag); }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
cb(all);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Templates
|
// Templates
|
||||||
@@ -578,6 +649,15 @@ define([
|
|||||||
});
|
});
|
||||||
cb(res);
|
cb(res);
|
||||||
};
|
};
|
||||||
|
Store.incrementTemplateUse = function (href) {
|
||||||
|
store.userObject.getPadAttribute(href, 'used', function (err, data) {
|
||||||
|
// This is a not critical function, abort in case of error to make sure we won't
|
||||||
|
// create any issue with the user object or the async store
|
||||||
|
if (err) { return; }
|
||||||
|
var used = typeof data === "number" ? ++data : 1;
|
||||||
|
store.userObject.setPadAttribute(href, 'used', used);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
// Pads
|
// Pads
|
||||||
Store.moveToTrash = function (data, cb) {
|
Store.moveToTrash = function (data, cb) {
|
||||||
@@ -588,17 +668,18 @@ define([
|
|||||||
Store.setPadTitle = function (data, cb) {
|
Store.setPadTitle = function (data, cb) {
|
||||||
var title = data.title;
|
var title = data.title;
|
||||||
var href = data.href;
|
var href = data.href;
|
||||||
|
var channel = data.channel;
|
||||||
var p = Hash.parsePadUrl(href);
|
var p = Hash.parsePadUrl(href);
|
||||||
var h = p.hashData;
|
var h = p.hashData;
|
||||||
|
|
||||||
if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); }
|
if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); }
|
||||||
|
|
||||||
var owners;
|
var owners;
|
||||||
if (Store.channel && Store.channel.wc && Util.base64ToHex(h.channel) === Store.channel.wc.id) {
|
if (Store.channel && Store.channel.wc && channel === Store.channel.wc.id) {
|
||||||
owners = Store.channel.data.owners || undefined;
|
owners = Store.channel.data.owners || undefined;
|
||||||
}
|
}
|
||||||
var expire;
|
var expire;
|
||||||
if (Store.channel && Store.channel.wc && Util.base64ToHex(h.channel) === Store.channel.wc.id) {
|
if (Store.channel && Store.channel.wc && channel === Store.channel.wc.id) {
|
||||||
expire = +Store.channel.data.expire || undefined;
|
expire = +Store.channel.data.expire || undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -621,13 +702,13 @@ define([
|
|||||||
// Different types, proceed to the next one
|
// Different types, proceed to the next one
|
||||||
// No hash data: corrupted pad?
|
// No hash data: corrupted pad?
|
||||||
if (p.type !== p2.type || !h2) { continue; }
|
if (p.type !== p2.type || !h2) { continue; }
|
||||||
|
// Different channel: continue
|
||||||
|
if (pad.channel !== channel) { continue; }
|
||||||
|
|
||||||
var shouldUpdate = p.hash.replace(/\/$/, '') === p2.hash.replace(/\/$/, '');
|
var shouldUpdate = p.hash.replace(/\/$/, '') === p2.hash.replace(/\/$/, '');
|
||||||
|
|
||||||
// If the hash is different but represents the same channel, check if weaker or stronger
|
// If the hash is different but represents the same channel, check if weaker or stronger
|
||||||
if (!shouldUpdate &&
|
if (!shouldUpdate && h.version !== 0) {
|
||||||
h.version === 1 && h2.version === 1 &&
|
|
||||||
h.channel === h2.channel) {
|
|
||||||
// We had view & now we have edit, update
|
// We had view & now we have edit, update
|
||||||
if (h2.mode === 'view' && h.mode === 'edit') { shouldUpdate = true; }
|
if (h2.mode === 'view' && h.mode === 'edit') { shouldUpdate = true; }
|
||||||
// Same mode and we had present URL, update
|
// Same mode and we had present URL, update
|
||||||
@@ -664,10 +745,12 @@ define([
|
|||||||
if (!contains) {
|
if (!contains) {
|
||||||
Store.addPad({
|
Store.addPad({
|
||||||
href: href,
|
href: href,
|
||||||
|
channel: channel,
|
||||||
title: title,
|
title: title,
|
||||||
owners: owners,
|
owners: owners,
|
||||||
expire: expire,
|
expire: expire,
|
||||||
path: data.path || (store.data && store.data.initialPath)
|
password: data.password,
|
||||||
|
path: data.path
|
||||||
}, cb);
|
}, cb);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -707,10 +790,7 @@ define([
|
|||||||
Store.getPadData = function (id, cb) {
|
Store.getPadData = function (id, cb) {
|
||||||
cb(store.userObject.getFileData(id));
|
cb(store.userObject.getFileData(id));
|
||||||
};
|
};
|
||||||
Store.setInitialPath = function (path) {
|
|
||||||
if (!store.data) { return; }
|
|
||||||
store.data.initialPath = path;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Messaging (manage friends from the userlist)
|
// Messaging (manage friends from the userlist)
|
||||||
var getMessagingCfg = function () {
|
var getMessagingCfg = function () {
|
||||||
@@ -742,9 +822,9 @@ define([
|
|||||||
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {};
|
var allPads = Util.find(store.proxy, ['drive', 'filesData']) || {};
|
||||||
|
|
||||||
// If we have a stronger version in drive, add it and add a redirect button
|
// If we have a stronger version in drive, add it and add a redirect button
|
||||||
var stronger = Hash.findStronger(data.href, allPads);
|
var stronger = Hash.findStronger(data.href, data.channel, allPads);
|
||||||
if (stronger) {
|
if (stronger) {
|
||||||
var parsed2 = Hash.parsePadUrl(stronger);
|
var parsed2 = Hash.parsePadUrl(stronger.href);
|
||||||
return void cb(parsed2.hash);
|
return void cb(parsed2.hash);
|
||||||
}
|
}
|
||||||
cb();
|
cb();
|
||||||
@@ -836,8 +916,12 @@ define([
|
|||||||
channel.data = padData || {};
|
channel.data = padData || {};
|
||||||
postMessage("PAD_READY");
|
postMessage("PAD_READY");
|
||||||
}, // post EV_PAD_READY
|
}, // post EV_PAD_READY
|
||||||
onMessage: function (m) {
|
onMessage: function (user, m, validateKey) {
|
||||||
postMessage("PAD_MESSAGE", m);
|
postMessage("PAD_MESSAGE", {
|
||||||
|
user: user,
|
||||||
|
msg: m,
|
||||||
|
validateKey: validateKey
|
||||||
|
});
|
||||||
}, // post EV_PAD_MESSAGE
|
}, // post EV_PAD_MESSAGE
|
||||||
onJoin: function (m) {
|
onJoin: function (m) {
|
||||||
postMessage("PAD_JOIN", m);
|
postMessage("PAD_JOIN", m);
|
||||||
@@ -906,7 +990,7 @@ define([
|
|||||||
if (parsed[1][3] !== data.channel) { return; }
|
if (parsed[1][3] !== data.channel) { return; }
|
||||||
msg = parsed[1][4];
|
msg = parsed[1][4];
|
||||||
if (msg) {
|
if (msg) {
|
||||||
msg = msg.replace(/^cp\|/, '');
|
msg = msg.replace(/cp\|(([A-Za-z0-9+\/=]+)\|)?/, '');
|
||||||
//var decryptedMsg = crypto.decrypt(msg, true);
|
//var decryptedMsg = crypto.decrypt(msg, true);
|
||||||
msgs.push(msg);
|
msgs.push(msg);
|
||||||
}
|
}
|
||||||
@@ -956,11 +1040,24 @@ define([
|
|||||||
postMessage("DRIVE_LOG", msg);
|
postMessage("DRIVE_LOG", msg);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
var todo = function () {
|
nThen(function (waitFor) {
|
||||||
|
postMessage('LOADING_DRIVE', {
|
||||||
|
state: 2
|
||||||
|
});
|
||||||
|
userObject.migrate(waitFor());
|
||||||
|
}).nThen(function (waitFor) {
|
||||||
|
Migrate(proxy, waitFor(), function (version, progress) {
|
||||||
|
postMessage('LOADING_DRIVE', {
|
||||||
|
state: 2,
|
||||||
|
progress: progress
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}).nThen(function () {
|
||||||
|
postMessage('LOADING_DRIVE', {
|
||||||
|
state: 3
|
||||||
|
});
|
||||||
userObject.fixFiles();
|
userObject.fixFiles();
|
||||||
|
|
||||||
Migrate(proxy);
|
|
||||||
|
|
||||||
var requestLogin = function () {
|
var requestLogin = function () {
|
||||||
postMessage("REQUEST_LOGIN");
|
postMessage("REQUEST_LOGIN");
|
||||||
};
|
};
|
||||||
@@ -1023,16 +1120,16 @@ define([
|
|||||||
proxy.on('change', [Constants.tokenKey], function () {
|
proxy.on('change', [Constants.tokenKey], function () {
|
||||||
postMessage("UPDATE_TOKEN", { token: proxy[Constants.tokenKey] });
|
postMessage("UPDATE_TOKEN", { token: proxy[Constants.tokenKey] });
|
||||||
});
|
});
|
||||||
};
|
});
|
||||||
userObject.migrate(todo);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var connect = function (data, cb) {
|
var connect = function (data, cb) {
|
||||||
var hash = data.userHash || data.anonHash || Hash.createRandomHash();
|
var hash = data.userHash || data.anonHash || Hash.createRandomHash('drive');
|
||||||
storeHash = hash;
|
storeHash = hash;
|
||||||
if (!hash) {
|
if (!hash) {
|
||||||
throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...');
|
throw new Error('[Store.init] Unable to find or create a drive hash. Aborting...');
|
||||||
}
|
}
|
||||||
|
// No password for drive
|
||||||
var secret = Hash.getSecrets('drive', hash);
|
var secret = Hash.getSecrets('drive', hash);
|
||||||
var listmapConfig = {
|
var listmapConfig = {
|
||||||
data: {},
|
data: {},
|
||||||
@@ -1055,7 +1152,7 @@ define([
|
|||||||
store.realtime = info.realtime;
|
store.realtime = info.realtime;
|
||||||
store.network = info.network;
|
store.network = info.network;
|
||||||
if (!data.userHash) {
|
if (!data.userHash) {
|
||||||
returned.anonHash = Hash.getEditHashFromKeys(info.channel, secret.keys);
|
returned.anonHash = Hash.getEditHashFromKeys(secret);
|
||||||
}
|
}
|
||||||
}).on('ready', function () {
|
}).on('ready', function () {
|
||||||
if (store.userObject) { return; } // the store is already ready, it is a reconnection
|
if (store.userObject) { return; } // the store is already ready, it is a reconnection
|
||||||
@@ -1066,6 +1163,7 @@ define([
|
|||||||
&& !drive['filesData']) {
|
&& !drive['filesData']) {
|
||||||
drive[Constants.oldStorageKey] = [];
|
drive[Constants.oldStorageKey] = [];
|
||||||
}
|
}
|
||||||
|
postMessage('LOADING_DRIVE', { state: 1 });
|
||||||
// Drive already exist: return the existing drive, don't load data from legacy store
|
// Drive already exist: return the existing drive, don't load data from legacy store
|
||||||
onReady(returned, cb);
|
onReady(returned, cb);
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ define([], function () {
|
|||||||
|
|
||||||
// shim between chainpad and netflux
|
// shim between chainpad and netflux
|
||||||
var msgIn = function (peerId, msg) {
|
var msgIn = function (peerId, msg) {
|
||||||
return msg.replace(/^cp\|/, '');
|
return msg.replace(/^cp\|([A-Za-z0-9+\/=]+\|)?/, '');
|
||||||
};
|
};
|
||||||
|
|
||||||
var msgOut = function (msg) {
|
var msgOut = function (msg) {
|
||||||
@@ -130,7 +130,7 @@ define([], function () {
|
|||||||
message = unBencode(message);//.slice(message.indexOf(':[') + 1);
|
message = unBencode(message);//.slice(message.indexOf(':[') + 1);
|
||||||
|
|
||||||
// pass the message into Chainpad
|
// pass the message into Chainpad
|
||||||
onMessage(message);
|
onMessage(peer, message, validateKey);
|
||||||
//sframeChan.query('Q_RT_MESSAGE', message, function () { });
|
//sframeChan.query('Q_RT_MESSAGE', message, function () { });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -92,7 +92,7 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
var logoutHandlers = [];
|
var logoutHandlers = [];
|
||||||
LocalStore.logout = function (cb) {
|
LocalStore.logout = function (cb, isDeletion) {
|
||||||
[
|
[
|
||||||
Constants.userNameKey,
|
Constants.userNameKey,
|
||||||
Constants.userHashKey,
|
Constants.userHashKey,
|
||||||
@@ -108,13 +108,15 @@ define([
|
|||||||
// Make sure we have an FS_hash in localStorage before reloading all the tabs
|
// Make sure we have an FS_hash in localStorage before reloading all the tabs
|
||||||
// so that we don't end up with tabs using different anon hashes
|
// so that we don't end up with tabs using different anon hashes
|
||||||
if (!LocalStore.getFSHash()) {
|
if (!LocalStore.getFSHash()) {
|
||||||
LocalStore.setFSHash(Hash.createRandomHash());
|
LocalStore.setFSHash(Hash.createRandomHash('drive'));
|
||||||
}
|
}
|
||||||
eraseTempSessionValues();
|
eraseTempSessionValues();
|
||||||
|
|
||||||
logoutHandlers.forEach(function (h) {
|
if (!isDeletion) {
|
||||||
if (typeof (h) === "function") { h(); }
|
logoutHandlers.forEach(function (h) {
|
||||||
});
|
if (typeof (h) === "function") { h(); }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (typeof(AppConfig.customizeLogout) === 'function') {
|
if (typeof(AppConfig.customizeLogout) === 'function') {
|
||||||
return void AppConfig.customizeLogout(cb);
|
return void AppConfig.customizeLogout(cb);
|
||||||
|
|||||||
@@ -120,12 +120,12 @@ define([
|
|||||||
case 'GET_PAD_DATA': {
|
case 'GET_PAD_DATA': {
|
||||||
Store.getPadData(data, cb); break;
|
Store.getPadData(data, cb); break;
|
||||||
}
|
}
|
||||||
case 'SET_INITIAL_PATH': {
|
|
||||||
Store.setInitialPath(data); break;
|
|
||||||
}
|
|
||||||
case 'GET_STRONGER_HASH': {
|
case 'GET_STRONGER_HASH': {
|
||||||
Store.getStrongerHash(data, cb); break;
|
Store.getStrongerHash(data, cb); break;
|
||||||
}
|
}
|
||||||
|
case 'INCREMENT_TEMPLATE_USE': {
|
||||||
|
Store.incrementTemplateUse(data); break;
|
||||||
|
}
|
||||||
// Messaging
|
// Messaging
|
||||||
case 'INVITE_FROM_USERLIST': {
|
case 'INVITE_FROM_USERLIST': {
|
||||||
Store.inviteFromUserlist(data, cb); break;
|
Store.inviteFromUserlist(data, cb); break;
|
||||||
|
|||||||
@@ -51,14 +51,28 @@ define([
|
|||||||
|
|
||||||
var b64Key = Nacl.util.encodeBase64(key);
|
var b64Key = Nacl.util.encodeBase64(key);
|
||||||
|
|
||||||
var hash = Hash.getFileHashFromKeys(id, b64Key);
|
var secret = {
|
||||||
|
version: 1,
|
||||||
|
channel: id,
|
||||||
|
keys: {
|
||||||
|
fileKeyStr: b64Key
|
||||||
|
}
|
||||||
|
};
|
||||||
|
var hash = Hash.getFileHashFromKeys(secret);
|
||||||
var href = '/file/#' + hash;
|
var href = '/file/#' + hash;
|
||||||
|
|
||||||
var title = metadata.name;
|
var title = metadata.name;
|
||||||
|
|
||||||
if (noStore) { return void onComplete(href); }
|
if (noStore) { return void onComplete(href); }
|
||||||
|
|
||||||
common.setPadTitle(title || "", href, path, function (err) {
|
// PASSWORD_FILES
|
||||||
|
var data = {
|
||||||
|
title: title || "",
|
||||||
|
href: href,
|
||||||
|
path: path,
|
||||||
|
channel: id
|
||||||
|
};
|
||||||
|
common.setPadTitle(data, function (err) {
|
||||||
if (err) { return void console.error(err); }
|
if (err) { return void console.error(err); }
|
||||||
onComplete(href);
|
onComplete(href);
|
||||||
common.setPadAttribute('fileType', metadata.type, null, href);
|
common.setPadAttribute('fileType', metadata.type, null, href);
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ define([
|
|||||||
return void todo();
|
return void todo();
|
||||||
}
|
}
|
||||||
if (!pinPads) { return; }
|
if (!pinPads) { return; }
|
||||||
pinPads([Hash.hrefToHexChannelId(data.href)], function (obj) {
|
pinPads([data.channel], function (obj) {
|
||||||
if (obj && obj.error) { return void cb(obj.error); }
|
if (obj && obj.error) { return void cb(obj.error); }
|
||||||
todo();
|
todo();
|
||||||
});
|
});
|
||||||
@@ -98,7 +98,7 @@ define([
|
|||||||
exp.getFiles([FILES_DATA]).forEach(function (id) {
|
exp.getFiles([FILES_DATA]).forEach(function (id) {
|
||||||
if (filesList.indexOf(id) === -1) {
|
if (filesList.indexOf(id) === -1) {
|
||||||
var fd = exp.getFileData(id);
|
var fd = exp.getFileData(id);
|
||||||
var channelId = fd && fd.href && Hash.hrefToHexChannelId(fd.href);
|
var channelId = fd.channel;
|
||||||
// If trying to remove an owned pad, remove it from server also
|
// If trying to remove an owned pad, remove it from server also
|
||||||
if (!isOwnPadRemoved &&
|
if (!isOwnPadRemoved &&
|
||||||
fd.owners && fd.owners.indexOf(edPublic) !== -1 && channelId) {
|
fd.owners && fd.owners.indexOf(edPublic) !== -1 && channelId) {
|
||||||
@@ -552,32 +552,52 @@ define([
|
|||||||
for (var id in fd) {
|
for (var id in fd) {
|
||||||
id = Number(id);
|
id = Number(id);
|
||||||
var el = fd[id];
|
var el = fd[id];
|
||||||
|
|
||||||
|
// Clean corrupted data
|
||||||
if (!el || typeof(el) !== "object") {
|
if (!el || typeof(el) !== "object") {
|
||||||
debug("An element in filesData was not an object.", el);
|
debug("An element in filesData was not an object.", el);
|
||||||
toClean.push(id);
|
toClean.push(id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Clean missing href
|
||||||
if (!el.href) {
|
if (!el.href) {
|
||||||
debug("Removing an element in filesData with a missing href.", el);
|
debug("Removing an element in filesData with a missing href.", el);
|
||||||
toClean.push(id);
|
toClean.push(id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (/^https*:\/\//.test(el.href)) { el.href = Hash.getRelativeHref(el.href); }
|
|
||||||
if (!el.ctime) { el.ctime = el.atime; }
|
|
||||||
|
|
||||||
var parsed = Hash.parsePadUrl(el.href);
|
var parsed = Hash.parsePadUrl(el.href);
|
||||||
if (!el.title) { el.title = Hash.getDefaultName(parsed); }
|
// Clean invalid hash
|
||||||
if (!parsed.hash) {
|
if (!parsed.hash) {
|
||||||
debug("Removing an element in filesData with a invalid href.", el);
|
debug("Removing an element in filesData with a invalid href.", el);
|
||||||
toClean.push(id);
|
toClean.push(id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
// Clean invalid type
|
||||||
if (!parsed.type) {
|
if (!parsed.type) {
|
||||||
debug("Removing an element in filesData with a invalid type.", el);
|
debug("Removing an element in filesData with a invalid type.", el);
|
||||||
toClean.push(id);
|
toClean.push(id);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fix href
|
||||||
|
if (/^https*:\/\//.test(el.href)) { el.href = Hash.getRelativeHref(el.href); }
|
||||||
|
// Fix creation time
|
||||||
|
if (!el.ctime) { el.ctime = el.atime; }
|
||||||
|
// Fix title
|
||||||
|
if (!el.title) { el.title = Hash.getDefaultName(parsed); }
|
||||||
|
// Fix channel
|
||||||
|
if (!el.channel) {
|
||||||
|
if (parsed.hashData && parsed.hashData.type === "file") {
|
||||||
|
// PASSWORD_FILES
|
||||||
|
el.channel = Util.base64ToHex(parsed.hashData.channel);
|
||||||
|
} else {
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
||||||
|
el.channel = secret.channel;
|
||||||
|
}
|
||||||
|
console.log('Adding missing channel in filesData ', el.channel);
|
||||||
|
}
|
||||||
|
|
||||||
if ((loggedIn || config.testMode) && rootFiles.indexOf(id) === -1) {
|
if ((loggedIn || config.testMode) && rootFiles.indexOf(id) === -1) {
|
||||||
debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el);
|
debug("An element in filesData was not in ROOT, TEMPLATE or TRASH.", id, el);
|
||||||
var newName = Hash.createChannelId();
|
var newName = Hash.createChannelId();
|
||||||
|
|||||||
@@ -165,6 +165,17 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exp.removePins = function (cb) {
|
||||||
|
rpc.send('REMOVE_PINS', undefined, function (e, response) {
|
||||||
|
if (e) { return void cb(e); }
|
||||||
|
if (response && response.length && response[0] === "OK") {
|
||||||
|
cb();
|
||||||
|
} else {
|
||||||
|
cb('INVALID_RESPONSE');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
exp.uploadComplete = function (cb) {
|
exp.uploadComplete = function (cb) {
|
||||||
rpc.send('UPLOAD_COMPLETE', null, function (e, res) {
|
rpc.send('UPLOAD_COMPLETE', null, function (e, res) {
|
||||||
if (e) { return void cb(e); }
|
if (e) { return void cb(e); }
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ define([
|
|||||||
|
|
||||||
'/bower_components/file-saver/FileSaver.min.js',
|
'/bower_components/file-saver/FileSaver.min.js',
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
@@ -279,6 +279,8 @@ define([
|
|||||||
var newContentStr = cpNfInner.chainpad.getUserDoc();
|
var newContentStr = cpNfInner.chainpad.getUserDoc();
|
||||||
if (state === STATE.DELETED) { return; }
|
if (state === STATE.DELETED) { return; }
|
||||||
|
|
||||||
|
//UI.updateLoadingProgress({ state: -1 }, false);
|
||||||
|
|
||||||
var newPad = false;
|
var newPad = false;
|
||||||
if (newContentStr === '') { newPad = true; }
|
if (newContentStr === '') { newPad = true; }
|
||||||
|
|
||||||
@@ -315,8 +317,7 @@ define([
|
|||||||
privateDat.availableHashes.viewHash;
|
privateDat.availableHashes.viewHash;
|
||||||
var href = privateDat.pathname + '#' + hash;
|
var href = privateDat.pathname + '#' + hash;
|
||||||
if (AppConfig.textAnalyzer && textContentGetter) {
|
if (AppConfig.textAnalyzer && textContentGetter) {
|
||||||
var channelId = Hash.hrefToHexChannelId(href);
|
AppConfig.textAnalyzer(textContentGetter, privateDat.channel);
|
||||||
AppConfig.textAnalyzer(textContentGetter, channelId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (options.thumbnail && privateDat.thumbnails) {
|
if (options.thumbnail && privateDat.thumbnails) {
|
||||||
@@ -432,6 +433,9 @@ define([
|
|||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
UI.addLoadingScreen();
|
UI.addLoadingScreen();
|
||||||
SFCommon.create(waitFor(function (c) { common = c; }));
|
SFCommon.create(waitFor(function (c) { common = c; }));
|
||||||
|
/*UI.updateLoadingProgress({
|
||||||
|
state: 1
|
||||||
|
}, false);*/
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
common.getSframeChannel().onReady(waitFor());
|
common.getSframeChannel().onReady(waitFor());
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
@@ -443,7 +447,7 @@ define([
|
|||||||
patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer,
|
patchTransformer: options.patchTransformer || ChainPad.SmartJSONTransformer,
|
||||||
|
|
||||||
// cryptpad debug logging (default is 1)
|
// cryptpad debug logging (default is 1)
|
||||||
// logLevel: 2,
|
logLevel: 1,
|
||||||
validateContent: options.validateContent || function (content) {
|
validateContent: options.validateContent || function (content) {
|
||||||
try {
|
try {
|
||||||
JSON.parse(content);
|
JSON.parse(content);
|
||||||
@@ -457,7 +461,12 @@ define([
|
|||||||
},
|
},
|
||||||
onRemote: onRemote,
|
onRemote: onRemote,
|
||||||
onLocal: onLocal,
|
onLocal: onLocal,
|
||||||
onInit: function () { stateChange(STATE.INITIALIZING); },
|
onInit: function () {
|
||||||
|
/*UI.updateLoadingProgress({
|
||||||
|
state: 2
|
||||||
|
}, false);*/
|
||||||
|
stateChange(STATE.INITIALIZING);
|
||||||
|
},
|
||||||
onReady: function () { evStart.reg(onReady); },
|
onReady: function () { evStart.reg(onReady); },
|
||||||
onConnectionChange: onConnectionChange,
|
onConnectionChange: onConnectionChange,
|
||||||
onError: onError
|
onError: onError
|
||||||
@@ -572,6 +581,9 @@ define([
|
|||||||
toolbar.$rightside.append($templateButton);
|
toolbar.$rightside.append($templateButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var $importTemplateButton = common.createButton('importtemplate', true);
|
||||||
|
toolbar.$drawer.append($importTemplateButton);
|
||||||
|
|
||||||
/* add a forget button */
|
/* add a forget button */
|
||||||
toolbar.$rightside.append(common.createButton('forget', true, {}, function (err) {
|
toolbar.$rightside.append(common.createButton('forget', true, {}, function (err) {
|
||||||
if (err) { return; }
|
if (err) { return; }
|
||||||
|
|||||||
@@ -41,7 +41,7 @@ define([
|
|||||||
var patchTransformer = config.patchTransformer;
|
var patchTransformer = config.patchTransformer;
|
||||||
var validateContent = config.validateContent;
|
var validateContent = config.validateContent;
|
||||||
var avgSyncMilliseconds = config.avgSyncMilliseconds;
|
var avgSyncMilliseconds = config.avgSyncMilliseconds;
|
||||||
var logLevel = typeof(config.logLevel) !== 'undefined'? config.logLevel : 2;
|
var logLevel = typeof(config.logLevel) !== 'undefined'? config.logLevel : 1;
|
||||||
var readOnly = config.readOnly || false;
|
var readOnly = config.readOnly || false;
|
||||||
var sframeChan = config.sframeChan;
|
var sframeChan = config.sframeChan;
|
||||||
var metadataMgr = config.metadataMgr;
|
var metadataMgr = config.metadataMgr;
|
||||||
|
|||||||
@@ -39,9 +39,11 @@ define([], function () {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// shim between chainpad and netflux
|
// shim between chainpad and netflux
|
||||||
var msgIn = function (msg) {
|
var msgIn = function (peer, msg) {
|
||||||
try {
|
try {
|
||||||
var decryptedMsg = Crypto.decrypt(msg, isNewHash);
|
var isHk = peer.length !== 32;
|
||||||
|
var key = isNewHash ? validateKey : false;
|
||||||
|
var decryptedMsg = Crypto.decrypt(msg, key, isHk);
|
||||||
return decryptedMsg;
|
return decryptedMsg;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err);
|
console.error(err);
|
||||||
@@ -53,7 +55,16 @@ define([], function () {
|
|||||||
if (readOnly) { return; }
|
if (readOnly) { return; }
|
||||||
try {
|
try {
|
||||||
var cmsg = Crypto.encrypt(msg);
|
var cmsg = Crypto.encrypt(msg);
|
||||||
if (msg.indexOf('[4') === 0) { cmsg = 'cp|' + cmsg; }
|
if (msg.indexOf('[4') === 0) {
|
||||||
|
var id = '';
|
||||||
|
if (window.nacl) {
|
||||||
|
var hash = window.nacl.hash(window.nacl.util.decodeUTF8(msg));
|
||||||
|
id = window.nacl.util.encodeBase64(hash.slice(0, 8)) + '|';
|
||||||
|
} else {
|
||||||
|
console.log("Checkpoint sent without an ID. Nacl is missing.");
|
||||||
|
}
|
||||||
|
cmsg = 'cp|' + id + cmsg;
|
||||||
|
}
|
||||||
return cmsg;
|
return cmsg;
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.log(msg);
|
console.log(msg);
|
||||||
@@ -67,8 +78,11 @@ define([], function () {
|
|||||||
padRpc.sendPadMsg(msg, cb);
|
padRpc.sendPadMsg(msg, cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
var onMessage = function(msg) {
|
var onMessage = function(msgObj) {
|
||||||
var message = msgIn(msg);
|
if (msgObj.validateKey && !validateKey) {
|
||||||
|
validateKey = msgObj.validateKey;
|
||||||
|
}
|
||||||
|
var message = msgIn(msgObj.user, msgObj.msg);
|
||||||
|
|
||||||
verbose(message);
|
verbose(message);
|
||||||
|
|
||||||
|
|||||||
@@ -332,6 +332,7 @@ define([
|
|||||||
//var cursor = editor.getCursor();
|
//var cursor = editor.getCursor();
|
||||||
//var cleanName = data.name.replace(/[\[\]]/g, '');
|
//var cleanName = data.name.replace(/[\[\]]/g, '');
|
||||||
//var text = '';
|
//var text = '';
|
||||||
|
// PASSWORD_FILES
|
||||||
var parsed = Hash.parsePadUrl(data.url);
|
var parsed = Hash.parsePadUrl(data.url);
|
||||||
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
||||||
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
||||||
|
|||||||
@@ -333,6 +333,8 @@ define([
|
|||||||
var editor = config.ckeditor;
|
var editor = config.ckeditor;
|
||||||
editor.document.on('drop', function (ev) {
|
editor.document.on('drop', function (ev) {
|
||||||
var dropped = ev.data.$.dataTransfer.files;
|
var dropped = ev.data.$.dataTransfer.files;
|
||||||
|
editor.document.focus();
|
||||||
|
if (!dropped || !dropped.length) { return; }
|
||||||
onFileDrop(dropped, ev);
|
onFileDrop(dropped, ev);
|
||||||
ev.data.preventDefault(true);
|
ev.data.preventDefault(true);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -24,6 +24,8 @@ define([
|
|||||||
var Utils = {};
|
var Utils = {};
|
||||||
var AppConfig;
|
var AppConfig;
|
||||||
var Test;
|
var Test;
|
||||||
|
var password;
|
||||||
|
var initialPathInDrive;
|
||||||
|
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
// Load #2, the loading screen is up so grab whatever you need...
|
// Load #2, the loading screen is up so grab whatever you need...
|
||||||
@@ -88,7 +90,16 @@ define([
|
|||||||
SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) {
|
SFrameChannel.create($('#sbox-iframe')[0].contentWindow, waitFor(function (sfc) {
|
||||||
sframeChan = sfc;
|
sframeChan = sfc;
|
||||||
}), false, { cache: cache, localStore: localStore, language: Cryptpad.getLanguage() });
|
}), false, { cache: cache, localStore: localStore, language: Cryptpad.getLanguage() });
|
||||||
Cryptpad.ready(waitFor(), {
|
Cryptpad.loading.onDriveEvent.reg(function (data) {
|
||||||
|
if (sframeChan) { sframeChan.event('EV_LOADING_INFO', data); }
|
||||||
|
});
|
||||||
|
Cryptpad.ready(waitFor(function () {
|
||||||
|
if (sframeChan) {
|
||||||
|
sframeChan.event('EV_LOADING_INFO', {
|
||||||
|
state: -1
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}), {
|
||||||
messenger: cfg.messaging,
|
messenger: cfg.messaging,
|
||||||
driveEvents: cfg.driveEvents
|
driveEvents: cfg.driveEvents
|
||||||
});
|
});
|
||||||
@@ -113,6 +124,7 @@ define([
|
|||||||
|
|
||||||
if (cfg.getSecrets) {
|
if (cfg.getSecrets) {
|
||||||
var w = waitFor();
|
var w = waitFor();
|
||||||
|
// No password for drive, profile and todo
|
||||||
cfg.getSecrets(Cryptpad, Utils, waitFor(function (err, s) {
|
cfg.getSecrets(Cryptpad, Utils, waitFor(function (err, s) {
|
||||||
secret = s;
|
secret = s;
|
||||||
Cryptpad.getShareHashes(secret, function (err, h) {
|
Cryptpad.getShareHashes(secret, function (err, h) {
|
||||||
@@ -121,19 +133,54 @@ define([
|
|||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
} else {
|
} else {
|
||||||
secret = Utils.Hash.getSecrets();
|
var parsed = Utils.Hash.parsePadUrl(window.location.href);
|
||||||
if (!secret.channel) {
|
var todo = function () {
|
||||||
// New pad: create a new random channel id
|
secret = Utils.Hash.getSecrets(parsed.type, void 0, password);
|
||||||
secret.channel = Utils.Hash.createChannelId();
|
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
|
||||||
|
};
|
||||||
|
|
||||||
|
// Prompt the password here if we have a hash containing /p/
|
||||||
|
// or get it from the pad attributes
|
||||||
|
var needPassword = parsed.hashData && parsed.hashData.password;
|
||||||
|
if (needPassword) {
|
||||||
|
Cryptpad.getPadAttribute('password', waitFor(function (err, val) {
|
||||||
|
if (val) {
|
||||||
|
// We already know the password, use it!
|
||||||
|
password = val;
|
||||||
|
todo();
|
||||||
|
} else {
|
||||||
|
// Ask for the password and check if the pad exists
|
||||||
|
// If the pad doesn't exist, it means the password is oncorrect
|
||||||
|
// or the pad has been deleted
|
||||||
|
var correctPassword = waitFor();
|
||||||
|
sframeChan.on('Q_PAD_PASSWORD_VALUE', function (data, cb) {
|
||||||
|
password = data;
|
||||||
|
Cryptpad.isNewChannel(window.location.href, password, function (e, isNew) {
|
||||||
|
if (Boolean(isNew)) {
|
||||||
|
// Ask again in the inner iframe
|
||||||
|
// We should receive a new Q_PAD_PASSWORD_VALUE
|
||||||
|
cb(false);
|
||||||
|
} else {
|
||||||
|
todo();
|
||||||
|
correctPassword();
|
||||||
|
cb(true);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
sframeChan.event("EV_PAD_PASSWORD");
|
||||||
|
}
|
||||||
|
}), parsed.getUrl());
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
Cryptpad.getShareHashes(secret, waitFor(function (err, h) { hashes = h; }));
|
// If no password, continue...
|
||||||
|
todo();
|
||||||
}
|
}
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
// Check if the pad exists on server
|
// Check if the pad exists on server
|
||||||
if (!window.location.hash) { isNewFile = true; return; }
|
if (!window.location.hash) { isNewFile = true; return; }
|
||||||
|
|
||||||
if (realtime) {
|
if (realtime) {
|
||||||
Cryptpad.isNewChannel(window.location.href, waitFor(function (e, isNew) {
|
Cryptpad.isNewChannel(window.location.href, password, waitFor(function (e, isNew) {
|
||||||
if (e) { return console.error(e); }
|
if (e) { return console.error(e); }
|
||||||
isNewFile = Boolean(isNew);
|
isNewFile = Boolean(isNew);
|
||||||
}));
|
}));
|
||||||
@@ -188,7 +235,9 @@ define([
|
|||||||
},
|
},
|
||||||
isNewFile: isNewFile,
|
isNewFile: isNewFile,
|
||||||
isDeleted: isNewFile && window.location.hash.length > 0,
|
isDeleted: isNewFile && window.location.hash.length > 0,
|
||||||
forceCreationScreen: forceCreationScreen
|
forceCreationScreen: forceCreationScreen,
|
||||||
|
password: password,
|
||||||
|
channel: secret.channel
|
||||||
};
|
};
|
||||||
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
|
for (var k in additionalPriv) { metaObj.priv[k] = additionalPriv[k]; }
|
||||||
|
|
||||||
@@ -256,7 +305,13 @@ define([
|
|||||||
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newTitle, cb) {
|
sframeChan.on('Q_SET_PAD_TITLE_IN_DRIVE', function (newTitle, cb) {
|
||||||
currentTitle = newTitle;
|
currentTitle = newTitle;
|
||||||
setDocumentTitle();
|
setDocumentTitle();
|
||||||
Cryptpad.setPadTitle(newTitle, undefined, undefined, function (err) {
|
var data = {
|
||||||
|
password: password,
|
||||||
|
title: newTitle,
|
||||||
|
channel: secret.channel,
|
||||||
|
path: initialPathInDrive // Where to store the pad if we don't have it in our drive
|
||||||
|
};
|
||||||
|
Cryptpad.setPadTitle(data, function (err) {
|
||||||
cb(err);
|
cb(err);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -325,7 +380,9 @@ define([
|
|||||||
validateKey: secret.keys.validateKey
|
validateKey: secret.keys.validateKey
|
||||||
}, function (encryptedMsgs) {
|
}, function (encryptedMsgs) {
|
||||||
cb(encryptedMsgs.map(function (msg) {
|
cb(encryptedMsgs.map(function (msg) {
|
||||||
return crypto.decrypt(msg, true);
|
// The 3rd parameter "true" means we're going to skip signature validation.
|
||||||
|
// We don't need it since the message is already validated serverside by hk
|
||||||
|
return crypto.decrypt(msg, true, true);
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@@ -336,6 +393,7 @@ define([
|
|||||||
// If we have a stronger hash, use it for pad attributes
|
// If we have a stronger hash, use it for pad attributes
|
||||||
href = window.location.pathname + '#' + hashes.editHash;
|
href = window.location.pathname + '#' + hashes.editHash;
|
||||||
}
|
}
|
||||||
|
if (data.href) { href = data.href; }
|
||||||
Cryptpad.getPadAttribute(data.key, function (e, data) {
|
Cryptpad.getPadAttribute(data.key, function (e, data) {
|
||||||
cb({
|
cb({
|
||||||
error: e,
|
error: e,
|
||||||
@@ -349,6 +407,7 @@ define([
|
|||||||
// If we have a stronger hash, use it for pad attributes
|
// If we have a stronger hash, use it for pad attributes
|
||||||
href = window.location.pathname + '#' + hashes.editHash;
|
href = window.location.pathname + '#' + hashes.editHash;
|
||||||
}
|
}
|
||||||
|
if (data.href) { href = data.href; }
|
||||||
Cryptpad.setPadAttribute(data.key, data.value, function (e) {
|
Cryptpad.setPadAttribute(data.key, data.value, function (e) {
|
||||||
cb({error:e});
|
cb({error:e});
|
||||||
}, href);
|
}, href);
|
||||||
@@ -429,6 +488,8 @@ define([
|
|||||||
// File picker
|
// File picker
|
||||||
var FP = {};
|
var FP = {};
|
||||||
var initFilePicker = function (cfg) {
|
var initFilePicker = function (cfg) {
|
||||||
|
// cfg.hidden means pre-loading the filepicker while keeping it hidden.
|
||||||
|
// if cfg.hidden is true and the iframe already exists, do nothing
|
||||||
if (!FP.$iframe) {
|
if (!FP.$iframe) {
|
||||||
var config = {};
|
var config = {};
|
||||||
config.onFilePicked = function (data) {
|
config.onFilePicked = function (data) {
|
||||||
@@ -447,7 +508,7 @@ define([
|
|||||||
};
|
};
|
||||||
FP.$iframe = $('<iframe>', {id: 'sbox-filePicker-iframe'}).appendTo($('body'));
|
FP.$iframe = $('<iframe>', {id: 'sbox-filePicker-iframe'}).appendTo($('body'));
|
||||||
FP.picker = FilePicker.create(config);
|
FP.picker = FilePicker.create(config);
|
||||||
} else {
|
} else if (!cfg.hidden) {
|
||||||
FP.$iframe.show();
|
FP.$iframe.show();
|
||||||
FP.picker.refresh(cfg);
|
FP.picker.refresh(cfg);
|
||||||
}
|
}
|
||||||
@@ -469,9 +530,9 @@ define([
|
|||||||
cb(templates.length > 0);
|
cb(templates.length > 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
var getKey = function (href) {
|
var getKey = function (href, channel) {
|
||||||
var parsed = Utils.Hash.parsePadUrl(href);
|
var parsed = Utils.Hash.parsePadUrl(href);
|
||||||
return 'thumbnail-' + parsed.type + '-' + parsed.hashData.channel;
|
return 'thumbnail-' + parsed.type + '-' + channel;
|
||||||
};
|
};
|
||||||
sframeChan.on('Q_CREATE_TEMPLATES', function (type, cb) {
|
sframeChan.on('Q_CREATE_TEMPLATES', function (type, cb) {
|
||||||
Cryptpad.getSecureFilesList({
|
Cryptpad.getSecureFilesList({
|
||||||
@@ -484,12 +545,13 @@ define([
|
|||||||
var res = [];
|
var res = [];
|
||||||
nThen(function (waitFor) {
|
nThen(function (waitFor) {
|
||||||
Object.keys(data).map(function (el) {
|
Object.keys(data).map(function (el) {
|
||||||
var k = getKey(data[el].href);
|
var k = getKey(data[el].href, data[el].channel);
|
||||||
Utils.LocalStore.getThumbnail(k, waitFor(function (e, thumb) {
|
Utils.LocalStore.getThumbnail(k, waitFor(function (e, thumb) {
|
||||||
res.push({
|
res.push({
|
||||||
id: el,
|
id: el,
|
||||||
name: data[el].filename || data[el].title || '?',
|
name: data[el].filename || data[el].title || '?',
|
||||||
thumbnail: thumb
|
thumbnail: thumb,
|
||||||
|
used: data[el].used || 0
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
@@ -513,19 +575,6 @@ define([
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
sframeChan.on('Q_TAGS_GET', function (data, cb) {
|
|
||||||
Cryptpad.getPadTags(data, function (err, data) {
|
|
||||||
cb({
|
|
||||||
error: err,
|
|
||||||
data: data
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
sframeChan.on('EV_TAGS_SET', function (data) {
|
|
||||||
Cryptpad.resetTags(data.href, data.tags);
|
|
||||||
});
|
|
||||||
|
|
||||||
sframeChan.on('Q_PIN_GET_USAGE', function (data, cb) {
|
sframeChan.on('Q_PIN_GET_USAGE', function (data, cb) {
|
||||||
Cryptpad.isOverPinLimit(function (err, overLimit, data) {
|
Cryptpad.isOverPinLimit(function (err, overLimit, data) {
|
||||||
cb({
|
cb({
|
||||||
@@ -546,6 +595,15 @@ define([
|
|||||||
Cryptpad.removeOwnedChannel(channel, cb);
|
Cryptpad.removeOwnedChannel(channel, cb);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
sframeChan.on('Q_GET_ALL_TAGS', function (data, cb) {
|
||||||
|
Cryptpad.listAllTags(function (err, tags) {
|
||||||
|
cb({
|
||||||
|
error: err,
|
||||||
|
tags: tags
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
if (cfg.addRpc) {
|
if (cfg.addRpc) {
|
||||||
cfg.addRpc(sframeChan, Cryptpad, Utils);
|
cfg.addRpc(sframeChan, Cryptpad, Utils);
|
||||||
}
|
}
|
||||||
@@ -630,7 +688,7 @@ define([
|
|||||||
isNewHash: isNewHash,
|
isNewHash: isNewHash,
|
||||||
readOnly: readOnly,
|
readOnly: readOnly,
|
||||||
crypto: Crypto.createEncryptor(secret.keys),
|
crypto: Crypto.createEncryptor(secret.keys),
|
||||||
onConnect: function (wc) {
|
onConnect: function () {
|
||||||
if (window.location.hash && window.location.hash !== '#') {
|
if (window.location.hash && window.location.hash !== '#') {
|
||||||
window.location = parsed.getUrl({
|
window.location = parsed.getUrl({
|
||||||
present: parsed.hashData.present,
|
present: parsed.hashData.present,
|
||||||
@@ -639,20 +697,36 @@ define([
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (readOnly || cfg.noHash) { return; }
|
if (readOnly || cfg.noHash) { return; }
|
||||||
replaceHash(Utils.Hash.getEditHashFromKeys(wc, secret.keys));
|
replaceHash(Utils.Hash.getEditHashFromKeys(secret));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
Object.keys(rtConfig).forEach(function (k) {
|
|
||||||
cpNfCfg[k] = rtConfig[k];
|
nThen(function (waitFor) {
|
||||||
|
if (isNewFile && cfg.owned && !window.location.hash) {
|
||||||
|
Cryptpad.getMetadata(waitFor(function (err, m) {
|
||||||
|
cpNfCfg.owners = [m.priv.edPublic];
|
||||||
|
}));
|
||||||
|
} else if (isNewFile && !cfg.useCreationScreen && window.location.hash) {
|
||||||
|
console.log("new file with hash in the address bar in an app without pcs and which requires owners");
|
||||||
|
sframeChan.onReady(function () {
|
||||||
|
sframeChan.query("EV_LOADING_ERROR", "DELETED");
|
||||||
|
});
|
||||||
|
waitFor.abort();
|
||||||
|
}
|
||||||
|
}).nThen(function () {
|
||||||
|
Object.keys(rtConfig).forEach(function (k) {
|
||||||
|
cpNfCfg[k] = rtConfig[k];
|
||||||
|
});
|
||||||
|
CpNfOuter.start(cpNfCfg);
|
||||||
});
|
});
|
||||||
CpNfOuter.start(cpNfCfg);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
sframeChan.on('Q_CREATE_PAD', function (data, cb) {
|
sframeChan.on('Q_CREATE_PAD', function (data, cb) {
|
||||||
if (!isNewFile || rtStarted) { return; }
|
if (!isNewFile || rtStarted) { return; }
|
||||||
// Create a new hash
|
// Create a new hash
|
||||||
var newHash = Utils.Hash.createRandomHash();
|
password = data.password;
|
||||||
secret = Utils.Hash.getSecrets(parsed.type, newHash);
|
var newHash = Utils.Hash.createRandomHash(parsed.type, password);
|
||||||
|
secret = Utils.Hash.getSecrets(parsed.type, newHash, password);
|
||||||
|
|
||||||
// Update the hash in the address bar
|
// Update the hash in the address bar
|
||||||
var ohc = window.onhashchange;
|
var ohc = window.onhashchange;
|
||||||
@@ -664,7 +738,7 @@ define([
|
|||||||
// Update metadata values and send new metadata inside
|
// Update metadata values and send new metadata inside
|
||||||
parsed = Utils.Hash.parsePadUrl(window.location.href);
|
parsed = Utils.Hash.parsePadUrl(window.location.href);
|
||||||
defaultTitle = Utils.Hash.getDefaultName(parsed);
|
defaultTitle = Utils.Hash.getDefaultName(parsed);
|
||||||
hashes = Utils.Hash.getHashes(secret.channel, secret);
|
hashes = Utils.Hash.getHashes(secret);
|
||||||
readOnly = false;
|
readOnly = false;
|
||||||
updateMeta();
|
updateMeta();
|
||||||
|
|
||||||
@@ -678,7 +752,7 @@ define([
|
|||||||
nThen(function(waitFor) {
|
nThen(function(waitFor) {
|
||||||
if (data.templateId) {
|
if (data.templateId) {
|
||||||
if (data.templateId === -1) {
|
if (data.templateId === -1) {
|
||||||
Cryptpad.setInitialPath(['template']);
|
initialPathInDrive = ['template'];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Cryptpad.getPadData(data.templateId, waitFor(function (err, d) {
|
Cryptpad.getPadData(data.templateId, waitFor(function (err, d) {
|
||||||
@@ -706,8 +780,8 @@ define([
|
|||||||
|
|
||||||
Utils.Feedback.reportAppUsage();
|
Utils.Feedback.reportAppUsage();
|
||||||
|
|
||||||
if (!realtime) { return; }
|
if (!realtime && !Test.testing) { return; }
|
||||||
if (isNewFile && cfg.useCreationScreen) { return; }
|
if (isNewFile && cfg.useCreationScreen && !Test.testing) { return; }
|
||||||
//if (isNewFile && Utils.LocalStore.isLoggedIn()
|
//if (isNewFile && Utils.LocalStore.isLoggedIn()
|
||||||
// && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; }
|
// && AppConfig.displayCreationScreen && cfg.useCreationScreen) { return; }
|
||||||
|
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ define([
|
|||||||
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
|
return '<script src="' + origin + '/common/media-tag-nacl.min.js"></script>';
|
||||||
};
|
};
|
||||||
funcs.getMediatagFromHref = function (href) {
|
funcs.getMediatagFromHref = function (href) {
|
||||||
|
// PASSWORD_FILES
|
||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
var secret = Hash.getSecrets('file', parsed.hash);
|
var secret = Hash.getSecrets('file', parsed.hash);
|
||||||
var data = ctx.metadataMgr.getPrivateData();
|
var data = ctx.metadataMgr.getPrivateData();
|
||||||
@@ -126,8 +127,7 @@ define([
|
|||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
funcs.getFileSize = function (href, cb) {
|
funcs.getFileSize = function (channelId, cb) {
|
||||||
var channelId = Hash.hrefToHexChannelId(href);
|
|
||||||
funcs.sendAnonRpcMsg("GET_FILE_SIZE", channelId, function (data) {
|
funcs.sendAnonRpcMsg("GET_FILE_SIZE", channelId, function (data) {
|
||||||
if (!data) { return void cb("No response"); }
|
if (!data) { return void cb("No response"); }
|
||||||
if (data.error) { return void cb(data.error); }
|
if (data.error) { return void cb(data.error); }
|
||||||
@@ -170,6 +170,7 @@ define([
|
|||||||
|
|
||||||
// Store
|
// Store
|
||||||
funcs.handleNewFile = function (waitFor) {
|
funcs.handleNewFile = function (waitFor) {
|
||||||
|
if (window.__CRYPTPAD_TEST__) { return; }
|
||||||
var priv = ctx.metadataMgr.getPrivateData();
|
var priv = ctx.metadataMgr.getPrivateData();
|
||||||
if (priv.isNewFile) {
|
if (priv.isNewFile) {
|
||||||
var c = (priv.settings.general && priv.settings.general.creation) || {};
|
var c = (priv.settings.general && priv.settings.general.creation) || {};
|
||||||
@@ -196,6 +197,7 @@ define([
|
|||||||
ctx.sframeChan.query("Q_CREATE_PAD", {
|
ctx.sframeChan.query("Q_CREATE_PAD", {
|
||||||
owned: cfg.owned,
|
owned: cfg.owned,
|
||||||
expire: cfg.expire,
|
expire: cfg.expire,
|
||||||
|
password: cfg.password,
|
||||||
template: cfg.template,
|
template: cfg.template,
|
||||||
templateId: cfg.templateId
|
templateId: cfg.templateId
|
||||||
}, cb);
|
}, cb);
|
||||||
@@ -233,17 +235,20 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
funcs.getPadAttribute = function (key, cb) {
|
// href is optional here: if not provided, we use the href of the current tab
|
||||||
|
funcs.getPadAttribute = function (key, cb, href) {
|
||||||
ctx.sframeChan.query('Q_GET_PAD_ATTRIBUTE', {
|
ctx.sframeChan.query('Q_GET_PAD_ATTRIBUTE', {
|
||||||
key: key
|
key: key,
|
||||||
|
href: href
|
||||||
}, function (err, res) {
|
}, function (err, res) {
|
||||||
cb (err || res.error, res.data);
|
cb (err || res.error, res.data);
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
funcs.setPadAttribute = function (key, value, cb) {
|
funcs.setPadAttribute = function (key, value, cb, href) {
|
||||||
cb = cb || $.noop;
|
cb = cb || $.noop;
|
||||||
ctx.sframeChan.query('Q_SET_PAD_ATTRIBUTE', {
|
ctx.sframeChan.query('Q_SET_PAD_ATTRIBUTE', {
|
||||||
key: key,
|
key: key,
|
||||||
|
href: href,
|
||||||
value: value
|
value: value
|
||||||
}, cb);
|
}, cb);
|
||||||
};
|
};
|
||||||
@@ -343,6 +348,27 @@ define([
|
|||||||
window.open(bounceHref);
|
window.open(bounceHref);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
funcs.fixLinks = function (domElement) {
|
||||||
|
var origin = ctx.metadataMgr.getPrivateData().origin;
|
||||||
|
$(domElement).find('a[target="_blank"]').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
var href = $(this).attr('href');
|
||||||
|
var absolute = /^https?:\/\//i;
|
||||||
|
if (!absolute.test(href)) {
|
||||||
|
if (href.slice(0,1) !== '/') { href = '/' + href; }
|
||||||
|
href = origin + href;
|
||||||
|
}
|
||||||
|
funcs.openUnsafeURL(href);
|
||||||
|
});
|
||||||
|
$(domElement).find('a[target!="_blank"]').click(function (e) {
|
||||||
|
e.preventDefault();
|
||||||
|
e.stopPropagation();
|
||||||
|
funcs.gotoURL($(this).attr('href'));
|
||||||
|
});
|
||||||
|
return $(domElement)[0];
|
||||||
|
};
|
||||||
|
|
||||||
funcs.whenRealtimeSyncs = evRealtimeSynced.reg;
|
funcs.whenRealtimeSyncs = evRealtimeSynced.reg;
|
||||||
|
|
||||||
var logoutHandlers = [];
|
var logoutHandlers = [];
|
||||||
@@ -397,19 +423,6 @@ define([
|
|||||||
|
|
||||||
UI.addTooltips();
|
UI.addTooltips();
|
||||||
|
|
||||||
ctx.sframeChan.on('EV_LOGOUT', function () {
|
|
||||||
$(window).on('keyup', function (e) {
|
|
||||||
if (e.keyCode === 27) {
|
|
||||||
UI.removeLoadingScreen();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
UI.addLoadingScreen({hideTips: true});
|
|
||||||
UI.errorLoadingScreen(Messages.onLogout, true);
|
|
||||||
logoutHandlers.forEach(function (h) {
|
|
||||||
if (typeof (h) === "function") { h(); }
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
ctx.sframeChan.on('Q_INCOMING_FRIEND_REQUEST', function (confirmMsg, cb) {
|
ctx.sframeChan.on('Q_INCOMING_FRIEND_REQUEST', function (confirmMsg, cb) {
|
||||||
UI.confirm(confirmMsg, cb, null, true);
|
UI.confirm(confirmMsg, cb, null, true);
|
||||||
});
|
});
|
||||||
@@ -419,12 +432,46 @@ define([
|
|||||||
UI.log(data.logText);
|
UI.log(data.logText);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
ctx.sframeChan.on("EV_PAD_PASSWORD", function () {
|
||||||
|
UIElements.displayPasswordPrompt(funcs);
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.sframeChan.on('EV_LOADING_INFO', function (data) {
|
||||||
|
UI.updateLoadingProgress(data, true);
|
||||||
|
});
|
||||||
|
|
||||||
ctx.metadataMgr.onReady(waitFor());
|
ctx.metadataMgr.onReady(waitFor());
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
try {
|
try {
|
||||||
var feedback = ctx.metadataMgr.getPrivateData().feedbackAllowed;
|
var feedback = ctx.metadataMgr.getPrivateData().feedbackAllowed;
|
||||||
Feedback.init(feedback);
|
Feedback.init(feedback);
|
||||||
} catch (e) { Feedback.init(false); }
|
} catch (e) { Feedback.init(false); }
|
||||||
|
|
||||||
|
ctx.sframeChan.on('EV_LOADING_ERROR', function (err) {
|
||||||
|
if (err === 'DELETED') {
|
||||||
|
var msg = Messages.deletedError + '<br>' + Messages.errorRedirectToHome;
|
||||||
|
UI.errorLoadingScreen(msg, false, function () {
|
||||||
|
funcs.gotoURL('/drive/');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx.sframeChan.on('EV_LOGOUT', function () {
|
||||||
|
$(window).on('keyup', function (e) {
|
||||||
|
if (e.keyCode === 27) {
|
||||||
|
UI.removeLoadingScreen();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
UI.addLoadingScreen({hideTips: true});
|
||||||
|
var origin = ctx.metadataMgr.getPrivateData().origin;
|
||||||
|
var href = origin + "/login/";
|
||||||
|
var onLogoutMsg = Messages._getKey('onLogout', ['<a href="' + href + '" target="_blank">', '</a>']);
|
||||||
|
UI.errorLoadingScreen(onLogoutMsg, true);
|
||||||
|
logoutHandlers.forEach(function (h) {
|
||||||
|
if (typeof (h) === "function") { h(); }
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
ctx.sframeChan.ready();
|
ctx.sframeChan.ready();
|
||||||
cb(funcs);
|
cb(funcs);
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -165,10 +165,6 @@ define({
|
|||||||
// Put one entry in the parent sessionStorage
|
// Put one entry in the parent sessionStorage
|
||||||
'Q_SESSIONSTORAGE_PUT': true,
|
'Q_SESSIONSTORAGE_PUT': true,
|
||||||
|
|
||||||
// Set and get the tags using the tag prompt button
|
|
||||||
'Q_TAGS_GET': true,
|
|
||||||
'EV_TAGS_SET': true,
|
|
||||||
|
|
||||||
// Merge the anonymous drive (FS_hash) into the current logged in user's drive, to keep the pads
|
// Merge the anonymous drive (FS_hash) into the current logged in user's drive, to keep the pads
|
||||||
// in the drive at registration.
|
// in the drive at registration.
|
||||||
'Q_MERGE_ANON_DRIVE': true,
|
'Q_MERGE_ANON_DRIVE': true,
|
||||||
@@ -227,4 +223,17 @@ define({
|
|||||||
// This is for sending data out of the iframe when we are in testing mode
|
// This is for sending data out of the iframe when we are in testing mode
|
||||||
// The exact protocol is defined in common/test.js
|
// The exact protocol is defined in common/test.js
|
||||||
'EV_TESTDATA': true,
|
'EV_TESTDATA': true,
|
||||||
|
|
||||||
|
// Critical error outside the iframe during loading screen
|
||||||
|
'EV_LOADING_ERROR': true,
|
||||||
|
|
||||||
|
// Ask for the pad password when a pad is protected
|
||||||
|
'EV_PAD_PASSWORD': true,
|
||||||
|
'Q_PAD_PASSWORD_VALUE': true,
|
||||||
|
|
||||||
|
// Loading events to display in the loading screen
|
||||||
|
'EV_LOADING_INFO': true,
|
||||||
|
|
||||||
|
// Get all existing tags
|
||||||
|
'Q_GET_ALL_TAGS': true,
|
||||||
});
|
});
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
1
www/common/tippy.min.js
vendored
1
www/common/tippy.min.js
vendored
File diff suppressed because one or more lines are too long
1
www/common/tippy/tippy.css
Normal file
1
www/common/tippy/tippy.css
Normal file
File diff suppressed because one or more lines are too long
1
www/common/tippy/tippy.min.js
vendored
Normal file
1
www/common/tippy/tippy.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
@@ -576,9 +576,7 @@ define([
|
|||||||
if (Common.isLoggedIn()) { return; }
|
if (Common.isLoggedIn()) { return; }
|
||||||
var pd = config.metadataMgr.getPrivateData();
|
var pd = config.metadataMgr.getPrivateData();
|
||||||
var o = pd.origin;
|
var o = pd.origin;
|
||||||
var hashes = pd.availableHashes;
|
var cid = pd.channel;
|
||||||
var url = pd.origin + pd.pathname + '#' + (hashes.editHash || hashes.viewHash);
|
|
||||||
var cid = Hash.hrefToHexChannelId(url);
|
|
||||||
Common.sendAnonRpcMsg('IS_CHANNEL_PINNED', cid, function (x) {
|
Common.sendAnonRpcMsg('IS_CHANNEL_PINNED', cid, function (x) {
|
||||||
if (x.error || !Array.isArray(x.response)) { return void console.log(x); }
|
if (x.error || !Array.isArray(x.response)) { return void console.log(x); }
|
||||||
if (x.response[0] === true) {
|
if (x.response[0] === true) {
|
||||||
|
|||||||
@@ -384,11 +384,9 @@ define([
|
|||||||
// Get drive ids of files from their channel ids
|
// Get drive ids of files from their channel ids
|
||||||
exp.findChannels = function (channels) {
|
exp.findChannels = function (channels) {
|
||||||
var allFilesList = files[FILES_DATA];
|
var allFilesList = files[FILES_DATA];
|
||||||
var channels64 = channels.slice().map(Util.hexToBase64);
|
|
||||||
return getFiles([FILES_DATA]).filter(function (k) {
|
return getFiles([FILES_DATA]).filter(function (k) {
|
||||||
var data = allFilesList[k];
|
var data = allFilesList[k];
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
return channels.indexOf(data.channel) !== -1;
|
||||||
return parsed.hashData && channels64.indexOf(parsed.hashData.channel) !== -1;
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -629,6 +627,21 @@ define([
|
|||||||
if (typeof cb === "function") { cb(); }
|
if (typeof cb === "function") { cb(); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tags
|
||||||
|
exp.getTagsList = function () {
|
||||||
|
var tags = {};
|
||||||
|
var data;
|
||||||
|
var pushTag = function (tag) {
|
||||||
|
tags[tag] = tags[tag] ? ++tags[tag] : 1;
|
||||||
|
};
|
||||||
|
for (var id in files[FILES_DATA]) {
|
||||||
|
data = files[FILES_DATA][id];
|
||||||
|
if (!data.tags || !Array.isArray(data.tags)) { continue; }
|
||||||
|
data.tags.forEach(pushTag);
|
||||||
|
}
|
||||||
|
return tags;
|
||||||
|
};
|
||||||
|
|
||||||
return exp;
|
return exp;
|
||||||
};
|
};
|
||||||
return module;
|
return module;
|
||||||
|
|||||||
@@ -1,17 +1,13 @@
|
|||||||
@import (once) "../../customize/src/less2/include/browser.less";
|
@import (once) "../../customize/src/less2/include/browser.less";
|
||||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
|
||||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/avatar.less';
|
@import (once) '../../customize/src/less2/include/avatar.less';
|
||||||
|
@import (once) '../../customize/src/less2/include/framework.less';
|
||||||
|
|
||||||
.toolbar_main(
|
.framework_min_main(
|
||||||
@bg-color: @colortheme_friends-bg,
|
@bg-color: @colortheme_friends-bg,
|
||||||
@warn-color: @colortheme_friends-warn,
|
@warn-color: @colortheme_friends-warn,
|
||||||
@color: @colortheme_friends-color
|
@color: @colortheme_friends-color
|
||||||
);
|
);
|
||||||
.fileupload_main();
|
|
||||||
.alertify_main();
|
|
||||||
|
|
||||||
// body
|
// body
|
||||||
&.cp-app-contacts {
|
&.cp-app-contacts {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ define([
|
|||||||
'/common/common-interface.js',
|
'/common/common-interface.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
|
|||||||
@@ -1,15 +1,11 @@
|
|||||||
@import (once) "../../customize/src/less2/include/browser.less";
|
@import (once) "../../customize/src/less2/include/browser.less";
|
||||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
|
||||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/tools.less';
|
@import (once) '../../customize/src/less2/include/tools.less';
|
||||||
@import (once) '../../customize/src/less2/include/tokenfield.less';
|
@import (once) '../../customize/src/less2/include/tokenfield.less';
|
||||||
|
@import (once) '../../customize/src/less2/include/framework.less';
|
||||||
|
|
||||||
.toolbar_main();
|
|
||||||
.fileupload_main();
|
|
||||||
.alertify_main();
|
|
||||||
.tokenfield_main();
|
.tokenfield_main();
|
||||||
|
.framework_min_main();
|
||||||
|
|
||||||
// body
|
// body
|
||||||
&.cp-app-debug {
|
&.cp-app-debug {
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ define([
|
|||||||
'/bower_components/secure-fabric.js/dist/fabric.min.js',
|
'/bower_components/secure-fabric.js/dist/fabric.min.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
|
|||||||
@@ -1,20 +1,17 @@
|
|||||||
@import (once) "../../customize/src/less2/include/browser.less";
|
@import (once) "../../customize/src/less2/include/browser.less";
|
||||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
|
||||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/leftside-menu.less';
|
@import (once) '../../customize/src/less2/include/leftside-menu.less';
|
||||||
@import (once) "../../customize/src/less2/include/tools.less";
|
@import (once) "../../customize/src/less2/include/tools.less";
|
||||||
@import (once) "../../customize/src/less2/include/limit-bar.less";
|
@import (once) "../../customize/src/less2/include/limit-bar.less";
|
||||||
@import (once) "../../customize/src/less2/include/tokenfield.less";
|
@import (once) "../../customize/src/less2/include/tokenfield.less";
|
||||||
|
@import (once) '../../customize/src/less2/include/framework.less';
|
||||||
|
|
||||||
.toolbar_main(
|
.framework_min_main(
|
||||||
@bg-color: @colortheme_drive-bg,
|
@bg-color: @colortheme_drive-bg,
|
||||||
@warn-color: @colortheme_drive-warn,
|
@warn-color: @colortheme_drive-warn,
|
||||||
@color: @colortheme_drive-color
|
@color: @colortheme_drive-color
|
||||||
);
|
);
|
||||||
.fileupload_main();
|
|
||||||
.alertify_main();
|
|
||||||
.limit-bar_main();
|
.limit-bar_main();
|
||||||
.tokenfield_main();
|
.tokenfield_main();
|
||||||
|
|
||||||
@@ -465,6 +462,8 @@ span {
|
|||||||
padding-right: 15px;
|
padding-right: 15px;
|
||||||
}
|
}
|
||||||
.cp-app-drive-search-opendir {
|
.cp-app-drive-search-opendir {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
a {
|
a {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
color: #41b7d8;
|
color: #41b7d8;
|
||||||
@@ -498,6 +497,19 @@ span {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
&.cp-app-drive-tags-list {
|
||||||
|
width: 100%;
|
||||||
|
table {
|
||||||
|
margin: 10px 50px;
|
||||||
|
width: ~"calc(100% - 100px)";
|
||||||
|
table-layout: fixed;
|
||||||
|
td, th {
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.cp-app-drive-element {
|
.cp-app-drive-element {
|
||||||
@@ -547,6 +559,10 @@ span {
|
|||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
|
flex-flow: column;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
display: inline-flex;
|
||||||
&:hover {
|
&:hover {
|
||||||
opacity: 0.7;
|
opacity: 0.7;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ define([
|
|||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
@@ -51,20 +51,65 @@ define([
|
|||||||
|
|
||||||
var E_OVER_LIMIT = 'E_OVER_LIMIT';
|
var E_OVER_LIMIT = 'E_OVER_LIMIT';
|
||||||
|
|
||||||
var SEARCH = "search";
|
|
||||||
var SEARCH_NAME = Messages.fm_searchName;
|
|
||||||
var ROOT = "root";
|
var ROOT = "root";
|
||||||
var ROOT_NAME = Messages.fm_rootName;
|
var ROOT_NAME = Messages.fm_rootName;
|
||||||
|
var SEARCH = "search";
|
||||||
|
var SEARCH_NAME = Messages.fm_searchName;
|
||||||
|
var TRASH = "trash";
|
||||||
|
var TRASH_NAME = Messages.fm_trashName;
|
||||||
var FILES_DATA = Constants.storageKey;
|
var FILES_DATA = Constants.storageKey;
|
||||||
var FILES_DATA_NAME = Messages.fm_filesDataName;
|
var FILES_DATA_NAME = Messages.fm_filesDataName;
|
||||||
var TEMPLATE = "template";
|
var TEMPLATE = "template";
|
||||||
var TEMPLATE_NAME = Messages.fm_templateName;
|
var TEMPLATE_NAME = Messages.fm_templateName;
|
||||||
var TRASH = "trash";
|
|
||||||
var TRASH_NAME = Messages.fm_trashName;
|
|
||||||
var RECENT = "recent";
|
var RECENT = "recent";
|
||||||
var RECENT_NAME = Messages.fm_recentPadsName;
|
var RECENT_NAME = Messages.fm_recentPadsName;
|
||||||
var OWNED = "owned";
|
var OWNED = "owned";
|
||||||
var OWNED_NAME = Messages.fm_ownedPadsName;
|
var OWNED_NAME = Messages.fm_ownedPadsName;
|
||||||
|
var TAGS = "tags";
|
||||||
|
var TAGS_NAME = Messages.fm_tagsName;
|
||||||
|
|
||||||
|
// Icons
|
||||||
|
var faFolder = 'fa-folder';
|
||||||
|
var faFolderOpen = 'fa-folder-open';
|
||||||
|
var faReadOnly = 'fa-eye';
|
||||||
|
var faRename = 'fa-pencil';
|
||||||
|
var faTrash = 'fa-trash';
|
||||||
|
var faDelete = 'fa-eraser';
|
||||||
|
var faProperties = 'fa-database';
|
||||||
|
var faTags = 'fa-hashtag';
|
||||||
|
var faEmpty = 'fa-trash-o';
|
||||||
|
var faRestore = 'fa-repeat';
|
||||||
|
var faShowParent = 'fa-location-arrow';
|
||||||
|
var $folderIcon = $('<span>', {
|
||||||
|
"class": faFolder + " fa cp-app-drive-icon-folder cp-app-drive-content-icon"
|
||||||
|
});
|
||||||
|
//var $folderIcon = $('<img>', {src: "/customize/images/icons/folder.svg", "class": "folder icon"});
|
||||||
|
var $folderEmptyIcon = $folderIcon.clone();
|
||||||
|
var $folderOpenedIcon = $('<span>', {"class": faFolderOpen + " fa cp-app-drive-icon-folder"});
|
||||||
|
//var $folderOpenedIcon = $('<img>', {src: "/customize/images/icons/folderOpen.svg", "class": "folder icon"});
|
||||||
|
var $folderOpenedEmptyIcon = $folderOpenedIcon.clone();
|
||||||
|
//var $upIcon = $('<span>', {"class": "fa fa-arrow-circle-up"});
|
||||||
|
var $unsortedIcon = $('<span>', {"class": "fa fa-files-o"});
|
||||||
|
var $templateIcon = $('<span>', {"class": "fa fa-cubes"});
|
||||||
|
var $recentIcon = $('<span>', {"class": "fa fa-clock-o"});
|
||||||
|
var $trashIcon = $('<span>', {"class": "fa " + faTrash});
|
||||||
|
var $trashEmptyIcon = $('<span>', {"class": "fa fa-trash-o"});
|
||||||
|
//var $collapseIcon = $('<span>', {"class": "fa fa-minus-square-o cp-app-drive-icon-expcol"});
|
||||||
|
var $expandIcon = $('<span>', {"class": "fa fa-plus-square-o cp-app-drive-icon-expcol"});
|
||||||
|
var $emptyTrashIcon = $('<button>', {"class": "fa fa-ban"});
|
||||||
|
var $listIcon = $('<button>', {"class": "fa fa-list"});
|
||||||
|
var $gridIcon = $('<button>', {"class": "fa fa-th-large"});
|
||||||
|
var $sortAscIcon = $('<span>', {"class": "fa fa-angle-up sortasc"});
|
||||||
|
var $sortDescIcon = $('<span>', {"class": "fa fa-angle-down sortdesc"});
|
||||||
|
var $closeIcon = $('<span>', {"class": "fa fa-window-close"});
|
||||||
|
//var $backupIcon = $('<span>', {"class": "fa fa-life-ring"});
|
||||||
|
var $searchIcon = $('<span>', {"class": "fa fa-search cp-app-drive-tree-search-con"});
|
||||||
|
var $addIcon = $('<span>', {"class": "fa fa-plus"});
|
||||||
|
var $renamedIcon = $('<span>', {"class": "fa fa-flag"});
|
||||||
|
var $readonlyIcon = $('<span>', {"class": "fa " + faReadOnly});
|
||||||
|
var $ownedIcon = $('<span>', {"class": "fa fa-id-card-o"});
|
||||||
|
var $ownerIcon = $('<span>', {"class": "fa fa-id-card"});
|
||||||
|
var $tagsIcon = $('<span>', {"class": "fa " + faTags});
|
||||||
|
|
||||||
var LS_LAST = "app-drive-lastOpened";
|
var LS_LAST = "app-drive-lastOpened";
|
||||||
var LS_OPENED = "app-drive-openedFolders";
|
var LS_OPENED = "app-drive-openedFolders";
|
||||||
@@ -157,48 +202,6 @@ define([
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Icons
|
|
||||||
var faFolder = 'fa-folder';
|
|
||||||
var faFolderOpen = 'fa-folder-open';
|
|
||||||
var faReadOnly = 'fa-eye';
|
|
||||||
var faRename = 'fa-pencil';
|
|
||||||
var faTrash = 'fa-trash';
|
|
||||||
var faDelete = 'fa-eraser';
|
|
||||||
var faProperties = 'fa-database';
|
|
||||||
var faTags = 'fa-hashtag';
|
|
||||||
var faEmpty = 'fa-trash-o';
|
|
||||||
var faRestore = 'fa-repeat';
|
|
||||||
var faShowParent = 'fa-location-arrow';
|
|
||||||
var $folderIcon = $('<span>', {
|
|
||||||
"class": faFolder + " fa cp-app-drive-icon-folder cp-app-drive-content-icon"
|
|
||||||
});
|
|
||||||
//var $folderIcon = $('<img>', {src: "/customize/images/icons/folder.svg", "class": "folder icon"});
|
|
||||||
var $folderEmptyIcon = $folderIcon.clone();
|
|
||||||
var $folderOpenedIcon = $('<span>', {"class": faFolderOpen + " fa cp-app-drive-icon-folder"});
|
|
||||||
//var $folderOpenedIcon = $('<img>', {src: "/customize/images/icons/folderOpen.svg", "class": "folder icon"});
|
|
||||||
var $folderOpenedEmptyIcon = $folderOpenedIcon.clone();
|
|
||||||
//var $upIcon = $('<span>', {"class": "fa fa-arrow-circle-up"});
|
|
||||||
var $unsortedIcon = $('<span>', {"class": "fa fa-files-o"});
|
|
||||||
var $templateIcon = $('<span>', {"class": "fa fa-cubes"});
|
|
||||||
var $recentIcon = $('<span>', {"class": "fa fa-clock-o"});
|
|
||||||
var $trashIcon = $('<span>', {"class": "fa " + faTrash});
|
|
||||||
var $trashEmptyIcon = $('<span>', {"class": "fa fa-trash-o"});
|
|
||||||
//var $collapseIcon = $('<span>', {"class": "fa fa-minus-square-o cp-app-drive-icon-expcol"});
|
|
||||||
var $expandIcon = $('<span>', {"class": "fa fa-plus-square-o cp-app-drive-icon-expcol"});
|
|
||||||
var $emptyTrashIcon = $('<button>', {"class": "fa fa-ban"});
|
|
||||||
var $listIcon = $('<button>', {"class": "fa fa-list"});
|
|
||||||
var $gridIcon = $('<button>', {"class": "fa fa-th-large"});
|
|
||||||
var $sortAscIcon = $('<span>', {"class": "fa fa-angle-up sortasc"});
|
|
||||||
var $sortDescIcon = $('<span>', {"class": "fa fa-angle-down sortdesc"});
|
|
||||||
var $closeIcon = $('<span>', {"class": "fa fa-window-close"});
|
|
||||||
//var $backupIcon = $('<span>', {"class": "fa fa-life-ring"});
|
|
||||||
var $searchIcon = $('<span>', {"class": "fa fa-search cp-app-drive-tree-search-con"});
|
|
||||||
var $addIcon = $('<span>', {"class": "fa fa-plus"});
|
|
||||||
var $renamedIcon = $('<span>', {"class": "fa fa-flag"});
|
|
||||||
var $readonlyIcon = $('<span>', {"class": "fa " + faReadOnly});
|
|
||||||
var $ownedIcon = $('<span>', {"class": "fa fa-id-card-o"});
|
|
||||||
var $ownerIcon = $('<span>', {"class": "fa fa-id-card"});
|
|
||||||
|
|
||||||
var history = {
|
var history = {
|
||||||
isHistoryMode: false,
|
isHistoryMode: false,
|
||||||
};
|
};
|
||||||
@@ -360,17 +363,24 @@ define([
|
|||||||
// Categories dislayed in the menu
|
// Categories dislayed in the menu
|
||||||
// _WORKGROUP_ : do not display unsorted
|
// _WORKGROUP_ : do not display unsorted
|
||||||
var displayedCategories = [ROOT, TRASH, SEARCH, RECENT];
|
var displayedCategories = [ROOT, TRASH, SEARCH, RECENT];
|
||||||
|
|
||||||
|
// PCS enabled: display owned pads
|
||||||
if (AppConfig.displayCreationScreen) { displayedCategories.push(OWNED); }
|
if (AppConfig.displayCreationScreen) { displayedCategories.push(OWNED); }
|
||||||
|
// Templates enabled: display template category
|
||||||
if (AppConfig.enableTemplates) { displayedCategories.push(TEMPLATE); }
|
if (AppConfig.enableTemplates) { displayedCategories.push(TEMPLATE); }
|
||||||
|
// Tags used: display Tags category
|
||||||
|
if (Object.keys(filesOp.getTagsList()).length) { displayedCategories.push(TAGS); }
|
||||||
|
|
||||||
if (isWorkgroup()) { displayedCategories = [ROOT, TRASH, SEARCH]; }
|
if (isWorkgroup()) { displayedCategories = [ROOT, TRASH, SEARCH]; }
|
||||||
var virtualCategories = [SEARCH, RECENT, OWNED];
|
var virtualCategories = [SEARCH, RECENT, OWNED, TAGS];
|
||||||
|
|
||||||
if (!APP.loggedIn) {
|
if (!APP.loggedIn) {
|
||||||
displayedCategories = [FILES_DATA];
|
displayedCategories = [FILES_DATA];
|
||||||
currentPath = [FILES_DATA];
|
currentPath = [FILES_DATA];
|
||||||
$tree.hide();
|
$tree.hide();
|
||||||
if (Object.keys(files.root).length && !proxy.anonymousAlert) {
|
if (Object.keys(files.root).length && !proxy.anonymousAlert) {
|
||||||
UI.alert(Messages.fm_alert_anonymous, null, true);
|
var msg = common.fixLinks($('<div>').html(Messages.fm_alert_anonymous));
|
||||||
|
UI.alert(msg);
|
||||||
proxy.anonymousAlert = true;
|
proxy.anonymousAlert = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1295,7 +1305,7 @@ define([
|
|||||||
$span.attr('title', name);
|
$span.attr('title', name);
|
||||||
|
|
||||||
var type = Messages.type[hrefData.type] || hrefData.type;
|
var type = Messages.type[hrefData.type] || hrefData.type;
|
||||||
common.displayThumbnail(data.href, $span, function ($thumb) {
|
common.displayThumbnail(data.href, data.channel, $span, function ($thumb) {
|
||||||
// Called only if the thumbnail exists
|
// Called only if the thumbnail exists
|
||||||
// Remove the .hide() added by displayThumnail() because it hides the icon in
|
// Remove the .hide() added by displayThumnail() because it hides the icon in
|
||||||
// list mode too
|
// list mode too
|
||||||
@@ -1443,6 +1453,7 @@ define([
|
|||||||
case SEARCH: pName = SEARCH_NAME; break;
|
case SEARCH: pName = SEARCH_NAME; break;
|
||||||
case RECENT: pName = RECENT_NAME; break;
|
case RECENT: pName = RECENT_NAME; break;
|
||||||
case OWNED: pName = OWNED_NAME; break;
|
case OWNED: pName = OWNED_NAME; break;
|
||||||
|
case TAGS: pName = TAGS_NAME; break;
|
||||||
default: pName = name;
|
default: pName = name;
|
||||||
}
|
}
|
||||||
return pName;
|
return pName;
|
||||||
@@ -1511,18 +1522,14 @@ define([
|
|||||||
case OWNED:
|
case OWNED:
|
||||||
msg = Messages.fm_info_owned;
|
msg = Messages.fm_info_owned;
|
||||||
break;
|
break;
|
||||||
|
case TAGS:
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
msg = undefined;
|
msg = undefined;
|
||||||
}
|
}
|
||||||
if (!APP.loggedIn) {
|
if (!APP.loggedIn) {
|
||||||
msg = Messages.fm_info_anonymous;
|
msg = Messages.fm_info_anonymous;
|
||||||
$box.html(msg);
|
return $(common.fixLinks($box.html(msg)));
|
||||||
$box.find('a[target!="_blank"]').click(function (e) {
|
|
||||||
e.preventDefault();
|
|
||||||
var href = $(this).attr('href');
|
|
||||||
common.gotoURL(href);
|
|
||||||
});
|
|
||||||
return $box;
|
|
||||||
}
|
}
|
||||||
if (!msg || APP.store['hide-info-' + path[0]] === '1') {
|
if (!msg || APP.store['hide-info-' + path[0]] === '1') {
|
||||||
$box.hide();
|
$box.hide();
|
||||||
@@ -2057,6 +2064,7 @@ define([
|
|||||||
$element.data('context', 'default');
|
$element.data('context', 'default');
|
||||||
$container.append($element);
|
$container.append($element);
|
||||||
});
|
});
|
||||||
|
createGhostIcon($container);
|
||||||
};
|
};
|
||||||
|
|
||||||
var displayTrashRoot = function ($list, $folderHeader, $fileHeader) {
|
var displayTrashRoot = function ($list, $folderHeader, $fileHeader) {
|
||||||
@@ -2100,7 +2108,7 @@ define([
|
|||||||
var parsed = Hash.parsePadUrl(href);
|
var parsed = Hash.parsePadUrl(href);
|
||||||
var $table = $('<table>');
|
var $table = $('<table>');
|
||||||
var $icon = $('<td>', {'rowspan': '3', 'class': 'cp-app-drive-search-icon'})
|
var $icon = $('<td>', {'rowspan': '3', 'class': 'cp-app-drive-search-icon'})
|
||||||
.append(getFileIcon(href));
|
.append(getFileIcon(r.id));
|
||||||
var $title = $('<td>', {
|
var $title = $('<td>', {
|
||||||
'class': 'cp-app-drive-search-col1 cp-app-drive-search-title'
|
'class': 'cp-app-drive-search-col1 cp-app-drive-search-title'
|
||||||
}).text(r.data.title)
|
}).text(r.data.title)
|
||||||
@@ -2140,6 +2148,13 @@ define([
|
|||||||
}
|
}
|
||||||
var $openDir = $('<td>', {'class': 'cp-app-drive-search-opendir'}).append($a);
|
var $openDir = $('<td>', {'class': 'cp-app-drive-search-opendir'}).append($a);
|
||||||
|
|
||||||
|
$('<a>').text(Messages.fc_prop).click(function () {
|
||||||
|
APP.getProperties(r.id, function (e, $prop) {
|
||||||
|
if (e) { return void logError(e); }
|
||||||
|
UI.alert($prop[0], undefined, true);
|
||||||
|
});
|
||||||
|
}).appendTo($openDir);
|
||||||
|
|
||||||
// rows 1-3
|
// rows 1-3
|
||||||
$('<tr>').append($icon).append($title).append($typeName).append($type).appendTo($table);
|
$('<tr>').append($icon).append($title).append($typeName).append($type).appendTo($table);
|
||||||
$('<tr>').append($path).append($atimeName).append($atime).appendTo($table);
|
$('<tr>').append($path).append($atimeName).append($atime).appendTo($table);
|
||||||
@@ -2230,6 +2245,35 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Tags category
|
||||||
|
var displayTags = function ($container) {
|
||||||
|
var list = filesOp.getTagsList();
|
||||||
|
if (Object.keys(list).length === 0) { return; }
|
||||||
|
var sortedTags = Object.keys(list);
|
||||||
|
sortedTags.sort(function (a, b) {
|
||||||
|
return list[b] - list[a];
|
||||||
|
});
|
||||||
|
var lines = [
|
||||||
|
h('tr', [
|
||||||
|
h('th', Messages.fm_tags_name),
|
||||||
|
h('th', Messages.fm_tags_used)
|
||||||
|
])
|
||||||
|
];
|
||||||
|
sortedTags.forEach(function (tag) {
|
||||||
|
var tagLink = h('a', { href: '#' }, '#' + tag);
|
||||||
|
$(tagLink).click(function () {
|
||||||
|
if (displayedCategories.indexOf(SEARCH) !== -1) {
|
||||||
|
APP.Search.$input.val('#' + tag).keyup();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
lines.push(h('tr', [
|
||||||
|
h('td', tagLink),
|
||||||
|
h('td.cp-app-drive-tags-used', list[tag])
|
||||||
|
]));
|
||||||
|
});
|
||||||
|
$(h('li.cp-app-drive-tags-list', h('table', lines))).appendTo($container);
|
||||||
|
};
|
||||||
|
|
||||||
// Display the selected directory into the content part (rightside)
|
// Display the selected directory into the content part (rightside)
|
||||||
// NOTE: Elements in the trash are not using the same storage structure as the others
|
// NOTE: Elements in the trash are not using the same storage structure as the others
|
||||||
// _WORKGROUP_ : do not change the lastOpenedFolder value in localStorage
|
// _WORKGROUP_ : do not change the lastOpenedFolder value in localStorage
|
||||||
@@ -2259,10 +2303,9 @@ define([
|
|||||||
var isTrashRoot = filesOp.comparePath(path, [TRASH]);
|
var isTrashRoot = filesOp.comparePath(path, [TRASH]);
|
||||||
var isTemplate = filesOp.comparePath(path, [TEMPLATE]);
|
var isTemplate = filesOp.comparePath(path, [TEMPLATE]);
|
||||||
var isAllFiles = filesOp.comparePath(path, [FILES_DATA]);
|
var isAllFiles = filesOp.comparePath(path, [FILES_DATA]);
|
||||||
var isSearch = path[0] === SEARCH;
|
|
||||||
var isRecent = path[0] === RECENT;
|
|
||||||
var isOwned = path[0] === OWNED;
|
|
||||||
var isVirtual = virtualCategories.indexOf(path[0]) !== -1;
|
var isVirtual = virtualCategories.indexOf(path[0]) !== -1;
|
||||||
|
var isSearch = path[0] === SEARCH;
|
||||||
|
var isTags = path[0] === TAGS;
|
||||||
|
|
||||||
var root = isVirtual ? undefined : filesOp.find(path);
|
var root = isVirtual ? undefined : filesOp.find(path);
|
||||||
if (!isVirtual && typeof(root) === "undefined") {
|
if (!isVirtual && typeof(root) === "undefined") {
|
||||||
@@ -2296,7 +2339,7 @@ define([
|
|||||||
|
|
||||||
var $dirContent = $('<div>', {id: FOLDER_CONTENT_ID});
|
var $dirContent = $('<div>', {id: FOLDER_CONTENT_ID});
|
||||||
$dirContent.data('path', path);
|
$dirContent.data('path', path);
|
||||||
if (!isSearch) {
|
if (!isSearch && !isTags) {
|
||||||
var mode = getViewMode();
|
var mode = getViewMode();
|
||||||
if (mode) {
|
if (mode) {
|
||||||
$dirContent.addClass(getViewModeClass());
|
$dirContent.addClass(getViewModeClass());
|
||||||
@@ -2358,10 +2401,12 @@ define([
|
|||||||
displayTrashRoot($list, $folderHeader, $fileHeader);
|
displayTrashRoot($list, $folderHeader, $fileHeader);
|
||||||
} else if (isSearch) {
|
} else if (isSearch) {
|
||||||
displaySearch($list, path[1]);
|
displaySearch($list, path[1]);
|
||||||
} else if (isRecent) {
|
} else if (path[0] === RECENT) {
|
||||||
displayRecent($list);
|
displayRecent($list);
|
||||||
} else if (isOwned) {
|
} else if (path[0] === OWNED) {
|
||||||
displayOwned($list);
|
displayOwned($list);
|
||||||
|
} else if (isTags) {
|
||||||
|
displayTags($list);
|
||||||
} else {
|
} else {
|
||||||
$dirContent.contextmenu(openContextMenu('content'));
|
$dirContent.contextmenu(openContextMenu('content'));
|
||||||
if (filesOp.hasSubfolder(root)) { $list.append($folderHeader); }
|
if (filesOp.hasSubfolder(root)) { $list.append($folderHeader); }
|
||||||
@@ -2503,25 +2548,6 @@ define([
|
|||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var createTemplate = function ($container, path) {
|
|
||||||
var $icon = $templateIcon.clone();
|
|
||||||
var isOpened = filesOp.comparePath(path, currentPath);
|
|
||||||
var $element = createTreeElement(TEMPLATE_NAME, $icon, [TEMPLATE], false, true, false, isOpened);
|
|
||||||
$element.addClass('cp-app-drive-tree-root');
|
|
||||||
var $list = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($element);
|
|
||||||
$container.append($list);
|
|
||||||
};
|
|
||||||
|
|
||||||
var createAllFiles = function ($container, path) {
|
|
||||||
var $icon = $unsortedIcon.clone();
|
|
||||||
var isOpened = filesOp.comparePath(path, currentPath);
|
|
||||||
var $allfilesElement = createTreeElement(FILES_DATA_NAME, $icon, [FILES_DATA], false, false, false, isOpened);
|
|
||||||
$allfilesElement.addClass('root');
|
|
||||||
var $allfilesList = $('<ul>', { 'class': 'cp-app-drive-tree-category' })
|
|
||||||
.append($allfilesElement);
|
|
||||||
$container.append($allfilesList);
|
|
||||||
};
|
|
||||||
|
|
||||||
var createTrash = function ($container, path) {
|
var createTrash = function ($container, path) {
|
||||||
var $icon = filesOp.isFolderEmpty(files[TRASH]) ? $trashEmptyIcon.clone() : $trashIcon.clone();
|
var $icon = filesOp.isFolderEmpty(files[TRASH]) ? $trashEmptyIcon.clone() : $trashIcon.clone();
|
||||||
var isOpened = filesOp.comparePath(path, currentPath);
|
var isOpened = filesOp.comparePath(path, currentPath);
|
||||||
@@ -2534,29 +2560,11 @@ define([
|
|||||||
$container.append($trashList);
|
$container.append($trashList);
|
||||||
};
|
};
|
||||||
|
|
||||||
var createRecent = function ($container, path) {
|
|
||||||
var $icon = $recentIcon.clone();
|
|
||||||
var isOpened = filesOp.comparePath(path, currentPath);
|
|
||||||
var $element = createTreeElement(RECENT_NAME, $icon, [RECENT], false, false, false, isOpened);
|
|
||||||
$element.addClass('root');
|
|
||||||
var $list = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($element);
|
|
||||||
$container.append($list);
|
|
||||||
};
|
|
||||||
|
|
||||||
var createOwned = function ($container, path) {
|
|
||||||
var $icon = $ownedIcon.clone(); // TODO
|
|
||||||
var isOpened = filesOp.comparePath(path, currentPath);
|
|
||||||
var $element = createTreeElement(OWNED_NAME, $icon, [OWNED], false, false, false, isOpened);
|
|
||||||
$element.addClass('root');
|
|
||||||
var $list = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($element);
|
|
||||||
$container.append($list);
|
|
||||||
};
|
|
||||||
|
|
||||||
var search = APP.Search = {};
|
var search = APP.Search = {};
|
||||||
var createSearch = function ($container) {
|
var createSearch = function ($container) {
|
||||||
var isInSearch = currentPath[0] === SEARCH;
|
var isInSearch = currentPath[0] === SEARCH;
|
||||||
var $div = $('<div>', {'id': 'cp-app-drive-tree-search', 'class': 'cp-unselectable'});
|
var $div = $('<div>', {'id': 'cp-app-drive-tree-search', 'class': 'cp-unselectable'});
|
||||||
var $input = $('<input>', {
|
var $input = APP.Search.$input = $('<input>', {
|
||||||
id: 'cp-app-drive-tree-search-input',
|
id: 'cp-app-drive-tree-search-input',
|
||||||
type: 'text',
|
type: 'text',
|
||||||
draggable: false,
|
draggable: false,
|
||||||
@@ -2606,6 +2614,38 @@ define([
|
|||||||
$container.append($div);
|
$container.append($div);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var categories = {};
|
||||||
|
categories[FILES_DATA] = {
|
||||||
|
name: FILES_DATA_NAME,
|
||||||
|
$icon: $unsortedIcon
|
||||||
|
};
|
||||||
|
categories[TEMPLATE] = {
|
||||||
|
name: TEMPLATE_NAME,
|
||||||
|
droppable: true,
|
||||||
|
$icon: $templateIcon
|
||||||
|
};
|
||||||
|
categories[RECENT] = {
|
||||||
|
name: RECENT_NAME,
|
||||||
|
$icon: $recentIcon
|
||||||
|
};
|
||||||
|
categories[OWNED] = {
|
||||||
|
name: OWNED_NAME,
|
||||||
|
$icon: $ownedIcon
|
||||||
|
};
|
||||||
|
categories[TAGS] = {
|
||||||
|
name: TAGS_NAME,
|
||||||
|
$icon: $tagsIcon
|
||||||
|
};
|
||||||
|
var createCategory = function ($container, cat) {
|
||||||
|
var options = categories[cat];
|
||||||
|
var $icon = options.$icon.clone();
|
||||||
|
var isOpened = filesOp.comparePath([cat], currentPath);
|
||||||
|
var $element = createTreeElement(options.name, $icon, [cat], options.draggable, options.droppable, false, isOpened);
|
||||||
|
$element.addClass('cp-app-drive-tree-root');
|
||||||
|
var $list = $('<ul>', { 'class': 'cp-app-drive-tree-category' }).append($element);
|
||||||
|
$container.append($list);
|
||||||
|
};
|
||||||
|
|
||||||
APP.resetTree = function () {
|
APP.resetTree = function () {
|
||||||
var $categories = $tree.find('.cp-app-drive-tree-categories-container');
|
var $categories = $tree.find('.cp-app-drive-tree-categories-container');
|
||||||
var s = $categories.scrollTop() || 0;
|
var s = $categories.scrollTop() || 0;
|
||||||
@@ -2614,11 +2654,12 @@ define([
|
|||||||
if (displayedCategories.indexOf(SEARCH) !== -1) { createSearch($tree); }
|
if (displayedCategories.indexOf(SEARCH) !== -1) { createSearch($tree); }
|
||||||
var $div = $('<div>', {'class': 'cp-app-drive-tree-categories-container'})
|
var $div = $('<div>', {'class': 'cp-app-drive-tree-categories-container'})
|
||||||
.appendTo($tree);
|
.appendTo($tree);
|
||||||
if (displayedCategories.indexOf(RECENT) !== -1) { createRecent($div, [RECENT]); }
|
if (displayedCategories.indexOf(TAGS) !== -1) { createCategory($div, TAGS); }
|
||||||
if (displayedCategories.indexOf(OWNED) !== -1) { createOwned($div, [OWNED]); }
|
if (displayedCategories.indexOf(RECENT) !== -1) { createCategory($div, RECENT); }
|
||||||
|
if (displayedCategories.indexOf(OWNED) !== -1) { createCategory($div, OWNED); }
|
||||||
if (displayedCategories.indexOf(ROOT) !== -1) { createTree($div, [ROOT]); }
|
if (displayedCategories.indexOf(ROOT) !== -1) { createTree($div, [ROOT]); }
|
||||||
if (displayedCategories.indexOf(TEMPLATE) !== -1) { createTemplate($div, [TEMPLATE]); }
|
if (displayedCategories.indexOf(TEMPLATE) !== -1) { createCategory($div, TEMPLATE); }
|
||||||
if (displayedCategories.indexOf(FILES_DATA) !== -1) { createAllFiles($div, [FILES_DATA]); }
|
if (displayedCategories.indexOf(FILES_DATA) !== -1) { createCategory($div, FILES_DATA); }
|
||||||
if (displayedCategories.indexOf(TRASH) !== -1) { createTrash($div, [TRASH]); }
|
if (displayedCategories.indexOf(TRASH) !== -1) { createTrash($div, [TRASH]); }
|
||||||
|
|
||||||
$tree.append(APP.$limit);
|
$tree.append(APP.$limit);
|
||||||
@@ -2657,9 +2698,9 @@ define([
|
|||||||
if (parsed.hashData.type !== "pad") { return; }
|
if (parsed.hashData.type !== "pad") { return; }
|
||||||
var i = data.href.indexOf('#') + 1;
|
var i = data.href.indexOf('#') + 1;
|
||||||
var base = data.href.slice(0, i);
|
var base = data.href.slice(0, i);
|
||||||
var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash);
|
var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
||||||
if (!hrefsecret.keys) { return; }
|
if (!hrefsecret.keys) { return; }
|
||||||
var viewHash = Hash.getViewHashFromKeys(hrefsecret.channel, hrefsecret.keys);
|
var viewHash = Hash.getViewHashFromKeys(hrefsecret);
|
||||||
return base + viewHash;
|
return base + viewHash;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -2672,7 +2713,7 @@ define([
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
var getProperties = function (el, cb) {
|
var getProperties = APP.getProperties = function (el, cb) {
|
||||||
if (!filesOp.isFile(el)) {
|
if (!filesOp.isFile(el)) {
|
||||||
return void cb('NOT_FILE');
|
return void cb('NOT_FILE');
|
||||||
}
|
}
|
||||||
@@ -2724,24 +2765,6 @@ define([
|
|||||||
$(window).focus();
|
$(window).focus();
|
||||||
if (!res) { return; }
|
if (!res) { return; }
|
||||||
filesOp.delete(pathsList, refresh);
|
filesOp.delete(pathsList, refresh);
|
||||||
/*
|
|
||||||
// Try to delete each selected pad from server, and delete from drive if no error
|
|
||||||
var n = nThen(function () {});
|
|
||||||
pathsList.forEach(function (p) {
|
|
||||||
var el = filesOp.find(p);
|
|
||||||
var data = filesOp.getFileData(el);
|
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
|
||||||
var channel = Util.base64ToHex(parsed.hashData.channel);
|
|
||||||
n = n.nThen(function (waitFor) {
|
|
||||||
sframeChan.query('Q_REMOVE_OWNED_CHANNEL', channel,
|
|
||||||
waitFor(function (e) {
|
|
||||||
if (e) { return void console.error(e); }
|
|
||||||
filesOp.delete([p], function () {}, false, true);
|
|
||||||
}));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
n.nThen(function () { refresh(); });
|
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
$contextMenu.on("click", "a", function(e) {
|
$contextMenu.on("click", "a", function(e) {
|
||||||
|
|||||||
@@ -39,6 +39,7 @@ define([
|
|||||||
var getSecrets = function (Cryptpad, Utils, cb) {
|
var getSecrets = function (Cryptpad, Utils, cb) {
|
||||||
var hash = window.location.hash.slice(1) || Utils.LocalStore.getUserHash() ||
|
var hash = window.location.hash.slice(1) || Utils.LocalStore.getUserHash() ||
|
||||||
Utils.LocalStore.getFSHash();
|
Utils.LocalStore.getFSHash();
|
||||||
|
// No password for drive
|
||||||
cb(null, Utils.Hash.getSecrets('drive', hash));
|
cb(null, Utils.Hash.getSecrets('drive', hash));
|
||||||
};
|
};
|
||||||
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
var addRpc = function (sframeChan, Cryptpad, Utils) {
|
||||||
|
|||||||
@@ -1,26 +1,17 @@
|
|||||||
@import (once) "../../customize/src/less2/include/browser.less";
|
@import (once) "../../customize/src/less2/include/browser.less";
|
||||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
|
||||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/tokenfield.less';
|
@import (once) '../../customize/src/less2/include/tokenfield.less';
|
||||||
|
@import (once) '../../customize/src/less2/include/framework.less';
|
||||||
|
|
||||||
.toolbar_main(
|
.framework_min_main(
|
||||||
@bg-color: @colortheme_file-bg,
|
@bg-color: @colortheme_file-bg,
|
||||||
@warn-color: @colortheme_file-warn,
|
@warn-color: @colortheme_file-warn,
|
||||||
@color: @colortheme_file-color
|
@color: @colortheme_file-color
|
||||||
);
|
);
|
||||||
.fileupload_main();
|
|
||||||
.alertify_main();
|
|
||||||
.tokenfield_main();
|
.tokenfield_main();
|
||||||
|
|
||||||
@button-border: 2px;
|
@button-border: 2px;
|
||||||
|
|
||||||
/*html, body {
|
|
||||||
margin: 0px;
|
|
||||||
height: 100%;
|
|
||||||
}*/
|
|
||||||
|
|
||||||
// body
|
// body
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: column;
|
flex-flow: column;
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ define([
|
|||||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||||
], function () {
|
], function () {
|
||||||
var Nacl = window.nacl;
|
var Nacl = window.nacl;
|
||||||
var PARANOIA = true;
|
//var PARANOIA = true;
|
||||||
|
|
||||||
var plainChunkLength = 128 * 1024;
|
var plainChunkLength = 128 * 1024;
|
||||||
var cypherChunkLength = 131088;
|
var cypherChunkLength = 131088;
|
||||||
@@ -36,24 +36,11 @@ define([
|
|||||||
var increment = function (N) {
|
var increment = function (N) {
|
||||||
var l = N.length;
|
var l = N.length;
|
||||||
while (l-- > 1) {
|
while (l-- > 1) {
|
||||||
if (PARANOIA) {
|
|
||||||
if (typeof(N[l]) !== 'number') {
|
|
||||||
throw new Error('E_UNSAFE_TYPE');
|
|
||||||
}
|
|
||||||
if (N[l] > 255) {
|
|
||||||
throw new Error('E_OUT_OF_BOUNDS');
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* jshint probably suspects this is unsafe because we lack types
|
/* jshint probably suspects this is unsafe because we lack types
|
||||||
but as long as this is only used on nonces, it should be safe */
|
but as long as this is only used on nonces, it should be safe */
|
||||||
if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line
|
if (N[l] !== 255) { return void N[l]++; } // jshint ignore:line
|
||||||
|
if (l === 0) { throw new Error('E_NONCE_TOO_LARGE'); }
|
||||||
N[l] = 0;
|
N[l] = 0;
|
||||||
|
|
||||||
// you don't need to worry about this running out.
|
|
||||||
// you'd need a REAAAALLY big file
|
|
||||||
if (l === 0) {
|
|
||||||
throw new Error('E_NONCE_TOO_LARGE');
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -160,19 +147,21 @@ define([
|
|||||||
}
|
}
|
||||||
|
|
||||||
var takeChunk = function (cb) {
|
var takeChunk = function (cb) {
|
||||||
var start = i * cypherChunkLength + 2 + metadataLength;
|
setTimeout(function () {
|
||||||
var end = start + cypherChunkLength;
|
var start = i * cypherChunkLength + 2 + metadataLength;
|
||||||
i++;
|
var end = start + cypherChunkLength;
|
||||||
var box = new Uint8Array(u8.subarray(start, end));
|
i++;
|
||||||
|
var box = new Uint8Array(u8.subarray(start, end));
|
||||||
|
|
||||||
// decrypt the chunk
|
// decrypt the chunk
|
||||||
var plaintext = Nacl.secretbox.open(box, nonce, key);
|
var plaintext = Nacl.secretbox.open(box, nonce, key);
|
||||||
increment(nonce);
|
increment(nonce);
|
||||||
|
|
||||||
if (!plaintext) { return cb('DECRYPTION_ERROR'); }
|
if (!plaintext) { return cb('DECRYPTION_ERROR'); }
|
||||||
|
|
||||||
_progress(end);
|
_progress(end);
|
||||||
cb(void 0, plaintext);
|
cb(void 0, plaintext);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
var chunks = [];
|
var chunks = [];
|
||||||
@@ -219,7 +208,7 @@ define([
|
|||||||
|
|
||||||
var state = 0;
|
var state = 0;
|
||||||
var next = function (cb) {
|
var next = function (cb) {
|
||||||
if (state === 2) { return void cb(); }
|
if (state === 2) { return void setTimeout(cb); }
|
||||||
|
|
||||||
var start;
|
var start;
|
||||||
var end;
|
var end;
|
||||||
@@ -238,7 +227,9 @@ define([
|
|||||||
.concat(slice(box)));
|
.concat(slice(box)));
|
||||||
state++;
|
state++;
|
||||||
|
|
||||||
return void cb(void 0, prefixed);
|
return void setTimeout(function () {
|
||||||
|
cb(void 0, prefixed);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// encrypt the rest of the file...
|
// encrypt the rest of the file...
|
||||||
@@ -253,7 +244,9 @@ define([
|
|||||||
// regular data is done
|
// regular data is done
|
||||||
if (i * plainChunkLength >= u8.length) { state = 2; }
|
if (i * plainChunkLength >= u8.length) { state = 2; }
|
||||||
|
|
||||||
return void cb(void 0, box);
|
setTimeout(function () {
|
||||||
|
cb(void 0, box);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
return next;
|
return next;
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ define([
|
|||||||
'/bower_components/file-saver/FileSaver.min.js',
|
'/bower_components/file-saver/FileSaver.min.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
|
|
||||||
], function (
|
], function (
|
||||||
@@ -61,6 +61,7 @@ define([
|
|||||||
if (!priv.filehash) {
|
if (!priv.filehash) {
|
||||||
uploadMode = true;
|
uploadMode = true;
|
||||||
} else {
|
} else {
|
||||||
|
// PASSWORD_FILES
|
||||||
secret = Hash.getSecrets('file', priv.filehash);
|
secret = Hash.getSecrets('file', priv.filehash);
|
||||||
if (!secret.keys) { throw new Error("You need a hash"); }
|
if (!secret.keys) { throw new Error("You need a hash"); }
|
||||||
hexFileName = Util.base64ToHex(secret.channel);
|
hexFileName = Util.base64ToHex(secret.channel);
|
||||||
@@ -124,6 +125,12 @@ define([
|
|||||||
|
|
||||||
var rightsideDisplayed = false;
|
var rightsideDisplayed = false;
|
||||||
$(window.document).on('decryption', function (e) {
|
$(window.document).on('decryption', function (e) {
|
||||||
|
/* FIXME
|
||||||
|
we're listening for decryption events and assuming that only
|
||||||
|
the main media-tag exists. In practice there is also your avatar
|
||||||
|
and there could be other things in the future, so we should
|
||||||
|
figure out a generic way target media-tag decryption events.
|
||||||
|
*/
|
||||||
var decrypted = e.originalEvent;
|
var decrypted = e.originalEvent;
|
||||||
if (decrypted.callback) {
|
if (decrypted.callback) {
|
||||||
decrypted.callback();
|
decrypted.callback();
|
||||||
@@ -133,9 +140,6 @@ define([
|
|||||||
$dlform.hide();
|
$dlform.hide();
|
||||||
var $dlButton = $dlview.find('media-tag button');
|
var $dlButton = $dlview.find('media-tag button');
|
||||||
if (ev) { $dlButton.click(); }
|
if (ev) { $dlButton.click(); }
|
||||||
if (!$dlButton.length) {
|
|
||||||
$appContainer.css('background', 'white');
|
|
||||||
}
|
|
||||||
$dlButton.addClass('btn btn-success');
|
$dlButton.addClass('btn btn-success');
|
||||||
var text = Messages.download_mt_button + '<br>';
|
var text = Messages.download_mt_button + '<br>';
|
||||||
text += '<b>' + Util.fixHTML(title) + '</b><br>';
|
text += '<b>' + Util.fixHTML(title) + '</b><br>';
|
||||||
@@ -230,8 +234,7 @@ define([
|
|||||||
if (typeof(sizeMb) === 'number' && sizeMb < 5) { return void onClick(); }
|
if (typeof(sizeMb) === 'number' && sizeMb < 5) { return void onClick(); }
|
||||||
$dlform.find('#cp-app-file-dlfile, #cp-app-file-dlprogress').click(onClick);
|
$dlform.find('#cp-app-file-dlfile, #cp-app-file-dlprogress').click(onClick);
|
||||||
};
|
};
|
||||||
var href = priv.origin + priv.pathname + priv.filehash;
|
common.getFileSize(hexFileName, function (e, data) {
|
||||||
common.getFileSize(href, function (e, data) {
|
|
||||||
if (e) {
|
if (e) {
|
||||||
return void UI.errorLoadingScreen(e);
|
return void UI.errorLoadingScreen(e);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,10 +3,12 @@
|
|||||||
@import (once) '../../customize/src/less2/include/icon-colors.less';
|
@import (once) '../../customize/src/less2/include/icon-colors.less';
|
||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
@import (once) '../../customize/src/less2/include/fileupload.less';
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
@import (once) '../../customize/src/less2/include/alertify.less';
|
||||||
|
@import (once) '../../customize/src/less2/include/tippy.less';
|
||||||
|
|
||||||
.iconColors_main();
|
.iconColors_main();
|
||||||
.fileupload_main();
|
.fileupload_main();
|
||||||
.alertify_main();
|
.alertify_main();
|
||||||
|
.tippy_main();
|
||||||
|
|
||||||
#cp-filepicker-dialog {
|
#cp-filepicker-dialog {
|
||||||
display: none;
|
display: none;
|
||||||
@@ -36,7 +38,8 @@
|
|||||||
line-height: 1em;
|
line-height: 1em;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
background-color: #111;
|
background-color: @colortheme_modal-bg;
|
||||||
|
box-shadow: 2px 2px 5px #000;
|
||||||
color: @darker;
|
color: @darker;
|
||||||
|
|
||||||
transition: all 0.1s;
|
transition: all 0.1s;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ define([
|
|||||||
'/customize/messages.js',
|
'/customize/messages.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
@@ -40,6 +40,7 @@ define([
|
|||||||
var parsed = Hash.parsePadUrl(data.url);
|
var parsed = Hash.parsePadUrl(data.url);
|
||||||
hideFileDialog();
|
hideFileDialog();
|
||||||
if (parsed.type === 'file') {
|
if (parsed.type === 'file') {
|
||||||
|
// PASSWORD_FILES
|
||||||
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
||||||
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
||||||
sframeChan.event("EV_FILE_PICKED", {
|
sframeChan.event("EV_FILE_PICKED", {
|
||||||
@@ -138,7 +139,7 @@ define([
|
|||||||
});
|
});
|
||||||
|
|
||||||
// Add thumbnail if it exists
|
// Add thumbnail if it exists
|
||||||
common.displayThumbnail(data.href, $span);
|
common.displayThumbnail(data.href, data.channel, $span);
|
||||||
});
|
});
|
||||||
$input.focus();
|
$input.focus();
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ define([
|
|||||||
'/common/outer/local-store.js',
|
'/common/outer/local-store.js',
|
||||||
'/common/test.js',
|
'/common/test.js',
|
||||||
|
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
], function ($, Cryptpad, Login, UI, Realtime, Feedback, LocalStore, Test) {
|
], function ($, Cryptpad, Login, UI, Realtime, Feedback, LocalStore, Test) {
|
||||||
$(function () {
|
$(function () {
|
||||||
var $main = $('#mainBlock');
|
var $main = $('#mainBlock');
|
||||||
|
|||||||
@@ -3,6 +3,43 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
<meta content="text/html; charset=utf-8" http-equiv="content-type"/>
|
||||||
<script async data-bootload="/pad/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
<script async data-bootload="/pad/inner.js" data-main="/common/sframe-boot.js?ver=1.6" src="/bower_components/requirejs/require.js?ver=2.3.5"></script>
|
||||||
|
<style>
|
||||||
|
html, body {
|
||||||
|
margin: 0px;
|
||||||
|
}
|
||||||
|
#cke_1_top {
|
||||||
|
overflow: visible;
|
||||||
|
padding: 0px;
|
||||||
|
display: flex;
|
||||||
|
}
|
||||||
|
#cke_1_toolbox {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
background-color: #c1e7ff;
|
||||||
|
}
|
||||||
|
#cke_1_toolbox .cke_toolbar {
|
||||||
|
height: 28px;
|
||||||
|
padding: 2px 0;
|
||||||
|
}
|
||||||
|
#cke_1_top .cryptpad-toolbar {
|
||||||
|
padding: 0;
|
||||||
|
display: block;
|
||||||
|
}
|
||||||
|
.cke_wysiwyg_frame {
|
||||||
|
min-width: 60%;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
#cke_1_top {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
body.app-pad .userlist-drawer {
|
||||||
|
display:none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="cp-app-pad">
|
<body class="cp-app-pad">
|
||||||
<textarea style="display:none" id="editor1" name="editor1"></textarea>
|
<textarea style="display:none" id="editor1" name="editor1"></textarea>
|
||||||
|
|||||||
133
www/pad/inner.js
133
www/pad/inner.js
@@ -36,7 +36,7 @@ define([
|
|||||||
'/bower_components/diff-dom/diffDOM.js',
|
'/bower_components/diff-dom/diffDOM.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
@@ -82,12 +82,54 @@ define([
|
|||||||
Cursor: Cursor,
|
Cursor: Cursor,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// MEDIATAG: Filter elements to serialize
|
||||||
|
// * Remove the drag&drop and resizers from the hyperjson
|
||||||
|
var isWidget = function (el) {
|
||||||
|
return typeof (el.getAttribute) === "function" &&
|
||||||
|
(el.getAttribute('data-cke-hidden-sel') ||
|
||||||
|
(el.getAttribute('class') &&
|
||||||
|
(/cke_widget_drag/.test(el.getAttribute('class')) ||
|
||||||
|
/cke_image_resizer/.test(el.getAttribute('class')))
|
||||||
|
)
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
var isNotMagicLine = function (el) {
|
var isNotMagicLine = function (el) {
|
||||||
return !(el && typeof(el.getAttribute) === 'function' &&
|
return !(el && typeof(el.getAttribute) === 'function' &&
|
||||||
el.getAttribute('class') &&
|
el.getAttribute('class') &&
|
||||||
el.getAttribute('class').split(' ').indexOf('non-realtime') !== -1);
|
el.getAttribute('class').split(' ').indexOf('non-realtime') !== -1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
var shouldSerialize = function (el) {
|
||||||
|
return isNotMagicLine(el) && !isWidget(el);
|
||||||
|
};
|
||||||
|
|
||||||
|
// MEDIATAG: Filter attributes in the serialized elements
|
||||||
|
var widgetFilter = function (hj) {
|
||||||
|
// Send a widget ID == 0 to avoid a fight between browsers and
|
||||||
|
// prevent the container from having the "selected" class (blue border)
|
||||||
|
if (hj[1].class) {
|
||||||
|
var split = hj[1].class.split(' ');
|
||||||
|
if (split.indexOf('cke_widget_wrapper') !== -1 &&
|
||||||
|
split.indexOf('cke_widget_block') !== -1) {
|
||||||
|
hj[1].class = "cke_widget_wrapper cke_widget_block";
|
||||||
|
hj[1]['data-cke-widget-id'] = "0";
|
||||||
|
}
|
||||||
|
if (split.indexOf('cke_widget_wrapper') !== -1 &&
|
||||||
|
split.indexOf('cke_widget_inline') !== -1) {
|
||||||
|
hj[1].class = "cke_widget_wrapper cke_widget_inline";
|
||||||
|
delete hj[1]['data-cke-widget-id'];
|
||||||
|
//hj[1]['data-cke-widget-id'] = "0";
|
||||||
|
}
|
||||||
|
// Remove the title attribute of the drag&drop icons (translation conflicts)
|
||||||
|
if (split.indexOf('cke_widget_drag_handler') !== -1 ||
|
||||||
|
split.indexOf('cke_image_resizer') !== -1) {
|
||||||
|
hj[1].title = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return hj;
|
||||||
|
};
|
||||||
|
|
||||||
var hjsonFilters = function (hj) {
|
var hjsonFilters = function (hj) {
|
||||||
/* catch `type="_moz"` before it goes over the wire */
|
/* catch `type="_moz"` before it goes over the wire */
|
||||||
var brFilter = function (hj) {
|
var brFilter = function (hj) {
|
||||||
@@ -100,6 +142,7 @@ define([
|
|||||||
};
|
};
|
||||||
brFilter(hj);
|
brFilter(hj);
|
||||||
mediatagContentFilter(hj);
|
mediatagContentFilter(hj);
|
||||||
|
widgetFilter(hj);
|
||||||
return hj;
|
return hj;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -168,6 +211,36 @@ define([
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// MEDIATAG
|
||||||
|
// Never modify widget ids
|
||||||
|
if (info.node && info.node.tagName === 'SPAN' && info.diff.name === 'data-cke-widget-id') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (info.node && info.node.tagName === 'SPAN' &&
|
||||||
|
info.node.getAttribute('class') &&
|
||||||
|
/cke_widget_wrapper/.test(info.node.getAttribute('class'))) {
|
||||||
|
if (info.diff.action === 'modifyAttribute' && info.diff.name === 'class') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
//console.log(info);
|
||||||
|
}
|
||||||
|
// CkEditor drag&drop icon container
|
||||||
|
if (info.node && info.node.tagName === 'SPAN' &&
|
||||||
|
info.node.getAttribute('class') &&
|
||||||
|
info.node.getAttribute('class').split(' ').indexOf('cke_widget_drag_handler_container') !== -1) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// CkEditor drag&drop title (language fight)
|
||||||
|
if (info.node && info.node.getAttribute &&
|
||||||
|
info.node.getAttribute('class') &&
|
||||||
|
(info.node.getAttribute('class').split(' ').indexOf('cke_widget_drag_handler') !== -1 ||
|
||||||
|
info.node.getAttribute('class').split(' ').indexOf('cke_image_resizer') !== -1 ) ) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Also reject any elements which would insert any one of
|
Also reject any elements which would insert any one of
|
||||||
our forbidden tag types: script, iframe, object,
|
our forbidden tag types: script, iframe, object,
|
||||||
@@ -199,20 +272,26 @@ define([
|
|||||||
if (info.node && info.node.tagName === 'SPAN' &&
|
if (info.node && info.node.tagName === 'SPAN' &&
|
||||||
info.node.getAttribute('contentEditable') === "false") {
|
info.node.getAttribute('contentEditable') === "false") {
|
||||||
// it seems to be a magicline plugin element...
|
// it seems to be a magicline plugin element...
|
||||||
|
// but it can also be a widget (MEDIATAG), in which case the removal was
|
||||||
|
// probably intentional
|
||||||
|
|
||||||
if (info.diff.action === 'removeElement') {
|
if (info.diff.action === 'removeElement') {
|
||||||
// and you're about to remove it...
|
// and you're about to remove it...
|
||||||
// this probably isn't what you want
|
if (!info.node.getAttribute('class') ||
|
||||||
|
!/cke_widget_wrapper/.test(info.node.getAttribute('class'))) {
|
||||||
|
// This element is not a widget!
|
||||||
|
// this probably isn't what you want
|
||||||
|
/*
|
||||||
|
I have never seen this in the console, but the
|
||||||
|
magic line is still getting removed on remote
|
||||||
|
edits. This suggests that it's getting removed
|
||||||
|
by something other than diffDom.
|
||||||
|
*/
|
||||||
|
console.log("preventing removal of the magic line!");
|
||||||
|
|
||||||
/*
|
// return true to prevent diff application
|
||||||
I have never seen this in the console, but the
|
return true;
|
||||||
magic line is still getting removed on remote
|
}
|
||||||
edits. This suggests that it's getting removed
|
|
||||||
by something other than diffDom.
|
|
||||||
*/
|
|
||||||
console.log("preventing removal of the magic line!");
|
|
||||||
|
|
||||||
// return true to prevent diff application
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,7 +401,7 @@ define([
|
|||||||
var src = tag.getAttribute('src');
|
var src = tag.getAttribute('src');
|
||||||
if (mediaTagMap[src]) {
|
if (mediaTagMap[src]) {
|
||||||
mediaTagMap[src].forEach(function (n) {
|
mediaTagMap[src].forEach(function (n) {
|
||||||
tag.appendChild(n);
|
tag.appendChild(n.cloneNode());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@@ -370,8 +449,11 @@ define([
|
|||||||
|
|
||||||
framework.setMediaTagEmbedder(function ($mt) {
|
framework.setMediaTagEmbedder(function ($mt) {
|
||||||
$mt.attr('contenteditable', 'false');
|
$mt.attr('contenteditable', 'false');
|
||||||
$mt.attr('tabindex', '1');
|
//$mt.attr('tabindex', '1');
|
||||||
editor.insertElement(new window.CKEDITOR.dom.element($mt[0]));
|
//MEDIATAG
|
||||||
|
var element = new window.CKEDITOR.dom.element($mt[0]);
|
||||||
|
editor.insertElement(element);
|
||||||
|
editor.widgets.initOn( element, 'mediatag' );
|
||||||
});
|
});
|
||||||
|
|
||||||
framework.setTitleRecommender(function () {
|
framework.setTitleRecommender(function () {
|
||||||
@@ -403,7 +485,18 @@ define([
|
|||||||
|
|
||||||
var patch = (DD).diff(inner, userDocStateDom);
|
var patch = (DD).diff(inner, userDocStateDom);
|
||||||
(DD).apply(inner, patch);
|
(DD).apply(inner, patch);
|
||||||
|
|
||||||
|
// MEDIATAG: Migrate old mediatags to the widget system
|
||||||
|
$(inner).find('media-tag:not(.cke_widget_element)').each(function (i, el) {
|
||||||
|
var element = new window.CKEDITOR.dom.element(el);
|
||||||
|
editor.widgets.initOn( element, 'mediatag' );
|
||||||
|
});
|
||||||
|
|
||||||
displayMediaTags(framework, inner, mediaTagMap);
|
displayMediaTags(framework, inner, mediaTagMap);
|
||||||
|
|
||||||
|
// MEDIATAG: Initialize mediatag widgets inserted in the document by other users
|
||||||
|
editor.widgets.checkWidgets();
|
||||||
|
|
||||||
if (framework.isReadOnly()) {
|
if (framework.isReadOnly()) {
|
||||||
var $links = $(inner).find('a');
|
var $links = $(inner).find('a');
|
||||||
// off so that we don't end up with multiple identical handlers
|
// off so that we don't end up with multiple identical handlers
|
||||||
@@ -425,7 +518,7 @@ define([
|
|||||||
framework.setContentGetter(function () {
|
framework.setContentGetter(function () {
|
||||||
displayMediaTags(framework, inner, mediaTagMap);
|
displayMediaTags(framework, inner, mediaTagMap);
|
||||||
inner.normalize();
|
inner.normalize();
|
||||||
return Hyperjson.fromDOM(inner, isNotMagicLine, hjsonFilters);
|
return Hyperjson.fromDOM(inner, shouldSerialize, hjsonFilters);
|
||||||
});
|
});
|
||||||
|
|
||||||
$bar.find('#cke_1_toolbar_collapser').hide();
|
$bar.find('#cke_1_toolbar_collapser').hide();
|
||||||
@@ -459,11 +552,15 @@ define([
|
|||||||
ckeditor: editor,
|
ckeditor: editor,
|
||||||
body: $('body'),
|
body: $('body'),
|
||||||
onUploaded: function (ev, data) {
|
onUploaded: function (ev, data) {
|
||||||
|
// PASSWORD_FILES
|
||||||
var parsed = Hash.parsePadUrl(data.url);
|
var parsed = Hash.parsePadUrl(data.url);
|
||||||
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
var hexFileName = Util.base64ToHex(parsed.hashData.channel);
|
||||||
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
var src = '/blob/' + hexFileName.slice(0,2) + '/' + hexFileName;
|
||||||
var mt = '<media-tag contenteditable="false" src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '" tabindex="1"></media-tag>';
|
var mt = '<media-tag contenteditable="false" src="' + src + '" data-crypto-key="cryptpad:' + parsed.hashData.key + '" tabindex="1"></media-tag>';
|
||||||
editor.insertElement(window.CKEDITOR.dom.element.createFromHtml(mt));
|
// MEDIATAG
|
||||||
|
var element = window.CKEDITOR.dom.element.createFromHtml(mt);
|
||||||
|
editor.insertElement(element);
|
||||||
|
editor.widgets.initOn( element, 'mediatag' );
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
window.APP.FM = framework._.sfCommon.createFileManager(fmConfig);
|
window.APP.FM = framework._.sfCommon.createFileManager(fmConfig);
|
||||||
@@ -508,6 +605,8 @@ define([
|
|||||||
Util.blobToImage($(el).data('blob'), waitFor(function (imgSrc) {
|
Util.blobToImage($(el).data('blob'), waitFor(function (imgSrc) {
|
||||||
$clone.find('media-tag[src="' + $(el).attr('src') + '"] img')
|
$clone.find('media-tag[src="' + $(el).attr('src') + '"] img')
|
||||||
.attr('src', imgSrc);
|
.attr('src', imgSrc);
|
||||||
|
$clone.find('media-tag').parent()
|
||||||
|
.find('.cke_widget_drag_handler_container').remove();
|
||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
}).nThen(function () {
|
}).nThen(function () {
|
||||||
|
|||||||
@@ -23,7 +23,13 @@ CKEDITOR.dialog.add('mediatag', function (editor) {
|
|||||||
},
|
},
|
||||||
],
|
],
|
||||||
onShow: function () {
|
onShow: function () {
|
||||||
var el = editor.plugins.mediatag.clicked;
|
var sel = editor.getSelection();
|
||||||
|
element = sel.getSelectedElement();
|
||||||
|
if (!element) { return; }
|
||||||
|
|
||||||
|
var el = element.findOne('media-tag');
|
||||||
|
if (!el) { return; }
|
||||||
|
|
||||||
var rect = el.getClientRect();
|
var rect = el.getClientRect();
|
||||||
var dialog = this.parts.contents.$;
|
var dialog = this.parts.contents.$;
|
||||||
var inputs = dialog.querySelectorAll('input');
|
var inputs = dialog.querySelectorAll('input');
|
||||||
@@ -34,7 +40,14 @@ CKEDITOR.dialog.add('mediatag', function (editor) {
|
|||||||
},
|
},
|
||||||
onOk: function() {
|
onOk: function() {
|
||||||
var dialog = this;
|
var dialog = this;
|
||||||
var el = editor.plugins.mediatag.clicked;
|
|
||||||
|
var sel = editor.getSelection();
|
||||||
|
element = sel.getSelectedElement();
|
||||||
|
if (!element) { return; }
|
||||||
|
|
||||||
|
var el = element.findOne('media-tag');
|
||||||
|
if (!el) { return; }
|
||||||
|
|
||||||
var dialog = this.parts.contents.$;
|
var dialog = this.parts.contents.$;
|
||||||
var inputs = dialog.querySelectorAll('input');
|
var inputs = dialog.querySelectorAll('input');
|
||||||
var wInput = inputs[0];
|
var wInput = inputs[0];
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
( function() {
|
( function() {
|
||||||
|
|
||||||
CKEDITOR.plugins.add( 'mediatag', {
|
CKEDITOR.plugins.add( 'mediatag', {
|
||||||
requires: 'dialog',
|
requires: 'dialog,widget',
|
||||||
//icons: 'image',
|
//icons: 'image',
|
||||||
//hidpi: true,
|
//hidpi: true,
|
||||||
onLoad: function () {
|
onLoad: function () {
|
||||||
@@ -38,144 +38,17 @@
|
|||||||
// Register the dialog.
|
// Register the dialog.
|
||||||
CKEDITOR.dialog.add( pluginName, this.path + 'mediatag-plugin-dialog.js' );
|
CKEDITOR.dialog.add( pluginName, this.path + 'mediatag-plugin-dialog.js' );
|
||||||
|
|
||||||
var allowed = 'media-tag[!data-crypto-key,!src,contenteditable,width,height]{border-style,border-width,float,height,margin,margin-bottom,margin-left,margin-right,margin-top,width}',
|
editor.widgets.add( 'mediatag', {
|
||||||
required = 'media-tag[data-crypto-key,src]';
|
|
||||||
|
|
||||||
// Register the command.
|
getLabel: function () { return " "; },
|
||||||
editor.addCommand( pluginName, new CKEDITOR.dialogCommand( pluginName, {
|
dialog: pluginName,
|
||||||
allowedContent: allowed,
|
inline: true,
|
||||||
requiredContent: required,
|
upcast: function( element ) {
|
||||||
contentTransformations: [
|
return element.name === 'media-tag';
|
||||||
[ 'media-tag{width}: sizeToStyle', 'media-tag[width]: sizeToAttribute' ],
|
|
||||||
[ 'media-tag{float}: alignmentToStyle', 'media-tag[align]: alignmentToAttribute' ]
|
|
||||||
]
|
|
||||||
} ) );
|
|
||||||
|
|
||||||
var isMediaTag = function (el) {
|
|
||||||
if (el.is('media-tag')) { return el; }
|
|
||||||
var mt = el.getParents().slice().filter(function (p) {
|
|
||||||
return p.is('media-tag');
|
|
||||||
});
|
|
||||||
if (mt.length !== 1) { return; }
|
|
||||||
return mt[0];
|
|
||||||
};
|
|
||||||
editor.on('doubleclick', function (evt) {
|
|
||||||
var element = evt.data.element;
|
|
||||||
var mt = isMediaTag(element);
|
|
||||||
if (mt && !element.data('cke-realelement')) {
|
|
||||||
editor.plugins.mediatag.clicked = mt;
|
|
||||||
evt.data.dialog = 'mediatag';
|
|
||||||
}
|
}
|
||||||
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// If the "contextmenu" plugin is loaded, register the listeners.
|
|
||||||
if (editor.contextMenu) {
|
|
||||||
editor.contextMenu.addListener(function (element) {
|
|
||||||
if (getSelectedMediatag(editor, element)) {
|
|
||||||
return { mediatag: CKEDITOR.TRISTATE_OFF };
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
afterInit: function( editor ) {
|
|
||||||
// Customize the behavior of the alignment commands. (http://dev.ckeditor.com/ticket/7430)
|
|
||||||
setupAlignCommand('left');
|
|
||||||
setupAlignCommand('right');
|
|
||||||
setupAlignCommand('center');
|
|
||||||
setupAlignCommand('block');
|
|
||||||
|
|
||||||
function setupAlignCommand (value) {
|
|
||||||
var command = editor.getCommand('justify' + value);
|
|
||||||
if (command) {
|
|
||||||
if (value === 'left' || value === 'right') {
|
|
||||||
command.on('exec', function (evt) {
|
|
||||||
var img = getSelectedMediatag(editor), align;
|
|
||||||
if (img) {
|
|
||||||
align = getMediatagAlignment(img);
|
|
||||||
if (align === value) {
|
|
||||||
img.removeStyle('float');
|
|
||||||
|
|
||||||
// Remove "align" attribute when necessary.
|
|
||||||
if (value === getMediatagAlignment(img))
|
|
||||||
img.removeAttribute( 'align' );
|
|
||||||
} else {
|
|
||||||
img.setStyle( 'float', value );
|
|
||||||
}
|
|
||||||
|
|
||||||
evt.cancel();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
|
|
||||||
command.on('refresh', function (evt) {
|
|
||||||
var img = getSelectedMediatag(editor), align;
|
|
||||||
if (img) {
|
|
||||||
align = getMediatagAlignment(img);
|
|
||||||
|
|
||||||
this.setState(
|
|
||||||
(align === value) ? CKEDITOR.TRISTATE_ON : ( value === 'right' || value === 'left' ) ? CKEDITOR.TRISTATE_OFF : CKEDITOR.TRISTATE_DISABLED );
|
|
||||||
|
|
||||||
evt.cancel();
|
|
||||||
}
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
function getSelectedMediatag (editor, element) {
|
|
||||||
if (!element) {
|
|
||||||
var sel = editor.getSelection();
|
|
||||||
element = sel.getSelectedElement();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (element && element.is('media-tag') && !element.data('cke-realelement')
|
|
||||||
&& !element.isReadOnly()) {
|
|
||||||
return element;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
function getMediatagAlignment (element) {
|
|
||||||
var align = element.getStyle('float');
|
|
||||||
|
|
||||||
if (align === 'inherit' || align === 'none') {
|
|
||||||
align = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!align) {
|
|
||||||
align = element.getAttribute('align');
|
|
||||||
}
|
|
||||||
|
|
||||||
return align;
|
|
||||||
}
|
|
||||||
} )();
|
} )();
|
||||||
|
|
||||||
/**
|
|
||||||
* Determines whether dimension inputs should be automatically filled when the image URL changes in the Image plugin dialog window.
|
|
||||||
*
|
|
||||||
* config.image_prefillDimensions = false;
|
|
||||||
*
|
|
||||||
* @since 4.5
|
|
||||||
* @cfg {Boolean} [image_prefillDimensions=true]
|
|
||||||
* @member CKEDITOR.config
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether to remove links when emptying the link URL field in the Image dialog window.
|
|
||||||
*
|
|
||||||
* config.image_removeLinkByEmptyURL = false;
|
|
||||||
*
|
|
||||||
* @cfg {Boolean} [image_removeLinkByEmptyURL=true]
|
|
||||||
* @member CKEDITOR.config
|
|
||||||
*/
|
|
||||||
CKEDITOR.config.mediatag_removeLinkByEmptyURL = true;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Padding text to set off the image in the preview area.
|
|
||||||
*
|
|
||||||
* config.image_previewText = CKEDITOR.tools.repeat( '___ ', 100 );
|
|
||||||
*
|
|
||||||
* @cfg {String} [image_previewText='Lorem ipsum dolor...' (placeholder text)]
|
|
||||||
* @member CKEDITOR.config
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,22 +1,15 @@
|
|||||||
@import (once) "../../customize/src/less2/include/browser.less";
|
@import (once) "../../customize/src/less2/include/browser.less";
|
||||||
@import (once) "../../customize/src/less2/include/toolbar.less";
|
|
||||||
@import (once) "../../customize/src/less2/include/markdown.less";
|
@import (once) "../../customize/src/less2/include/markdown.less";
|
||||||
@import (once) '../../customize/src/less2/include/fileupload.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/alertify.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/tokenfield.less';
|
|
||||||
@import (once) '../../customize/src/less2/include/tools.less';
|
@import (once) '../../customize/src/less2/include/tools.less';
|
||||||
@import (once) '../../customize/src/less2/include/avatar.less';
|
@import (once) '../../customize/src/less2/include/avatar.less';
|
||||||
@import (once) '../../customize/src/less2/include/creation.less';
|
@import (once) "../../customize/src/less2/include/framework.less";
|
||||||
|
|
||||||
.toolbar_main(
|
|
||||||
|
.framework_main(
|
||||||
@bg-color: @colortheme_poll-bg,
|
@bg-color: @colortheme_poll-bg,
|
||||||
@warn-color: @colortheme_poll-warn,
|
@warn-color: @colortheme_poll-warn,
|
||||||
@color: @colortheme_poll-color
|
@color: @colortheme_poll-color
|
||||||
);
|
);
|
||||||
.fileupload_main();
|
|
||||||
.alertify_main();
|
|
||||||
.tokenfield_main();
|
|
||||||
.creation_main();
|
|
||||||
|
|
||||||
@poll-fore: #555;
|
@poll-fore: #555;
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ define([
|
|||||||
'jquery',
|
'jquery',
|
||||||
'/common/toolbar3.js',
|
'/common/toolbar3.js',
|
||||||
'/common/common-util.js',
|
'/common/common-util.js',
|
||||||
'/common/cryptget.js',
|
|
||||||
'/bower_components/nthen/index.js',
|
'/bower_components/nthen/index.js',
|
||||||
'/common/sframe-common.js',
|
'/common/sframe-common.js',
|
||||||
'/common/common-realtime.js',
|
'/common/common-realtime.js',
|
||||||
@@ -26,13 +25,12 @@ define([
|
|||||||
'/bower_components/file-saver/FileSaver.min.js',
|
'/bower_components/file-saver/FileSaver.min.js',
|
||||||
|
|
||||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||||
'less!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||||
'less!/customize/src/less2/main.less',
|
'less!/customize/src/less2/main.less',
|
||||||
], function (
|
], function (
|
||||||
$,
|
$,
|
||||||
Toolbar,
|
Toolbar,
|
||||||
Util,
|
Util,
|
||||||
Cryptget,
|
|
||||||
nThen,
|
nThen,
|
||||||
SFCommon,
|
SFCommon,
|
||||||
CommonRealtime,
|
CommonRealtime,
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user