Merge branch 'staging' into editable-metadata

pull/1/head
ansuz 5 years ago
commit b7c75ea2d4

@ -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%);
}
}
}

@ -8,7 +8,7 @@ define([
module.main = function (userDoc, cb) {
var mode = userDoc.highlightMode || 'gfm';
var content = userDoc.content;
module.type = SFCodeMirror.getContentExtension(mode);
module.ext = SFCodeMirror.getContentExtension(mode);
cb(SFCodeMirror.fileExporter(content));
};

@ -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',
'data-icon': "fa-cloud-upload",
}, Messages.pad_mediatagImport)),
h('li', h('a.cp-app-code-context-download.dropdown-item', {
'tabindex': '-1',
}, Messages.pad_mediatagImport))
'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));

@ -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;

@ -6,141 +6,141 @@ define([
// mode language (extension)
var list = Modes.list = [
"APL apl .apl",
"ASCII-Armor asciiarmor",
"ASN.1 asn.1",
"ASCII-Armor asciiarmor .asc",
"ASN.1 asn.1 .asn1",
"Asterisk asterisk",
"Brainfuck brainfuck .b",
"C text/x-csrc .c",
"C text/x-c++src .cpp",
"C-like clike",
"Clojure clojure",
"CMake cmake",
"COBOL cobol",
"CoffeeScript coffeescript",
"Common_Lisp commonlisp",
"Crystal crystal",
"C-like clike .c",
"Clojure clojure .clj",
"CMake cmake _", /* no extension */
"COBOL cobol .cbl",
"CoffeeScript coffeescript .coffee",
"Common_Lisp commonlisp .lisp",
"Crystal crystal .cr",
"CSS css .css",
"Cypher cypher",
"D d",
"Dart dart",
"Diff diff",
"Django django",
"Dockerfile dockerfile",
"DTD dtd",
"Dylan dylan",
"EBNF ebnf",
"ECL ecl",
"Eiffel eiffel",
"Cypher cypher .cypher",
"D d .d",
"Dart dart .dart",
"Diff diff .diff",
"Django django .py",
"Dockerfile dockerfile _", /* no extension */
"DTD dtd .dtd",
"Dylan dylan .dylan",
"EBNF ebnf .ebnf",
"ECL ecl .ecl",
"Eiffel eiffel .e",
"Elm elm .elm",
"Erlang erlang",
"Factor factor",
"FCL fcl",
"Forth forth",
"Fortran fortran",
"GAS gas",
"Gherkin gherkin",
"Go go",
"Groovy groovy",
"Haml haml",
"Handlebars handlebars",
"Erlang erlang .erl",
"Factor factor .factor",
"FCL fcl .fcl",
"Forth forth .fs",
"Fortran fortran .f90",
"GAS gas .gas",
"Gherkin gherkin .feature",
"Go go .go",
"Groovy groovy .groovy",
"Haml haml .haml",
"Handlebars handlebars .hbs",
"Haskell haskell .hs",
"Haskell-Literate haskell-literate",
"Haxe haxe",
"Haskell-Literate haskell-literate .lhs",
"Haxe haxe .hx",
"HTML htmlmixed .html",
"HTTP http",
"IDL idl",
"JADE jade",
"HTTP http _", /* no extension */
"IDL idl .idl",
"JADE jade .jade",
"Java text/x-java .java",
"JavaScript javascript .js",
"Jinja2 jinja2",
"Jinja2 jinja2 .j2",
"JSX jsx .jsx",
"Julia julia",
"LiveScript livescript",
"Lua lua",
"Julia julia .jl",
"LiveScript livescript .ls",
"Lua lua .lua",
"Markdown gfm .md",
//"markdown markdown .md",
"Mathematica mathematica",
"mIRC mirc",
"ML mllike",
"Modelica modelica",
"MscGen mscgen",
"MUMPS mumps",
"Nginx nginx",
"NSIS nsis",
"N-Triples ntriples",
"Mathematica mathematica .nb",
"mIRC mirc .irc",
"ML mllike _", /* no extension */
"Modelica modelica .mo",
"MscGen mscgen .mscgen",
"MUMPS mumps .m",
"Nginx nginx .conf",
"NSIS nsis .nsi",
"N-Triples ntriples .nq",
"Objective-C text/x-objectivec .m",
"Octave octave",
"Octave octave .m",
"Org-mode orgmode .org",
"Oz oz",
"Pascal pascal",
"PEG.js pegjs",
"Perl perl",
"PHP php",
"Pig pig",
"PowerShell powershell",
"Properties properties",
"Protocol_Buffers protobuf",
"Puppet puppet",
"Oz oz .oz",
"Pascal pascal .pas",
"PEG.js pegjs .pegjs",
"Perl perl .pl",
"PHP php .php",
"Pig pig .pig",
"PowerShell powershell .ps1",
"Properties properties .properties",
"Protocol_Buffers protobuf .proto",
"Puppet puppet .pp",
"Python python .py",
"Q q",
"R r",
"RPM rpm",
"RST rst",
"Ruby ruby",
"Rust rust",
"Sass sass",
"Q q .q",
"R r .r",
"RPM rpm .rpm",
"RST rst .rst",
"Ruby ruby .rb",
"Rust rust .rs",
"Sass sass .sass",
"Scheme scheme .scm",
"Shell shell .sh",
"Sieve sieve",
"Slim slim",
"Smalltalk smalltalk",
"Smarty smarty",
"Solr solr",
"Soy soy",
"SPARQL sparql",
"Spreadsheet spreadsheet",
"SQL sql",
"sTeX stex",
"Stylus stylus",
"Swift swift",
"Tcl tcl",
"Sieve sieve .sieve",
"Slim slim .slim",
"Smalltalk smalltalk _", /* no extension */
"Smarty smarty _", /* no extension */
"Solr solr _", /* no extension */
"Soy soy .soy",
"SPARQL sparql .rq",
"Spreadsheet spreadsheet .xls",
"SQL sql .sql",
"sTeX stex .stex",
"Stylus stylus .styl",
"Swift swift .swift",
"Tcl tcl .tcl",
"Text text .txt",
"Textile textile",
"TiddlyWiki tiddlywiki",
"Tiki tiki",
"TOML toml",
"Tornado tornado",
"troff troff",
"Textile textile .textile",
"TiddlyWiki tiddlywiki .tw",
"Tiki tiki _", /* no extension */
"TOML toml .toml",
"Tornado tornado .tornado",
"troff troff .troff",
"TTCN ttcn",
"TTCN-cfg ttcn-cfg",
"Turtle turtle",
"Twig twig",
"Visual_Basic vb",
"VBScript vbscript",
"Velocity velocity",
"Verilog verilog",
"VHDL vhdl",
"Vue vue",
"XML xml",
"Turtle turtle .ttl",
"Twig twig .twig",
"Visual_Basic vb .vb",
"VBScript vbscript .vbs",
"Velocity velocity .vm",
"Verilog verilog .v",
"VHDL vhdl .vhdl",
"Vue vue .vue",
"XML xml .xml",
//"xwiki xwiki21",
"XQuery xquery",
"XQuery xquery .xquery",
"YAML yaml .yaml",
"YAML_Frontmatter yaml-frontmatter",
"Z80 z80"
"YAML_Frontmatter yaml-frontmatter _", /* no extension */
"Z80 z80 .z80"
].map(function (line) {
var kv = line.split(/\s/);
return {
language: kv[0].replace(/_/g, ' '),
mode: kv[1],
ext: kv[2],
ext: kv[2] === '_' ? '' : kv[2],
};
});
Modes.extensionOf = function (mode) {
var ext = '';
var ext;
list.some(function (o) {
if (o.mode !== mode) { return; }
ext = o.ext || '';
ext = o.ext;
return true;
});
return ext;

@ -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];
@ -1915,6 +1933,7 @@ define([
}
// No password for drive
var secret = Hash.getSecrets('drive', hash);
storeChannel = secret.channel;
var listmapConfig = {
data: {},
websocketURL: NetConfig.getWebsocketURL(),

@ -401,7 +401,7 @@ define([
var ext = (typeof(extension) === 'function') ? extension() : extension;
var suggestion = title.suggestTitle('cryptpad-document');
UI.prompt(Messages.exportPrompt,
Util.fixFileName(suggestion) + '.' + ext, function (filename)
Util.fixFileName(suggestion) + ext, function (filename)
{
if (!(typeof(filename) === 'string' && filename)) { return; }
if (async) {
@ -454,7 +454,7 @@ define([
return;
}
if (!mediaTagEmbedder) { console.log('mediaTagEmbedder missing'); return; }
if (data.type !== 'file') { console.log('unhandled embed type ' + data.type); return; }
if (data.type !== 'file') { console.log('unhandled embed type ' + data.type); return; }
var privateDat = cpNfInner.metadataMgr.getPrivateData();
var origin = privateDat.fileHost || privateDat.origin;
var src = data.src = origin + data.src;

@ -39,7 +39,8 @@ define([
};
module.getContentExtension = function (mode) {
return (Modes.extensionOf(mode) || '.txt').slice(1);
var ext = Modes.extensionOf(mode);
return ext !== undefined ? ext : '.txt';
};
module.fileExporter = function (content) {
return new Blob([ content ], { type: 'text/plain;charset=utf-8' });
@ -98,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;
}
@ -386,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%);

@ -17,8 +17,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',
@ -43,7 +41,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",
};
@ -299,6 +300,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', {
@ -369,16 +397,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',
@ -415,6 +461,7 @@ define([
}, Messages.fc_prop)),
])
]);
// add icons to the contextmenu options
$(menu).find("li a.dropdown-item").each(function (i, el) {
var $icon = $("<span>");
if ($(el).attr('data-icon')) {
@ -425,21 +472,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);
@ -565,7 +637,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('');
@ -675,7 +748,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();
});
@ -710,7 +785,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;
}
@ -723,7 +800,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 :
@ -842,12 +919,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)) {
@ -869,14 +946,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();
});
}
@ -897,7 +981,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
@ -1117,8 +1200,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) {
@ -1147,7 +1231,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'));
}
@ -1214,6 +1298,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
@ -1250,34 +1335,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");
@ -1289,18 +1373,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;
@ -1353,6 +1455,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) {
@ -1361,8 +1474,8 @@ define([
return false;
}
if (!$element.hasClass('cp-app-drive-element-selected')) {
onElementClick(undefined, $element);
if (!isElementSelected($element)) {
selectElement($element);
}
paths = getSelectedPaths($element);
@ -1432,6 +1545,7 @@ define([
if (!res) { return; }
manager.delete(pathsList, function () {
pathsList.forEach(removeFoldersOpened);
removeSelected();
refresh();
});
}, null, true);
@ -1442,7 +1556,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) {
@ -1459,7 +1573,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 = [{
@ -1478,7 +1592,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)) {
@ -1606,7 +1726,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);
@ -1615,7 +1736,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'});
@ -1635,25 +1756,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);
@ -1663,7 +1797,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) {
@ -1739,12 +1873,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) {
@ -1760,11 +1891,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'));
@ -1915,6 +2045,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 {
@ -2559,22 +2691,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');
@ -2701,8 +2830,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 () {
@ -2793,7 +2922,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');
@ -3017,7 +3146,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'));
}
@ -3027,11 +3156,6 @@ define([
return;
}
// Open the menu
$('.cp-contextmenu').css({
top: ($context.offset().top + 32) + 'px',
right: '0px',
left: ''
});
$li.contextmenu();
});
} else {
@ -3099,7 +3223,7 @@ define([
}
});*/
var $sel = $content.find('.cp-app-drive-element-selected');
var $sel = findSelectedElements();
if ($sel.length) {
$sel[0].scrollIntoView();
} else {
@ -3111,6 +3235,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 () {
@ -3461,6 +3588,7 @@ define([
if (!res) { return; }
manager.delete(pathsList, function () {
pathsList.forEach(removeFoldersOpened);
removeSelected();
refresh();
});
});
@ -3482,7 +3610,7 @@ define([
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) {
@ -3707,16 +3835,15 @@ define([
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);
}
@ -3728,10 +3855,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 ; }
@ -3750,7 +3876,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 {

@ -2,7 +2,9 @@
// Pads from the code app will be exported using this format instead of plain text.
define([
], function () {
var module = {};
var module = {
ext: '.json'
};
module.main = function (userDoc, cb) {
var content = userDoc.content;

@ -367,7 +367,7 @@ define([
});
}
framework.setFileExporter('json', function () {
framework.setFileExporter('.json', function () {
return new Blob([JSON.stringify(kanban.getBoardsJSON(), 0, 2)], {
type: 'application/json',
});

@ -5,7 +5,7 @@ define([
'/bower_components/nthen/index.js',
], function ($, Util, Hyperjson, nThen) {
var module = {
type: 'html'
ext: '.html'
};
var exportMediaTags = function (inner, cb) {

@ -786,7 +786,7 @@ define([
});
}, true);
framework.setFileExporter(Exporter.type, function (cb) {
framework.setFileExporter(Exporter.ext, function (cb) {
Exporter.main(inner, cb);
}, true);

@ -3,7 +3,9 @@
define([
'/customize/messages.js',
], function (Messages) {
var module = {};
var module = {
ext: '.csv'
};
var copyObject = function (obj) {
return JSON.parse(JSON.stringify(obj));

@ -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([
'/settings/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',
@ -1191,13 +1192,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();
@ -1205,15 +1206,25 @@ define([
$spinner.hide();
$ok.show();
});
}).appendTo($inputBlock);
};
$ok.hide().appendTo($inputBlock);
$spinner.hide().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); }
$input.val(val || '');
val = val || "#000";
jscolorL.fromString(val);
});
$colorPicker.appendTo($inputBlock);
$ok.hide().appendTo($inputBlock);
$spinner.hide().appendTo($inputBlock);
return $div;
};

@ -34,7 +34,7 @@ define([
var path = '/' + type + '/export.js';
require([path], function (Exporter) {
Exporter.main(json, function (data) {
result.ext = '.' + Exporter.type;
result.ext = Exporter.ext || '';
result.data = data;
cb(result);
});
@ -163,12 +163,12 @@ define([
var existingNames = [];
Object.keys(root).forEach(function (k) {
var el = root[k];
if (typeof el === "object") {
if (typeof el === "object" && el.metadata !== true) { // if folder
var fName = getUnique(sanitize(k), '', existingNames);
existingNames.push(fName.toLowerCase());
return void makeFolder(ctx, el, zip.folder(fName), fd);
}
if (ctx.data.sharedFolders[el]) {
if (ctx.data.sharedFolders[el]) { // if shared folder
var sfData = ctx.sf[el].metadata;
var sfName = getUnique(sanitize(sfData.title || 'Folder'), '', existingNames);
existingNames.push(sfName.toLowerCase());

@ -4,7 +4,7 @@ define([
'/common/sframe-common-codemirror.js',
], function (SFCodeMirror) {
var module = {
type: 'md'
ext: '.md'
};
module.main = function (userDoc, cb) {

@ -538,7 +538,7 @@ define([
editor.on('change', framework.localChange);
framework.setFileExporter(CodeMirror.getContentExtension, CodeMirror.fileExporter);
framework.setFileExporter(".md", CodeMirror.fileExporter);
framework.setFileImporter({}, CodeMirror.fileImporter);
framework.start();

@ -14,7 +14,7 @@ define([
var canvas = new Fabric.Canvas(canvas_node);
var content = userDoc.content;
canvas.loadFromJSON(content, function () {
module.type = 'svg';
module.ext = '.svg';
cb(canvas.toSVG());
});
};

@ -257,7 +257,7 @@ define([
metadataMgr.onChange(function () {
var md = metadataMgr.getMetadata();
if (md.palette) {
updateLocalPalette(md.palette);
updatePalette(md.palette);
}
});
@ -415,11 +415,11 @@ define([
setEditable(!locked);
});
framework.setFileExporter('png', function (cb) {
framework.setFileExporter('.png', function (cb) {
$canvas[0].toBlob(function (blob) {
cb(blob);
});
});
}, true);
framework.setNormalizer(function (c) {
return {

Loading…
Cancel
Save