Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging
This commit is contained in:
commit
90518224fe
21 changed files with 797 additions and 446 deletions
|
@ -90,6 +90,11 @@
|
|||
border: 1px solid #BBB;
|
||||
}
|
||||
|
||||
pre.mermaid {
|
||||
svg {
|
||||
max-width: 100%;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.markdown_preformatted-code (@color: #333) {
|
||||
|
|
|
@ -24,6 +24,9 @@
|
|||
.cp-modal-container {
|
||||
display: none;
|
||||
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
z-index: 100000; //Z modal container
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
@ -39,9 +42,11 @@
|
|||
|
||||
padding: @variables_padding;
|
||||
|
||||
position: absolute;
|
||||
top: 15vh; bottom: 15vh;
|
||||
left: 10vw; right: 10vw;
|
||||
position: relative;
|
||||
//top: 15vh; bottom: 15vh;
|
||||
//left: 10vw; right: 10vw;
|
||||
width: 90vw;
|
||||
max-height: 95vh;
|
||||
|
||||
overflow: auto;
|
||||
|
||||
|
|
|
@ -106,4 +106,60 @@
|
|||
.cp-teams-help {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
// mediatag preview
|
||||
#cp-mediatag-preview-modal {
|
||||
.cp-modal {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
.cp-mediatag-container {
|
||||
width: 100%;
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
overflow: auto;
|
||||
media-tag {
|
||||
& > * {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
video, iframe {
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
& > iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
min-height: 75vh;
|
||||
}
|
||||
& > .plain-text-reader {
|
||||
white-space: pre-wrap;
|
||||
text-align: left;
|
||||
word-break: break-word;
|
||||
color: @cryptpad_text_col;
|
||||
padding: 5px;
|
||||
}
|
||||
}
|
||||
pre.mermaid {
|
||||
overflow: unset;
|
||||
margin-bottom: 0;
|
||||
}
|
||||
.cp-spinner {
|
||||
border-color: @colortheme_logo-1;
|
||||
border-top-color: transparent;
|
||||
}
|
||||
}
|
||||
.cp-mediatag-control {
|
||||
align-self: center;
|
||||
.fa {
|
||||
margin: 10px;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
.cp-mediatag-outer {
|
||||
display: flex;
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
align-items: center;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -371,7 +371,7 @@
|
|||
width: 200px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
.fa {
|
||||
.fa, .cptools {
|
||||
font-size: 32px;
|
||||
min-width: 50px;
|
||||
}
|
||||
|
|
|
@ -462,6 +462,42 @@ define([
|
|||
return frame;
|
||||
};
|
||||
|
||||
UI.createModal = function (cfg) {
|
||||
var $body = cfg.$body || $('body');
|
||||
var $blockContainer = $body.find('#'+cfg.id);
|
||||
if (!$blockContainer.length) {
|
||||
$blockContainer = $(h('div.cp-modal-container#'+cfg.id, {
|
||||
tabindex: 1
|
||||
}));
|
||||
}
|
||||
var hide = function () {
|
||||
if (cfg.onClose) { return void cfg.onClose(); }
|
||||
$blockContainer.hide();
|
||||
if (cfg.onClosed) { cfg.onClosed(); }
|
||||
};
|
||||
$blockContainer.html('').appendTo($body);
|
||||
var $block = $(h('div.cp-modal')).appendTo($blockContainer);
|
||||
$(h('span.cp-modal-close.fa.fa-times', {
|
||||
title: Messages.filePicker_close
|
||||
})).click(hide).appendTo($block);
|
||||
$body.click(hide);
|
||||
$block.click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
$body.keydown(function (e) {
|
||||
if (e.which === 27) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
return {
|
||||
$modal: $blockContainer,
|
||||
show: function () {
|
||||
$blockContainer.css('display', 'flex');
|
||||
},
|
||||
hide: hide
|
||||
};
|
||||
};
|
||||
|
||||
UI.alert = function (msg, cb, opt) {
|
||||
var force = false;
|
||||
if (typeof(opt) === 'object') {
|
||||
|
@ -1254,5 +1290,65 @@ define([
|
|||
};
|
||||
};
|
||||
|
||||
UI.createContextMenu = function (menu) {
|
||||
var $menu = $(menu).appendTo($('body'));
|
||||
|
||||
var display = function (e) {
|
||||
$menu.css({ display: "block" });
|
||||
var h = $menu.outerHeight();
|
||||
var w = $menu.outerWidth();
|
||||
var wH = window.innerHeight;
|
||||
var wW = window.innerWidth;
|
||||
if (h > wH) {
|
||||
$menu.css({
|
||||
top: '0px',
|
||||
bottom: ''
|
||||
});
|
||||
} else if (e.pageY + h <= wH) {
|
||||
$menu.css({
|
||||
top: e.pageY+'px',
|
||||
bottom: ''
|
||||
});
|
||||
} else {
|
||||
$menu.css({
|
||||
bottom: '0px',
|
||||
top: ''
|
||||
});
|
||||
}
|
||||
if(w > wW) {
|
||||
$menu.css({
|
||||
left: '0px',
|
||||
right: ''
|
||||
});
|
||||
} else if (e.pageX + w <= wW) {
|
||||
$menu.css({
|
||||
left: e.pageX+'px',
|
||||
right: ''
|
||||
});
|
||||
} else {
|
||||
$menu.css({
|
||||
left: '',
|
||||
right: '0px',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var hide = function () {
|
||||
$menu.hide();
|
||||
};
|
||||
var remove = function () {
|
||||
$menu.remove();
|
||||
};
|
||||
|
||||
$('body').click(hide);
|
||||
|
||||
return {
|
||||
menu: menu,
|
||||
show: display,
|
||||
hide: hide,
|
||||
remove: remove
|
||||
};
|
||||
};
|
||||
|
||||
return UI;
|
||||
});
|
||||
|
|
|
@ -8,7 +8,6 @@ define([
|
|||
'/common/common-constants.js',
|
||||
'/common/common-feedback.js',
|
||||
'/common/hyperscript.js',
|
||||
'/common/media-tag.js',
|
||||
'/common/clipboard.js',
|
||||
'/customize/messages.js',
|
||||
'/customize/application_config.js',
|
||||
|
@ -18,19 +17,10 @@ define([
|
|||
'/common/visible.js',
|
||||
|
||||
'css!/customize/fonts/cptools/style.css',
|
||||
'/bower_components/croppie/croppie.min.js',
|
||||
'css!/bower_components/croppie/croppie.css',
|
||||
], function ($, Config, Util, Hash, Language, UI, Constants, Feedback, h, MediaTag, Clipboard,
|
||||
], function ($, Config, Util, Hash, Language, UI, Constants, Feedback, h, Clipboard,
|
||||
Messages, AppConfig, Pages, NThen, InviteInner, Visible) {
|
||||
var UIElements = {};
|
||||
|
||||
// Configure MediaTags to use our local viewer
|
||||
if (MediaTag) {
|
||||
MediaTag.setDefaultConfig('pdf', {
|
||||
viewer: '/common/pdfjs/web/viewer.html'
|
||||
});
|
||||
}
|
||||
|
||||
UIElements.prettySize = function (bytes) {
|
||||
var kB = Util.bytesToKilobytes(bytes);
|
||||
if (kB < 1024) { return kB + Messages.KB; }
|
||||
|
@ -110,7 +100,7 @@ define([
|
|||
var data = users[key];
|
||||
var name = data.displayName || data.name || Messages.anonymous;
|
||||
var avatar = h('span.cp-usergrid-avatar.cp-avatar');
|
||||
UIElements.displayAvatar(common, $(avatar), data.avatar, name);
|
||||
common.displayAvatar($(avatar), data.avatar, name);
|
||||
var removeBtn, el;
|
||||
if (config.remove) {
|
||||
removeBtn = h('span.fa.fa-times');
|
||||
|
@ -1930,205 +1920,6 @@ define([
|
|||
};
|
||||
};
|
||||
|
||||
// Avatars
|
||||
|
||||
UIElements.displayMediatagImage = function (Common, $tag, cb) {
|
||||
if (!$tag.length || !$tag.is('media-tag')) { return void cb('NOT_MEDIATAG'); }
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.addedNodes.length) {
|
||||
if (mutation.addedNodes.length > 1 ||
|
||||
mutation.addedNodes[0].nodeName !== 'IMG') {
|
||||
return void cb('NOT_IMAGE');
|
||||
}
|
||||
var $image = $tag.find('img');
|
||||
var onLoad = function () {
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
var _cb = cb;
|
||||
cb = $.noop;
|
||||
_cb(null, $image, img);
|
||||
};
|
||||
img.src = $image.attr('src');
|
||||
};
|
||||
if ($image[0].complete) { onLoad(); }
|
||||
$image.on('load', onLoad);
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe($tag[0], {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
characterData: false
|
||||
});
|
||||
MediaTag($tag[0]).on('error', function (data) {
|
||||
console.error(data);
|
||||
});
|
||||
};
|
||||
|
||||
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
||||
var isEmoji = function (str) {
|
||||
return emoji_patt.test(str);
|
||||
};
|
||||
var emojiStringToArray = function (str) {
|
||||
var split = str.split(emoji_patt);
|
||||
var arr = [];
|
||||
for (var i=0; i<split.length; i++) {
|
||||
var char = split[i];
|
||||
if (char !== "") {
|
||||
arr.push(char);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
var getFirstEmojiOrCharacter = UIElements.getFirstCharacter = function (str) {
|
||||
if (!str || !str.trim()) { return '?'; }
|
||||
var emojis = emojiStringToArray(str);
|
||||
return isEmoji(emojis[0])? emojis[0]: str[0];
|
||||
};
|
||||
var avatars = {};
|
||||
UIElements.setAvatar = function (hash, data) {
|
||||
avatars[hash] = data;
|
||||
};
|
||||
UIElements.getAvatar = function (hash) {
|
||||
return avatars[hash];
|
||||
};
|
||||
UIElements.displayAvatar = function (common, $container, href, name, cb) {
|
||||
var displayDefault = function () {
|
||||
var text = (href && typeof(href) === "string") ? href : getFirstEmojiOrCharacter(name);
|
||||
var $avatar = $('<span>', {'class': 'cp-avatar-default'}).text(text);
|
||||
$container.append($avatar);
|
||||
if (cb) { cb(); }
|
||||
};
|
||||
if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol
|
||||
if (!href || href.length === 1) { return void displayDefault(); }
|
||||
|
||||
var centerImage = function ($img, $image, img) {
|
||||
var w = img.width;
|
||||
var h = img.height;
|
||||
if (w>h) {
|
||||
$image.css('max-height', '100%');
|
||||
$img.css('flex-direction', 'column');
|
||||
if (cb) { cb($img); }
|
||||
return;
|
||||
}
|
||||
$image.css('max-width', '100%');
|
||||
$img.css('flex-direction', 'row');
|
||||
if (cb) { cb($img); }
|
||||
};
|
||||
|
||||
var parsed = Hash.parsePadUrl(href);
|
||||
if (parsed.type !== "file" || parsed.hashData.type !== "file") {
|
||||
var $img = $('<media-tag>').appendTo($container);
|
||||
var img = new Image();
|
||||
$(img).attr('src', href);
|
||||
img.onload = function () {
|
||||
centerImage($img, $(img), img);
|
||||
$(img).appendTo($img);
|
||||
};
|
||||
return;
|
||||
}
|
||||
// No password for avatars
|
||||
var privateData = common.getMetadataMgr().getPrivateData();
|
||||
var origin = privateData.fileHost || privateData.origin;
|
||||
var secret = Hash.getSecrets('file', parsed.hash);
|
||||
if (secret.keys && secret.channel) {
|
||||
var hexFileName = secret.channel;
|
||||
var cryptKey = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
|
||||
var src = origin + Hash.getBlobPathFromHex(hexFileName);
|
||||
common.getFileSize(hexFileName, function (e, data) {
|
||||
if (e || !data) { return void displayDefault(); }
|
||||
if (typeof data !== "number") { return void displayDefault(); }
|
||||
if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); }
|
||||
var $img = $('<media-tag>').appendTo($container);
|
||||
$img.attr('src', src);
|
||||
$img.attr('data-crypto-key', 'cryptpad:' + cryptKey);
|
||||
UIElements.displayMediatagImage(common, $img, function (err, $image, img) {
|
||||
if (err) { return void console.error(err); }
|
||||
centerImage($img, $image, img);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
var transformAvatar = function (file, cb) {
|
||||
if (file.type === 'image/gif') { return void cb(file); }
|
||||
var $croppie = $('<div>', {
|
||||
'class': 'cp-app-profile-resizer'
|
||||
});
|
||||
|
||||
if (typeof ($croppie.croppie) !== "function") {
|
||||
console.warn('fuck');
|
||||
return void cb(file);
|
||||
}
|
||||
|
||||
var todo = function () {
|
||||
UI.confirm($croppie[0], function (yes) {
|
||||
if (!yes) { return; }
|
||||
$croppie.croppie('result', {
|
||||
type: 'blob',
|
||||
size: {width: 300, height: 300}
|
||||
}).then(function(blob) {
|
||||
blob.lastModifiedDate = new Date();
|
||||
blob.name = 'avatar';
|
||||
cb(blob);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
$croppie.croppie({
|
||||
url: e.target.result,
|
||||
viewport: { width: 100, height: 100 },
|
||||
boundary: { width: 400, height: 300 },
|
||||
});
|
||||
todo();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
UIElements.addAvatar = function (common, cb) {
|
||||
var AVATAR_SIZE_LIMIT = 0.5;
|
||||
var allowedMediaTypes = [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/gif',
|
||||
];
|
||||
var fmConfig = {
|
||||
noHandlers: true,
|
||||
noStore: true,
|
||||
body: $('body'),
|
||||
onUploaded: cb
|
||||
};
|
||||
var FM = common.createFileManager(fmConfig);
|
||||
var accepted = ".gif,.jpg,.jpeg,.png";
|
||||
var data = {
|
||||
FM: FM,
|
||||
filter: function (file) {
|
||||
var sizeMB = Util.bytesToMegabytes(file.size);
|
||||
var type = file.type;
|
||||
// We can't resize .gif so we have to display an error if it is too big
|
||||
if (sizeMB > AVATAR_SIZE_LIMIT && type === 'image/gif') {
|
||||
UI.log(Messages._getKey('profile_uploadSizeError', [
|
||||
Messages._getKey('formattedMB', [AVATAR_SIZE_LIMIT])
|
||||
]));
|
||||
return false;
|
||||
}
|
||||
// Display an error if the image type is not allowed
|
||||
if (allowedMediaTypes.indexOf(type) === -1) {
|
||||
UI.log(Messages._getKey('profile_uploadTypeError', [
|
||||
accepted.split(',').join(', ')
|
||||
]));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
transformer: transformAvatar,
|
||||
accept: accepted
|
||||
};
|
||||
return data;
|
||||
};
|
||||
|
||||
/* Create a usage bar which keeps track of how much storage space is used
|
||||
by your CryptDrive. The getPinnedUsage RPC is one of the heavier calls,
|
||||
so we throttle its usage. Clients will not update more than once per
|
||||
|
@ -2640,7 +2431,7 @@ define([
|
|||
$displayName.text(newName || Messages.anonymous);
|
||||
if (accountName && oldUrl !== url) {
|
||||
$avatar.html('');
|
||||
UIElements.displayAvatar(Common, $avatar, url,
|
||||
Common.displayAvatar($avatar, url,
|
||||
newName || Messages.anonymous, function ($img) {
|
||||
oldUrl = url;
|
||||
$userAdmin.find('> button').removeClass('cp-avatar');
|
||||
|
@ -2747,37 +2538,6 @@ define([
|
|||
return $block;
|
||||
};
|
||||
|
||||
UIElements.createModal = function (cfg) {
|
||||
var $body = cfg.$body || $('body');
|
||||
var $blockContainer = $body.find('#'+cfg.id);
|
||||
if (!$blockContainer.length) {
|
||||
$blockContainer = $('<div>', {
|
||||
'class': 'cp-modal-container',
|
||||
tabindex: 1,
|
||||
'id': cfg.id
|
||||
});
|
||||
}
|
||||
var hide = function () {
|
||||
if (cfg.onClose) { return void cfg.onClose(); }
|
||||
$blockContainer.hide();
|
||||
};
|
||||
$blockContainer.html('').appendTo($body);
|
||||
var $block = $('<div>', {'class': 'cp-modal'}).appendTo($blockContainer);
|
||||
$('<span>', {
|
||||
'class': 'cp-modal-close fa fa-times',
|
||||
'title': Messages.filePicker_close
|
||||
}).click(hide).appendTo($block);
|
||||
$body.click(hide);
|
||||
$block.click(function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
$body.keydown(function (e) {
|
||||
if (e.which === 27) {
|
||||
hide();
|
||||
}
|
||||
});
|
||||
return $blockContainer;
|
||||
};
|
||||
|
||||
UIElements.createNewPadModal = function (common) {
|
||||
// if in drive, show new pad modal instead
|
||||
|
@ -2785,10 +2545,11 @@ define([
|
|||
return void $(".cp-app-drive-element-row.cp-app-drive-new-ghost").click();
|
||||
}
|
||||
|
||||
var $modal = UIElements.createModal({
|
||||
var modal = UI.createModal({
|
||||
id: 'cp-app-toolbar-creation-dialog',
|
||||
$body: $('body')
|
||||
});
|
||||
var $modal = modal.$modal;
|
||||
var $title = $('<h3>').text(Messages.fm_newFile);
|
||||
var $description = $('<p>').html(Messages.creation_newPadModalDescription);
|
||||
$modal.find('.cp-modal').append($title);
|
||||
|
@ -2874,7 +2635,7 @@ define([
|
|||
|
||||
$modal.find('.cp-modal').append($container).append($advancedContainer);
|
||||
window.setTimeout(function () {
|
||||
$modal.show();
|
||||
modal.show();
|
||||
$modal.focus();
|
||||
});
|
||||
};
|
||||
|
@ -3028,7 +2789,7 @@ define([
|
|||
var teams = Object.keys(privateData.teams).map(function (id) {
|
||||
var data = privateData.teams[id];
|
||||
var avatar = h('span.cp-creation-team-avatar.cp-avatar');
|
||||
UIElements.displayAvatar(common, $(avatar), data.avatar, data.name);
|
||||
common.displayAvatar($(avatar), data.avatar, data.name);
|
||||
return h('div.cp-creation-team', {
|
||||
'data-id': id,
|
||||
title: data.name,
|
||||
|
@ -3612,119 +3373,6 @@ define([
|
|||
|
||||
};
|
||||
|
||||
var createContextMenu = function (menu) {
|
||||
var $menu = $(menu).appendTo($('body'));
|
||||
|
||||
var display = function (e) {
|
||||
$menu.css({ display: "block" });
|
||||
var h = $menu.outerHeight();
|
||||
var w = $menu.outerWidth();
|
||||
var wH = window.innerHeight;
|
||||
var wW = window.innerWidth;
|
||||
if (h > wH) {
|
||||
$menu.css({
|
||||
top: '0px',
|
||||
bottom: ''
|
||||
});
|
||||
} else if (e.pageY + h <= wH) {
|
||||
$menu.css({
|
||||
top: e.pageY+'px',
|
||||
bottom: ''
|
||||
});
|
||||
} else {
|
||||
$menu.css({
|
||||
bottom: '0px',
|
||||
top: ''
|
||||
});
|
||||
}
|
||||
if(w > wW) {
|
||||
$menu.css({
|
||||
left: '0px',
|
||||
right: ''
|
||||
});
|
||||
} else if (e.pageX + w <= wW) {
|
||||
$menu.css({
|
||||
left: e.pageX+'px',
|
||||
right: ''
|
||||
});
|
||||
} else {
|
||||
$menu.css({
|
||||
left: '',
|
||||
right: '0px',
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
var hide = function () {
|
||||
$menu.hide();
|
||||
};
|
||||
var remove = function () {
|
||||
$menu.remove();
|
||||
};
|
||||
|
||||
$('body').click(hide);
|
||||
|
||||
return {
|
||||
menu: menu,
|
||||
show: display,
|
||||
hide: hide,
|
||||
remove: remove
|
||||
};
|
||||
};
|
||||
|
||||
var mediatagContextMenu;
|
||||
UIElements.importMediaTagMenu = function (common) {
|
||||
if (mediatagContextMenu) { return mediatagContextMenu; }
|
||||
|
||||
// Create context menu
|
||||
var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [
|
||||
h('ul.dropdown-menu', {
|
||||
'role': 'menu',
|
||||
'aria-labelledBy': 'dropdownMenu',
|
||||
'style': 'display:block;position:static;margin-bottom:5px;'
|
||||
}, [
|
||||
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',
|
||||
'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;
|
||||
|
||||
var $menu = $(m.menu);
|
||||
$menu.on('click', 'a', function (e) {
|
||||
e.stopPropagation();
|
||||
m.hide();
|
||||
var $mt = $menu.data('mediatag');
|
||||
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;
|
||||
};
|
||||
|
||||
UIElements.displayFriendRequestModal = function (common, data) {
|
||||
var msg = data.content.msg;
|
||||
var userData = msg.content.user;
|
||||
|
|
|
@ -467,6 +467,27 @@
|
|||
return false;
|
||||
};
|
||||
|
||||
var emoji_patt = /([\uD800-\uDBFF][\uDC00-\uDFFF])/;
|
||||
var isEmoji = function (str) {
|
||||
return emoji_patt.test(str);
|
||||
};
|
||||
var emojiStringToArray = function (str) {
|
||||
var split = str.split(emoji_patt);
|
||||
var arr = [];
|
||||
for (var i=0; i<split.length; i++) {
|
||||
var char = split[i];
|
||||
if (char !== "") {
|
||||
arr.push(char);
|
||||
}
|
||||
}
|
||||
return arr;
|
||||
};
|
||||
Util.getFirstCharacter = function (str) {
|
||||
if (!str || !str.trim()) { return '?'; }
|
||||
var emojis = emojiStringToArray(str);
|
||||
return isEmoji(emojis[0])? emojis[0]: str[0];
|
||||
};
|
||||
|
||||
if (typeof(module) !== 'undefined' && module.exports) {
|
||||
module.exports = Util;
|
||||
} else if ((typeof(define) !== 'undefined' && define !== null) && (define.amd !== null)) {
|
||||
|
|
|
@ -5,13 +5,14 @@ define([
|
|||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/hyperscript.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/media-tag.js',
|
||||
'/common/highlight/highlight.pack.js',
|
||||
'/customize/messages.js',
|
||||
'/bower_components/diff-dom/diffDOM.js',
|
||||
'/bower_components/tweetnacl/nacl-fast.min.js',
|
||||
'css!/common/highlight/styles/github.css'
|
||||
],function ($, ApiConfig, Marked, Hash, Util, h, MediaTag, Highlight, Messages) {
|
||||
],function ($, ApiConfig, Marked, Hash, Util, h, MT, MediaTag, Highlight, Messages) {
|
||||
var DiffMd = {};
|
||||
|
||||
var DiffDOM = window.diffDOM;
|
||||
|
@ -365,6 +366,53 @@ define([
|
|||
|
||||
var oldDom = domFromHTML($content[0].outerHTML);
|
||||
|
||||
var onPreview = function ($mt) {
|
||||
return function () {
|
||||
var isSvg = $mt.is('pre.mermaid');
|
||||
var mts = [];
|
||||
$content.find('media-tag, pre.mermaid').each(function (i, el) {
|
||||
if (el.nodeName.toLowerCase() === "pre") {
|
||||
return void mts.push({
|
||||
svg: el.cloneNode(true)
|
||||
});
|
||||
}
|
||||
var $el = $(el);
|
||||
mts.push({
|
||||
src: $el.attr('src'),
|
||||
key: $el.attr('data-crypto-key')
|
||||
});
|
||||
});
|
||||
|
||||
// Find initial position
|
||||
var idx = -1;
|
||||
mts.some(function (obj, i) {
|
||||
if (isSvg && $mt.find('svg').attr('id') === $(obj.svg).find('svg').attr('id')) {
|
||||
idx = i;
|
||||
return true;
|
||||
}
|
||||
if (!isSvg && obj.src === $mt.attr('src')) {
|
||||
idx = i;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (idx === -1) {
|
||||
if (isSvg) {
|
||||
mts.unshift({
|
||||
svg: $mt[0].cloneNode(true)
|
||||
});
|
||||
} else {
|
||||
mts.unshift({
|
||||
src: $mt.attr('src'),
|
||||
key: $mt.attr('data-crypto-key')
|
||||
});
|
||||
}
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
common.getMediaTagPreview(mts, idx);
|
||||
};
|
||||
};
|
||||
|
||||
var patch = makeDiff(oldDom, Dom, id);
|
||||
if (typeof(patch) === 'string') {
|
||||
throw new Error(patch);
|
||||
|
@ -372,9 +420,10 @@ define([
|
|||
DD.apply($content[0], patch);
|
||||
var $mts = $content.find('media-tag:not(:has(*))');
|
||||
$mts.each(function (i, el) {
|
||||
$(el).contextmenu(function (e) {
|
||||
var $mt = $(el).contextmenu(function (e) {
|
||||
e.preventDefault();
|
||||
$(contextMenu.menu).data('mediatag', $(el));
|
||||
$(contextMenu.menu).find('li').show();
|
||||
contextMenu.show(e);
|
||||
});
|
||||
MediaTag(el);
|
||||
|
@ -388,6 +437,13 @@ define([
|
|||
observer.disconnect();
|
||||
}
|
||||
});
|
||||
$mt.off('dblclick preview');
|
||||
$mt.on('preview', onPreview($mt));
|
||||
if ($mt.find('img').length) {
|
||||
$mt.on('dblclick', function () {
|
||||
$mt.trigger('preview');
|
||||
});
|
||||
}
|
||||
});
|
||||
observer.observe(el, {
|
||||
attributes: false,
|
||||
|
@ -407,6 +463,19 @@ define([
|
|||
|
||||
// loop over mermaid elements in the rendered content
|
||||
$content.find('pre.mermaid').each(function (index, el) {
|
||||
var $el = $(el);
|
||||
$el.off('contextmenu').on('contextmenu', function (e) {
|
||||
e.preventDefault();
|
||||
$(contextMenu.menu).data('mediatag', $el);
|
||||
$(contextMenu.menu).find('li:not(.cp-svg)').hide();
|
||||
contextMenu.show(e);
|
||||
});
|
||||
$el.off('dblclick preview');
|
||||
$el.on('preview', onPreview($el));
|
||||
$el.on('dblclick', function () {
|
||||
$el.trigger('preview');
|
||||
});
|
||||
|
||||
// since you've simply drawn the content that was supplied via markdown
|
||||
// you can assume that the index of your rendered charts matches that
|
||||
// of those in the markdown source.
|
||||
|
@ -417,7 +486,6 @@ define([
|
|||
// check if you had cached a pre-rendered instance of the supplied source
|
||||
if (typeof(cached) !== 'object') {
|
||||
try {
|
||||
var $el = $(el);
|
||||
Mermaid.init(undefined, $el);
|
||||
// clickable elements in mermaid don't work well with our sandboxing setup
|
||||
// the function below strips clickable elements but still leaves behind some artifacts
|
||||
|
|
|
@ -80,6 +80,7 @@ define([
|
|||
var faCollapseAll = 'fa-minus-square-o';
|
||||
var faShared = 'fa-shhare-alt';
|
||||
var faReadOnly = 'fa-eye';
|
||||
var faPreview = 'fa-eye';
|
||||
var faOpenInCode = 'cptools-code';
|
||||
var faRename = 'fa-pencil';
|
||||
var faColor = 'cptools-palette';
|
||||
|
@ -317,6 +318,10 @@ define([
|
|||
'style': 'display:block;position:static;margin-bottom:5px;'
|
||||
}, [
|
||||
h('span.cp-app-drive-context-noAction.dropdown-item.disabled', Messages.fc_noAction || "No action possible"),
|
||||
h('li', h('a.cp-app-drive-context-preview.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': faPreview,
|
||||
}, Messages.pad_mediatagPreview)),
|
||||
h('li', h('a.cp-app-drive-context-open.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': faFolderOpen,
|
||||
|
@ -1042,12 +1047,57 @@ define([
|
|||
return ret;
|
||||
};
|
||||
|
||||
var openFile = function (el, isRo) {
|
||||
var previewMediaTag = function (data) {
|
||||
var mts = [];
|
||||
$content.find('.cp-app-drive-element.cp-border-color-file').each(function (i, el) {
|
||||
var path = $(el).data('path');
|
||||
var id = manager.find(path);
|
||||
if (!id) { return; }
|
||||
var _data = manager.getFileData(id);
|
||||
if (!_data || _data.channel < 48) { return; }
|
||||
mts.push({
|
||||
channel: _data.channel,
|
||||
href: _data.href,
|
||||
password: _data.password
|
||||
});
|
||||
});
|
||||
|
||||
// Find initial position
|
||||
var idx = -1;
|
||||
mts.some(function (obj, i) {
|
||||
if (obj.channel === data.channel) {
|
||||
idx = i;
|
||||
return true;
|
||||
}
|
||||
});
|
||||
if (idx === -1) {
|
||||
mts.unshift({
|
||||
href: data.href,
|
||||
password: data.password
|
||||
});
|
||||
idx = 0;
|
||||
}
|
||||
|
||||
common.getMediaTagPreview(mts, idx);
|
||||
};
|
||||
|
||||
// `app`: true (force open wiht the app), false (force open in preview),
|
||||
// falsy (open in preview if default is not using the app)
|
||||
var defaultInApp = ['application/pdf'];
|
||||
var openFile = function (el, isRo, app) {
|
||||
var data = manager.getFileData(el);
|
||||
if (!data || (!data.href && !data.roHref)) {
|
||||
return void logError("Missing data for the file", el, data);
|
||||
}
|
||||
|
||||
var href = isRo ? data.roHref : (data.href || data.roHref);
|
||||
var parsed = Hash.parsePadUrl(href);
|
||||
|
||||
if (parsed.hashData && parsed.hashData.type === 'file' && !app
|
||||
&& (defaultInApp.indexOf(data.fileType) === -1 || app === false)) {
|
||||
return void previewMediaTag(data);
|
||||
}
|
||||
|
||||
var priv = metadataMgr.getPrivateData();
|
||||
var useUnsafe = Util.find(priv, ['settings', 'security', 'unsafeLinks']);
|
||||
if (useUnsafe !== false) { // true of undefined: use unsafe links
|
||||
|
@ -1055,7 +1105,6 @@ define([
|
|||
}
|
||||
|
||||
// Get hidden hash
|
||||
var parsed = Hash.parsePadUrl(href);
|
||||
var secret = Hash.getSecrets(parsed.type, parsed.hash, data.password);
|
||||
var opts = {};
|
||||
if (isRo) { opts.view = true; }
|
||||
|
@ -1175,6 +1224,7 @@ define([
|
|||
if (!$element.is('.cp-border-color-file')) {
|
||||
//hide.push('download');
|
||||
hide.push('openincode');
|
||||
hide.push('preview');
|
||||
}
|
||||
if ($element.is('.cp-border-color-sheet')) {
|
||||
hide.push('download');
|
||||
|
@ -1192,6 +1242,9 @@ define([
|
|||
if (!metadata || !Util.isPlainTextFile(metadata.fileType, metadata.title)) {
|
||||
hide.push('openincode');
|
||||
}
|
||||
if (metadata.channel && metadata.channel.length < 48) {
|
||||
hide.push('preview');
|
||||
}
|
||||
if (!metadata.channel || metadata.channel.length > 32 || metadata.rtChannel) {
|
||||
hide.push('makeacopy'); // Not for blobs
|
||||
}
|
||||
|
@ -1260,6 +1313,7 @@ define([
|
|||
hide.push('savelocal');
|
||||
hide.push('openincode'); // can't because of race condition
|
||||
hide.push('makeacopy');
|
||||
hide.push('preview');
|
||||
}
|
||||
if (containsFolder && paths.length > 1) {
|
||||
// Cannot open multiple folders
|
||||
|
@ -1276,12 +1330,12 @@ define([
|
|||
show = ['newfolder', 'newsharedfolder', 'uploadfiles', 'uploadfolder', 'newdoc'];
|
||||
break;
|
||||
case 'tree':
|
||||
show = ['open', 'openro', 'openincode', 'expandall', 'collapseall',
|
||||
show = ['open', 'openro', 'preview', 'openincode', 'expandall', 'collapseall',
|
||||
'color', 'download', 'share', 'savelocal', 'rename', 'delete', 'makeacopy',
|
||||
'deleteowned', 'removesf', 'access', 'properties', 'hashtag'];
|
||||
break;
|
||||
case 'default':
|
||||
show = ['open', 'openro', 'share', 'openparent', 'delete', 'deleteowned', 'properties', 'access', 'hashtag', 'makeacopy'];
|
||||
show = ['open', 'openro', 'preview', 'share', 'openparent', 'delete', 'deleteowned', 'properties', 'access', 'hashtag', 'makeacopy'];
|
||||
break;
|
||||
case 'trashtree': {
|
||||
show = ['empty'];
|
||||
|
@ -2892,17 +2946,18 @@ define([
|
|||
$element.append($('<span>', {'class': 'cp-app-drive-element-name'})
|
||||
.text(Messages.fm_newFile));
|
||||
$element.click(function () {
|
||||
var $modal = UIElements.createModal({
|
||||
var modal = UI.createModal({
|
||||
id: 'cp-app-drive-new-ghost-dialog',
|
||||
$body: $('body')
|
||||
});
|
||||
var $modal = modal.$modal;
|
||||
var $title = $('<h3>').text(Messages.fm_newFile);
|
||||
var $description = $('<p>').text(Messages.fm_newButtonTitle);
|
||||
$modal.find('.cp-modal').append($title);
|
||||
$modal.find('.cp-modal').append($description);
|
||||
var $content = createNewPadIcons($modal, isInRoot);
|
||||
$modal.find('.cp-modal').append($content);
|
||||
window.setTimeout(function () { $modal.show(); });
|
||||
window.setTimeout(function () { modal.show(); });
|
||||
addNewPadHandlers($modal, isInRoot);
|
||||
});
|
||||
};
|
||||
|
@ -3980,11 +4035,15 @@ define([
|
|||
else if ($this.hasClass('cp-app-drive-context-deleteowned')) {
|
||||
deleteOwnedPaths(paths);
|
||||
}
|
||||
else if ($this.hasClass('cp-app-drive-context-preview')) {
|
||||
if (paths.length !== 1) { return; }
|
||||
el = manager.find(paths[0].path);
|
||||
openFile(el, null, false);
|
||||
}
|
||||
else if ($this.hasClass('cp-app-drive-context-open')) {
|
||||
paths.forEach(function (p) {
|
||||
var $element = p.element;
|
||||
$element.click();
|
||||
$element.dblclick();
|
||||
var el = manager.find(p.path);
|
||||
openFile(el, false, true);
|
||||
});
|
||||
}
|
||||
else if ($this.hasClass('cp-app-drive-context-openro')) {
|
||||
|
@ -3999,7 +4058,7 @@ define([
|
|||
} else {
|
||||
if (!el || manager.isFolder(el)) { return; }
|
||||
}
|
||||
openFile(el, true);
|
||||
openFile(el, true, true);
|
||||
});
|
||||
}
|
||||
else if ($this.hasClass('cp-app-drive-context-makeacopy')) {
|
||||
|
|
400
www/common/inner/common-mediatag.js
Normal file
400
www/common/inner/common-mediatag.js
Normal file
|
@ -0,0 +1,400 @@
|
|||
define([
|
||||
'jquery',
|
||||
'/common/common-util.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-interface.js',
|
||||
'/common/hyperscript.js',
|
||||
'/common/media-tag.js',
|
||||
'/customize/messages.js',
|
||||
|
||||
'/bower_components/croppie/croppie.min.js',
|
||||
'/bower_components/file-saver/FileSaver.min.js',
|
||||
'css!/bower_components/croppie/croppie.css',
|
||||
], function ($, Util, Hash, UI, h, MediaTag, Messages) {
|
||||
var MT = {};
|
||||
|
||||
var Nacl = window.nacl;
|
||||
|
||||
// Configure MediaTags to use our local viewer
|
||||
if (MediaTag) {
|
||||
MediaTag.setDefaultConfig('pdf', {
|
||||
viewer: '/common/pdfjs/web/viewer.html'
|
||||
});
|
||||
}
|
||||
|
||||
// Cache of the avatars outer html (including <media-tag>)
|
||||
var avatars = {};
|
||||
|
||||
MT.getCursorAvatar = function (cursor) {
|
||||
var html = '<span class="cp-cursor-avatar">';
|
||||
html += (cursor.avatar && avatars[cursor.avatar]) || '';
|
||||
html += cursor.name + '</span>';
|
||||
return html;
|
||||
};
|
||||
|
||||
MT.displayMediatagImage = function (Common, $tag, _cb) {
|
||||
var cb = Util.once(_cb);
|
||||
if (!$tag.length || !$tag.is('media-tag')) { return void cb('NOT_MEDIATAG'); }
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function(mutation) {
|
||||
if (mutation.addedNodes.length) {
|
||||
if (mutation.addedNodes.length > 1 ||
|
||||
mutation.addedNodes[0].nodeName !== 'IMG') {
|
||||
return void cb('NOT_IMAGE');
|
||||
}
|
||||
var $image = $tag.find('img');
|
||||
var onLoad = function () {
|
||||
cb(null, $image);
|
||||
};
|
||||
if ($image[0].complete) { onLoad(); }
|
||||
$image.on('load', onLoad);
|
||||
}
|
||||
});
|
||||
});
|
||||
observer.observe($tag[0], {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
characterData: false
|
||||
});
|
||||
MediaTag($tag[0]).on('error', function (data) {
|
||||
console.error(data);
|
||||
});
|
||||
};
|
||||
|
||||
MT.displayAvatar = function (common, $container, href, name, _cb) {
|
||||
var cb = Util.once(Util.mkAsync(_cb || function () {}));
|
||||
var displayDefault = function () {
|
||||
var text = (href && typeof(href) === "string") ? href : Util.getFirstCharacter(name);
|
||||
var $avatar = $('<span>', {'class': 'cp-avatar-default'}).text(text);
|
||||
$container.append($avatar);
|
||||
if (cb) { cb(); }
|
||||
};
|
||||
if (!window.Symbol) { return void displayDefault(); } // IE doesn't have Symbol
|
||||
if (!href || href.length === 1) { return void displayDefault(); }
|
||||
|
||||
if (avatars[href]) {
|
||||
var nodes = $.parseHTML(avatars[href]);
|
||||
var $el = $(nodes[0]);
|
||||
$container.append($el);
|
||||
return void cb($el);
|
||||
}
|
||||
|
||||
var centerImage = function ($img, $image) {
|
||||
var img = $image[0];
|
||||
var w = img.width;
|
||||
var h = img.height;
|
||||
if (w>h) {
|
||||
$image.css('max-height', '100%');
|
||||
$img.css('flex-direction', 'column');
|
||||
avatars[href] = $img[0].outerHTML;
|
||||
if (cb) { cb($img); }
|
||||
return;
|
||||
}
|
||||
$image.css('max-width', '100%');
|
||||
$img.css('flex-direction', 'row');
|
||||
avatars[href] = $img[0].outerHTML;
|
||||
if (cb) { cb($img); }
|
||||
};
|
||||
|
||||
// No password for avatars
|
||||
var privateData = common.getMetadataMgr().getPrivateData();
|
||||
var origin = privateData.fileHost || privateData.origin;
|
||||
var parsed = Hash.parsePadUrl(href);
|
||||
var secret = Hash.getSecrets('file', parsed.hash);
|
||||
if (secret.keys && secret.channel) {
|
||||
var hexFileName = secret.channel;
|
||||
var cryptKey = Hash.encodeBase64(secret.keys && secret.keys.cryptKey);
|
||||
var src = origin + Hash.getBlobPathFromHex(hexFileName);
|
||||
common.getFileSize(hexFileName, function (e, data) {
|
||||
if (e || !data) { return void displayDefault(); }
|
||||
if (typeof data !== "number") { return void displayDefault(); }
|
||||
if (Util.bytesToMegabytes(data) > 0.5) { return void displayDefault(); }
|
||||
var $img = $('<media-tag>').appendTo($container);
|
||||
$img.attr('src', src);
|
||||
$img.attr('data-crypto-key', 'cryptpad:' + cryptKey);
|
||||
MT.displayMediatagImage(common, $img, function (err, $image) {
|
||||
if (err) { return void console.error(err); }
|
||||
centerImage($img, $image);
|
||||
});
|
||||
});
|
||||
}
|
||||
};
|
||||
var transformAvatar = function (file, cb) {
|
||||
if (file.type === 'image/gif') { return void cb(file); }
|
||||
var $croppie = $('<div>', {
|
||||
'class': 'cp-app-profile-resizer'
|
||||
});
|
||||
|
||||
if (typeof ($croppie.croppie) !== "function") {
|
||||
return void cb(file);
|
||||
}
|
||||
|
||||
var todo = function () {
|
||||
UI.confirm($croppie[0], function (yes) {
|
||||
if (!yes) { return; }
|
||||
$croppie.croppie('result', {
|
||||
type: 'blob',
|
||||
size: {width: 300, height: 300}
|
||||
}).then(function(blob) {
|
||||
blob.lastModifiedDate = new Date();
|
||||
blob.name = 'avatar';
|
||||
cb(blob);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
||||
var reader = new FileReader();
|
||||
reader.onload = function(e) {
|
||||
$croppie.croppie({
|
||||
url: e.target.result,
|
||||
viewport: { width: 100, height: 100 },
|
||||
boundary: { width: 400, height: 300 },
|
||||
});
|
||||
todo();
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
};
|
||||
MT.addAvatar = function (common, cb) {
|
||||
var AVATAR_SIZE_LIMIT = 0.5;
|
||||
var allowedMediaTypes = [
|
||||
'image/png',
|
||||
'image/jpeg',
|
||||
'image/jpg',
|
||||
'image/gif',
|
||||
];
|
||||
var fmConfig = {
|
||||
noHandlers: true,
|
||||
noStore: true,
|
||||
body: $('body'),
|
||||
onUploaded: cb
|
||||
};
|
||||
var FM = common.createFileManager(fmConfig);
|
||||
var accepted = ".gif,.jpg,.jpeg,.png";
|
||||
var data = {
|
||||
FM: FM,
|
||||
filter: function (file) {
|
||||
var sizeMB = Util.bytesToMegabytes(file.size);
|
||||
var type = file.type;
|
||||
// We can't resize .gif so we have to display an error if it is too big
|
||||
if (sizeMB > AVATAR_SIZE_LIMIT && type === 'image/gif') {
|
||||
UI.log(Messages._getKey('profile_uploadSizeError', [
|
||||
Messages._getKey('formattedMB', [AVATAR_SIZE_LIMIT])
|
||||
]));
|
||||
return false;
|
||||
}
|
||||
// Display an error if the image type is not allowed
|
||||
if (allowedMediaTypes.indexOf(type) === -1) {
|
||||
UI.log(Messages._getKey('profile_uploadTypeError', [
|
||||
accepted.split(',').join(', ')
|
||||
]));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
},
|
||||
transformer: transformAvatar,
|
||||
accept: accepted
|
||||
};
|
||||
return data;
|
||||
};
|
||||
|
||||
MT.getMediaTagPreview = function (common, tags, start) {
|
||||
if (!Array.isArray(tags) || !tags.length) { return; }
|
||||
|
||||
var i = start;
|
||||
var metadataMgr = common.getMetadataMgr();
|
||||
var priv = metadataMgr.getPrivateData();
|
||||
|
||||
var left, right;
|
||||
|
||||
var modal = UI.createModal({
|
||||
id: 'cp-mediatag-preview-modal',
|
||||
$body: $('body')
|
||||
});
|
||||
modal.show();
|
||||
var $modal = modal.$modal.focus();
|
||||
var $container = $modal.find('.cp-modal').append([
|
||||
h('div.cp-mediatag-control', left = h('span.fa.fa-chevron-left')),
|
||||
h('div.cp-mediatag-container', [
|
||||
h('div.cp-loading-spinner-container', h('span.cp-spinner')),
|
||||
]),
|
||||
h('div.cp-mediatag-control', right = h('span.fa.fa-chevron-right')),
|
||||
]);
|
||||
var $left = $(left);
|
||||
var $right = $(right);
|
||||
var $inner = $container.find('.cp-mediatag-container');
|
||||
|
||||
var $spinner = $container.find('.cp-loading-spinner-container');
|
||||
|
||||
var locked = false;
|
||||
var show = function (_i) {
|
||||
if (locked) { return; }
|
||||
locked = true;
|
||||
if (_i < 0) { i = 0; }
|
||||
else if (_i > tags.length -1) { i = tags.length - 1; }
|
||||
else { i = _i; }
|
||||
|
||||
// Show/hide controls
|
||||
$left.css('visibility', '');
|
||||
$right.css('visibility', '');
|
||||
if (i === 0) {
|
||||
$left.css('visibility', 'hidden');
|
||||
}
|
||||
if (i === tags.length - 1) {
|
||||
$right.css('visibility', 'hidden');
|
||||
}
|
||||
|
||||
// Reset modal
|
||||
$inner.find('media-tag, pre.mermaid').detach();
|
||||
$spinner.show();
|
||||
|
||||
// Check src and cryptkey
|
||||
var cfg = tags[i];
|
||||
|
||||
if (cfg.svg) {
|
||||
$spinner.hide();
|
||||
$inner.append(cfg.svg);
|
||||
locked = false;
|
||||
return;
|
||||
}
|
||||
|
||||
var src = cfg.src;
|
||||
var key = cfg.key;
|
||||
if (cfg.href) {
|
||||
var parsed = Hash.parsePadUrl(cfg.href);
|
||||
var secret = Hash.getSecrets(parsed.type, parsed.hash, cfg.password);
|
||||
var host = priv.fileHost || priv.origin || '';
|
||||
src = host + Hash.getBlobPathFromHex(secret.channel);
|
||||
var _key = secret.keys && secret.keys.cryptKey;
|
||||
if (_key) { key = 'cryptpad:' + Nacl.util.encodeBase64(_key); }
|
||||
}
|
||||
if (!src || !key) {
|
||||
locked = false;
|
||||
$spinner.hide();
|
||||
return void UI.log(Messages.error);
|
||||
}
|
||||
|
||||
var tag = h('media-tag', {
|
||||
src: src,
|
||||
'data-crypto-key': key
|
||||
});
|
||||
$inner.append(tag);
|
||||
|
||||
var observer = new MutationObserver(function(mutations) {
|
||||
mutations.forEach(function() {
|
||||
locked = false;
|
||||
$spinner.hide();
|
||||
});
|
||||
});
|
||||
observer.observe(tag, {
|
||||
attributes: false,
|
||||
childList: true,
|
||||
characterData: false
|
||||
});
|
||||
MediaTag(tag).on('error', function () {
|
||||
locked = false;
|
||||
$spinner.hide();
|
||||
UI.log(Messages.error);
|
||||
});
|
||||
};
|
||||
|
||||
show(i);
|
||||
var previous = function () {
|
||||
if (i === 0) { return; }
|
||||
show(i - 1);
|
||||
};
|
||||
var next = function () {
|
||||
if (i === tags.length - 1) { return; }
|
||||
show(i + 1);
|
||||
};
|
||||
$left.click(previous);
|
||||
$right.click(next);
|
||||
|
||||
$modal.on('keydown', function (e) {
|
||||
e.stopPropagation();
|
||||
});
|
||||
$modal.on('keyup', function (e) {
|
||||
//if (!Slide.shown) { return; }
|
||||
e.stopPropagation();
|
||||
if (e.ctrlKey) { return; }
|
||||
switch(e.which) {
|
||||
case 33: // pageup
|
||||
case 38: // up
|
||||
case 37: // left
|
||||
previous();
|
||||
break;
|
||||
case 34: // pagedown
|
||||
case 32: // space
|
||||
case 40: // down
|
||||
case 39: // right
|
||||
next();
|
||||
break;
|
||||
case 27: // esc
|
||||
$modal.hide();
|
||||
break;
|
||||
default:
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var mediatagContextMenu;
|
||||
MT.importMediaTagMenu = function (common) {
|
||||
if (mediatagContextMenu) { return mediatagContextMenu; }
|
||||
|
||||
// Create context menu
|
||||
var menu = h('div.cp-contextmenu.dropdown.cp-unselectable', [
|
||||
h('ul.dropdown-menu', {
|
||||
'role': 'menu',
|
||||
'aria-labelledBy': 'dropdownMenu',
|
||||
'style': 'display:block;position:static;margin-bottom:5px;'
|
||||
}, [
|
||||
h('li.cp-svg', h('a.cp-app-code-context-open.dropdown-item', {
|
||||
'tabindex': '-1',
|
||||
'data-icon': "fa-eye",
|
||||
}, Messages.pad_mediatagPreview)),
|
||||
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',
|
||||
'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 = UI.createContextMenu(menu);
|
||||
|
||||
mediatagContextMenu = m;
|
||||
|
||||
var $menu = $(m.menu);
|
||||
$menu.on('click', 'a', function (e) {
|
||||
e.stopPropagation();
|
||||
m.hide();
|
||||
var $mt = $menu.data('mediatag');
|
||||
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);
|
||||
}
|
||||
else if ($(this).hasClass("cp-app-code-context-open")) {
|
||||
$mt.trigger('preview');
|
||||
}
|
||||
});
|
||||
|
||||
return m;
|
||||
};
|
||||
|
||||
return MT;
|
||||
});
|
|
@ -879,7 +879,7 @@ define([
|
|||
h('i.fa.fa-bell'),
|
||||
Messages.contacts_unmute || 'unmute'
|
||||
]);
|
||||
UIElements.displayAvatar(common, $(avatar), data.avatar, data.name);
|
||||
common.displayAvatar($(avatar), data.avatar, data.name);
|
||||
$(button).click(function () {
|
||||
unmuteUser(curve, button);
|
||||
execCommand('UNMUTE_USER', curve, function (e, data) {
|
||||
|
|
|
@ -525,18 +525,23 @@ define([
|
|||
}
|
||||
});
|
||||
$embedButton = common.createButton('mediatag', true).click(function () {
|
||||
common.openFilePicker({
|
||||
var cfg = {
|
||||
types: ['file'],
|
||||
where: ['root']
|
||||
});
|
||||
};
|
||||
if ($embedButton.data('filter')) {
|
||||
cfg.filter = $embedButton.data('filter');
|
||||
}
|
||||
common.openFilePicker(cfg);
|
||||
}).appendTo(toolbar.$rightside).hide();
|
||||
};
|
||||
var setMediaTagEmbedder = function (mte) {
|
||||
var setMediaTagEmbedder = function (mte, filter) {
|
||||
if (!common.isLoggedIn()) { return; }
|
||||
if (!mte || readOnly) {
|
||||
$embedButton.hide();
|
||||
return;
|
||||
}
|
||||
if (filter) { $embedButton.data('filter', filter); }
|
||||
$embedButton.show();
|
||||
mediaTagEmbedder = mte;
|
||||
};
|
||||
|
|
|
@ -4,11 +4,12 @@ define([
|
|||
'/common/themes.js',
|
||||
'/customize/messages.js',
|
||||
'/common/common-ui-elements.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/text-cursor.js',
|
||||
'/bower_components/chainpad/chainpad.dist.js',
|
||||
], function ($, Modes, Themes, Messages, UIElements, Hash, Util, TextCursor, ChainPad) {
|
||||
], function ($, Modes, Themes, Messages, UIElements, MT, Hash, Util, TextCursor, ChainPad) {
|
||||
var module = {};
|
||||
|
||||
var cursorToPos = function(cursor, oldText) {
|
||||
|
@ -454,12 +455,7 @@ define([
|
|||
})[0];
|
||||
};
|
||||
var makeTippy = function (cursor) {
|
||||
var html = '<span class="cp-cursor-avatar">';
|
||||
if (cursor.avatar && UIElements.getAvatar(cursor.avatar)) {
|
||||
html += UIElements.getAvatar(cursor.avatar);
|
||||
}
|
||||
html += cursor.name + '</span>';
|
||||
return html;
|
||||
return MT.getCursorAvatar(cursor);
|
||||
};
|
||||
var marks = {};
|
||||
exp.removeCursors = function () {
|
||||
|
|
|
@ -11,6 +11,7 @@ define([
|
|||
'/common/sframe-common-codemirror.js',
|
||||
'/common/sframe-common-cursor.js',
|
||||
'/common/sframe-common-mailbox.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/metadata-manager.js',
|
||||
|
||||
'/customize/application_config.js',
|
||||
|
@ -35,6 +36,7 @@ define([
|
|||
CodeMirror,
|
||||
Cursor,
|
||||
Mailbox,
|
||||
MT,
|
||||
MetadataMgr,
|
||||
AppConfig,
|
||||
CommonRealtime,
|
||||
|
@ -90,8 +92,8 @@ define([
|
|||
funcs.initFilePicker = callWithCommon(UIElements.initFilePicker);
|
||||
funcs.openFilePicker = callWithCommon(UIElements.openFilePicker);
|
||||
funcs.openTemplatePicker = callWithCommon(UIElements.openTemplatePicker);
|
||||
funcs.displayMediatagImage = callWithCommon(UIElements.displayMediatagImage);
|
||||
funcs.displayAvatar = callWithCommon(UIElements.displayAvatar);
|
||||
funcs.displayMediatagImage = callWithCommon(MT.displayMediatagImage);
|
||||
funcs.displayAvatar = callWithCommon(MT.displayAvatar);
|
||||
funcs.createButton = callWithCommon(UIElements.createButton);
|
||||
funcs.createUsageBar = callWithCommon(UIElements.createUsageBar);
|
||||
funcs.updateTags = callWithCommon(UIElements.updateTags);
|
||||
|
@ -102,7 +104,8 @@ define([
|
|||
funcs.getBurnAfterReadingWarning = callWithCommon(UIElements.getBurnAfterReadingWarning);
|
||||
funcs.createNewPadModal = callWithCommon(UIElements.createNewPadModal);
|
||||
funcs.onServerError = callWithCommon(UIElements.onServerError);
|
||||
funcs.importMediaTagMenu = callWithCommon(UIElements.importMediaTagMenu);
|
||||
funcs.importMediaTagMenu = callWithCommon(MT.importMediaTagMenu);
|
||||
funcs.getMediaTagPreview = callWithCommon(MT.getMediaTagPreview);
|
||||
|
||||
// Thumb
|
||||
funcs.displayThumbnail = callWithCommon(Thumb.displayThumbnail);
|
||||
|
|
|
@ -7,10 +7,11 @@ define([
|
|||
'/common/common-hash.js',
|
||||
'/common/common-util.js',
|
||||
'/common/common-feedback.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/hyperscript.js',
|
||||
'/common/messenger-ui.js',
|
||||
'/customize/messages.js',
|
||||
], function ($, Config, ApiConfig, UIElements, UI, Hash, Util, Feedback, h,
|
||||
], function ($, Config, ApiConfig, UIElements, UI, Hash, Util, Feedback, MT, h,
|
||||
MessengerUI, Messages) {
|
||||
var Common;
|
||||
|
||||
|
@ -345,17 +346,9 @@ MessengerUI, Messages) {
|
|||
window.open(origin+'/profile/#' + data.profile);
|
||||
});
|
||||
}
|
||||
if (data.avatar && UIElements.getAvatar(data.avatar)) {
|
||||
$span.append(UIElements.getAvatar(data.avatar));
|
||||
$span.append($rightCol);
|
||||
} else {
|
||||
Common.displayAvatar($span, data.avatar, name, function ($img) {
|
||||
if (data.avatar && $img && $img.length) {
|
||||
UIElements.setAvatar(data.avatar, $img[0].outerHTML);
|
||||
}
|
||||
Common.displayAvatar($span, data.avatar, name, function () {
|
||||
$span.append($rightCol);
|
||||
});
|
||||
}
|
||||
$span.data('uid', data.uid);
|
||||
$editUsersList.append($span);
|
||||
});
|
||||
|
|
|
@ -81,11 +81,13 @@ define([
|
|||
var createFileDialog = function () {
|
||||
var types = filters.types || [];
|
||||
// Create modal
|
||||
var $blockContainer = UIElements.createModal({
|
||||
var modal = UI.createModal({
|
||||
id: 'cp-filepicker-dialog',
|
||||
$body: $body,
|
||||
onClose: hideFileDialog
|
||||
}).show();
|
||||
});
|
||||
modal.show();
|
||||
var $blockContainer = modal.$modal;
|
||||
// Set the fixed content
|
||||
var $block = $blockContainer.find('.cp-modal');
|
||||
|
||||
|
|
|
@ -9,6 +9,7 @@ define([
|
|||
'/common/common-hash.js',
|
||||
'/common/common-interface.js',
|
||||
'/common/common-ui-elements.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/modes.js',
|
||||
'/customize/messages.js',
|
||||
'/common/hyperscript.js',
|
||||
|
@ -40,6 +41,7 @@ define([
|
|||
Hash,
|
||||
UI,
|
||||
UIElements,
|
||||
MT,
|
||||
Modes,
|
||||
Messages,
|
||||
h,
|
||||
|
@ -90,13 +92,9 @@ define([
|
|||
|
||||
var getAvatar = function (cursor, noClear) {
|
||||
// Tippy
|
||||
var html = '<span class="cp-cursor-avatar">';
|
||||
if (cursor.avatar && UIElements.getAvatar(cursor.avatar)) {
|
||||
html += UIElements.getAvatar(cursor.avatar);
|
||||
}
|
||||
html += cursor.name + '</span>';
|
||||
var html = MT.getCursorAvatar(cursor);
|
||||
|
||||
var l = UIElements.getFirstCharacter(cursor.name || Messages.anonymous);
|
||||
var l = Util.getFirstCharacter(cursor.name || Messages.anonymous);
|
||||
|
||||
var text = '';
|
||||
if (cursor.color) {
|
||||
|
|
|
@ -41,12 +41,6 @@ define([
|
|||
var cursors = {};
|
||||
|
||||
var makeTippy = function (cursor) {
|
||||
/*var html = '<span class="cp-cursor-avatar">';
|
||||
if (cursor.avatar && UIElements.getAvatar(cursor.avatar)) {
|
||||
html += UIElements.getAvatar(cursor.avatar);
|
||||
}
|
||||
html += cursor.name + '</span>';
|
||||
return html;*/
|
||||
return cursor.name;
|
||||
};
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ define([
|
|||
'/common/common-ui-elements.js',
|
||||
'/common/common-realtime.js',
|
||||
'/common/clipboard.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/hyperscript.js',
|
||||
'/customize/messages.js',
|
||||
'/customize/application_config.js',
|
||||
|
@ -36,6 +37,7 @@ define([
|
|||
UIElements,
|
||||
Realtime,
|
||||
Clipboard,
|
||||
MT,
|
||||
h,
|
||||
Messages,
|
||||
AppConfig,
|
||||
|
@ -351,7 +353,7 @@ define([
|
|||
displayAvatar();
|
||||
if (APP.readOnly) { return; }
|
||||
|
||||
var data = UIElements.addAvatar(common, function (ev, data) {
|
||||
var data = MT.addAvatar(common, function (ev, data) {
|
||||
var old = common.getMetadataMgr().getUserData().avatar;
|
||||
var todo = function () {
|
||||
APP.module.execCommand("SET", {
|
||||
|
|
|
@ -12,6 +12,7 @@ define([
|
|||
'/common/sframe-common.js',
|
||||
'/common/proxy-manager.js',
|
||||
'/common/userObject.js',
|
||||
'/common/inner/common-mediatag.js',
|
||||
'/common/hyperscript.js',
|
||||
'/customize/application_config.js',
|
||||
'/common/messenger-ui.js',
|
||||
|
@ -35,6 +36,7 @@ define([
|
|||
SFCommon,
|
||||
ProxyManager,
|
||||
UserObject,
|
||||
MT,
|
||||
h,
|
||||
AppConfig,
|
||||
MessengerUI,
|
||||
|
@ -533,9 +535,11 @@ define([
|
|||
};
|
||||
|
||||
var makePermissions = function () {
|
||||
var $blockContainer = UIElements.createModal({
|
||||
var modal= UI.createModal({
|
||||
id: 'cp-teams-roster-dialog',
|
||||
}).show();
|
||||
});
|
||||
modal.show();
|
||||
var $blockContainer = modal.$modal;
|
||||
|
||||
var makeRow = function (arr, first) {
|
||||
return arr.map(function (val) {
|
||||
|
@ -966,7 +970,7 @@ define([
|
|||
// Upload
|
||||
var avatar = h('div.cp-team-avatar.cp-avatar');
|
||||
var $avatar = $(avatar);
|
||||
var data = UIElements.addAvatar(common, function (ev, data) {
|
||||
var data = MT.addAvatar(common, function (ev, data) {
|
||||
if (!data.url) { return void UI.warn(Messages.error); }
|
||||
APP.module.execCommand('GET_TEAM_METADATA', {
|
||||
teamId: APP.team
|
||||
|
@ -1051,7 +1055,7 @@ define([
|
|||
|
||||
var displayUser = function (common, data) {
|
||||
var avatar = h('span.cp-teams-invite-from-avatar.cp-avatar');
|
||||
UIElements.displayAvatar(common, $(avatar), data.avatar, data.displayName);
|
||||
common.displayAvatar($(avatar), data.avatar, data.displayName);
|
||||
return h('div.cp-teams-invite-from-author', [
|
||||
avatar,
|
||||
h('span.cp-teams-invite-from-name', data.displayName)
|
||||
|
|
|
@ -363,6 +363,11 @@ define([
|
|||
});
|
||||
};
|
||||
var addImageToCanvas = function (img) {
|
||||
// 1 MB maximum
|
||||
if (img.src && img.src.length > 1 * 1024 * 1024) {
|
||||
UI.warn(Messages.upload_tooLargeBrief);
|
||||
return;
|
||||
}
|
||||
var w = img.width;
|
||||
var h = img.height;
|
||||
if (w<h) {
|
||||
|
@ -381,6 +386,11 @@ define([
|
|||
var onUpload = function (e) {
|
||||
var file = e.target.files[0];
|
||||
var reader = new FileReader();
|
||||
// 1 MB maximum
|
||||
if (file.size > 1 * 1024 * 1024) {
|
||||
UI.warn(Messages.upload_tooLargeBrief);
|
||||
return;
|
||||
}
|
||||
reader.onload = function () {
|
||||
var img = new Image();
|
||||
img.onload = function () {
|
||||
|
@ -399,32 +409,18 @@ define([
|
|||
}).appendTo($rightside);
|
||||
|
||||
if (framework._.sfCommon.isLoggedIn()) {
|
||||
var fileDialogCfg = {
|
||||
onSelect: function (data) {
|
||||
if (data.type === 'file') {
|
||||
var mt = '<media-tag src="' + data.src + '" data-crypto-key="cryptpad:' + data.key + '"></media-tag>';
|
||||
framework._.sfCommon.displayMediatagImage($(mt), function (err, $image) {
|
||||
framework.setMediaTagEmbedder(function ($mt) {
|
||||
framework._.sfCommon.displayMediatagImage($mt, function (err, $image) {
|
||||
// Convert src from blob URL to base64 data URL
|
||||
Util.blobURLToImage($image.attr('src'), function (imgSrc) {
|
||||
var img = new Image();
|
||||
img.onload = function () { addImageToCanvas(img); };
|
||||
img.src = imgSrc;
|
||||
});
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
framework._.sfCommon.initFilePicker(fileDialogCfg);
|
||||
framework._.sfCommon.createButton('mediatag', true).click(function () {
|
||||
var pickerCfg = {
|
||||
types: ['file'],
|
||||
where: ['root'],
|
||||
filter: {
|
||||
}, {
|
||||
fileType: ['image/']
|
||||
}
|
||||
};
|
||||
framework._.sfCommon.openFilePicker(pickerCfg);
|
||||
}).appendTo($rightside);
|
||||
});
|
||||
|
||||
// Export to drive as PNG
|
||||
framework._.sfCommon.createButton('savetodrive', true, {}).click(function () {
|
||||
|
|
Loading…
Reference in a new issue