Merge branch 'staging' into exportFolderTests
commit
2ee3b77a43
|
@ -169,6 +169,28 @@ define([], function () {
|
|||
height: 100%;
|
||||
background: #5cb85c;
|
||||
}
|
||||
|
||||
@keyframes spin {
|
||||
from {
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
to {
|
||||
transform: rotate(1800deg);
|
||||
}
|
||||
}
|
||||
|
||||
.cp-spinner {
|
||||
display: inline-block;
|
||||
box-sizing: border-box;
|
||||
width: 80px;
|
||||
height: 80px;
|
||||
border: 11px solid lightgrey;
|
||||
border-radius: 50%;
|
||||
border-top-color: transparent;
|
||||
animation: spin infinite 3s;
|
||||
animation-timing-function: cubic-bezier(.6,0.15,0.4,0.85);
|
||||
}
|
||||
|
||||
*/}).toString().slice(14, -3);
|
||||
var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; });
|
||||
var elem = document.createElement('div');
|
||||
|
@ -182,7 +204,7 @@ define([], function () {
|
|||
'</div>',
|
||||
'<div class="cp-loading-container">',
|
||||
'<div class="cp-loading-spinner-container">',
|
||||
'<span class="fa fa-spinner fa-pulse fa-4x fa-fw"></span>',
|
||||
'<span class="cp-spinner"></span>',
|
||||
'</div>',
|
||||
'<p id="cp-loading-message"></p>',
|
||||
'</div>'
|
||||
|
|
|
@ -22,13 +22,16 @@
|
|||
}
|
||||
}
|
||||
.dropdown-toggle {
|
||||
transform: rotate(270deg);
|
||||
margin-left: 1rem;
|
||||
float: right;
|
||||
}
|
||||
.dropdown-menu {
|
||||
top: -0.7rem;
|
||||
left: 100%;
|
||||
&.left {
|
||||
left: -10rem;
|
||||
left: 0%;
|
||||
transform: translate(-100%);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -230,9 +230,15 @@ define([
|
|||
if (!Visible.currently()) { to = window.setTimeout(interval, Thumb.UPDATE_FIRST); }
|
||||
};
|
||||
|
||||
|
||||
var addThumbnail = function (err, thumb, $span, cb) {
|
||||
var u8 = Nacl.util.decodeBase64(thumb.split(',')[1]);
|
||||
var blob = new Blob([u8], {
|
||||
type: 'image/png'
|
||||
});
|
||||
var url = URL.createObjectURL(blob);
|
||||
var img = new Image();
|
||||
img.src = thumb.slice(0,5) === 'data:' ? thumb : 'data:image/png;base64,'+thumb;
|
||||
img.src = url;
|
||||
$span.find('.cp-icon').hide();
|
||||
$span.prepend(img);
|
||||
cb($(img));
|
||||
|
|
|
@ -573,9 +573,9 @@ define([
|
|||
onFriendShare.reg(saveValue);
|
||||
var getLinkValue = function (initValue) {
|
||||
var val = initValue || {};
|
||||
var edit = initValue ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
|
||||
var embed = initValue ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
|
||||
var present = initValue ? val.present : Util.isChecked($(link).find('#cp-share-present'));
|
||||
var edit = val.edit !== undefined ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
|
||||
var embed = val.embed !== undefined ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
|
||||
var present = val.present !== undefined ? val.present : Util.isChecked($(link).find('#cp-share-present'));
|
||||
|
||||
var hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash;
|
||||
var href = origin + pathname + '#' + hash;
|
||||
|
@ -2104,6 +2104,9 @@ define([
|
|||
};
|
||||
|
||||
UIElements.createNewPadModal = function (common) {
|
||||
// if in drive, show new pad modal instead
|
||||
if ($("body.cp-app-drive").length !== 0) { return void $(".cp-app-drive-element-row.cp-app-drive-new-ghost").click(); }
|
||||
|
||||
var $modal = UIElements.createModal({
|
||||
id: 'cp-app-toolbar-creation-dialog',
|
||||
$body: $('body')
|
||||
|
@ -2766,8 +2769,12 @@ define([
|
|||
UIElements.displayCrowdfunding(common);
|
||||
modal.delete();
|
||||
});
|
||||
var waitingForStoringCb = false;
|
||||
$(store).click(function () {
|
||||
if (waitingForStoringCb) { return; }
|
||||
waitingForStoringCb = true;
|
||||
common.getSframeChannel().query("Q_AUTOSTORE_STORE", null, function (err, obj) {
|
||||
waitingForStoringCb = false;
|
||||
var error = err || (obj && obj.error);
|
||||
if (error) {
|
||||
if (error === 'E_OVER_LIMIT') {
|
||||
|
@ -2854,11 +2861,27 @@ define([
|
|||
'aria-labelledBy': 'dropdownMenu',
|
||||
'style': 'display:block;position:static;margin-bottom:5px;'
|
||||
}, [
|
||||
h('li', h('a.dropdown-item', {
|
||||
h('li', h('a.cp-app-code-context-saveindrive.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
}, Messages.pad_mediatagImport))
|
||||
'data-icon': "fa-cloud-upload",
|
||||
}, Messages.pad_mediatagImport)),
|
||||
h('li', h('a.cp-app-code-context-download.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': "fa-download",
|
||||
}, Messages.download_mt_button)),
|
||||
])
|
||||
]);
|
||||
// create the icon for each contextmenu option
|
||||
$(menu).find("li a.dropdown-item").each(function (i, el) {
|
||||
var $icon = $("<span>");
|
||||
if ($(el).attr('data-icon')) {
|
||||
var font = $(el).attr('data-icon').indexOf('cptools') === 0 ? 'cptools' : 'fa';
|
||||
$icon.addClass(font).addClass($(el).attr('data-icon'));
|
||||
} else {
|
||||
$icon.text($(el).text());
|
||||
}
|
||||
$(el).prepend($icon);
|
||||
});
|
||||
var m = createContextMenu(menu);
|
||||
|
||||
mediatagContextMenu = m;
|
||||
|
@ -2868,7 +2891,13 @@ define([
|
|||
e.stopPropagation();
|
||||
m.hide();
|
||||
var $mt = $menu.data('mediatag');
|
||||
common.importMediaTag($mt);
|
||||
if ($(this).hasClass("cp-app-code-context-saveindrive")) {
|
||||
common.importMediaTag($mt);
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-code-context-download")) {
|
||||
var media = $mt[0]._mediaObject;
|
||||
window.saveAs(media._blob.content, media.name);
|
||||
}
|
||||
});
|
||||
|
||||
return m;
|
||||
|
|
|
@ -319,6 +319,12 @@ define([], function () {
|
|||
return window.innerHeight < 800 || window.innerWidth < 800;
|
||||
};
|
||||
|
||||
Util.stripTags = function (text) {
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = text;
|
||||
return div.innerText;
|
||||
};
|
||||
|
||||
return Util;
|
||||
});
|
||||
}(self));
|
||||
|
|
|
@ -52,11 +52,12 @@ define([
|
|||
Object.keys(b).forEach(function (k) { a[k] = b[k]; });
|
||||
};
|
||||
|
||||
var get = function (hash, cb, opt) {
|
||||
var get = function (hash, cb, opt, progress) {
|
||||
if (typeof(cb) !== 'function') {
|
||||
throw new Error('Cryptget expects a callback');
|
||||
}
|
||||
opt = opt || {};
|
||||
progress = progress || function () {};
|
||||
|
||||
var config = makeConfig(hash, opt);
|
||||
var Session = { cb: cb, hasNetwork: Boolean(opt.network) };
|
||||
|
@ -65,6 +66,7 @@ define([
|
|||
var rt = Session.session = info.realtime;
|
||||
Session.network = info.network;
|
||||
Session.leave = info.leave;
|
||||
progress(1);
|
||||
finish(Session, void 0, rt.getUserDoc());
|
||||
};
|
||||
|
||||
|
@ -72,6 +74,16 @@ define([
|
|||
finish(Session, info.error);
|
||||
};
|
||||
|
||||
// We use the new onMessage handler to compute the progress:
|
||||
// we should receive 2 checkpoints max, so 100 messages max
|
||||
// We're going to consider that 1 message = 1%, and we'll send 100%
|
||||
// at the end
|
||||
var i = 0;
|
||||
config.onMessage = function () {
|
||||
i++;
|
||||
progress(Math.min(0.99, i/100));
|
||||
};
|
||||
|
||||
overwrite(config, opt);
|
||||
|
||||
Session.realtime = CPNetflux.start(config);
|
||||
|
|
|
@ -254,8 +254,12 @@ define([
|
|||
common.clearOwnedChannel = function (channel, cb) {
|
||||
postMessage("CLEAR_OWNED_CHANNEL", channel, cb);
|
||||
};
|
||||
common.removeOwnedChannel = function (channel, cb) {
|
||||
postMessage("REMOVE_OWNED_CHANNEL", channel, cb);
|
||||
// "force" allows you to delete your drive ID
|
||||
common.removeOwnedChannel = function (channel, cb, force) {
|
||||
postMessage("REMOVE_OWNED_CHANNEL", {
|
||||
channel: channel,
|
||||
force: force
|
||||
}, cb);
|
||||
};
|
||||
|
||||
common.getDeletedPads = function (data, cb) {
|
||||
|
@ -950,7 +954,7 @@ define([
|
|||
common.logoutFromAll(waitFor(function () {
|
||||
postMessage("DISCONNECT");
|
||||
}));
|
||||
}));
|
||||
}), true);
|
||||
}
|
||||
}).nThen(function (waitFor) {
|
||||
if (!oldIsOwned) {
|
||||
|
|
|
@ -15,6 +15,7 @@ define([
|
|||
|
||||
var DiffDOM = window.diffDOM;
|
||||
var renderer = new Marked.Renderer();
|
||||
var restrictedRenderer = new Marked.Renderer();
|
||||
|
||||
var Mermaid = {
|
||||
init: function () {}
|
||||
|
@ -61,13 +62,18 @@ define([
|
|||
return h('div.cp-md-toc', content).outerHTML;
|
||||
};
|
||||
|
||||
DiffMd.render = function (md, sanitize) {
|
||||
DiffMd.render = function (md, sanitize, restrictedMd) {
|
||||
Marked.setOptions({
|
||||
renderer: restrictedMd ? restrictedRenderer : renderer,
|
||||
});
|
||||
var r = Marked(md, {
|
||||
sanitize: sanitize
|
||||
});
|
||||
|
||||
// Add Table of Content
|
||||
r = r.replace(/<div class="cp-md-toc"><\/div>/g, getTOC());
|
||||
if (!restrictedMd) {
|
||||
r = r.replace(/<div class="cp-md-toc"><\/div>/g, getTOC());
|
||||
}
|
||||
toc = [];
|
||||
|
||||
return r;
|
||||
|
@ -83,12 +89,7 @@ define([
|
|||
return defaultCode.apply(renderer, arguments);
|
||||
}
|
||||
};
|
||||
|
||||
var stripTags = function (text) {
|
||||
var div = document.createElement("div");
|
||||
div.innerHTML = text;
|
||||
return div.innerText;
|
||||
};
|
||||
restrictedRenderer.code = renderer.code;
|
||||
|
||||
renderer.heading = function (text, level) {
|
||||
var i = 0;
|
||||
|
@ -105,10 +106,13 @@ define([
|
|||
toc.push({
|
||||
level: level,
|
||||
id: id,
|
||||
title: stripTags(text)
|
||||
title: Util.stripTags(text)
|
||||
});
|
||||
return "<h" + level + " id=\"" + id + "\"><a href=\"#" + id + "\" class=\"anchor\"></a>" + text + "</h" + level + ">";
|
||||
};
|
||||
restrictedRenderer.heading = function (text) {
|
||||
return text;
|
||||
};
|
||||
|
||||
// Tasks list
|
||||
var checkedTaskItemPtn = /^\s*(<p>)?\[[xX]\](<\/p>)?\s*/;
|
||||
|
@ -138,6 +142,13 @@ define([
|
|||
var cls = (isCheckedTaskItem || isUncheckedTaskItem || hasBogusInput) ? ' class="todo-list-item"' : '';
|
||||
return '<li'+ cls + '>' + text + '</li>\n';
|
||||
};
|
||||
restrictedRenderer.listitem = function (text) {
|
||||
if (bogusCheckPtn.test(text)) {
|
||||
text = text.replace(bogusCheckPtn, '');
|
||||
}
|
||||
return '<li>' + text + '</li>\n';
|
||||
};
|
||||
|
||||
renderer.image = function (href, title, text) {
|
||||
if (href.slice(0,6) === '/file/') {
|
||||
// DEPRECATED
|
||||
|
@ -162,12 +173,19 @@ define([
|
|||
out += this.options.xhtml ? '/>' : '>';
|
||||
return out;
|
||||
};
|
||||
restrictedRenderer.image = renderer.image;
|
||||
|
||||
var renderParagraph = function (p) {
|
||||
return /<media\-tag[\s\S]*>/i.test(p)? p + '\n': '<p>' + p + '</p>\n';
|
||||
};
|
||||
renderer.paragraph = function (p) {
|
||||
if (p === '[TOC]') {
|
||||
return '<p><div class="cp-md-toc"></div></p>';
|
||||
}
|
||||
return /<media\-tag[\s\S]*>/i.test(p)? p + '\n': '<p>' + p + '</p>\n';
|
||||
return renderParagraph(p);
|
||||
};
|
||||
restrictedRenderer.paragraph = function (p) {
|
||||
return renderParagraph(p);
|
||||
};
|
||||
|
||||
var MutationObserver = window.MutationObserver;
|
||||
|
|
|
@ -30,9 +30,22 @@
|
|||
};
|
||||
|
||||
|
||||
var isplainTextFile = function (metadata) {
|
||||
// does its type begins with "text/"
|
||||
if (metadata.type.indexOf("text/") === 0) { return true; }
|
||||
// no type and no file extension -> let's guess it's plain text
|
||||
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(metadata.name) || [];
|
||||
if (!metadata.type && !parsedName[2]) { return true; }
|
||||
// other exceptions
|
||||
if (metadata.type === 'application/x-javascript') { return true; }
|
||||
if (metadata.type === 'application/xml') { return true; }
|
||||
return false;
|
||||
};
|
||||
|
||||
// Default config, can be overriden per media-tag call
|
||||
var config = {
|
||||
allowed: [
|
||||
'text/plain',
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
|
@ -53,6 +66,23 @@
|
|||
text: "Download"
|
||||
},
|
||||
Plugins: {
|
||||
/**
|
||||
* @param {object} metadataObject {name, metadatatype, owners} containing metadata of the file
|
||||
* @param {strint} url Url of the blob object
|
||||
* @param {Blob} content Blob object containing the data of the file
|
||||
* @param {object} cfg Object {Plugins, allowed, download, pdf} containing infos about plugins
|
||||
* @param {function} cb Callback function: (err, pluginElement) => {}
|
||||
*/
|
||||
text: function (metadata, url, content, cfg, cb) {
|
||||
var plainText = document.createElement('div');
|
||||
plainText.className = "plain-text-reader";
|
||||
var reader = new FileReader();
|
||||
reader.addEventListener('loadend', function (e) {
|
||||
plainText.innerText = e.srcElement.result;
|
||||
cb(void 0, plainText);
|
||||
});
|
||||
reader.readAsText(content);
|
||||
},
|
||||
image: function (metadata, url, content, cfg, cb) {
|
||||
var img = document.createElement('img');
|
||||
img.setAttribute('src', url);
|
||||
|
@ -271,6 +301,9 @@
|
|||
var blob = decrypted.content;
|
||||
|
||||
var mediaType = getType(mediaObject, metadata, cfg);
|
||||
if (isplainTextFile(metadata)) {
|
||||
mediaType = "text";
|
||||
}
|
||||
|
||||
if (mediaType === 'application') {
|
||||
mediaType = mediaObject.extension;
|
||||
|
|
|
@ -151,7 +151,7 @@ define([
|
|||
});
|
||||
try {
|
||||
var $d = $(d);
|
||||
DiffMd.apply(DiffMd.render(md || '', true), $d, common);
|
||||
DiffMd.apply(DiffMd.render(md || '', true, true), $d, common);
|
||||
$d.addClass("cp-app-contacts-content");
|
||||
|
||||
// override link clicking, because we're in an iframe
|
||||
|
@ -197,7 +197,7 @@ define([
|
|||
var getChat = function (id) {
|
||||
return $messages.find(dataQuery(id));
|
||||
};
|
||||
|
||||
|
||||
var scrollChatToBottom = function () {
|
||||
var $messagebox = $('.cp-app-contacts-messages');
|
||||
$messagebox.scrollTop($messagebox[0].scrollHeight);
|
||||
|
|
|
@ -99,6 +99,7 @@ define(['json.sortify'], function (Sortify) {
|
|||
var addAuthor = function () {
|
||||
if (!meta.user || !meta.user.netfluxId || !priv || !priv.edPublic) { return; }
|
||||
var authors = metadataObj.authors || {};
|
||||
var old = Sortify(authors);
|
||||
if (!authors[priv.edPublic]) {
|
||||
authors[priv.edPublic] = {
|
||||
nId: [meta.user.netfluxId],
|
||||
|
@ -110,9 +111,11 @@ define(['json.sortify'], function (Sortify) {
|
|||
authors[priv.edPublic].nId.push(meta.user.netfluxId);
|
||||
}
|
||||
}
|
||||
metadataObj.authors = authors;
|
||||
metadataLazyObj.authors = JSON.parse(JSON.stringify(authors));
|
||||
change();
|
||||
if (Sortify(authors) !== old) {
|
||||
metadataObj.authors = authors;
|
||||
metadataLazyObj.authors = JSON.parse(JSON.stringify(authors));
|
||||
change();
|
||||
}
|
||||
};
|
||||
|
||||
var netfluxId;
|
||||
|
|
|
@ -34,7 +34,7 @@ define([
|
|||
var sendDriveEvent = function () {};
|
||||
var registerProxyEvents = function () {};
|
||||
|
||||
var storeHash;
|
||||
var storeHash, storeChannel;
|
||||
|
||||
var store = window.CryptPad_AsyncStore = {
|
||||
modules: {}
|
||||
|
@ -239,6 +239,20 @@ define([
|
|||
|
||||
Store.removeOwnedChannel = function (clientId, data, cb) {
|
||||
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); }
|
||||
|
||||
// "data" used to be a string (channelID), now it can also be an object
|
||||
// data.force tells us we can safely remove the drive ID
|
||||
var channel = data;
|
||||
var force = false;
|
||||
if (data && typeof(data) === "object") {
|
||||
channel = data.channel;
|
||||
force = data.force;
|
||||
}
|
||||
|
||||
if (channel === storeChannel && !force) {
|
||||
return void cb({error: 'User drive removal blocked!'});
|
||||
}
|
||||
|
||||
store.rpc.removeOwnedChannel(data, function (err) {
|
||||
cb({error:err});
|
||||
});
|
||||
|
@ -573,7 +587,10 @@ define([
|
|||
}));
|
||||
}).nThen(function (waitFor) {
|
||||
// Delete Drive
|
||||
Store.removeOwnedChannel(clientId, secret.channel, waitFor());
|
||||
Store.removeOwnedChannel(clientId, {
|
||||
channel: secret.channel,
|
||||
force: true
|
||||
}, waitFor());
|
||||
}).nThen(function () {
|
||||
store.network.disconnect();
|
||||
cb({
|
||||
|
@ -786,6 +803,7 @@ define([
|
|||
var h = p.hashData;
|
||||
|
||||
if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); }
|
||||
if (p.type === "debug") { return void cb(); }
|
||||
|
||||
var channelData = Store.channels && Store.channels[channel];
|
||||
|
||||
|
@ -1090,7 +1108,6 @@ define([
|
|||
var channels = Store.channels = store.channels = {};
|
||||
|
||||
Store.joinPad = function (clientId, data) {
|
||||
console.log('joining', data.channel);
|
||||
var isNew = typeof channels[data.channel] === "undefined";
|
||||
var channel = channels[data.channel] = channels[data.channel] || {
|
||||
queue: [],
|
||||
|
@ -1915,6 +1932,7 @@ define([
|
|||
}
|
||||
// No password for drive
|
||||
var secret = Hash.getSecrets('drive', hash);
|
||||
storeChannel = secret.channel;
|
||||
var listmapConfig = {
|
||||
data: {},
|
||||
websocketURL: NetConfig.getWebsocketURL(),
|
||||
|
|
|
@ -99,9 +99,17 @@ define([
|
|||
// lines beginning with a hash are potentially valuable
|
||||
// works for markdown, python, bash, etc.
|
||||
var hash = /^#+(.*?)$/;
|
||||
var hashAndLink = /^#+\s*\[(.*?)\]\(.*\)\s*$/;
|
||||
if (hash.test(line)) {
|
||||
// test for link inside the title, and set text just to the name of the link
|
||||
if (hashAndLink.test(line)) {
|
||||
line.replace(hashAndLink, function (a, one) {
|
||||
text = Util.stripTags(one);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
line.replace(hash, function (a, one) {
|
||||
text = one;
|
||||
text = Util.stripTags(one);
|
||||
});
|
||||
return true;
|
||||
}
|
||||
|
@ -387,21 +395,32 @@ define([
|
|||
exp.mkIndentSettings = function (metadataMgr) {
|
||||
var setIndentation = function (units, useTabs, fontSize, spellcheck) {
|
||||
if (typeof(units) !== 'number') { return; }
|
||||
var doc = editor.getDoc();
|
||||
editor.setOption('indentUnit', units);
|
||||
editor.setOption('tabSize', units);
|
||||
editor.setOption('indentWithTabs', useTabs);
|
||||
editor.setOption('spellcheck', spellcheck);
|
||||
if (!useTabs) {
|
||||
editor.setOption("extraKeys", {
|
||||
Tab: function() {
|
||||
editor.replaceSelection(Array(units + 1).join(" "));
|
||||
editor.setOption("extraKeys", {
|
||||
Tab: function() {
|
||||
if (doc.somethingSelected()) {
|
||||
editor.execCommand("indentMore");
|
||||
}
|
||||
});
|
||||
} else {
|
||||
editor.setOption("extraKeys", {
|
||||
Tab: undefined,
|
||||
});
|
||||
}
|
||||
else {
|
||||
if (!useTabs) { editor.execCommand("insertSoftTab"); }
|
||||
else { editor.execCommand("insertTab"); }
|
||||
}
|
||||
},
|
||||
"Shift-Tab": function () {
|
||||
editor.execCommand("indentLess");
|
||||
},
|
||||
"Backspace": function () {
|
||||
var cursor = doc.getCursor();
|
||||
var line = doc.getLine(cursor.line);
|
||||
if (line.substring(0, cursor.ch).trim() === "") { editor.execCommand("indentLess"); }
|
||||
else { editor.execCommand("delCharBefore"); }
|
||||
|
||||
},
|
||||
});
|
||||
$('.CodeMirror').css('font-size', fontSize+'px');
|
||||
};
|
||||
|
||||
|
|
|
@ -838,13 +838,6 @@ define([
|
|||
Cryptpad.setLanguage(data, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_CLEAR_OWNED_CHANNEL', function (channel, cb) {
|
||||
Cryptpad.clearOwnedChannel(channel, cb);
|
||||
});
|
||||
sframeChan.on('Q_REMOVE_OWNED_CHANNEL', function (channel, cb) {
|
||||
Cryptpad.removeOwnedChannel(channel, cb);
|
||||
});
|
||||
|
||||
sframeChan.on('Q_GET_ALL_TAGS', function (data, cb) {
|
||||
Cryptpad.listAllTags(function (err, tags) {
|
||||
cb({
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
@drive_content-bg-ro: darken(@drive_content-bg, 10%);
|
||||
|
||||
@drive_selected-bg: #888;
|
||||
@drive_droppable-bg: #FE9A2E;
|
||||
|
||||
|
||||
/* PAGE */
|
||||
|
@ -107,7 +108,7 @@
|
|||
|
||||
.cp-app-drive-container {
|
||||
flex: 1;
|
||||
overflow: auto;
|
||||
overflow-x: auto;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
flex-flow: row;
|
||||
|
@ -121,6 +122,7 @@
|
|||
#cp-app-drive-tree {
|
||||
resize: none;
|
||||
width: 100% !important;
|
||||
min-width: unset;
|
||||
max-width: unset;
|
||||
max-height: unset;
|
||||
border-bottom: 1px solid @drive_mobile-tree-border-col;
|
||||
|
@ -156,7 +158,7 @@
|
|||
}
|
||||
|
||||
.cp-app-drive-element-droppable {
|
||||
background-color: #FE9A2E;
|
||||
background-color: @drive_droppable-bg;
|
||||
color: #222;
|
||||
}
|
||||
|
||||
|
@ -239,7 +241,6 @@
|
|||
max-height: 100%;
|
||||
.cp-app-drive-tree-categories-container {
|
||||
flex: 1;
|
||||
max-width: 500px;
|
||||
overflow: auto;
|
||||
}
|
||||
img.cp-app-drive-icon {
|
||||
|
@ -438,13 +439,13 @@
|
|||
flex: 1;
|
||||
// Needed to avoid the folder's path to overflows
|
||||
// https://stackoverflow.com/questions/38223879/white-space-nowrap-breaks-flexbox-layout
|
||||
min-width: 0;
|
||||
// min-width: 0;
|
||||
}
|
||||
#cp-app-drive-content {
|
||||
box-sizing: border-box;
|
||||
background: @drive_content-bg;
|
||||
color: @drive_content-fg;
|
||||
overflow: auto;
|
||||
overflow-y: auto;
|
||||
flex: 1;
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
|
@ -939,6 +940,7 @@
|
|||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
transition: all 0.15s;
|
||||
cursor: pointer;
|
||||
|
||||
&:first-child {
|
||||
flex-shrink: 1;
|
||||
|
@ -946,17 +948,20 @@
|
|||
|
||||
&.cp-app-drive-path-separator {
|
||||
color: #ccc;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
&.cp-app-drive-path-collapse {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
&:hover {
|
||||
&.cp-app-drive-element-droppable {
|
||||
background-color: @drive_droppable-bg;
|
||||
}
|
||||
&:not(.cp-app-drive-element-droppable):hover {
|
||||
&:not(.cp-app-drive-path-separator) {
|
||||
background-color: darken(@colortheme_drive-bg, 15%);
|
||||
text-decoration: underline;
|
||||
cursor: pointer;
|
||||
}
|
||||
& ~ .cp-app-drive-path-element {
|
||||
background-color: darken(@colortheme_drive-bg, 15%);
|
||||
|
|
|
@ -18,8 +18,6 @@ define([
|
|||
'/bower_components/chainpad-listmap/chainpad-listmap.js',
|
||||
'/customize/messages.js',
|
||||
|
||||
'/common/jscolor.js',
|
||||
|
||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
'less!/drive/app-drive.less',
|
||||
|
@ -45,7 +43,10 @@ define([
|
|||
{
|
||||
var APP = window.APP = {
|
||||
editable: false,
|
||||
mobile: function () { return $('body').width() <= 600; }, // Menu and content area are not inline-block anymore for mobiles
|
||||
mobile: function () {
|
||||
if (window.matchMedia) { return !window.matchMedia('(any-pointer:fine)').matches; }
|
||||
else { return $('body').width() <= 600; }
|
||||
},
|
||||
isMac: navigator.platform === "MacIntel",
|
||||
};
|
||||
|
||||
|
@ -301,6 +302,33 @@ define([
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
APP.selectedFiles = [];
|
||||
|
||||
var isElementSelected = function ($element) {
|
||||
var elementId = $element.data("path").slice(-1)[0];
|
||||
return APP.selectedFiles.indexOf(elementId) !== -1;
|
||||
};
|
||||
var selectElement = function ($element) {
|
||||
var elementId = $element.data("path").slice(-1)[0];
|
||||
if (APP.selectedFiles.indexOf(elementId) === -1) {
|
||||
APP.selectedFiles.push(elementId);
|
||||
}
|
||||
$element.addClass("cp-app-drive-element-selected");
|
||||
};
|
||||
var unselectElement = function ($element) {
|
||||
var elementId = $element.data("path").slice(-1)[0];
|
||||
var index = APP.selectedFiles.indexOf(elementId);
|
||||
if (index !== -1) {
|
||||
APP.selectedFiles.splice(index, 1);
|
||||
}
|
||||
$element.removeClass("cp-app-drive-element-selected");
|
||||
};
|
||||
var findSelectedElements = function () {
|
||||
return $(".cp-app-drive-element-selected");
|
||||
};
|
||||
|
||||
|
||||
var createContextMenu = function () {
|
||||
var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [
|
||||
h('ul.dropdown-menu', {
|
||||
|
@ -365,16 +393,34 @@ define([
|
|||
'data-icon': AppConfig.applicationsIcon.slide,
|
||||
'data-type': 'slide'
|
||||
}, Messages.button_newslide)),
|
||||
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': AppConfig.applicationsIcon.poll,
|
||||
'data-type': 'poll'
|
||||
}, Messages.button_newpoll)),
|
||||
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': AppConfig.applicationsIcon.whiteboard,
|
||||
'data-type': 'whiteboard'
|
||||
}, Messages.button_newwhiteboard)),
|
||||
h('li.dropdown-submenu', [
|
||||
h('a.cp-app-drive-context-newdocmenu.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': "fa-plus",
|
||||
}, Messages.fm_morePads || "More pads"), //XXX
|
||||
h("ul.dropdown-menu", [
|
||||
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': AppConfig.applicationsIcon.sheet,
|
||||
'data-type': 'sheet'
|
||||
}, Messages.button_newsheet)),
|
||||
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': AppConfig.applicationsIcon.whiteboard,
|
||||
'data-type': 'whiteboard'
|
||||
}, Messages.button_newwhiteboard)),
|
||||
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': AppConfig.applicationsIcon.kanban,
|
||||
'data-type': 'kanban'
|
||||
}, Messages.button_newkanban)),
|
||||
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': AppConfig.applicationsIcon.poll,
|
||||
'data-type': 'poll'
|
||||
}, Messages.button_newpoll)),
|
||||
]),
|
||||
]),
|
||||
$separator.clone()[0],
|
||||
h('li', h('a.cp-app-drive-context-empty.dropdown-item.cp-app-drive-context-editable', {
|
||||
'tabindex': '-1',
|
||||
|
@ -420,6 +466,7 @@ define([
|
|||
}, Messages.fc_remove_sharedfolder)),
|
||||
])
|
||||
]);
|
||||
// add icons to the contextmenu options
|
||||
$(menu).find("li a.dropdown-item").each(function (i, el) {
|
||||
var $icon = $("<span>");
|
||||
if ($(el).attr('data-icon')) {
|
||||
|
@ -430,21 +477,46 @@ define([
|
|||
}
|
||||
$(el).prepend($icon);
|
||||
});
|
||||
// add events handlers for the contextmenu submenus
|
||||
$(menu).find(".dropdown-submenu").each(function (i, el) {
|
||||
var $el = $(el);
|
||||
var $a = $el.children().filter("a");
|
||||
var $sub = $el.find(".dropdown-menu").first();
|
||||
var timeoutId;
|
||||
var showSubmenu = function () {
|
||||
clearTimeout(timeoutId);
|
||||
$sub.toggleClass("left", $el.offset().left + $el.outerWidth() + $sub.outerWidth() > $(window).width());
|
||||
$el.siblings().find(".dropdown-menu").hide();
|
||||
$sub.show();
|
||||
};
|
||||
var hideSubmenu = function () {
|
||||
$sub.hide();
|
||||
$sub.removeClass("left");
|
||||
};
|
||||
var mouseOutSubmenu = function () {
|
||||
// don't hide immediately the submenu
|
||||
timeoutId = setTimeout(hideSubmenu, 100);
|
||||
};
|
||||
// Add submenu expand icon
|
||||
$a.append(h("span.dropdown-toggle"));
|
||||
// Show / hide submenu
|
||||
$el.hover(function () {
|
||||
setTimeout(function () { // wait for dom to update
|
||||
$sub.toggleClass("left", $el.offset().left + $el.outerWidth() + $sub.outerWidth() > $(window).width());
|
||||
$sub.show();
|
||||
});
|
||||
showSubmenu();
|
||||
}, function () {
|
||||
$sub.hide();
|
||||
$sub.removeClass("left");
|
||||
mouseOutSubmenu();
|
||||
});
|
||||
// handle click event
|
||||
$el.click(function (e) {
|
||||
var targetItem = $(e.target).closest(".dropdown-item")[0]; // don't close contextmenu if open submenu
|
||||
var elTarget = $el.children(".dropdown-item")[0];
|
||||
if (targetItem === elTarget) { e.stopPropagation(); }
|
||||
if ($el.children().filter(".dropdown-menu:visible").length !== 0) {
|
||||
$el.find(".dropdown-menu").hide();
|
||||
hideSubmenu();
|
||||
}
|
||||
else {
|
||||
showSubmenu();
|
||||
}
|
||||
});
|
||||
});
|
||||
return $(menu);
|
||||
|
@ -570,7 +642,8 @@ define([
|
|||
var sel = {};
|
||||
|
||||
var removeSelected = function (keepObj) {
|
||||
$('.cp-app-drive-element-selected').removeClass("cp-app-drive-element-selected");
|
||||
APP.selectedFiles = [];
|
||||
findSelectedElements().removeClass("cp-app-drive-element-selected");
|
||||
var $container = $driveToolbar.find('#cp-app-drive-toolbar-contextbuttons');
|
||||
if (!$container.length) { return; }
|
||||
$container.html('');
|
||||
|
@ -680,7 +753,9 @@ define([
|
|||
delete sel.move;
|
||||
$content.find('.cp-app-drive-element-selected-tmp')
|
||||
.removeClass('cp-app-drive-element-selected-tmp')
|
||||
.addClass('cp-app-drive-element-selected');
|
||||
.each(function (idx, element) {
|
||||
selectElement($(element));
|
||||
});
|
||||
e.stopPropagation();
|
||||
});
|
||||
|
||||
|
@ -715,7 +790,9 @@ define([
|
|||
// Ctrl+A select all
|
||||
if (e.which === 65 && (e.ctrlKey || (e.metaKey && APP.isMac))) {
|
||||
$content.find('.cp-app-drive-element:not(.cp-app-drive-element-selected)')
|
||||
.addClass('cp-app-drive-element-selected');
|
||||
.each(function (idx, element) {
|
||||
selectElement($(element));
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -728,7 +805,7 @@ define([
|
|||
APP.onElementClick(ev, $(el));
|
||||
};
|
||||
|
||||
var $selection = $content.find('.cp-app-drive-element.cp-app-drive-element-selected');
|
||||
var $selection = findSelectedElements();
|
||||
if ($selection.length === 0) { return void click($elements.first()[0]); }
|
||||
|
||||
var lastIndex = typeof sel.endSelected === "number" ? sel.endSelected :
|
||||
|
@ -847,12 +924,12 @@ define([
|
|||
return;
|
||||
}
|
||||
removeInput();
|
||||
removeSelected();
|
||||
var $name = $element.find('.cp-app-drive-element-name');
|
||||
if (!$name.length) {
|
||||
$name = $element.find('> .cp-app-drive-element');
|
||||
}
|
||||
$name.hide();
|
||||
var isFolder = $element.is(".cp-app-drive-element-folder:not(.cp-app-drive-element-sharedf)");
|
||||
var el = manager.find(path);
|
||||
var name = manager.isFile(el) ? manager.getTitle(el) : path[path.length - 1];
|
||||
if (manager.isSharedFolder(el)) {
|
||||
|
@ -874,14 +951,21 @@ define([
|
|||
var newName = $input.val();
|
||||
if (JSON.stringify(path) === JSON.stringify(currentPath)) {
|
||||
manager.rename(path, $input.val(), function () {
|
||||
renameFoldersOpened(path, newName);
|
||||
path[path.length - 1] = newName;
|
||||
if (isFolder) {
|
||||
renameFoldersOpened(path, newName);
|
||||
path[path.length - 1] = newName;
|
||||
}
|
||||
APP.displayDirectory(path);
|
||||
});
|
||||
}
|
||||
else {
|
||||
manager.rename(path, $input.val(), function () {
|
||||
renameFoldersOpened(path, newName);
|
||||
if (isFolder) {
|
||||
renameFoldersOpened(path, newName);
|
||||
unselectElement($element);
|
||||
$element.data("path", $element.data("path").slice(0, -1).concat(newName));
|
||||
selectElement($element);
|
||||
}
|
||||
refresh();
|
||||
});
|
||||
}
|
||||
|
@ -902,7 +986,6 @@ define([
|
|||
|
||||
// We don't want to open the file/folder when clicking on the input
|
||||
$input.on('click dblclick', function (e) {
|
||||
removeSelected();
|
||||
e.stopPropagation();
|
||||
});
|
||||
// Remove the browser ability to drag text from the input to avoid
|
||||
|
@ -1119,8 +1202,9 @@ define([
|
|||
|
||||
var getSelectedPaths = function ($element) {
|
||||
var paths = [];
|
||||
if ($('.cp-app-drive-element-selected').length > 1) {
|
||||
var $selected = $('.cp-app-drive-element-selected');
|
||||
if (!$element || $element.length === 0) { return paths; }
|
||||
if (findSelectedElements().length > 1) {
|
||||
var $selected = findSelectedElements();
|
||||
$selected.each(function (idx, elmt) {
|
||||
var ePath = $(elmt).data('path');
|
||||
if (ePath) {
|
||||
|
@ -1149,7 +1233,7 @@ define([
|
|||
} else {
|
||||
$driveToolbar.find('cp-app-drive-toolbar-emptytrash').hide();
|
||||
}
|
||||
var $li = $content.find('.cp-app-drive-element-selected');
|
||||
var $li = findSelectedElements();
|
||||
if ($li.length === 0) {
|
||||
$li = findDataHolder($tree.find('.cp-app-drive-element-active'));
|
||||
}
|
||||
|
@ -1216,6 +1300,7 @@ define([
|
|||
if (pos+eh <= h && pos >= 0) { return; }
|
||||
$content.scrollTop(v);
|
||||
};
|
||||
|
||||
// Add the "selected" class to the "li" corresponding to the clicked element
|
||||
var onElementClick = APP.onElementClick = function (e, $element) {
|
||||
// If "Ctrl" is pressed, do not remove the current selection
|
||||
|
@ -1252,34 +1337,33 @@ define([
|
|||
var $el;
|
||||
removeSelected(true);
|
||||
sel.oldSelection.forEach(function (el) {
|
||||
if (!$(el).hasClass("cp-app-drive-element-selected")) {
|
||||
$(el).addClass("cp-app-drive-element-selected");
|
||||
if (!isElementSelected($(el))) {
|
||||
selectElement($(el));
|
||||
}
|
||||
});
|
||||
for (var i = Math.min(sel.startSelected, sel.endSelected);
|
||||
i <= Math.max(sel.startSelected, sel.endSelected);
|
||||
i++) {
|
||||
$el = $($elements.get(i));
|
||||
if (!$el.hasClass("cp-app-drive-element-selected")) {
|
||||
$el.addClass("cp-app-drive-element-selected");
|
||||
if (!isElementSelected($el)) {
|
||||
selectElement($el);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (!$element.hasClass("cp-app-drive-element-selected")) {
|
||||
$element.addClass("cp-app-drive-element-selected");
|
||||
if (!isElementSelected($element)) {
|
||||
selectElement($element);
|
||||
} else {
|
||||
$element.removeClass("cp-app-drive-element-selected");
|
||||
unselectElement($element);
|
||||
}
|
||||
}
|
||||
updateContextButton();
|
||||
};
|
||||
|
||||
var displayMenu = function (e) {
|
||||
var $menu = $contextMenu;
|
||||
// show / hide dropdown separators
|
||||
var hideSeparators = function ($menu) {
|
||||
var showSep = false;
|
||||
var $lastVisibleSep = null;
|
||||
// show / hide drop-down divider
|
||||
$menu.find(".dropdown-menu").children().each(function (i, el) {
|
||||
$menu.children().each(function (i, el) {
|
||||
var $el = $(el);
|
||||
if ($el.is(".dropdown-divider")) {
|
||||
$el.css("display", showSep ? "list-item" : "none");
|
||||
|
@ -1291,18 +1375,36 @@ define([
|
|||
}
|
||||
});
|
||||
if (!showSep && $lastVisibleSep) { $lastVisibleSep.css("display", "none"); } // remove last divider if no options after
|
||||
};
|
||||
|
||||
// prepare and display contextmenu
|
||||
var displayMenu = function (e) {
|
||||
var $menu = $contextMenu;
|
||||
// show / hide submenus
|
||||
$menu.find(".dropdown-submenu").each(function (i, el) {
|
||||
var $el = $(el);
|
||||
$el.children(".dropdown-menu").css("display", "none");
|
||||
$el.find("li").each(function (i, li) {
|
||||
if ($(li).css("display") !== "none") {
|
||||
$(el).css("display", "block");
|
||||
$el.css("display", "block");
|
||||
return;
|
||||
}
|
||||
});
|
||||
});
|
||||
// show / hide separators
|
||||
$menu.find(".dropdown-menu").each(function (i, menu) {
|
||||
hideSeparators($(menu));
|
||||
});
|
||||
// show contextmenu at cursor position
|
||||
$menu.css({ display: "block" });
|
||||
if (APP.mobile()) { return; }
|
||||
if (APP.mobile()) {
|
||||
$menu.css({
|
||||
top: ($("#cp-app-drive-toolbar-context-mobile").offset().top + 32) + 'px',
|
||||
right: '0px',
|
||||
left: ''
|
||||
});
|
||||
return;
|
||||
}
|
||||
var h = $menu.outerHeight();
|
||||
var w = $menu.outerWidth();
|
||||
var wH = window.innerHeight;
|
||||
|
@ -1355,6 +1457,17 @@ define([
|
|||
} else {
|
||||
var $element = findDataHolder($(e.target));
|
||||
|
||||
// if clicked from tree
|
||||
var fromTree = $element.closest("#cp-app-drive-tree").length;
|
||||
if (fromTree) {
|
||||
removeSelected();
|
||||
}
|
||||
|
||||
// if clicked on non selected element
|
||||
if (!isElementSelected($element)) {
|
||||
removeSelected();
|
||||
}
|
||||
|
||||
if (type === 'trash' && !$element.data('path')) { return; }
|
||||
|
||||
if (!$element.length) {
|
||||
|
@ -1363,8 +1476,8 @@ define([
|
|||
return false;
|
||||
}
|
||||
|
||||
if (!$element.hasClass('cp-app-drive-element-selected')) {
|
||||
onElementClick(undefined, $element);
|
||||
if (!isElementSelected($element)) {
|
||||
selectElement($element);
|
||||
}
|
||||
|
||||
paths = getSelectedPaths($element);
|
||||
|
@ -1434,6 +1547,7 @@ define([
|
|||
if (!res) { return; }
|
||||
manager.delete(pathsList, function () {
|
||||
pathsList.forEach(removeFoldersOpened);
|
||||
removeSelected();
|
||||
refresh();
|
||||
});
|
||||
}, null, true);
|
||||
|
@ -1444,7 +1558,7 @@ define([
|
|||
var paths = [];
|
||||
var $element = findDataHolder($(ev.target));
|
||||
if ($element.hasClass('cp-app-drive-element-selected')) {
|
||||
var $selected = $('.cp-app-drive-element-selected');
|
||||
var $selected = findSelectedElements();
|
||||
$selected.each(function (idx, elmt) {
|
||||
var ePath = $(elmt).data('path');
|
||||
if (ePath) {
|
||||
|
@ -1461,7 +1575,7 @@ define([
|
|||
});
|
||||
} else {
|
||||
removeSelected();
|
||||
$element.addClass('cp-app-drive-element-selected');
|
||||
selectElement($element);
|
||||
var val = manager.find(path);
|
||||
if (!val) { return; } // The element is not in the object
|
||||
paths = [{
|
||||
|
@ -1480,7 +1594,13 @@ define([
|
|||
|
||||
var findDropPath = function (target) {
|
||||
var $target = $(target);
|
||||
var $el = findDataHolder($target);
|
||||
var $el;
|
||||
if ($target.is(".cp-app-drive-path-element")) {
|
||||
$el = $target;
|
||||
}
|
||||
else {
|
||||
$el = findDataHolder($target);
|
||||
}
|
||||
var newPath = $el.data('path');
|
||||
var dropEl = newPath && manager.find(newPath);
|
||||
if (newPath && manager.isSharedFolder(dropEl)) {
|
||||
|
@ -1608,7 +1728,8 @@ define([
|
|||
$owner.attr('title', Messages.fm_padIsOwnedOther);
|
||||
}
|
||||
};
|
||||
var addFileData = function (element, $span) {
|
||||
var thumbsUrls = {};
|
||||
var addFileData = function (element, $element) {
|
||||
if (!manager.isFile(element)) { return; }
|
||||
|
||||
var data = manager.getFileData(element);
|
||||
|
@ -1617,7 +1738,7 @@ define([
|
|||
|
||||
var hrefData = Hash.parsePadUrl(href);
|
||||
if (hrefData.type) {
|
||||
$span.addClass('cp-border-color-'+hrefData.type);
|
||||
$element.addClass('cp-border-color-'+hrefData.type);
|
||||
}
|
||||
|
||||
var $state = $('<span>', {'class': 'cp-app-drive-element-state'});
|
||||
|
@ -1637,25 +1758,38 @@ define([
|
|||
var $expire = $expirableIcon.clone().appendTo($state);
|
||||
$expire.attr('title', Messages._getKey('fm_expirablePad', [new Date(data.expire).toLocaleString()]));
|
||||
}
|
||||
_addOwnership($span, $state, data);
|
||||
_addOwnership($element, $state, data);
|
||||
|
||||
var name = manager.getTitle(element);
|
||||
|
||||
// The element with the class '.name' is underlined when the 'li' is hovered
|
||||
var $name = $('<span>', {'class': 'cp-app-drive-element-name'}).text(name);
|
||||
$span.append($name);
|
||||
$span.append($state);
|
||||
$span.attr('title', name);
|
||||
$element.append($name);
|
||||
$element.append($state);
|
||||
$element.attr('title', name);
|
||||
|
||||
// display the thumbnail
|
||||
// if the thumbnail has already been displayed once, do not reload it, keep the same url
|
||||
if (thumbsUrls[element]) {
|
||||
var img = new Image();
|
||||
img.src = thumbsUrls[element];
|
||||
$element.find('.cp-icon').addClass('cp-app-drive-element-list');
|
||||
$element.prepend(img);
|
||||
$(img).addClass('cp-app-drive-element-grid cp-app-drive-element-thumbnail');
|
||||
$(img).attr("draggable", false);
|
||||
}
|
||||
else {
|
||||
common.displayThumbnail(href || data.roHref, data.channel, data.password, $element, function ($thumb) {
|
||||
// Called only if the thumbnail exists
|
||||
// Remove the .hide() added by displayThumnail() because it hides the icon in list mode too
|
||||
$element.find('.cp-icon').removeAttr('style').addClass('cp-app-drive-element-list');
|
||||
$thumb.addClass('cp-app-drive-element-grid cp-app-drive-element-thumbnail');
|
||||
$thumb.attr("draggable", false);
|
||||
thumbsUrls[element] = $thumb[0].src;
|
||||
});
|
||||
}
|
||||
|
||||
var type = Messages.type[hrefData.type] || hrefData.type;
|
||||
common.displayThumbnail(href || data.roHref, data.channel, data.password, $span, function ($thumb) {
|
||||
// Called only if the thumbnail exists
|
||||
// Remove the .hide() added by displayThumnail() because it hides the icon in
|
||||
// list mode too
|
||||
$span.find('.cp-icon').removeAttr('style').addClass('cp-app-drive-element-list');
|
||||
$thumb.addClass('cp-app-drive-element-grid')
|
||||
.addClass('cp-app-drive-element-thumbnail');
|
||||
});
|
||||
var $type = $('<span>', {
|
||||
'class': 'cp-app-drive-element-type cp-app-drive-element-list'
|
||||
}).text(type);
|
||||
|
@ -1665,7 +1799,7 @@ define([
|
|||
var $cdate = $('<span>', {
|
||||
'class': 'cp-app-drive-element-ctime cp-app-drive-element-list'
|
||||
}).text(getDate(data.ctime));
|
||||
$span.append($type).append($adate).append($cdate);
|
||||
$element.append($type).append($adate).append($cdate);
|
||||
};
|
||||
|
||||
var addFolderData = function (element, key, $span) {
|
||||
|
@ -1741,12 +1875,9 @@ define([
|
|||
draggable: true,
|
||||
'class': 'cp-app-drive-element-row'
|
||||
});
|
||||
if (!isFolder && Array.isArray(APP.selectedFiles)) {
|
||||
var idx = APP.selectedFiles.indexOf(element);
|
||||
if (idx !== -1) {
|
||||
$element.addClass('cp-app-drive-element-selected');
|
||||
APP.selectedFiles.splice(idx, 1);
|
||||
}
|
||||
$element.data('path', newPath);
|
||||
if (isElementSelected($element)) {
|
||||
selectElement($element);
|
||||
}
|
||||
$element.prepend($icon).dblclick(function () {
|
||||
if (isFolder) {
|
||||
|
@ -1762,11 +1893,10 @@ define([
|
|||
addFileData(element, $element);
|
||||
}
|
||||
$element.addClass(liClass);
|
||||
$element.data('path', newPath);
|
||||
addDragAndDropHandlers($element, newPath, isFolder, !isTrash);
|
||||
$element.click(function(e) {
|
||||
e.stopPropagation();
|
||||
onElementClick(e, $element, newPath);
|
||||
onElementClick(e, $element);
|
||||
});
|
||||
if (!isTrash) {
|
||||
$element.contextmenu(openContextMenu('tree'));
|
||||
|
@ -1917,6 +2047,8 @@ define([
|
|||
} else if (idx > 0 && manager.isFile(el)) {
|
||||
name = getElementName(path);
|
||||
}
|
||||
$span.data("path", path.slice(0, idx + 1));
|
||||
addDragAndDropHandlers($span, path.slice(0, idx), true, true);
|
||||
|
||||
if (idx === 0) { name = p === SHARED_FOLDER ? name : getPrettyName(p); }
|
||||
else {
|
||||
|
@ -2561,22 +2693,19 @@ define([
|
|||
'class': 'cp-app-drive-element cp-app-drive-element-file cp-app-drive-element-row' + roClass,
|
||||
draggable: draggable
|
||||
});
|
||||
if (Array.isArray(APP.selectedFiles)) {
|
||||
var sidx = APP.selectedFiles.indexOf(id);
|
||||
if (sidx !== -1) {
|
||||
$element.addClass('cp-app-drive-element-selected');
|
||||
APP.selectedFiles.splice(sidx, 1);
|
||||
}
|
||||
|
||||
var path = [rootName, idx];
|
||||
$element.data('path', path);
|
||||
if (isElementSelected($element)) {
|
||||
selectElement($element);
|
||||
}
|
||||
$element.prepend($icon).dblclick(function () {
|
||||
openFile(id);
|
||||
});
|
||||
addFileData(id, $element);
|
||||
var path = [rootName, idx];
|
||||
$element.data('path', path);
|
||||
$element.click(function(e) {
|
||||
e.stopPropagation();
|
||||
onElementClick(e, $element, path);
|
||||
onElementClick(e, $element);
|
||||
});
|
||||
$element.contextmenu(openContextMenu('default'));
|
||||
$element.data('context', 'default');
|
||||
|
@ -2703,8 +2832,8 @@ define([
|
|||
e.preventDefault();
|
||||
if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; }
|
||||
else { parentPath.pop(); }
|
||||
APP.selectedFiles = [r.id];
|
||||
APP.displayDirectory(parentPath);
|
||||
APP.selectedFiles = path.slice(-1);
|
||||
}).appendTo($openDir);
|
||||
}
|
||||
$('<a>').text(Messages.fc_prop).click(function () {
|
||||
|
@ -2795,7 +2924,7 @@ define([
|
|||
$element.data('path', path);
|
||||
$element.click(function(e) {
|
||||
e.stopPropagation();
|
||||
onElementClick(e, $element, path);
|
||||
onElementClick(e, $element);
|
||||
});
|
||||
$element.contextmenu(openContextMenu('default'));
|
||||
$element.data('context', 'default');
|
||||
|
@ -3019,7 +3148,7 @@ define([
|
|||
$context.click(function (e) {
|
||||
e.preventDefault();
|
||||
e.stopPropagation();
|
||||
var $li = $content.find('.cp-app-drive-element-selected');
|
||||
var $li = findSelectedElements();
|
||||
if ($li.length !== 1) {
|
||||
$li = findDataHolder($tree.find('.cp-app-drive-element-active'));
|
||||
}
|
||||
|
@ -3029,11 +3158,6 @@ define([
|
|||
return;
|
||||
}
|
||||
// Open the menu
|
||||
$('.cp-contextmenu').css({
|
||||
top: ($context.offset().top + 32) + 'px',
|
||||
right: '0px',
|
||||
left: ''
|
||||
});
|
||||
$li.contextmenu();
|
||||
});
|
||||
} else {
|
||||
|
@ -3101,7 +3225,7 @@ define([
|
|||
}
|
||||
});*/
|
||||
|
||||
var $sel = $content.find('.cp-app-drive-element-selected');
|
||||
var $sel = findSelectedElements();
|
||||
if ($sel.length) {
|
||||
$sel[0].scrollIntoView();
|
||||
} else {
|
||||
|
@ -3113,6 +3237,9 @@ define([
|
|||
if (history.isHistoryMode) {
|
||||
return void _displayDirectory(path, force);
|
||||
}
|
||||
if (!manager.comparePath(currentPath, path)) {
|
||||
removeSelected();
|
||||
}
|
||||
updateObject(sframeChan, proxy, function () {
|
||||
copyObjectValue(files, proxy.drive);
|
||||
updateSharedFolders(sframeChan, manager, files, folders, function () {
|
||||
|
@ -3463,6 +3590,7 @@ define([
|
|||
if (!res) { return; }
|
||||
manager.delete(pathsList, function () {
|
||||
pathsList.forEach(removeFoldersOpened);
|
||||
removeSelected();
|
||||
refresh();
|
||||
});
|
||||
});
|
||||
|
@ -3495,6 +3623,7 @@ define([
|
|||
var paths = $contextMenu.data('paths');
|
||||
var pathsList = [];
|
||||
var type = $contextMenu.attr('data-menu-type');
|
||||
var $this = $(this);
|
||||
|
||||
var el, data;
|
||||
if (paths.length === 0) {
|
||||
|
@ -3503,11 +3632,11 @@ define([
|
|||
return;
|
||||
}
|
||||
|
||||
if ($(this).hasClass("cp-app-drive-context-rename")) {
|
||||
if ($this.hasClass("cp-app-drive-context-rename")) {
|
||||
if (paths.length !== 1) { return; }
|
||||
displayRenameInput(paths[0].element, paths[0].path);
|
||||
}
|
||||
if ($(this).hasClass("cp-app-drive-context-color")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-color")) {
|
||||
var currentColor = getFolderColor(paths[0].path);
|
||||
pickFolderColor(paths[0].element, currentColor, function (color) {
|
||||
paths.forEach(function (p) {
|
||||
|
@ -3516,24 +3645,24 @@ define([
|
|||
refresh();
|
||||
});
|
||||
}
|
||||
else if($(this).hasClass("cp-app-drive-context-delete")) {
|
||||
else if($this.hasClass("cp-app-drive-context-delete")) {
|
||||
if (!APP.loggedIn) {
|
||||
return void deletePaths(paths);
|
||||
}
|
||||
paths.forEach(function (p) { pathsList.push(p.path); });
|
||||
moveElements(pathsList, [TRASH], false, refresh);
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-deleteowned')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-deleteowned')) {
|
||||
deleteOwnedPaths(paths);
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-open')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-open')) {
|
||||
paths.forEach(function (p) {
|
||||
var $element = p.element;
|
||||
$element.click();
|
||||
$element.dblclick();
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-openro')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-openro')) {
|
||||
paths.forEach(function (p) {
|
||||
var el = manager.find(p.path);
|
||||
if (paths[0].path[0] === SHARED_FOLDER && APP.newSharedFolder) {
|
||||
|
@ -3551,10 +3680,10 @@ define([
|
|||
openFile(null, href);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-expandall') ||
|
||||
$(this).hasClass('cp-app-drive-context-collapseall')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-expandall') ||
|
||||
$this.hasClass('cp-app-drive-context-collapseall')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
var opened = $(this).hasClass('cp-app-drive-context-expandall');
|
||||
var opened = $this.hasClass('cp-app-drive-context-expandall');
|
||||
var openRecursive = function (path) {
|
||||
setFolderOpened(path, opened);
|
||||
var folderContent = manager.find(path);
|
||||
|
@ -3577,8 +3706,8 @@ define([
|
|||
openRecursive(paths[0].path);
|
||||
refresh();
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-download')) {
|
||||
console.error('DOWNLOAD');
|
||||
|
||||
else if ($this.hasClass('cp-app-drive-context-download')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
var path = paths[0];
|
||||
el = manager.find(path.path);
|
||||
|
@ -3627,7 +3756,7 @@ define([
|
|||
}
|
||||
}
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-share')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-share')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
el = manager.find(paths[0].path);
|
||||
var parsed, modal;
|
||||
|
@ -3678,7 +3807,7 @@ define([
|
|||
wide: Object.keys(friends).length !== 0
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-newfolder')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-newfolder')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
var onFolderCreated = function (err, info) {
|
||||
if (err) { return void logError(err); }
|
||||
|
@ -3691,21 +3820,21 @@ define([
|
|||
}
|
||||
manager.addFolder(paths[0].path, null, onFolderCreated);
|
||||
}
|
||||
else if ($(this).hasClass('cp-app-drive-context-newsharedfolder')) {
|
||||
else if ($this.hasClass('cp-app-drive-context-newsharedfolder')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
addSharedFolderModal(function (obj) {
|
||||
if (!obj) { return; }
|
||||
manager.addSharedFolder(paths[0].path, obj, refresh);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-newdoc")) {
|
||||
var ntype = $(this).data('type') || 'pad';
|
||||
else if ($this.hasClass("cp-app-drive-context-newdoc")) {
|
||||
var ntype = $this.data('type') || 'pad';
|
||||
var path2 = manager.isPathIn(currentPath, [TRASH]) ? '' : currentPath;
|
||||
common.sessionStorage.put(Constants.newPadPathKey, path2, function () {
|
||||
common.openURL('/' + ntype + '/');
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-properties")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-properties")) {
|
||||
if (type === 'trash') {
|
||||
var pPath = paths[0].path;
|
||||
if (paths.length !== 1 || pPath.length !== 4) { return; }
|
||||
|
@ -3725,7 +3854,7 @@ define([
|
|||
UI.alert($prop[0], undefined, true);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-hashtag")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-hashtag")) {
|
||||
if (paths.length !== 1) { return; }
|
||||
el = manager.find(paths[0].path);
|
||||
data = manager.getFileData(el);
|
||||
|
@ -3733,7 +3862,7 @@ define([
|
|||
var href = data.href || data.roHref;
|
||||
common.updateTags(href);
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-empty")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-empty")) {
|
||||
if (paths.length !== 1 || !paths[0].element
|
||||
|| !manager.comparePath(paths[0].path, [TRASH])) {
|
||||
log(Messages.fm_forbidden);
|
||||
|
@ -3744,13 +3873,13 @@ define([
|
|||
manager.emptyTrash(refresh);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-remove")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-remove")) {
|
||||
return void deletePaths(paths);
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-removesf")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-removesf")) {
|
||||
return void deletePaths(paths);
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-restore")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-restore")) {
|
||||
if (paths.length !== 1) { return; }
|
||||
var restorePath = paths[0].path;
|
||||
var restoreName = paths[0].path[paths[0].path.length - 1];
|
||||
|
@ -3767,21 +3896,20 @@ define([
|
|||
manager.restore(restorePath, refresh);
|
||||
});
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-drive-context-openparent")) {
|
||||
else if ($this.hasClass("cp-app-drive-context-openparent")) {
|
||||
if (paths.length !== 1) { return; }
|
||||
var parentPath = paths[0].path.slice();
|
||||
if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; }
|
||||
else { parentPath.pop(); }
|
||||
el = manager.find(paths[0].path);
|
||||
APP.selectedFiles = [el];
|
||||
APP.displayDirectory(parentPath);
|
||||
APP.selectedFiles = paths[0].path.slice(-1);
|
||||
}
|
||||
APP.hideMenu();
|
||||
});
|
||||
|
||||
$content.on("keydown", function (e) {
|
||||
if (e.which === 113) {
|
||||
var paths = $contextMenu.data('paths');
|
||||
$(window).on("keydown", function (e) {
|
||||
if (e.which === 113) { // if F2 key pressed
|
||||
var paths = getSelectedPaths(findSelectedElements().first());
|
||||
if (paths.length !== 1) { return; }
|
||||
displayRenameInput(paths[0].element, paths[0].path);
|
||||
}
|
||||
|
@ -3793,10 +3921,9 @@ define([
|
|||
e.preventDefault();
|
||||
});
|
||||
$appContainer.on('mouseup', function (e) {
|
||||
//if (sel.down) { return; }
|
||||
if (e.which !== 1) { return ; }
|
||||
if ($(e.target).is(".dropdown-submenu a, .dropdown-submenu a span")) { return; } // if we click on dropdown-submenu, don't close menu
|
||||
APP.hideMenu(e);
|
||||
//removeSelected(e);
|
||||
});
|
||||
$appContainer.on('click', function (e) {
|
||||
if (e.which !== 1) { return ; }
|
||||
|
@ -3815,7 +3942,7 @@ define([
|
|||
if (manager.isPathIn(currentPath, [FILES_DATA]) && APP.loggedIn) {
|
||||
return; // We can't remove elements directly from filesData
|
||||
}
|
||||
var $selected = $('.cp-app-drive-element-selected');
|
||||
var $selected = findSelectedElements();
|
||||
if (!$selected.length) { return; }
|
||||
var paths = [];
|
||||
var isTrash = manager.isPathIn(currentPath, [TRASH]);
|
||||
|
|
|
@ -52,6 +52,16 @@
|
|||
max-width: 100%;
|
||||
max-height: ~"calc(100vh - 96px)";
|
||||
}
|
||||
.plain-text-reader {
|
||||
align-self: flex-start;
|
||||
width: 90vw;
|
||||
height: 100%;
|
||||
padding: 2em;
|
||||
background-color: white;
|
||||
overflow-y: auto;
|
||||
word-wrap: break-word;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
}
|
||||
|
||||
#cp-app-file-upload-form, #cp-app-file-download-form {
|
||||
|
|
|
@ -111,8 +111,14 @@
|
|||
vertical-align: middle;
|
||||
margin-right: 5px;
|
||||
}
|
||||
input[type="color"] {
|
||||
width: 100px;
|
||||
.cp-settings-cursor-color-picker {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
height: 25px;
|
||||
width: 70px;
|
||||
margin-right: 10px;
|
||||
cursor: pointer;
|
||||
border: 1px solid black;
|
||||
}
|
||||
.cp-settings-language-selector {
|
||||
button.btn {
|
||||
|
|
|
@ -15,6 +15,7 @@ define([
|
|||
'/common/make-backup.js',
|
||||
'/common/common-feedback.js',
|
||||
|
||||
'/common/jscolor.js',
|
||||
'/bower_components/file-saver/FileSaver.min.js',
|
||||
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
|
||||
'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
|
||||
|
@ -1182,13 +1183,13 @@ define([
|
|||
|
||||
var $inputBlock = $('<div>').appendTo($div);
|
||||
|
||||
var $colorPicker = $("<div>", { class: "cp-settings-cursor-color-picker"});
|
||||
var $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
|
||||
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
|
||||
|
||||
var $input = $('<input>', {
|
||||
type: 'color',
|
||||
}).on('change', function () {
|
||||
var val = $input.val();
|
||||
// when jscolor picker value change
|
||||
var onchange = function (colorL) {
|
||||
var val = "#" + colorL.toString();
|
||||
if (!/^#[0-9a-fA-F]{6}$/.test(val)) { return; }
|
||||
$spinner.show();
|
||||
$ok.hide();
|
||||
|
@ -1196,15 +1197,25 @@ define([
|
|||
$spinner.hide();
|
||||
$ok.show();
|
||||
});
|
||||
}).appendTo($inputBlock);
|
||||
};
|
||||
|
||||
// jscolor picker
|
||||
var jscolorL = new window.jscolor($colorPicker[0],{showOnClick: false, onFineChange: onchange, valueElement:undefined});
|
||||
$colorPicker.click(function () {
|
||||
jscolorL.show();
|
||||
});
|
||||
|
||||
// set default color
|
||||
common.getAttribute(['general', 'cursor', 'color'], function (e, val) {
|
||||
if (e) { return void console.error(e); }
|
||||
val = val || "#000";
|
||||
jscolorL.fromString(val);
|
||||
});
|
||||
|
||||
$colorPicker.appendTo($inputBlock);
|
||||
$ok.hide().appendTo($inputBlock);
|
||||
$spinner.hide().appendTo($inputBlock);
|
||||
|
||||
common.getAttribute(['general', 'cursor', 'color'], function (e, val) {
|
||||
if (e) { return void console.error(e); }
|
||||
$input.val(val || '');
|
||||
});
|
||||
return $div;
|
||||
};
|
||||
|
||||
|
|
|
@ -257,7 +257,7 @@ define([
|
|||
metadataMgr.onChange(function () {
|
||||
var md = metadataMgr.getMetadata();
|
||||
if (md.palette) {
|
||||
updateLocalPalette(md.palette);
|
||||
updatePalette(md.palette);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
Loading…
Reference in New Issue