Open plain text files in code app && plain text files thumbnail

pull/1/head
ClemDee 5 years ago
parent 3a8914aefa
commit f55c8c6b04

@ -7,6 +7,7 @@ define(function () {
fileHashKey: 'FS_hash',
// sessionStorage
newPadPathKey: "newPadPath",
newPadFileData: "newPadFileData",
// Store
displayNameKey: 'cryptpad.username',
oldStorageKey: 'CryptPad_RECENTPADS',

@ -15,6 +15,7 @@ define([
};
var supportedTypes = [
'text/plain',
'image/png',
'image/jpeg',
'image/jpg',
@ -23,7 +24,11 @@ define([
'application/pdf'
];
Thumb.isSupportedType = function (type) {
Thumb.isSupportedType = function (file) {
var type = file.type;
if (Util.isPlainTextFile(file.type, file.name)) {
type = "text/plain";
}
return supportedTypes.some(function (t) {
return type.indexOf(t) !== -1;
});
@ -164,6 +169,26 @@ define([
});
});
};
Thumb.fromPlainTextBlob = function (blob, cb) {
var canvas = document.createElement("canvas");
canvas.width = canvas.height = Thumb.dimension;
var reader = new FileReader();
reader.addEventListener('loadend', function (e) {
var content = e.srcElement.result;
var lines = content.split("\n");
var canvasContext = canvas.getContext("2d");
var fontSize = 4;
canvas.height = (lines.length) * (fontSize + 1);
canvasContext.font = fontSize + 'px monospace';
lines.forEach(function (text, i) {
canvasContext.fillText(text, 5, i * (fontSize + 1));
});
var D = getResizedDimensions(canvas, "txt");
Thumb.fromCanvas(canvas, D, cb);
});
reader.readAsText(blob);
};
Thumb.fromBlob = function (blob, cb) {
if (blob.type.indexOf('video/') !== -1) {
return void Thumb.fromVideoBlob(blob, cb);
@ -171,6 +196,9 @@ define([
if (blob.type.indexOf('application/pdf') !== -1) {
return void Thumb.fromPdfBlob(blob, cb);
}
if (Util.isPlainTextFile(blob.type, blob.name)) {
return void Thumb.fromPlainTextBlob(blob, cb);
}
Thumb.fromImageBlob(blob, cb);
};

@ -2274,7 +2274,10 @@ define([
if (!common.isLoggedIn()) { return void cb(); }
var sframeChan = common.getSframeChannel();
var metadataMgr = common.getMetadataMgr();
var privateData = metadataMgr.getPrivateData();
var type = metadataMgr.getMetadataLazy().type;
var fromFileData = privateData.fromFileData;
var $body = $('body');
var $creationContainer = $('<div>', { id: 'cp-creation-container' }).appendTo($body);
@ -2286,7 +2289,8 @@ define([
// Title
//var colorClass = 'cp-icon-color-'+type;
//$creation.append(h('h2.cp-creation-title', Messages.newButtonTitle));
$creation.append(h('h3.cp-creation-title', Messages['button_new'+type]));
var newPadH3Title = Messages['button_new' + type];
$creation.append(h('h3.cp-creation-title', newPadH3Title));
//$creation.append(h('h2.cp-creation-title.'+colorClass, Messages.newButtonTitle));
// Deleted pad warning
@ -2296,7 +2300,7 @@ define([
));
}
var origin = common.getMetadataMgr().getPrivateData().origin;
var origin = privateData.origin;
var createHelper = function (href, text) {
var q = h('a.cp-creation-help.fa.fa-question-circle', {
title: text,
@ -2453,7 +2457,26 @@ define([
});
if (i < TEMPLATES_DISPLAYED) { $(left).addClass('hidden'); }
};
redraw(0);
if (fromFileData) {
var todo = function (thumbnail) {
allData = [{
name: fromFileData.title,
id: 0,
thumbnail: thumbnail,
icon: h('span.cptools.cptools-file'),
}];
redraw(0);
};
todo();
sframeChan.query("Q_GET_FILE_THUMBNAIL", null, function (err, res) {
if (err || (res && res.error)) { return; }
todo(res.data);
});
}
else {
redraw(0);
}
// Change template selection when Tab is pressed
next = function (revert) {

@ -319,21 +319,26 @@ define([], function () {
return window.innerHeight < 800 || window.innerWidth < 800;
};
Util.isPlainTextFile = function (metadata) {
if (!metadata || !metadata.href) { return; }
console.log("%c" + metadata.title + " : " + metadata.fileType, "color: #3a7");
console.log(metadata);
var href = metadata.roHref || metadata.href;
// is it a file ?
if (!href || href.indexOf("/file/") === -1) { return false; }
// return an
Util.parseFilename = function (filename) {
if (!filename || !filename.trim()) { return {}; }
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(filename) || [];
return {
name: parsedName[1],
ext: parsedName[2],
}
}
// Tell if a file is plain text from its metadata={title, fileType}
Util.isPlainTextFile = function (type, name) {
// does its type begins with "text/"
if (metadata.fileType.indexOf("text/") === 0) { return true; }
if (type && type.indexOf("text/") === 0) { return true; }
// no type and no file extension -> let's guess it's plain text
var parsedName = /^(\.?.+?)(\.[^.]+)?$/.exec(metadata.title) || [];
if (!metadata.fileType && !parsedName[2]) { return true; }
var parsedName = Util.parseFilename(name);
if (!type && name && !parsedName.ext) { return true; }
// other exceptions
if (metadata.fileType === 'application/x-javascript') { return true; }
if (metadata.fileType === 'application/xml') { return true; }
if (type === 'application/x-javascript') { return true; }
if (type === 'application/xml') { return true; }
return false;
};

@ -9,11 +9,12 @@ define([
'/common/outer/local-store.js',
'/common/outer/worker-channel.js',
'/common/outer/login-block.js',
'/file/file-crypto.js',
'/customize/application_config.js',
'/bower_components/nthen/index.js',
], function (Config, Messages, Util, Hash,
Messaging, Constants, Feedback, LocalStore, Channel, Block,
Messaging, Constants, Feedback, LocalStore, Channel, Block, FileCrypto,
AppConfig, Nthen) {
/* This file exposes functionality which is specific to Cryptpad, but not to
@ -567,6 +568,64 @@ define([
});
};
common.useFile = function (Crypt, cb, optsPut) {
var data = common.fromFileData;
var parsed = Hash.parsePadUrl(data.href);
var parsed2 = Hash.parsePadUrl(window.location.href);
var hash = parsed.hash;
var name = data.title;
var secret = Hash.getSecrets('file', hash, data.password);
var src = Hash.getBlobPathFromHex(secret.channel);
var key = secret.keys && secret.keys.cryptKey;
var u8;
var res;
var mode;
var val;
Nthen(function(waitFor) {
Util.fetch(src, waitFor(function (err, _u8) {
if (err) { return void waitFor.abort(); }
u8 = _u8;
}));
}).nThen(function (waitFor) {
FileCrypto.decrypt(u8, key, waitFor(function (err, _res) {
if (err || !_res.content) { return void waitFor.abort(); }
res = _res;
}));
}).nThen(function (waitFor) {
var ext = Util.parseFilename(data.title).ext;
if (!ext) {
mode = "text";
return;
}
require(["/common/modes.js"], waitFor(function (Modes) {
var fileType = Modes.list.some(function (fType) {
if (fType.ext === ext) {
mode = fType.mode;
return true;
}
});
}));
}).nThen(function (waitFor) {
var reader = new FileReader();
reader.addEventListener('loadend', waitFor(function (e) {
val = {
content: e.srcElement.result,
highlightMode: mode,
metadata: {
defaultTitle: name,
title: name,
type: "code",
},
};
}));
reader.readAsText(res.content);
}).nThen(function () {
Crypt.put(parsed2.hash, JSON.stringify(val), cb, optsPut);
});
};
// Forget button
common.moveToTrash = function (cb, href) {
href = href || window.location.href;
@ -1263,6 +1322,12 @@ define([
messenger: rdyCfg.messenger, // Boolean
driveEvents: rdyCfg.driveEvents // Boolean
};
// if a pad is created from a file
if (sessionStorage[Constants.newPadFileData]) {
common.fromFileData = JSON.parse(sessionStorage[Constants.newPadFileData]);
delete sessionStorage[Constants.newPadFileData];
}
if (sessionStorage[Constants.newPadPathKey]) {
common.initialPath = sessionStorage[Constants.newPadPathKey];
delete sessionStorage[Constants.newPadPathKey];

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

@ -367,7 +367,7 @@ define([
blobToArrayBuffer(file, function (e, buffer) {
if (e) { console.error(e); }
file_arraybuffer = buffer;
if (!Thumb.isSupportedType(file.type)) { return getName(); }
if (!Thumb.isSupportedType(file)) { return getName(); }
// make a resized thumbnail from the image..
Thumb.fromBlob(file, function (e, thumb64) {
if (e) { console.error(e); }

@ -317,6 +317,9 @@ define([
channel: secret.channel,
enableSF: localStorage.CryptPad_SF === "1", // TODO to remove when enabled by default
devMode: localStorage.CryptPad_dev === "1",
fromFileData: Cryptpad.fromFileData ? {
title: Cryptpad.fromFileData.title
} : undefined,
};
if (window.CryptPad_newSharedFolder) {
additionalPriv.newSharedFolder = window.CryptPad_newSharedFolder;
@ -357,6 +360,8 @@ define([
sframeChan.event("EV_NEW_VERSION");
});
// Put in the following function the RPC queries that should also work in filepicker
var addCommonRpc = function (sframeChan) {
sframeChan.on('Q_ANON_RPC_MESSAGE', function (data, cb) {
@ -808,6 +813,22 @@ define([
});
});
sframeChan.on('Q_GET_FILE_THUMBNAIL', function (data, cb) {
if (!Cryptpad.fromFileData.href) {
return void cb({
error: "EINVAL",
});
}
var key = getKey(Cryptpad.fromFileData.href, Cryptpad.fromFileData.channel);
Utils.LocalStore.getThumbnail(key, function (e, data) {
if (data === "EMPTY") { data = null; }
cb({
error: e,
data: data
});
});
});
sframeChan.on('EV_GOTO_URL', function (url) {
if (url) {
window.location.href = url;
@ -1080,11 +1101,11 @@ define([
}));
}
}).nThen(function () {
var cryptputCfg = $.extend(true, {}, rtConfig, {password: password});
if (data.template) {
// Pass rtConfig to useTemplate because Cryptput will create the file and
// we need to have the owners and expiration time in the first line on the
// server
var cryptputCfg = $.extend(true, {}, rtConfig, {password: password});
Cryptpad.useTemplate({
href: data.template
}, Cryptget, function () {
@ -1093,6 +1114,14 @@ define([
}, cryptputCfg);
return;
}
// if we open a new code from a file
if (Cryptpad.fromFileData) {
Cryptpad.useFile(Cryptget, function () {
startRealtime();
cb();
}, cryptputCfg);
return;
}
// Start realtime outside the iframe and callback
startRealtime(rtConfig);
cb();

@ -1025,10 +1025,15 @@ define([
hide.push('openro'); // Remove open 'view' mode
}
// if it's not a plain text file
var isPlainTextFile = false;
var metadata = manager.getFileData(manager.find(path));
if (!metadata || !Util.isPlainTextFile(metadata)) {
hide.push('openincode');
if (metadata) {
var href = metadata.roHref || metadata.href;
if (href && Hash.parsePadUrl(href).type === "file") {
isPlainTextFile = Util.isPlainTextFile(metadata.fileType, metadata.title);
}
}
if (!isPlainTextFile) { hide.push('openincode'); }
} else if ($element.is('.cp-app-drive-element-sharedf')) {
if (containsFolder) {
// More than 1 folder selected: cannot create a new subfolder
@ -3539,11 +3544,20 @@ define([
}
else if ($(this).hasClass('cp-app-drive-context-openincode')) {
paths.forEach(function (p) {
console.info("p", p);
var el = manager.find(p.path);
var metadata = manager.getFileData(el);
console.log(el);
// open code from template
var simpleData = {
title: metadata.filename || metadata.title,
href: metadata.href,
password: metadata.password,
channel: metadata.channel,
};
nThen(function (waitFor) {
common.sessionStorage.put(Constants.newPadFileData, JSON.stringify(simpleData), waitFor());
common.sessionStorage.put(Constants.newPadPathKey, currentPath, waitFor());
}).nThen(function () {
common.openURL('/code/');
});
});
}
else if ($(this).hasClass('cp-app-drive-context-expandall') ||

Loading…
Cancel
Save