Merge branch 'staging' into editable-metadata

pull/1/head
ansuz 5 years ago
commit b7c75ea2d4

@ -169,6 +169,28 @@ define([], function () {
height: 100%; height: 100%;
background: #5cb85c; 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); */}).toString().slice(14, -3);
var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; }); var urlArgs = window.location.href.replace(/^.*\?([^\?]*)$/, function (all, x) { return x; });
var elem = document.createElement('div'); var elem = document.createElement('div');
@ -182,7 +204,7 @@ define([], function () {
'</div>', '</div>',
'<div class="cp-loading-container">', '<div class="cp-loading-container">',
'<div class="cp-loading-spinner-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>', '</div>',
'<p id="cp-loading-message"></p>', '<p id="cp-loading-message"></p>',
'</div>' '</div>'

@ -22,13 +22,16 @@
} }
} }
.dropdown-toggle { .dropdown-toggle {
transform: rotate(270deg);
margin-left: 1rem; margin-left: 1rem;
float: right;
} }
.dropdown-menu { .dropdown-menu {
top: -0.7rem; top: -0.7rem;
left: 100%; left: 100%;
&.left { &.left {
left: -10rem; left: 0%;
transform: translate(-100%);
} }
} }
} }

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

@ -230,9 +230,15 @@ define([
if (!Visible.currently()) { to = window.setTimeout(interval, Thumb.UPDATE_FIRST); } if (!Visible.currently()) { to = window.setTimeout(interval, Thumb.UPDATE_FIRST); }
}; };
var addThumbnail = function (err, thumb, $span, cb) { 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(); 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.find('.cp-icon').hide();
$span.prepend(img); $span.prepend(img);
cb($(img)); cb($(img));

@ -573,9 +573,9 @@ define([
onFriendShare.reg(saveValue); onFriendShare.reg(saveValue);
var getLinkValue = function (initValue) { var getLinkValue = function (initValue) {
var val = initValue || {}; var val = initValue || {};
var edit = initValue ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true')); var edit = val.edit !== undefined ? val.edit : Util.isChecked($(link).find('#cp-share-editable-true'));
var embed = initValue ? val.embed : Util.isChecked($(link).find('#cp-share-embed')); var embed = val.embed !== undefined ? val.embed : Util.isChecked($(link).find('#cp-share-embed'));
var present = initValue ? val.present : Util.isChecked($(link).find('#cp-share-present')); 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 hash = (!hashes.viewHash || (edit && hashes.editHash)) ? hashes.editHash : hashes.viewHash;
var href = origin + pathname + '#' + hash; var href = origin + pathname + '#' + hash;
@ -2104,6 +2104,9 @@ define([
}; };
UIElements.createNewPadModal = function (common) { 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({ var $modal = UIElements.createModal({
id: 'cp-app-toolbar-creation-dialog', id: 'cp-app-toolbar-creation-dialog',
$body: $('body') $body: $('body')
@ -2766,8 +2769,12 @@ define([
UIElements.displayCrowdfunding(common); UIElements.displayCrowdfunding(common);
modal.delete(); modal.delete();
}); });
var waitingForStoringCb = false;
$(store).click(function () { $(store).click(function () {
if (waitingForStoringCb) { return; }
waitingForStoringCb = true;
common.getSframeChannel().query("Q_AUTOSTORE_STORE", null, function (err, obj) { common.getSframeChannel().query("Q_AUTOSTORE_STORE", null, function (err, obj) {
waitingForStoringCb = false;
var error = err || (obj && obj.error); var error = err || (obj && obj.error);
if (error) { if (error) {
if (error === 'E_OVER_LIMIT') { if (error === 'E_OVER_LIMIT') {
@ -2854,11 +2861,27 @@ define([
'aria-labelledBy': 'dropdownMenu', 'aria-labelledBy': 'dropdownMenu',
'style': 'display:block;position:static;margin-bottom:5px;' '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', '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); var m = createContextMenu(menu);
mediatagContextMenu = m; mediatagContextMenu = m;
@ -2868,7 +2891,13 @@ define([
e.stopPropagation(); e.stopPropagation();
m.hide(); m.hide();
var $mt = $menu.data('mediatag'); 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; return m;

@ -319,6 +319,12 @@ define([], function () {
return window.innerHeight < 800 || window.innerWidth < 800; return window.innerHeight < 800 || window.innerWidth < 800;
}; };
Util.stripTags = function (text) {
var div = document.createElement("div");
div.innerHTML = text;
return div.innerText;
};
return Util; return Util;
}); });
}(self)); }(self));

@ -254,8 +254,12 @@ define([
common.clearOwnedChannel = function (channel, cb) { common.clearOwnedChannel = function (channel, cb) {
postMessage("CLEAR_OWNED_CHANNEL", channel, cb); postMessage("CLEAR_OWNED_CHANNEL", channel, cb);
}; };
common.removeOwnedChannel = function (channel, cb) { // "force" allows you to delete your drive ID
postMessage("REMOVE_OWNED_CHANNEL", channel, cb); common.removeOwnedChannel = function (channel, cb, force) {
postMessage("REMOVE_OWNED_CHANNEL", {
channel: channel,
force: force
}, cb);
}; };
common.getDeletedPads = function (data, cb) { common.getDeletedPads = function (data, cb) {
@ -950,7 +954,7 @@ define([
common.logoutFromAll(waitFor(function () { common.logoutFromAll(waitFor(function () {
postMessage("DISCONNECT"); postMessage("DISCONNECT");
})); }));
})); }), true);
} }
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
if (!oldIsOwned) { if (!oldIsOwned) {

@ -15,6 +15,7 @@ define([
var DiffDOM = window.diffDOM; var DiffDOM = window.diffDOM;
var renderer = new Marked.Renderer(); var renderer = new Marked.Renderer();
var restrictedRenderer = new Marked.Renderer();
var Mermaid = { var Mermaid = {
init: function () {} init: function () {}
@ -61,13 +62,18 @@ define([
return h('div.cp-md-toc', content).outerHTML; 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, { var r = Marked(md, {
sanitize: sanitize sanitize: sanitize
}); });
// Add Table of Content // 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 = []; toc = [];
return r; return r;
@ -83,12 +89,7 @@ define([
return defaultCode.apply(renderer, arguments); return defaultCode.apply(renderer, arguments);
} }
}; };
restrictedRenderer.code = renderer.code;
var stripTags = function (text) {
var div = document.createElement("div");
div.innerHTML = text;
return div.innerText;
};
renderer.heading = function (text, level) { renderer.heading = function (text, level) {
var i = 0; var i = 0;
@ -105,10 +106,13 @@ define([
toc.push({ toc.push({
level: level, level: level,
id: id, id: id,
title: stripTags(text) title: Util.stripTags(text)
}); });
return "<h" + level + " id=\"" + id + "\"><a href=\"#" + id + "\" class=\"anchor\"></a>" + text + "</h" + level + ">"; return "<h" + level + " id=\"" + id + "\"><a href=\"#" + id + "\" class=\"anchor\"></a>" + text + "</h" + level + ">";
}; };
restrictedRenderer.heading = function (text) {
return text;
};
// Tasks list // Tasks list
var checkedTaskItemPtn = /^\s*(<p>)?\[[xX]\](<\/p>)?\s*/; var checkedTaskItemPtn = /^\s*(<p>)?\[[xX]\](<\/p>)?\s*/;
@ -138,6 +142,13 @@ define([
var cls = (isCheckedTaskItem || isUncheckedTaskItem || hasBogusInput) ? ' class="todo-list-item"' : ''; var cls = (isCheckedTaskItem || isUncheckedTaskItem || hasBogusInput) ? ' class="todo-list-item"' : '';
return '<li'+ cls + '>' + text + '</li>\n'; 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) { renderer.image = function (href, title, text) {
if (href.slice(0,6) === '/file/') { if (href.slice(0,6) === '/file/') {
// DEPRECATED // DEPRECATED
@ -162,12 +173,19 @@ define([
out += this.options.xhtml ? '/>' : '>'; out += this.options.xhtml ? '/>' : '>';
return out; 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) { renderer.paragraph = function (p) {
if (p === '[TOC]') { if (p === '[TOC]') {
return '<p><div class="cp-md-toc"></div></p>'; 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; 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 // Default config, can be overriden per media-tag call
var config = { var config = {
allowed: [ allowed: [
'text/plain',
'image/png', 'image/png',
'image/jpeg', 'image/jpeg',
'image/jpg', 'image/jpg',
@ -53,6 +66,23 @@
text: "Download" text: "Download"
}, },
Plugins: { 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) { image: function (metadata, url, content, cfg, cb) {
var img = document.createElement('img'); var img = document.createElement('img');
img.setAttribute('src', url); img.setAttribute('src', url);
@ -271,6 +301,9 @@
var blob = decrypted.content; var blob = decrypted.content;
var mediaType = getType(mediaObject, metadata, cfg); var mediaType = getType(mediaObject, metadata, cfg);
if (isplainTextFile(metadata)) {
mediaType = "text";
}
if (mediaType === 'application') { if (mediaType === 'application') {
mediaType = mediaObject.extension; mediaType = mediaObject.extension;

@ -151,7 +151,7 @@ define([
}); });
try { try {
var $d = $(d); 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"); $d.addClass("cp-app-contacts-content");
// override link clicking, because we're in an iframe // override link clicking, because we're in an iframe
@ -197,7 +197,7 @@ define([
var getChat = function (id) { var getChat = function (id) {
return $messages.find(dataQuery(id)); return $messages.find(dataQuery(id));
}; };
var scrollChatToBottom = function () { var scrollChatToBottom = function () {
var $messagebox = $('.cp-app-contacts-messages'); var $messagebox = $('.cp-app-contacts-messages');
$messagebox.scrollTop($messagebox[0].scrollHeight); $messagebox.scrollTop($messagebox[0].scrollHeight);

@ -99,6 +99,7 @@ define(['json.sortify'], function (Sortify) {
var addAuthor = function () { var addAuthor = function () {
if (!meta.user || !meta.user.netfluxId || !priv || !priv.edPublic) { return; } if (!meta.user || !meta.user.netfluxId || !priv || !priv.edPublic) { return; }
var authors = metadataObj.authors || {}; var authors = metadataObj.authors || {};
var old = Sortify(authors);
if (!authors[priv.edPublic]) { if (!authors[priv.edPublic]) {
authors[priv.edPublic] = { authors[priv.edPublic] = {
nId: [meta.user.netfluxId], nId: [meta.user.netfluxId],
@ -110,9 +111,11 @@ define(['json.sortify'], function (Sortify) {
authors[priv.edPublic].nId.push(meta.user.netfluxId); authors[priv.edPublic].nId.push(meta.user.netfluxId);
} }
} }
metadataObj.authors = authors; if (Sortify(authors) !== old) {
metadataLazyObj.authors = JSON.parse(JSON.stringify(authors)); metadataObj.authors = authors;
change(); metadataLazyObj.authors = JSON.parse(JSON.stringify(authors));
change();
}
}; };
var netfluxId; var netfluxId;

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

@ -34,7 +34,7 @@ define([
var sendDriveEvent = function () {}; var sendDriveEvent = function () {};
var registerProxyEvents = function () {}; var registerProxyEvents = function () {};
var storeHash; var storeHash, storeChannel;
var store = window.CryptPad_AsyncStore = { var store = window.CryptPad_AsyncStore = {
modules: {} modules: {}
@ -239,6 +239,20 @@ define([
Store.removeOwnedChannel = function (clientId, data, cb) { Store.removeOwnedChannel = function (clientId, data, cb) {
if (!store.rpc) { return void cb({error: 'RPC_NOT_READY'}); } 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) { store.rpc.removeOwnedChannel(data, function (err) {
cb({error:err}); cb({error:err});
}); });
@ -573,7 +587,10 @@ define([
})); }));
}).nThen(function (waitFor) { }).nThen(function (waitFor) {
// Delete Drive // Delete Drive
Store.removeOwnedChannel(clientId, secret.channel, waitFor()); Store.removeOwnedChannel(clientId, {
channel: secret.channel
force: true
}, waitFor());
}).nThen(function () { }).nThen(function () {
store.network.disconnect(); store.network.disconnect();
cb({ cb({
@ -786,6 +803,7 @@ define([
var h = p.hashData; var h = p.hashData;
if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); } if (AppConfig.disableAnonymousStore && !store.loggedIn) { return void cb(); }
if (p.type === "debug") { return void cb(); }
var channelData = Store.channels && Store.channels[channel]; var channelData = Store.channels && Store.channels[channel];
@ -1915,6 +1933,7 @@ define([
} }
// No password for drive // No password for drive
var secret = Hash.getSecrets('drive', hash); var secret = Hash.getSecrets('drive', hash);
storeChannel = secret.channel;
var listmapConfig = { var listmapConfig = {
data: {}, data: {},
websocketURL: NetConfig.getWebsocketURL(), websocketURL: NetConfig.getWebsocketURL(),

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

@ -39,7 +39,8 @@ define([
}; };
module.getContentExtension = function (mode) { 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) { module.fileExporter = function (content) {
return new Blob([ content ], { type: 'text/plain;charset=utf-8' }); return new Blob([ content ], { type: 'text/plain;charset=utf-8' });
@ -98,9 +99,17 @@ define([
// lines beginning with a hash are potentially valuable // lines beginning with a hash are potentially valuable
// works for markdown, python, bash, etc. // works for markdown, python, bash, etc.
var hash = /^#+(.*?)$/; var hash = /^#+(.*?)$/;
var hashAndLink = /^#+\s*\[(.*?)\]\(.*\)\s*$/;
if (hash.test(line)) { 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) { line.replace(hash, function (a, one) {
text = one; text = Util.stripTags(one);
}); });
return true; return true;
} }
@ -386,21 +395,32 @@ define([
exp.mkIndentSettings = function (metadataMgr) { exp.mkIndentSettings = function (metadataMgr) {
var setIndentation = function (units, useTabs, fontSize, spellcheck) { var setIndentation = function (units, useTabs, fontSize, spellcheck) {
if (typeof(units) !== 'number') { return; } if (typeof(units) !== 'number') { return; }
var doc = editor.getDoc();
editor.setOption('indentUnit', units); editor.setOption('indentUnit', units);
editor.setOption('tabSize', units); editor.setOption('tabSize', units);
editor.setOption('indentWithTabs', useTabs); editor.setOption('indentWithTabs', useTabs);
editor.setOption('spellcheck', spellcheck); editor.setOption('spellcheck', spellcheck);
if (!useTabs) { editor.setOption("extraKeys", {
editor.setOption("extraKeys", { Tab: function() {
Tab: function() { if (doc.somethingSelected()) {
editor.replaceSelection(Array(units + 1).join(" ")); editor.execCommand("indentMore");
} }
}); else {
} else { if (!useTabs) { editor.execCommand("insertSoftTab"); }
editor.setOption("extraKeys", { else { editor.execCommand("insertTab"); }
Tab: undefined, }
}); },
} "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'); $('.CodeMirror').css('font-size', fontSize+'px');
}; };

@ -838,13 +838,6 @@ define([
Cryptpad.setLanguage(data, cb); 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) { sframeChan.on('Q_GET_ALL_TAGS', function (data, cb) {
Cryptpad.listAllTags(function (err, tags) { Cryptpad.listAllTags(function (err, tags) {
cb({ cb({

@ -30,6 +30,7 @@
@drive_content-bg-ro: darken(@drive_content-bg, 10%); @drive_content-bg-ro: darken(@drive_content-bg, 10%);
@drive_selected-bg: #888; @drive_selected-bg: #888;
@drive_droppable-bg: #FE9A2E;
/* PAGE */ /* PAGE */
@ -107,7 +108,7 @@
.cp-app-drive-container { .cp-app-drive-container {
flex: 1; flex: 1;
overflow: auto; overflow-x: auto;
width: 100%; width: 100%;
display: flex; display: flex;
flex-flow: row; flex-flow: row;
@ -121,6 +122,7 @@
#cp-app-drive-tree { #cp-app-drive-tree {
resize: none; resize: none;
width: 100% !important; width: 100% !important;
min-width: unset;
max-width: unset; max-width: unset;
max-height: unset; max-height: unset;
border-bottom: 1px solid @drive_mobile-tree-border-col; border-bottom: 1px solid @drive_mobile-tree-border-col;
@ -156,7 +158,7 @@
} }
.cp-app-drive-element-droppable { .cp-app-drive-element-droppable {
background-color: #FE9A2E; background-color: @drive_droppable-bg;
color: #222; color: #222;
} }
@ -239,7 +241,6 @@
max-height: 100%; max-height: 100%;
.cp-app-drive-tree-categories-container { .cp-app-drive-tree-categories-container {
flex: 1; flex: 1;
max-width: 500px;
overflow: auto; overflow: auto;
} }
img.cp-app-drive-icon { img.cp-app-drive-icon {
@ -438,13 +439,13 @@
flex: 1; flex: 1;
// Needed to avoid the folder's path to overflows // Needed to avoid the folder's path to overflows
// https://stackoverflow.com/questions/38223879/white-space-nowrap-breaks-flexbox-layout // https://stackoverflow.com/questions/38223879/white-space-nowrap-breaks-flexbox-layout
min-width: 0; // min-width: 0;
} }
#cp-app-drive-content { #cp-app-drive-content {
box-sizing: border-box; box-sizing: border-box;
background: @drive_content-bg; background: @drive_content-bg;
color: @drive_content-fg; color: @drive_content-fg;
overflow: auto; overflow-y: auto;
flex: 1; flex: 1;
display: flex; display: flex;
flex-flow: column; flex-flow: column;
@ -939,6 +940,7 @@
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
transition: all 0.15s; transition: all 0.15s;
cursor: pointer;
&:first-child { &:first-child {
flex-shrink: 1; flex-shrink: 1;
@ -946,17 +948,20 @@
&.cp-app-drive-path-separator { &.cp-app-drive-path-separator {
color: #ccc; color: #ccc;
cursor: default;
} }
&.cp-app-drive-path-collapse { &.cp-app-drive-path-collapse {
position: relative; 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) { &:not(.cp-app-drive-path-separator) {
background-color: darken(@colortheme_drive-bg, 15%); background-color: darken(@colortheme_drive-bg, 15%);
text-decoration: underline; text-decoration: underline;
cursor: pointer;
} }
& ~ .cp-app-drive-path-element { & ~ .cp-app-drive-path-element {
background-color: darken(@colortheme_drive-bg, 15%); background-color: darken(@colortheme_drive-bg, 15%);

@ -17,8 +17,6 @@ define([
'/bower_components/chainpad-listmap/chainpad-listmap.js', '/bower_components/chainpad-listmap/chainpad-listmap.js',
'/customize/messages.js', '/customize/messages.js',
'/common/jscolor.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
'less!/drive/app-drive.less', 'less!/drive/app-drive.less',
@ -43,7 +41,10 @@ define([
{ {
var APP = window.APP = { var APP = window.APP = {
editable: false, 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", 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 createContextMenu = function () {
var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [ var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [
h('ul.dropdown-menu', { h('ul.dropdown-menu', {
@ -369,16 +397,34 @@ define([
'data-icon': AppConfig.applicationsIcon.slide, 'data-icon': AppConfig.applicationsIcon.slide,
'data-type': 'slide' 'data-type': 'slide'
}, Messages.button_newslide)), }, Messages.button_newslide)),
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { h('li.dropdown-submenu', [
'tabindex': '-1', h('a.cp-app-drive-context-newdocmenu.dropdown-item', {
'data-icon': AppConfig.applicationsIcon.poll, 'tabindex': '-1',
'data-type': 'poll' 'data-icon': "fa-plus",
}, Messages.button_newpoll)), }, Messages.fm_morePads || "More pads"), //XXX
h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', { h("ul.dropdown-menu", [
'tabindex': '-1', h('li', h('a.cp-app-drive-context-newdoc.dropdown-item.cp-app-drive-context-editable', {
'data-icon': AppConfig.applicationsIcon.whiteboard, 'tabindex': '-1',
'data-type': 'whiteboard' 'data-icon': AppConfig.applicationsIcon.sheet,
}, Messages.button_newwhiteboard)), '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], $separator.clone()[0],
h('li', h('a.cp-app-drive-context-empty.dropdown-item.cp-app-drive-context-editable', { h('li', h('a.cp-app-drive-context-empty.dropdown-item.cp-app-drive-context-editable', {
'tabindex': '-1', 'tabindex': '-1',
@ -415,6 +461,7 @@ define([
}, Messages.fc_prop)), }, Messages.fc_prop)),
]) ])
]); ]);
// add icons to the contextmenu options
$(menu).find("li a.dropdown-item").each(function (i, el) { $(menu).find("li a.dropdown-item").each(function (i, el) {
var $icon = $("<span>"); var $icon = $("<span>");
if ($(el).attr('data-icon')) { if ($(el).attr('data-icon')) {
@ -425,21 +472,46 @@ define([
} }
$(el).prepend($icon); $(el).prepend($icon);
}); });
// add events handlers for the contextmenu submenus
$(menu).find(".dropdown-submenu").each(function (i, el) { $(menu).find(".dropdown-submenu").each(function (i, el) {
var $el = $(el); var $el = $(el);
var $a = $el.children().filter("a"); var $a = $el.children().filter("a");
var $sub = $el.find(".dropdown-menu").first(); 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 // Add submenu expand icon
$a.append(h("span.dropdown-toggle")); $a.append(h("span.dropdown-toggle"));
// Show / hide submenu // Show / hide submenu
$el.hover(function () { $el.hover(function () {
setTimeout(function () { // wait for dom to update showSubmenu();
$sub.toggleClass("left", $el.offset().left + $el.outerWidth() + $sub.outerWidth() > $(window).width());
$sub.show();
});
}, function () { }, function () {
$sub.hide(); mouseOutSubmenu();
$sub.removeClass("left"); });
// 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); return $(menu);
@ -565,7 +637,8 @@ define([
var sel = {}; var sel = {};
var removeSelected = function (keepObj) { 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'); var $container = $driveToolbar.find('#cp-app-drive-toolbar-contextbuttons');
if (!$container.length) { return; } if (!$container.length) { return; }
$container.html(''); $container.html('');
@ -675,7 +748,9 @@ define([
delete sel.move; delete sel.move;
$content.find('.cp-app-drive-element-selected-tmp') $content.find('.cp-app-drive-element-selected-tmp')
.removeClass('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(); e.stopPropagation();
}); });
@ -710,7 +785,9 @@ define([
// Ctrl+A select all // Ctrl+A select all
if (e.which === 65 && (e.ctrlKey || (e.metaKey && APP.isMac))) { if (e.which === 65 && (e.ctrlKey || (e.metaKey && APP.isMac))) {
$content.find('.cp-app-drive-element:not(.cp-app-drive-element-selected)') $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; return;
} }
@ -723,7 +800,7 @@ define([
APP.onElementClick(ev, $(el)); 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]); } if ($selection.length === 0) { return void click($elements.first()[0]); }
var lastIndex = typeof sel.endSelected === "number" ? sel.endSelected : var lastIndex = typeof sel.endSelected === "number" ? sel.endSelected :
@ -842,12 +919,12 @@ define([
return; return;
} }
removeInput(); removeInput();
removeSelected();
var $name = $element.find('.cp-app-drive-element-name'); var $name = $element.find('.cp-app-drive-element-name');
if (!$name.length) { if (!$name.length) {
$name = $element.find('> .cp-app-drive-element'); $name = $element.find('> .cp-app-drive-element');
} }
$name.hide(); $name.hide();
var isFolder = $element.is(".cp-app-drive-element-folder:not(.cp-app-drive-element-sharedf)");
var el = manager.find(path); var el = manager.find(path);
var name = manager.isFile(el) ? manager.getTitle(el) : path[path.length - 1]; var name = manager.isFile(el) ? manager.getTitle(el) : path[path.length - 1];
if (manager.isSharedFolder(el)) { if (manager.isSharedFolder(el)) {
@ -869,14 +946,21 @@ define([
var newName = $input.val(); var newName = $input.val();
if (JSON.stringify(path) === JSON.stringify(currentPath)) { if (JSON.stringify(path) === JSON.stringify(currentPath)) {
manager.rename(path, $input.val(), function () { manager.rename(path, $input.val(), function () {
renameFoldersOpened(path, newName); if (isFolder) {
path[path.length - 1] = newName; renameFoldersOpened(path, newName);
path[path.length - 1] = newName;
}
APP.displayDirectory(path); APP.displayDirectory(path);
}); });
} }
else { else {
manager.rename(path, $input.val(), function () { 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(); refresh();
}); });
} }
@ -897,7 +981,6 @@ define([
// We don't want to open the file/folder when clicking on the input // We don't want to open the file/folder when clicking on the input
$input.on('click dblclick', function (e) { $input.on('click dblclick', function (e) {
removeSelected();
e.stopPropagation(); e.stopPropagation();
}); });
// Remove the browser ability to drag text from the input to avoid // Remove the browser ability to drag text from the input to avoid
@ -1117,8 +1200,9 @@ define([
var getSelectedPaths = function ($element) { var getSelectedPaths = function ($element) {
var paths = []; var paths = [];
if ($('.cp-app-drive-element-selected').length > 1) { if (!$element || $element.length === 0) { return paths; }
var $selected = $('.cp-app-drive-element-selected'); if (findSelectedElements().length > 1) {
var $selected = findSelectedElements();
$selected.each(function (idx, elmt) { $selected.each(function (idx, elmt) {
var ePath = $(elmt).data('path'); var ePath = $(elmt).data('path');
if (ePath) { if (ePath) {
@ -1147,7 +1231,7 @@ define([
} else { } else {
$driveToolbar.find('cp-app-drive-toolbar-emptytrash').hide(); $driveToolbar.find('cp-app-drive-toolbar-emptytrash').hide();
} }
var $li = $content.find('.cp-app-drive-element-selected'); var $li = findSelectedElements();
if ($li.length === 0) { if ($li.length === 0) {
$li = findDataHolder($tree.find('.cp-app-drive-element-active')); $li = findDataHolder($tree.find('.cp-app-drive-element-active'));
} }
@ -1214,6 +1298,7 @@ define([
if (pos+eh <= h && pos >= 0) { return; } if (pos+eh <= h && pos >= 0) { return; }
$content.scrollTop(v); $content.scrollTop(v);
}; };
// Add the "selected" class to the "li" corresponding to the clicked element // Add the "selected" class to the "li" corresponding to the clicked element
var onElementClick = APP.onElementClick = function (e, $element) { var onElementClick = APP.onElementClick = function (e, $element) {
// If "Ctrl" is pressed, do not remove the current selection // If "Ctrl" is pressed, do not remove the current selection
@ -1250,34 +1335,33 @@ define([
var $el; var $el;
removeSelected(true); removeSelected(true);
sel.oldSelection.forEach(function (el) { sel.oldSelection.forEach(function (el) {
if (!$(el).hasClass("cp-app-drive-element-selected")) { if (!isElementSelected($(el))) {
$(el).addClass("cp-app-drive-element-selected"); selectElement($(el));
} }
}); });
for (var i = Math.min(sel.startSelected, sel.endSelected); for (var i = Math.min(sel.startSelected, sel.endSelected);
i <= Math.max(sel.startSelected, sel.endSelected); i <= Math.max(sel.startSelected, sel.endSelected);
i++) { i++) {
$el = $($elements.get(i)); $el = $($elements.get(i));
if (!$el.hasClass("cp-app-drive-element-selected")) { if (!isElementSelected($el)) {
$el.addClass("cp-app-drive-element-selected"); selectElement($el);
} }
} }
} else { } else {
if (!$element.hasClass("cp-app-drive-element-selected")) { if (!isElementSelected($element)) {
$element.addClass("cp-app-drive-element-selected"); selectElement($element);
} else { } else {
$element.removeClass("cp-app-drive-element-selected"); unselectElement($element);
} }
} }
updateContextButton(); updateContextButton();
}; };
var displayMenu = function (e) { // show / hide dropdown separators
var $menu = $contextMenu; var hideSeparators = function ($menu) {
var showSep = false; var showSep = false;
var $lastVisibleSep = null; var $lastVisibleSep = null;
// show / hide drop-down divider $menu.children().each(function (i, el) {
$menu.find(".dropdown-menu").children().each(function (i, el) {
var $el = $(el); var $el = $(el);
if ($el.is(".dropdown-divider")) { if ($el.is(".dropdown-divider")) {
$el.css("display", showSep ? "list-item" : "none"); $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 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 // show / hide submenus
$menu.find(".dropdown-submenu").each(function (i, el) { $menu.find(".dropdown-submenu").each(function (i, el) {
var $el = $(el); var $el = $(el);
$el.children(".dropdown-menu").css("display", "none");
$el.find("li").each(function (i, li) { $el.find("li").each(function (i, li) {
if ($(li).css("display") !== "none") { if ($(li).css("display") !== "none") {
$(el).css("display", "block"); $el.css("display", "block");
return; return;
} }
}); });
}); });
// show / hide separators
$menu.find(".dropdown-menu").each(function (i, menu) {
hideSeparators($(menu));
});
// show contextmenu at cursor position
$menu.css({ display: "block" }); $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 h = $menu.outerHeight();
var w = $menu.outerWidth(); var w = $menu.outerWidth();
var wH = window.innerHeight; var wH = window.innerHeight;
@ -1353,6 +1455,17 @@ define([
} else { } else {
var $element = findDataHolder($(e.target)); 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 (type === 'trash' && !$element.data('path')) { return; }
if (!$element.length) { if (!$element.length) {
@ -1361,8 +1474,8 @@ define([
return false; return false;
} }
if (!$element.hasClass('cp-app-drive-element-selected')) { if (!isElementSelected($element)) {
onElementClick(undefined, $element); selectElement($element);
} }
paths = getSelectedPaths($element); paths = getSelectedPaths($element);
@ -1432,6 +1545,7 @@ define([
if (!res) { return; } if (!res) { return; }
manager.delete(pathsList, function () { manager.delete(pathsList, function () {
pathsList.forEach(removeFoldersOpened); pathsList.forEach(removeFoldersOpened);
removeSelected();
refresh(); refresh();
}); });
}, null, true); }, null, true);
@ -1442,7 +1556,7 @@ define([
var paths = []; var paths = [];
var $element = findDataHolder($(ev.target)); var $element = findDataHolder($(ev.target));
if ($element.hasClass('cp-app-drive-element-selected')) { if ($element.hasClass('cp-app-drive-element-selected')) {
var $selected = $('.cp-app-drive-element-selected'); var $selected = findSelectedElements();
$selected.each(function (idx, elmt) { $selected.each(function (idx, elmt) {
var ePath = $(elmt).data('path'); var ePath = $(elmt).data('path');
if (ePath) { if (ePath) {
@ -1459,7 +1573,7 @@ define([
}); });
} else { } else {
removeSelected(); removeSelected();
$element.addClass('cp-app-drive-element-selected'); selectElement($element);
var val = manager.find(path); var val = manager.find(path);
if (!val) { return; } // The element is not in the object if (!val) { return; } // The element is not in the object
paths = [{ paths = [{
@ -1478,7 +1592,13 @@ define([
var findDropPath = function (target) { var findDropPath = function (target) {
var $target = $(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 newPath = $el.data('path');
var dropEl = newPath && manager.find(newPath); var dropEl = newPath && manager.find(newPath);
if (newPath && manager.isSharedFolder(dropEl)) { if (newPath && manager.isSharedFolder(dropEl)) {
@ -1606,7 +1726,8 @@ define([
$owner.attr('title', Messages.fm_padIsOwnedOther); $owner.attr('title', Messages.fm_padIsOwnedOther);
} }
}; };
var addFileData = function (element, $span) { var thumbsUrls = {};
var addFileData = function (element, $element) {
if (!manager.isFile(element)) { return; } if (!manager.isFile(element)) { return; }
var data = manager.getFileData(element); var data = manager.getFileData(element);
@ -1615,7 +1736,7 @@ define([
var hrefData = Hash.parsePadUrl(href); var hrefData = Hash.parsePadUrl(href);
if (hrefData.type) { 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'}); var $state = $('<span>', {'class': 'cp-app-drive-element-state'});
@ -1635,25 +1756,38 @@ define([
var $expire = $expirableIcon.clone().appendTo($state); var $expire = $expirableIcon.clone().appendTo($state);
$expire.attr('title', Messages._getKey('fm_expirablePad', [new Date(data.expire).toLocaleString()])); $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); var name = manager.getTitle(element);
// The element with the class '.name' is underlined when the 'li' is hovered // The element with the class '.name' is underlined when the 'li' is hovered
var $name = $('<span>', {'class': 'cp-app-drive-element-name'}).text(name); var $name = $('<span>', {'class': 'cp-app-drive-element-name'}).text(name);
$span.append($name); $element.append($name);
$span.append($state); $element.append($state);
$span.attr('title', name); $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; 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>', { var $type = $('<span>', {
'class': 'cp-app-drive-element-type cp-app-drive-element-list' 'class': 'cp-app-drive-element-type cp-app-drive-element-list'
}).text(type); }).text(type);
@ -1663,7 +1797,7 @@ define([
var $cdate = $('<span>', { var $cdate = $('<span>', {
'class': 'cp-app-drive-element-ctime cp-app-drive-element-list' 'class': 'cp-app-drive-element-ctime cp-app-drive-element-list'
}).text(getDate(data.ctime)); }).text(getDate(data.ctime));
$span.append($type).append($adate).append($cdate); $element.append($type).append($adate).append($cdate);
}; };
var addFolderData = function (element, key, $span) { var addFolderData = function (element, key, $span) {
@ -1739,12 +1873,9 @@ define([
draggable: true, draggable: true,
'class': 'cp-app-drive-element-row' 'class': 'cp-app-drive-element-row'
}); });
if (!isFolder && Array.isArray(APP.selectedFiles)) { $element.data('path', newPath);
var idx = APP.selectedFiles.indexOf(element); if (isElementSelected($element)) {
if (idx !== -1) { selectElement($element);
$element.addClass('cp-app-drive-element-selected');
APP.selectedFiles.splice(idx, 1);
}
} }
$element.prepend($icon).dblclick(function () { $element.prepend($icon).dblclick(function () {
if (isFolder) { if (isFolder) {
@ -1760,11 +1891,10 @@ define([
addFileData(element, $element); addFileData(element, $element);
} }
$element.addClass(liClass); $element.addClass(liClass);
$element.data('path', newPath);
addDragAndDropHandlers($element, newPath, isFolder, !isTrash); addDragAndDropHandlers($element, newPath, isFolder, !isTrash);
$element.click(function(e) { $element.click(function(e) {
e.stopPropagation(); e.stopPropagation();
onElementClick(e, $element, newPath); onElementClick(e, $element);
}); });
if (!isTrash) { if (!isTrash) {
$element.contextmenu(openContextMenu('tree')); $element.contextmenu(openContextMenu('tree'));
@ -1915,6 +2045,8 @@ define([
} else if (idx > 0 && manager.isFile(el)) { } else if (idx > 0 && manager.isFile(el)) {
name = getElementName(path); 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); } if (idx === 0) { name = p === SHARED_FOLDER ? name : getPrettyName(p); }
else { else {
@ -2559,22 +2691,19 @@ define([
'class': 'cp-app-drive-element cp-app-drive-element-file cp-app-drive-element-row' + roClass, 'class': 'cp-app-drive-element cp-app-drive-element-file cp-app-drive-element-row' + roClass,
draggable: draggable draggable: draggable
}); });
if (Array.isArray(APP.selectedFiles)) {
var sidx = APP.selectedFiles.indexOf(id); var path = [rootName, idx];
if (sidx !== -1) { $element.data('path', path);
$element.addClass('cp-app-drive-element-selected'); if (isElementSelected($element)) {
APP.selectedFiles.splice(sidx, 1); selectElement($element);
}
} }
$element.prepend($icon).dblclick(function () { $element.prepend($icon).dblclick(function () {
openFile(id); openFile(id);
}); });
addFileData(id, $element); addFileData(id, $element);
var path = [rootName, idx];
$element.data('path', path);
$element.click(function(e) { $element.click(function(e) {
e.stopPropagation(); e.stopPropagation();
onElementClick(e, $element, path); onElementClick(e, $element);
}); });
$element.contextmenu(openContextMenu('default')); $element.contextmenu(openContextMenu('default'));
$element.data('context', 'default'); $element.data('context', 'default');
@ -2701,8 +2830,8 @@ define([
e.preventDefault(); e.preventDefault();
if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; } if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; }
else { parentPath.pop(); } else { parentPath.pop(); }
APP.selectedFiles = [r.id];
APP.displayDirectory(parentPath); APP.displayDirectory(parentPath);
APP.selectedFiles = path.slice(-1);
}).appendTo($openDir); }).appendTo($openDir);
} }
$('<a>').text(Messages.fc_prop).click(function () { $('<a>').text(Messages.fc_prop).click(function () {
@ -2793,7 +2922,7 @@ define([
$element.data('path', path); $element.data('path', path);
$element.click(function(e) { $element.click(function(e) {
e.stopPropagation(); e.stopPropagation();
onElementClick(e, $element, path); onElementClick(e, $element);
}); });
$element.contextmenu(openContextMenu('default')); $element.contextmenu(openContextMenu('default'));
$element.data('context', 'default'); $element.data('context', 'default');
@ -3017,7 +3146,7 @@ define([
$context.click(function (e) { $context.click(function (e) {
e.preventDefault(); e.preventDefault();
e.stopPropagation(); e.stopPropagation();
var $li = $content.find('.cp-app-drive-element-selected'); var $li = findSelectedElements();
if ($li.length !== 1) { if ($li.length !== 1) {
$li = findDataHolder($tree.find('.cp-app-drive-element-active')); $li = findDataHolder($tree.find('.cp-app-drive-element-active'));
} }
@ -3027,11 +3156,6 @@ define([
return; return;
} }
// Open the menu // Open the menu
$('.cp-contextmenu').css({
top: ($context.offset().top + 32) + 'px',
right: '0px',
left: ''
});
$li.contextmenu(); $li.contextmenu();
}); });
} else { } else {
@ -3099,7 +3223,7 @@ define([
} }
});*/ });*/
var $sel = $content.find('.cp-app-drive-element-selected'); var $sel = findSelectedElements();
if ($sel.length) { if ($sel.length) {
$sel[0].scrollIntoView(); $sel[0].scrollIntoView();
} else { } else {
@ -3111,6 +3235,9 @@ define([
if (history.isHistoryMode) { if (history.isHistoryMode) {
return void _displayDirectory(path, force); return void _displayDirectory(path, force);
} }
if (!manager.comparePath(currentPath, path)) {
removeSelected();
}
updateObject(sframeChan, proxy, function () { updateObject(sframeChan, proxy, function () {
copyObjectValue(files, proxy.drive); copyObjectValue(files, proxy.drive);
updateSharedFolders(sframeChan, manager, files, folders, function () { updateSharedFolders(sframeChan, manager, files, folders, function () {
@ -3461,6 +3588,7 @@ define([
if (!res) { return; } if (!res) { return; }
manager.delete(pathsList, function () { manager.delete(pathsList, function () {
pathsList.forEach(removeFoldersOpened); pathsList.forEach(removeFoldersOpened);
removeSelected();
refresh(); refresh();
}); });
}); });
@ -3482,7 +3610,7 @@ define([
if (paths.length !== 1) { return; } if (paths.length !== 1) { return; }
displayRenameInput(paths[0].element, paths[0].path); 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); var currentColor = getFolderColor(paths[0].path);
pickFolderColor(paths[0].element, currentColor, function (color) { pickFolderColor(paths[0].element, currentColor, function (color) {
paths.forEach(function (p) { paths.forEach(function (p) {
@ -3707,16 +3835,15 @@ define([
var parentPath = paths[0].path.slice(); var parentPath = paths[0].path.slice();
if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; } if (manager.isInTrashRoot(parentPath)) { parentPath = [TRASH]; }
else { parentPath.pop(); } else { parentPath.pop(); }
el = manager.find(paths[0].path);
APP.selectedFiles = [el];
APP.displayDirectory(parentPath); APP.displayDirectory(parentPath);
APP.selectedFiles = paths[0].path.slice(-1);
} }
APP.hideMenu(); APP.hideMenu();
}); });
$content.on("keydown", function (e) { $(window).on("keydown", function (e) {
if (e.which === 113) { if (e.which === 113) { // if F2 key pressed
var paths = $contextMenu.data('paths'); var paths = getSelectedPaths(findSelectedElements().first());
if (paths.length !== 1) { return; } if (paths.length !== 1) { return; }
displayRenameInput(paths[0].element, paths[0].path); displayRenameInput(paths[0].element, paths[0].path);
} }
@ -3728,10 +3855,9 @@ define([
e.preventDefault(); e.preventDefault();
}); });
$appContainer.on('mouseup', function (e) { $appContainer.on('mouseup', function (e) {
//if (sel.down) { return; }
if (e.which !== 1) { 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); APP.hideMenu(e);
//removeSelected(e);
}); });
$appContainer.on('click', function (e) { $appContainer.on('click', function (e) {
if (e.which !== 1) { return ; } if (e.which !== 1) { return ; }
@ -3750,7 +3876,7 @@ define([
if (manager.isPathIn(currentPath, [FILES_DATA]) && APP.loggedIn) { if (manager.isPathIn(currentPath, [FILES_DATA]) && APP.loggedIn) {
return; // We can't remove elements directly from filesData return; // We can't remove elements directly from filesData
} }
var $selected = $('.cp-app-drive-element-selected'); var $selected = findSelectedElements();
if (!$selected.length) { return; } if (!$selected.length) { return; }
var paths = []; var paths = [];
var isTrash = manager.isPathIn(currentPath, [TRASH]); var isTrash = manager.isPathIn(currentPath, [TRASH]);

@ -52,6 +52,16 @@
max-width: 100%; max-width: 100%;
max-height: ~"calc(100vh - 96px)"; 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 { #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. // Pads from the code app will be exported using this format instead of plain text.
define([ define([
], function () { ], function () {
var module = {}; var module = {
ext: '.json'
};
module.main = function (userDoc, cb) { module.main = function (userDoc, cb) {
var content = userDoc.content; 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)], { return new Blob([JSON.stringify(kanban.getBoardsJSON(), 0, 2)], {
type: 'application/json', type: 'application/json',
}); });

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

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

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

@ -111,8 +111,14 @@
vertical-align: middle; vertical-align: middle;
margin-right: 5px; margin-right: 5px;
} }
input[type="color"] { .cp-settings-cursor-color-picker {
width: 100px; display: inline-block;
vertical-align: middle;
height: 25px;
width: 70px;
margin-right: 10px;
cursor: pointer;
border: 1px solid black;
} }
.cp-settings-language-selector { .cp-settings-language-selector {
button.btn { button.btn {

@ -15,6 +15,7 @@ define([
'/settings/make-backup.js', '/settings/make-backup.js',
'/common/common-feedback.js', '/common/common-feedback.js',
'/common/jscolor.js',
'/bower_components/file-saver/FileSaver.min.js', '/bower_components/file-saver/FileSaver.min.js',
'css!/bower_components/bootstrap/dist/css/bootstrap.min.css', 'css!/bower_components/bootstrap/dist/css/bootstrap.min.css',
'css!/bower_components/components-font-awesome/css/font-awesome.min.css', 'css!/bower_components/components-font-awesome/css/font-awesome.min.css',
@ -1191,13 +1192,13 @@ define([
var $inputBlock = $('<div>').appendTo($div); 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 $ok = $('<span>', {'class': 'fa fa-check', title: Messages.saved});
var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'}); var $spinner = $('<span>', {'class': 'fa fa-spinner fa-pulse'});
var $input = $('<input>', { // when jscolor picker value change
type: 'color', var onchange = function (colorL) {
}).on('change', function () { var val = "#" + colorL.toString();
var val = $input.val();
if (!/^#[0-9a-fA-F]{6}$/.test(val)) { return; } if (!/^#[0-9a-fA-F]{6}$/.test(val)) { return; }
$spinner.show(); $spinner.show();
$ok.hide(); $ok.hide();
@ -1205,15 +1206,25 @@ define([
$spinner.hide(); $spinner.hide();
$ok.show(); $ok.show();
}); });
}).appendTo($inputBlock); };
$ok.hide().appendTo($inputBlock); // jscolor picker
$spinner.hide().appendTo($inputBlock); 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) { common.getAttribute(['general', 'cursor', 'color'], function (e, val) {
if (e) { return void console.error(e); } 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; return $div;
}; };

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

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

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

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

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

Loading…
Cancel
Save