Merge branch 'rohref' into sharedfolder
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -15,4 +15,5 @@ npm-debug.log
|
|||||||
pins/
|
pins/
|
||||||
blob/
|
blob/
|
||||||
blobstage/
|
blobstage/
|
||||||
|
block/
|
||||||
privileged.conf
|
privileged.conf
|
||||||
|
|||||||
42
CHANGELOG.md
42
CHANGELOG.md
@@ -1,3 +1,45 @@
|
|||||||
|
# Echidna release (v2.4.0)
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
For version 2.4.0 we chose to use our time to address difficulties that some users had, and to release some features which have been in development for some time. With the recent release of the _password-protected-pads_ feature, some users desired to be able to change the passwords that they'd already set, or to add a password to a pad retroactively. Other users wanted to recover information that had accidentally been deleted from their pads, but found that the history feature was difficult to use on networks with poor connectivity. Others still found that loading pads in general was too slow.
|
||||||
|
|
||||||
|
## Update notes
|
||||||
|
|
||||||
|
* We have released new clientside dependencies, so server administrators will need to run `bower update`
|
||||||
|
* This release also depends on new serverside dependencies, so administrators will also need to run `npm update`
|
||||||
|
* This release (optionally) takes advantage of Webworker APIs, so administrators may need to update their Content Security Headers to include worker-src (and child-src for safari)
|
||||||
|
* see cryptpad/docs/example.nginx.conf for more details regarding configuration for nginx as a reverse proxy
|
||||||
|
* to enable webworkers as an experimental feature, add `AppConfig.disableWorkers = false;` to your `cryptpad/customize/application-config.js`
|
||||||
|
* Finally, administrators will need to restart their servers after updating, as clients will require new functionality
|
||||||
|
|
||||||
|
## What's new
|
||||||
|
|
||||||
|
### Features
|
||||||
|
|
||||||
|
* CryptPad now takes advantage of some very modern browser APIs
|
||||||
|
* Shared Workers allow common tasks for all CryptPad editors to be handled by a single background process which runs in the background. This results in better performance savings for anyone using multiple editors at once in different tabs
|
||||||
|
* Webworkers are used in situations where shared workers are not supported, for most of the same tasks. They are not shared amongst different tabs, but can allow for a more responsive user experience since some heavy commands will be run in the background
|
||||||
|
* Not all browsers feature complete support for webworkers. For cases where they are not supported at all, or where cryptographic APIs are not supported within their context (https://developer.microsoft.com/en-us/microsoft-edge/platform/issues/7607496/), we fall back to an asynchronous context in the same thread
|
||||||
|
* Pads with no password can now be updated to include a password, and pads with a password can have their passwords changed
|
||||||
|
* right-click on the pad in question, and see its properties. The following dialog will present the option to change its password
|
||||||
|
* changing a pad's password will remove its history
|
||||||
|
* Accessing a pad's history used to require that clients fetch the entire history of the pad before they could view any of it. History retrieval is now done on an on-demand basis, approximately 100 versions of the pad at a time
|
||||||
|
* this also features an updated UI with a slider
|
||||||
|
* We've refactored our whiteboard application to be compatible with our internal framework. As a result, it will be easier to maintain and will have all the same features as the other editors built with the same framework
|
||||||
|
* We've defined some new server-side features which will allow clients to change their user passwords in a coming release
|
||||||
|
* We've updated our messaging server implementation
|
||||||
|
* the aspect of the server which stores and distributes history has been untangled from the aspect which tracks user lists and broadcasts messages
|
||||||
|
* the server will now store the time when each message was received, so as to be able to allow users to view the time of edits in a later release
|
||||||
|
|
||||||
|
### Bug fixes
|
||||||
|
|
||||||
|
* When a user tries to register, but enters credentials which have already been used for that CryptPad instance, we prompt them to log in as that user. We discovered that the login had stopped working at some point. This has been fixed
|
||||||
|
* Server administrators may have seen warnings from npm when attempting to update. We have fixed invalid entries and added missing entries where appropriate such that there are no more warnings
|
||||||
|
* Static info pages have been restyled to be more responsive, thanks to @CatalinScr
|
||||||
|
* Support for friend requests in pads with version 0 hashes has been repaired
|
||||||
|
* We noticed a regression in how default titles for pads were suggested, and have implemented the intended behaviour
|
||||||
|
|
||||||
# Donkey release (v2.3.0)
|
# Donkey release (v2.3.0)
|
||||||
|
|
||||||
## Goals
|
## Goals
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
out.chainpadError = 'Ein kritischer Fehler hat stattgefunden, bei den Updates deines Dokuments. Dieses Dokument ist schreibgeschützt, damit du sicher machen kannst, dass keine Inhalt verloren geht.<br>'+
|
out.chainpadError = 'Ein kritischer Fehler hat stattgefunden, bei den Updates deines Dokuments. Dieses Dokument ist schreibgeschützt, damit du sicher machen kannst, dass keine Inhalt verloren geht.<br>'+
|
||||||
'Druck auf <em>Esc</em>, um das Dokument schreibgeschützt zu lesen, oder lade es neu, um das Editierien wiederanzufangen.';
|
'Druck auf <em>Esc</em>, um das Dokument schreibgeschützt zu lesen, oder lade es neu, um das Editierien wiederanzufangen.';
|
||||||
out.errorCopy = ' Du kannst noch den Inhalt woanders kopieren, nachdem du <em>Esc</em> drucken.<br>Wenn du die Seite verlässt, verschwindet der Inhalt für immer!';
|
out.errorCopy = ' Du kannst noch den Inhalt woanders kopieren, nachdem du <em>Esc</em> drucken.<br>Wenn du die Seite verlässt, verschwindet der Inhalt für immer!';
|
||||||
|
out.errorRedirectToHome = 'Drucke <em>Esc</em>, um zu deinem CryptDrive zu gehen.';
|
||||||
|
|
||||||
out.loading = "Laden...";
|
out.loading = "Laden...";
|
||||||
out.error = "Fehler";
|
out.error = "Fehler";
|
||||||
|
|||||||
@@ -6,12 +6,11 @@
|
|||||||
|
|
||||||
server {
|
server {
|
||||||
listen 443 ssl http2;
|
listen 443 ssl http2;
|
||||||
|
server_name your-main-domain.com your-sandbox-domain.com;
|
||||||
|
|
||||||
server_name cryptpad.fr www.cryptpad.fr beta.cryptpad.fr;
|
ssl_certificate /home/cryptpad/.acme.sh/your-main-domain.com/fullchain.cer;
|
||||||
|
ssl_certificate_key /home/cryptpad/.acme.sh/your-main-domain.com/your-main-domain.com.key;
|
||||||
ssl_certificate /home/cryptpad/.acme.sh/alpha.cryptpad.fr/fullchain.cer;
|
ssl_trusted_certificate /home/cryptpad/.acme.sh/your-main-domain.com/ca.cer;
|
||||||
ssl_certificate_key /home/cryptpad/.acme.sh/alpha.cryptpad.fr/alpha.cryptpad.fr.key;
|
|
||||||
ssl_trusted_certificate /home/cryptpad/.acme.sh/alpha.cryptpad.fr/ca.cer;
|
|
||||||
|
|
||||||
ssl_dhparam /etc/nginx/dhparam.pem;
|
ssl_dhparam /etc/nginx/dhparam.pem;
|
||||||
ssl_session_timeout 5m;
|
ssl_session_timeout 5m;
|
||||||
@@ -27,6 +26,7 @@ server {
|
|||||||
|
|
||||||
root /home/cryptpad/cryptpad;
|
root /home/cryptpad/cryptpad;
|
||||||
index index.html;
|
index index.html;
|
||||||
|
error_page 404 /customize.dist/404.html;
|
||||||
|
|
||||||
if ($args ~ ver=) {
|
if ($args ~ ver=) {
|
||||||
set $cacheControl max-age=31536000;
|
set $cacheControl max-age=31536000;
|
||||||
@@ -34,25 +34,31 @@ server {
|
|||||||
# Will not set any header if it is emptystring
|
# Will not set any header if it is emptystring
|
||||||
add_header Cache-Control $cacheControl;
|
add_header Cache-Control $cacheControl;
|
||||||
|
|
||||||
set $styleSrc "'unsafe-inline' 'self'";
|
set $styleSrc "'unsafe-inline' 'self' your-main-domain.com";
|
||||||
set $scriptSrc "'self'";
|
set $scriptSrc "'self' your-main-domain.com";
|
||||||
set $connectSrc "'self' wss://cryptpad.fr wss://api.cryptpad.fr";
|
set $connectSrc "'self' https://your-main-domain.com wss://your-main-domain.com https://api.your-main-domain.com wss://your-main-domain.com your-main-domain.com blob: your-main-domain.com";
|
||||||
set $fontSrc "'self'";
|
set $fontSrc "'self' data: your-main-domain.com";
|
||||||
set $imgSrc "data: * blob:";
|
set $imgSrc "data: * blob:";
|
||||||
set $frameSrc "'self' beta.cryptpad.fr";
|
set $frameSrc "'self' your-sandbox-domain.com blob:";
|
||||||
|
set $mediaSrc "* blob:";
|
||||||
|
set $childSrc "https://your-main-domain.com";
|
||||||
|
set $workerSrc "https://your-main-domain.com";
|
||||||
|
|
||||||
if ($uri = /pad/inner.html) {
|
set $unsafe 0;
|
||||||
set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline'";
|
if ($uri = "/pad/inner.html") { set $unsafe 1; }
|
||||||
|
if ($host != sandbox.cryptpad.info) { set $unsafe 0; }
|
||||||
|
if ($unsafe) {
|
||||||
|
set $scriptSrc "'self' 'unsafe-eval' 'unsafe-inline' new2.cryptpad.fr cryptpad.fr";
|
||||||
}
|
}
|
||||||
add_header Content-Security-Policy "default-src 'none'; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc;";
|
add_header Content-Security-Policy "default-src 'none'; child-src $childSrc; worker-src $workerSrc; media-src $mediaSrc; style-src $styleSrc; script-src $scriptSrc; connect-src $connectSrc; font-src $fontSrc; img-src $imgSrc; frame-src $frameSrc;";
|
||||||
|
|
||||||
location = /cryptpad_websocket {
|
|
||||||
|
location ^~ /cryptpad_websocket {
|
||||||
proxy_pass http://localhost:3000;
|
proxy_pass http://localhost:3000;
|
||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
|
|
||||||
# add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
|
||||||
# WebSocket support (nginx 1.4)
|
# WebSocket support (nginx 1.4)
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
@@ -72,8 +78,8 @@ server {
|
|||||||
proxy_set_header X-Real-IP $remote_addr;
|
proxy_set_header X-Real-IP $remote_addr;
|
||||||
proxy_set_header Host $host;
|
proxy_set_header Host $host;
|
||||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||||
}
|
}
|
||||||
|
|
||||||
location ^~ /blob/ {
|
location ^~ /blob/ {
|
||||||
add_header Cache-Control max-age=31536000;
|
add_header Cache-Control max-age=31536000;
|
||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
@@ -84,11 +90,9 @@ server {
|
|||||||
try_files $uri =404;
|
try_files $uri =404;
|
||||||
}
|
}
|
||||||
|
|
||||||
## TODO fix in the code so that we don't need this
|
location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media|profile|contacts|todo|filepicker|debug|kanban)$ {
|
||||||
location ~ ^/(register|login|settings|user|pad|drive|poll|slide|code|whiteboard|file|media)$ {
|
|
||||||
rewrite ^(.*)$ $1/ redirect;
|
rewrite ^(.*)$ $1/ redirect;
|
||||||
}
|
}
|
||||||
|
|
||||||
try_files /www/$uri /www/$uri/index.html /customize/$uri;
|
try_files /www/$uri /www/$uri/index.html /customize/$uri;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -398,10 +398,16 @@ Version 1
|
|||||||
Hash.findWeaker = function (href, channel, recents) {
|
Hash.findWeaker = function (href, channel, recents) {
|
||||||
var parsed = parsePadUrl(href);
|
var parsed = parsePadUrl(href);
|
||||||
if (!parsed.hash) { return false; }
|
if (!parsed.hash) { return false; }
|
||||||
|
// We can't have a weaker hash if we're already in view mode
|
||||||
|
if (parsed.hashData && parsed.hashData.mode === 'view') { return; }
|
||||||
var weaker;
|
var weaker;
|
||||||
Object.keys(recents).some(function (id) {
|
Object.keys(recents).some(function (id) {
|
||||||
var pad = recents[id];
|
var pad = recents[id];
|
||||||
var p = parsePadUrl(pad.href);
|
if (pad.href || !pad.roHref) {
|
||||||
|
// This pad has an edit link, so it can't be weaker
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
var p = parsePadUrl(pad.roHref);
|
||||||
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
|
if (channel !== pad.channel) { return; } // Not the same channel
|
||||||
@@ -430,6 +436,10 @@ Version 1
|
|||||||
var stronger;
|
var stronger;
|
||||||
Object.keys(recents).some(function (id) {
|
Object.keys(recents).some(function (id) {
|
||||||
var pad = recents[id];
|
var pad = recents[id];
|
||||||
|
if (!pad.href) {
|
||||||
|
// This pad doesn't have an edit link, so it can't be stronger
|
||||||
|
return;
|
||||||
|
}
|
||||||
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
|
||||||
|
|||||||
@@ -665,7 +665,7 @@ define([
|
|||||||
// Update the current state
|
// Update the current state
|
||||||
loading.driveState = data.state;
|
loading.driveState = data.state;
|
||||||
data.progress = data.progress || 100;
|
data.progress = data.progress || 100;
|
||||||
data.msg = Messages['loading_drive_'+data.state] || '';
|
data.msg = Messages['loading_drive_'+ Math.floor(data.state)] || '';
|
||||||
$progress.html(data.msg);
|
$progress.html(data.msg);
|
||||||
if (data.progress) {
|
if (data.progress) {
|
||||||
$progress.append(h('div.cp-loading-progress-bar', [
|
$progress.append(h('div.cp-loading-progress-bar', [
|
||||||
@@ -761,7 +761,7 @@ define([
|
|||||||
UI.getFileIcon = function (data) {
|
UI.getFileIcon = function (data) {
|
||||||
var $icon = UI.getIcon();
|
var $icon = UI.getIcon();
|
||||||
if (!data) { return $icon; }
|
if (!data) { return $icon; }
|
||||||
var href = data.href;
|
var href = data.href || data.roHref;
|
||||||
var type = data.type;
|
var type = data.type;
|
||||||
if (!href && !type) { return $icon; }
|
if (!href && !type) { return $icon; }
|
||||||
|
|
||||||
|
|||||||
@@ -73,26 +73,14 @@ define([
|
|||||||
data.password = val;
|
data.password = val;
|
||||||
}));
|
}));
|
||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
|
var base = common.getMetadataMgr().getPrivateData().origin;
|
||||||
common.getPadAttribute('href', waitFor(function (err, val) {
|
common.getPadAttribute('href', waitFor(function (err, val) {
|
||||||
var base = common.getMetadataMgr().getPrivateData().origin;
|
if (!val) { return; }
|
||||||
|
|
||||||
var parsed = Hash.parsePadUrl(val);
|
|
||||||
if (parsed.hashData.mode === "view") {
|
|
||||||
data.roHref = base + val;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We're not in a read-only pad
|
|
||||||
data.href = base + val;
|
data.href = base + val;
|
||||||
|
}));
|
||||||
// Get Read-only href
|
common.getPadAttribute('roHref', waitFor(function (err, val) {
|
||||||
if (parsed.hashData.type !== "pad") { return; }
|
if (!val) { return; }
|
||||||
var i = data.href.indexOf('#') + 1;
|
data.roHref = base + val;
|
||||||
var hBase = data.href.slice(0, i);
|
|
||||||
var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
|
||||||
if (!hrefsecret.keys) { return; }
|
|
||||||
var viewHash = Hash.getViewHashFromKeys(hrefsecret);
|
|
||||||
data.roHref = hBase + viewHash;
|
|
||||||
}));
|
}));
|
||||||
common.getPadAttribute('channel', waitFor(function (err, val) {
|
common.getPadAttribute('channel', waitFor(function (err, val) {
|
||||||
data.channel = val;
|
data.channel = val;
|
||||||
@@ -162,7 +150,7 @@ define([
|
|||||||
$d.append(password);
|
$d.append(password);
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
var parsed = Hash.parsePadUrl(data.href || data.roHref);
|
||||||
if (owned && parsed.hashData.type === 'pad') {
|
if (owned && parsed.hashData.type === 'pad') {
|
||||||
var sframeChan = common.getSframeChannel();
|
var sframeChan = common.getSframeChannel();
|
||||||
var changePwTitle = Messages.properties_changePassword;
|
var changePwTitle = Messages.properties_changePassword;
|
||||||
@@ -186,7 +174,7 @@ define([
|
|||||||
UI.confirm(changePwConfirm, function (yes) {
|
UI.confirm(changePwConfirm, function (yes) {
|
||||||
if (!yes) { return; }
|
if (!yes) { return; }
|
||||||
sframeChan.query("Q_PAD_PASSWORD_CHANGE", {
|
sframeChan.query("Q_PAD_PASSWORD_CHANGE", {
|
||||||
href: data.href,
|
href: data.href || data.roHref,
|
||||||
password: $(newPassword).find('input').val()
|
password: $(newPassword).find('input').val()
|
||||||
}, function (err, data) {
|
}, function (err, data) {
|
||||||
if (err || data.error) {
|
if (err || data.error) {
|
||||||
@@ -195,11 +183,11 @@ define([
|
|||||||
UI.findOKButton().click();
|
UI.findOKButton().click();
|
||||||
if (data.warning) {
|
if (data.warning) {
|
||||||
return void UI.alert(Messages.properties_passwordWarning, function () {
|
return void UI.alert(Messages.properties_passwordWarning, function () {
|
||||||
common.gotoURL(hasPassword ? undefined : data.href);
|
common.gotoURL(hasPassword ? undefined : (data.href || data.roHref));
|
||||||
}, {force: true});
|
}, {force: true});
|
||||||
}
|
}
|
||||||
return void UI.alert(Messages.properties_passwordSuccess, function () {
|
return void UI.alert(Messages.properties_passwordSuccess, function () {
|
||||||
common.gotoURL(hasPassword ? undefined : data.href);
|
common.gotoURL(hasPassword ? undefined : (data.href || data.roHref));
|
||||||
}, {force: true});
|
}, {force: true});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -613,7 +613,7 @@ define([
|
|||||||
if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); }
|
if (!parsed.hash) { return void cb({ error: 'EINVAL_HREF' }); }
|
||||||
|
|
||||||
var warning = false;
|
var warning = false;
|
||||||
var newHash;
|
var newHash, newRoHref;
|
||||||
var oldChannel;
|
var oldChannel;
|
||||||
if (parsed.hashData.password) {
|
if (parsed.hashData.password) {
|
||||||
newHash = parsed.hash;
|
newHash = parsed.hash;
|
||||||
@@ -678,6 +678,11 @@ define([
|
|||||||
common.setPadAttribute('channel', secret.channel, waitFor(function (err) {
|
common.setPadAttribute('channel', secret.channel, waitFor(function (err) {
|
||||||
if (err) { warning = true; }
|
if (err) { warning = true; }
|
||||||
}), href);
|
}), href);
|
||||||
|
var viewHash = Hash.getViewHashFromKeys(secret);
|
||||||
|
newRoHref = '/' + parsed.type + '/#' + viewHash;
|
||||||
|
common.setPadAttribute('roHref', newRoHref, waitFor(function (err) {
|
||||||
|
if (err) { warning = true; }
|
||||||
|
}), href);
|
||||||
|
|
||||||
if (parsed.hashData.password) { return; } // same hash
|
if (parsed.hashData.password) { return; } // same hash
|
||||||
common.setPadAttribute('href', newHref, waitFor(function (err) {
|
common.setPadAttribute('href', newHref, waitFor(function (err) {
|
||||||
@@ -687,7 +692,8 @@ define([
|
|||||||
cb({
|
cb({
|
||||||
warning: warning,
|
warning: warning,
|
||||||
hash: newHash,
|
hash: newHash,
|
||||||
href: newHref
|
href: newHref,
|
||||||
|
roHref: newRoHref
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -115,23 +115,25 @@ define([
|
|||||||
var newRecentPads = proxy.drive[newFo.FILES_DATA];
|
var newRecentPads = proxy.drive[newFo.FILES_DATA];
|
||||||
var oldFiles = oldFo.getFiles([newFo.FILES_DATA]);
|
var oldFiles = oldFo.getFiles([newFo.FILES_DATA]);
|
||||||
var newHrefs = Object.keys(newRecentPads).map(function (id) {
|
var newHrefs = Object.keys(newRecentPads).map(function (id) {
|
||||||
return newRecentPads[id].href;
|
return newRecentPads[id].href || newRecentPads[id].roHref;
|
||||||
});
|
});
|
||||||
oldFiles.forEach(function (id) {
|
oldFiles.forEach(function (id) {
|
||||||
var href = oldRecentPads[id].href;
|
var href = oldRecentPads[id].href || oldRecentPads[id].roHref;
|
||||||
|
var isRo = href === oldRecentPads[id].roHref;
|
||||||
// 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, oldRecentPads[id].channel, newRecentPads)) { return; }
|
// If the current href is read-only, don't check, we won't have a stronger
|
||||||
|
if (isRo && 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
|
// If the current href is an edit link, don't check, we won't have a weaker
|
||||||
var weaker = Hash.findWeaker(href, oldRecentPads[id].channel, newRecentPads);
|
if (!isRo) {
|
||||||
if (weaker) {
|
var weaker = Hash.findWeaker(href, oldRecentPads[id].channel, newRecentPads);
|
||||||
// Update RECENTPADS
|
if (weaker) {
|
||||||
weaker.href = href;
|
// Update RECENTPADS
|
||||||
// Update the file in the drive
|
weaker.href = 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
|
||||||
var paths = oldFo.findFile(id);
|
var paths = oldFo.findFile(id);
|
||||||
|
|||||||
@@ -123,12 +123,58 @@ define([
|
|||||||
}));
|
}));
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
n.nThen(waitFor());
|
n.nThen(waitFor(function () {
|
||||||
|
Feedback.send('Migrate-6', true);
|
||||||
|
userObject.version = version = 6;
|
||||||
|
}));
|
||||||
};
|
};
|
||||||
if (version < 6) {
|
if (version < 6) {
|
||||||
addChannelId();
|
addChannelId();
|
||||||
Feedback.send('Migrate-6', true);
|
}
|
||||||
userObject.version = version = 6;
|
}).nThen(function (waitFor) {
|
||||||
|
var addRoHref = function () {
|
||||||
|
var data = userObject.drive.filesData;
|
||||||
|
var el, parsed;
|
||||||
|
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];
|
||||||
|
if (!el.href || (el.roHref && false)) {
|
||||||
|
// Already migrated
|
||||||
|
return void progress(7, Math.round(100*i/padsLength));
|
||||||
|
}
|
||||||
|
parsed = Hash.parsePadUrl(el.href);
|
||||||
|
if (parsed.hashData.type !== "pad") {
|
||||||
|
// No read-only mode for files
|
||||||
|
return void progress(7, Math.round(100*i/padsLength));
|
||||||
|
}
|
||||||
|
if (parsed.hashData.mode === "view") {
|
||||||
|
// This is a read-only pad in our drive
|
||||||
|
el.roHref = el.href;
|
||||||
|
delete el.href;
|
||||||
|
console.log('Move href to roHref in filesData ', el.roHref);
|
||||||
|
} else {
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
||||||
|
var hash = Hash.getViewHashFromKeys(secret);
|
||||||
|
if (hash) {
|
||||||
|
// Version 0 won't have a view hash available
|
||||||
|
el.roHref = '/' + parsed.type + '/#' + hash;
|
||||||
|
console.log('Adding missing roHref in filesData ', el.href);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
progress(6, Math.round(100*i/padsLength));
|
||||||
|
}));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
n.nThen(waitFor(function () {
|
||||||
|
Feedback.send('Migrate-7', true);
|
||||||
|
userObject.version = version = 7;
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
if (version < 7) {
|
||||||
|
addRoHref();
|
||||||
}
|
}
|
||||||
/*}).nThen(function (waitFor) {
|
/*}).nThen(function (waitFor) {
|
||||||
// Test progress bar in the loading screen
|
// Test progress bar in the loading screen
|
||||||
|
|||||||
@@ -426,10 +426,11 @@ define([
|
|||||||
cb(JSON.parse(JSON.stringify(metadata)));
|
cb(JSON.parse(JSON.stringify(metadata)));
|
||||||
};
|
};
|
||||||
|
|
||||||
var makePad = function (href, title) {
|
var makePad = function (href, roHref, title) {
|
||||||
var now = +new Date();
|
var now = +new Date();
|
||||||
return {
|
return {
|
||||||
href: href,
|
href: href,
|
||||||
|
roHref: roHref,
|
||||||
atime: now,
|
atime: now,
|
||||||
ctime: now,
|
ctime: now,
|
||||||
title: title || Hash.getDefaultName(Hash.parsePadUrl(href)),
|
title: title || Hash.getDefaultName(Hash.parsePadUrl(href)),
|
||||||
@@ -437,8 +438,15 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
Store.addPad = function (clientId, data, cb) {
|
Store.addPad = function (clientId, data, cb) {
|
||||||
if (!data.href) { return void cb({error:'NO_HREF'}); }
|
if (!data.href && !data.roHref) { return void cb({error:'NO_HREF'}); }
|
||||||
var pad = makePad(data.href, data.title);
|
if (!data.roHref) {
|
||||||
|
var parsed = Hash.parsePadUrl(data.href);
|
||||||
|
if (parsed.hashData.type === "pad") {
|
||||||
|
var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
||||||
|
data.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
var pad = makePad(data.href, data.roHref, 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.password) { pad.password = data.password; }
|
||||||
@@ -736,9 +744,9 @@ define([
|
|||||||
// Edit > Edit (present) > View > View (present)
|
// Edit > Edit (present) > View > View (present)
|
||||||
for (var id in allPads) {
|
for (var id in allPads) {
|
||||||
var pad = allPads[id];
|
var pad = allPads[id];
|
||||||
if (!pad.href) { continue; }
|
if (!pad.href && !pad.roHref) { continue; }
|
||||||
|
|
||||||
var p2 = Hash.parsePadUrl(pad.href);
|
var p2 = Hash.parsePadUrl(pad.href || pad.roHref);
|
||||||
var h2 = p2.hashData;
|
var h2 = p2.hashData;
|
||||||
|
|
||||||
// Different types, proceed to the next one
|
// Different types, proceed to the next one
|
||||||
@@ -789,8 +797,14 @@ define([
|
|||||||
|
|
||||||
// Add the pad if it does not exist in our drive
|
// Add the pad if it does not exist in our drive
|
||||||
if (!contains) {
|
if (!contains) {
|
||||||
|
var roHref;
|
||||||
|
if (h.mode === "view") {
|
||||||
|
roHref = href;
|
||||||
|
href = undefined;
|
||||||
|
}
|
||||||
Store.addPad(clientId, {
|
Store.addPad(clientId, {
|
||||||
href: href,
|
href: href,
|
||||||
|
roHref: roHref,
|
||||||
channel: channel,
|
channel: channel,
|
||||||
title: title,
|
title: title,
|
||||||
owners: owners,
|
owners: owners,
|
||||||
@@ -827,7 +841,7 @@ define([
|
|||||||
};
|
};
|
||||||
store.userObject.getFiles(where).forEach(function (id) {
|
store.userObject.getFiles(where).forEach(function (id) {
|
||||||
var data = store.userObject.getFileData(id);
|
var data = store.userObject.getFileData(id);
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
var parsed = Hash.parsePadUrl(data.href || data.roHref);
|
||||||
if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) &&
|
if ((!types || types.length === 0 || types.indexOf(parsed.type) !== -1) &&
|
||||||
hashes.indexOf(parsed.hash) === -1 &&
|
hashes.indexOf(parsed.hash) === -1 &&
|
||||||
!isFiltered(parsed.type, data)) {
|
!isFiltered(parsed.type, data)) {
|
||||||
@@ -1421,7 +1435,7 @@ define([
|
|||||||
}).nThen(function (waitFor) {
|
}).nThen(function (waitFor) {
|
||||||
Migrate(proxy, waitFor(), function (version, progress) {
|
Migrate(proxy, waitFor(), function (version, progress) {
|
||||||
postMessage(clientId, 'LOADING_DRIVE', {
|
postMessage(clientId, 'LOADING_DRIVE', {
|
||||||
state: 2,
|
state: (2 + (version / 10)),
|
||||||
progress: progress
|
progress: progress
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -50,19 +50,6 @@ define([
|
|||||||
var data = exp.getFileData(id);
|
var data = exp.getFileData(id);
|
||||||
cb(null, clone(data[attr]));
|
cb(null, clone(data[attr]));
|
||||||
};
|
};
|
||||||
var removePadAttribute = exp.removePadAttribute = function (f) {
|
|
||||||
if (typeof(f) !== 'string') {
|
|
||||||
console.error("Can't find pad attribute for an undefined pad");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Object.keys(files).forEach(function (key) {
|
|
||||||
var hash = f.indexOf('#') !== -1 ? f.slice(f.indexOf('#') + 1) : null;
|
|
||||||
if (hash && key.indexOf(hash) === 0) {
|
|
||||||
exp.debug("Deleting pad attribute in the realtime object");
|
|
||||||
delete files[key];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
exp.pushData = function (data, cb) {
|
exp.pushData = function (data, cb) {
|
||||||
if (typeof cb !== "function") { cb = function () {}; }
|
if (typeof cb !== "function") { cb = function () {}; }
|
||||||
@@ -145,12 +132,9 @@ define([
|
|||||||
|
|
||||||
if (!loggedIn && !config.testMode) {
|
if (!loggedIn && !config.testMode) {
|
||||||
allFilesPaths.forEach(function (path) {
|
allFilesPaths.forEach(function (path) {
|
||||||
var el = exp.find(path);
|
var id = path[1];
|
||||||
if (!el) { return; }
|
|
||||||
var id = exp.getIdFromHref(el.href);
|
|
||||||
if (!id) { return; }
|
if (!id) { return; }
|
||||||
spliceFileData(id);
|
spliceFileData(id);
|
||||||
removePadAttribute(el.href);
|
|
||||||
});
|
});
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -259,7 +243,6 @@ define([
|
|||||||
if (!id) { return; }
|
if (!id) { return; }
|
||||||
if (!loggedIn && !config.testMode) {
|
if (!loggedIn && !config.testMode) {
|
||||||
// delete permanently
|
// delete permanently
|
||||||
exp.removePadAttribute(href);
|
|
||||||
spliceFileData(id);
|
spliceFileData(id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -268,14 +251,7 @@ define([
|
|||||||
};
|
};
|
||||||
|
|
||||||
// REPLACE
|
// REPLACE
|
||||||
exp.replace = function (o, n) {
|
// If all the occurences of an href are in the trash, remove them and add the file in root.
|
||||||
var idO = exp.getIdFromHref(o);
|
|
||||||
if (!idO || !exp.isFile(idO)) { return; }
|
|
||||||
var data = exp.getFileData(idO);
|
|
||||||
if (!data) { return; }
|
|
||||||
data.href = n;
|
|
||||||
};
|
|
||||||
// If all the occurences of an href are in the trash, remvoe them and add the file in root.
|
|
||||||
// This is use with setPadTitle when we open a stronger version of a deleted pad
|
// This is use with setPadTitle when we open a stronger version of a deleted pad
|
||||||
exp.restoreHref = function (href) {
|
exp.restoreHref = function (href) {
|
||||||
var idO = exp.getIdFromHref(href);
|
var idO = exp.getIdFromHref(href);
|
||||||
@@ -563,13 +539,15 @@ define([
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
// Clean missing href
|
// Clean missing href
|
||||||
if (!el.href) {
|
if (!el.href && !el.roHref) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
||||||
var parsed = Hash.parsePadUrl(el.href);
|
var parsed = Hash.parsePadUrl(el.href || el.roHref);
|
||||||
|
var secret;
|
||||||
|
|
||||||
// Clean invalid hash
|
// 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);
|
||||||
@@ -583,6 +561,23 @@ define([
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If we have an edit link, check the view link
|
||||||
|
if (el.href && parsed.hashData.type === "pad") {
|
||||||
|
if (parsed.hashData.mode === "view") {
|
||||||
|
el.roHref = el.href;
|
||||||
|
delete el.href;
|
||||||
|
} else if (!el.roHref) {
|
||||||
|
secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
||||||
|
el.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret);
|
||||||
|
} else {
|
||||||
|
var parsed2 = Hash.parsePadUrl(el.roHref);
|
||||||
|
if (!parsed2.hash || !parsed2.type) {
|
||||||
|
secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
||||||
|
el.roHref = '/' + parsed.type + '/#' + Hash.getViewHashFromKeys(secret);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Fix href
|
// Fix href
|
||||||
if (/^https*:\/\//.test(el.href)) { el.href = Hash.getRelativeHref(el.href); }
|
if (/^https*:\/\//.test(el.href)) { el.href = Hash.getRelativeHref(el.href); }
|
||||||
// Fix creation time
|
// Fix creation time
|
||||||
@@ -592,7 +587,9 @@ define([
|
|||||||
// Fix channel
|
// Fix channel
|
||||||
if (!el.channel) {
|
if (!el.channel) {
|
||||||
try {
|
try {
|
||||||
var secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
if (!secret) {
|
||||||
|
secret = Hash.getSecrets(parsed.type, parsed.hash, el.password);
|
||||||
|
}
|
||||||
el.channel = secret.channel;
|
el.channel = secret.channel;
|
||||||
console.log('Adding missing channel in filesData ', el.channel);
|
console.log('Adding missing channel in filesData ', el.channel);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -79,11 +79,7 @@ define([
|
|||||||
exp.isReadOnlyFile = function (element) {
|
exp.isReadOnlyFile = function (element) {
|
||||||
if (!isFile(element)) { return false; }
|
if (!isFile(element)) { return false; }
|
||||||
var data = exp.getFileData(element);
|
var data = exp.getFileData(element);
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
return Boolean(data.roHref && !data.href);
|
||||||
if (!parsed) { return false; }
|
|
||||||
var pHash = parsed.hashData;
|
|
||||||
if (!pHash || pHash.type !== "pad") { return; }
|
|
||||||
return pHash && pHash.mode === 'view';
|
|
||||||
};
|
};
|
||||||
|
|
||||||
var isFolder = exp.isFolder = function (element) {
|
var isFolder = exp.isFolder = function (element) {
|
||||||
@@ -140,7 +136,7 @@ define([
|
|||||||
var getTitle = exp.getTitle = function (file, type) {
|
var getTitle = exp.getTitle = function (file, type) {
|
||||||
if (workgroup) { debug("No titles in workgroups"); return; }
|
if (workgroup) { debug("No titles in workgroups"); return; }
|
||||||
var data = getFileData(file);
|
var data = getFileData(file);
|
||||||
if (!file || !data || !data.href) {
|
if (!file || !data || !(data.href || data.roHref)) {
|
||||||
error("getTitle called with a non-existing file id: ", file, data);
|
error("getTitle called with a non-existing file id: ", file, data);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -289,7 +285,8 @@ define([
|
|||||||
var getIdFromHref = exp.getIdFromHref = function (href) {
|
var getIdFromHref = exp.getIdFromHref = function (href) {
|
||||||
var result;
|
var result;
|
||||||
getFiles([FILES_DATA]).some(function (id) {
|
getFiles([FILES_DATA]).some(function (id) {
|
||||||
if (files[FILES_DATA][id].href === href) {
|
if (files[FILES_DATA][id].href === href ||
|
||||||
|
files[FILES_DATA][id].roHref === href) {
|
||||||
result = id;
|
result = id;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -666,10 +666,10 @@ define([
|
|||||||
var openFile = function (el, href) {
|
var openFile = function (el, href) {
|
||||||
if (!href) {
|
if (!href) {
|
||||||
var data = filesOp.getFileData(el);
|
var data = filesOp.getFileData(el);
|
||||||
if (!data || !data.href) {
|
if (!data || (!data.href && !data.roHref)) {
|
||||||
return void logError("Missing data for the file", el, data);
|
return void logError("Missing data for the file", el, data);
|
||||||
}
|
}
|
||||||
href = data.href;
|
href = data.href || data.roHref;
|
||||||
}
|
}
|
||||||
window.open(APP.origin + href);
|
window.open(APP.origin + href);
|
||||||
};
|
};
|
||||||
@@ -1271,9 +1271,10 @@ define([
|
|||||||
if (!filesOp.isFile(element)) { return; }
|
if (!filesOp.isFile(element)) { return; }
|
||||||
|
|
||||||
var data = filesOp.getFileData(element);
|
var data = filesOp.getFileData(element);
|
||||||
|
var href = data.href || data.roHref;
|
||||||
if (!data) { return void logError("No data for the file", element); }
|
if (!data) { return void logError("No data for the file", element); }
|
||||||
|
|
||||||
var hrefData = Hash.parsePadUrl(data.href);
|
var hrefData = Hash.parsePadUrl(href);
|
||||||
if (hrefData.type) {
|
if (hrefData.type) {
|
||||||
$span.addClass('cp-border-color-'+hrefData.type);
|
$span.addClass('cp-border-color-'+hrefData.type);
|
||||||
}
|
}
|
||||||
@@ -1305,7 +1306,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, data.channel, data.password, $span, function ($thumb) {
|
common.displayThumbnail(href || data.roHref, data.channel, data.password, $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
|
||||||
@@ -1847,7 +1848,7 @@ define([
|
|||||||
var data = filesOp.getFileData(id);
|
var data = filesOp.getFileData(id);
|
||||||
if (!data) { return ''; }
|
if (!data) { return ''; }
|
||||||
if (prop === 'type') {
|
if (prop === 'type') {
|
||||||
var hrefData = Hash.parsePadUrl(data.href);
|
var hrefData = Hash.parsePadUrl(data.href || data.roHref);
|
||||||
return hrefData.type;
|
return hrefData.type;
|
||||||
}
|
}
|
||||||
if (prop === 'atime' || prop === 'ctime') {
|
if (prop === 'atime' || prop === 'ctime') {
|
||||||
@@ -1882,7 +1883,7 @@ define([
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
if (prop === 'type') {
|
if (prop === 'type') {
|
||||||
var hrefData = Hash.parsePadUrl(e.href);
|
var hrefData = Hash.parsePadUrl(e.href || e.roHref);
|
||||||
return hrefData.type;
|
return hrefData.type;
|
||||||
}
|
}
|
||||||
if (prop === 'atime' || prop === 'ctime') {
|
if (prop === 'atime' || prop === 'ctime') {
|
||||||
@@ -2690,20 +2691,6 @@ define([
|
|||||||
return $div.html();
|
return $div.html();
|
||||||
};
|
};
|
||||||
|
|
||||||
var getReadOnlyUrl = APP.getRO = function (id) {
|
|
||||||
if (!filesOp.isFile(id)) { return; }
|
|
||||||
var data = filesOp.getFileData(id);
|
|
||||||
if (!data) { return; }
|
|
||||||
var parsed = Hash.parsePadUrl(data.href);
|
|
||||||
if (parsed.hashData.type !== "pad") { return; }
|
|
||||||
var i = data.href.indexOf('#') + 1;
|
|
||||||
var base = data.href.slice(0, i);
|
|
||||||
var hrefsecret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
|
||||||
if (!hrefsecret.keys) { return; }
|
|
||||||
var viewHash = Hash.getViewHashFromKeys(hrefsecret);
|
|
||||||
return base + viewHash;
|
|
||||||
};
|
|
||||||
|
|
||||||
// Disable middle click in the context menu to avoid opening /drive/inner.html# in new tabs
|
// Disable middle click in the context menu to avoid opening /drive/inner.html# in new tabs
|
||||||
$(window).click(function (e) {
|
$(window).click(function (e) {
|
||||||
if (!e.target || !$(e.target).parents('.cp-dropdown-content').length) { return; }
|
if (!e.target || !$(e.target).parents('.cp-dropdown-content').length) { return; }
|
||||||
@@ -2717,19 +2704,16 @@ define([
|
|||||||
if (!filesOp.isFile(el)) {
|
if (!filesOp.isFile(el)) {
|
||||||
return void cb('NOT_FILE');
|
return void cb('NOT_FILE');
|
||||||
}
|
}
|
||||||
var ro = filesOp.isReadOnlyFile(el);
|
//var ro = filesOp.isReadOnlyFile(el);
|
||||||
var base = APP.origin;
|
var base = APP.origin;
|
||||||
var data = JSON.parse(JSON.stringify(filesOp.getFileData(el)));
|
var data = JSON.parse(JSON.stringify(filesOp.getFileData(el)));
|
||||||
if (!data || !data.href) { return void cb('INVALID_FILE'); }
|
if (!data || !(data.href || data.roHref)) { return void cb('INVALID_FILE'); }
|
||||||
data.href = base + data.href;
|
|
||||||
|
|
||||||
var roUrl;
|
if (data.href) {
|
||||||
if (ro) {
|
data.href = base + data.href;
|
||||||
data.roHref = data.href;
|
}
|
||||||
delete data.href;
|
if (data.roHref) {
|
||||||
} else {
|
data.roHref = base + data.roHref;
|
||||||
roUrl = getReadOnlyUrl(el);
|
|
||||||
if (roUrl) { data.roHref = base + roUrl; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
UIElements.getProperties(common, data, cb);
|
UIElements.getProperties(common, data, cb);
|
||||||
@@ -2804,10 +2788,15 @@ define([
|
|||||||
else if ($(this).hasClass('cp-app-drive-context-openro')) {
|
else if ($(this).hasClass('cp-app-drive-context-openro')) {
|
||||||
paths.forEach(function (p) {
|
paths.forEach(function (p) {
|
||||||
var el = filesOp.find(p.path);
|
var el = filesOp.find(p.path);
|
||||||
if (filesOp.isPathIn(p.path, [FILES_DATA])) { el = el.href; }
|
var href;
|
||||||
if (!el || filesOp.isFolder(el)) { return; }
|
if (filesOp.isPathIn(p.path, [FILES_DATA])) {
|
||||||
var roUrl = getReadOnlyUrl(el);
|
href = el.roHref;
|
||||||
openFile(null, roUrl);
|
} else {
|
||||||
|
if (!el || filesOp.isFolder(el)) { return; }
|
||||||
|
var data = filesOp.getFileData(el);
|
||||||
|
href = data.roHref;
|
||||||
|
}
|
||||||
|
openFile(null, href);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
else if ($(this).hasClass('cp-app-drive-context-newfolder')) {
|
else if ($(this).hasClass('cp-app-drive-context-newfolder')) {
|
||||||
@@ -2847,7 +2836,7 @@ define([
|
|||||||
el = filesOp.find(paths[0].path);
|
el = filesOp.find(paths[0].path);
|
||||||
var data = filesOp.getFileData(el);
|
var data = filesOp.getFileData(el);
|
||||||
if (!data) { return void console.error("Expected to find a file"); }
|
if (!data) { return void console.error("Expected to find a file"); }
|
||||||
var href = data.href;
|
var href = data.href || data.roHref;
|
||||||
common.updateTags(href);
|
common.updateTags(href);
|
||||||
}
|
}
|
||||||
else if ($(this).hasClass("cp-app-drive-context-empty")) {
|
else if ($(this).hasClass("cp-app-drive-context-empty")) {
|
||||||
|
|||||||
@@ -237,7 +237,8 @@ define([
|
|||||||
&& typeof files.template[0] === "number"
|
&& typeof files.template[0] === "number"
|
||||||
&& typeof files.filesData[files.template[0]] === "object"
|
&& typeof files.filesData[files.template[0]] === "object"
|
||||||
&& !files.filesData[files.template[0]].filename
|
&& !files.filesData[files.template[0]].filename
|
||||||
&& files.filesData[files.template[0]].href === href3
|
&& !files.filesData[files.template[0]].href
|
||||||
|
&& files.filesData[files.template[0]].roHref === href3
|
||||||
&& typeof fileId2 === "number"
|
&& typeof fileId2 === "number"
|
||||||
&& typeof files.filesData[fileId2] === "object"
|
&& typeof files.filesData[fileId2] === "object"
|
||||||
&& files.filesData[fileId2].filename === "Trash"
|
&& files.filesData[fileId2].filename === "Trash"
|
||||||
@@ -392,11 +393,6 @@ define([
|
|||||||
console.log("DRIVE operations: rename");
|
console.log("DRIVE operations: rename");
|
||||||
return cb();
|
return cb();
|
||||||
}
|
}
|
||||||
fo.replace(href1, href2);
|
|
||||||
if (fo.getFileData(id1).href !== href2) {
|
|
||||||
console.log("DRIVE operations: replace");
|
|
||||||
return cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
cb(true);
|
cb(true);
|
||||||
}, "DRIVE operations");
|
}, "DRIVE operations");
|
||||||
|
|||||||
Reference in New Issue
Block a user