Merge branch 'staging' of github.com:xwiki-labs/cryptpad into staging

This commit is contained in:
ansuz 2020-04-06 10:16:12 -04:00
commit 90518224fe
21 changed files with 797 additions and 446 deletions

View file

@ -90,6 +90,11 @@
border: 1px solid #BBB;
}
pre.mermaid {
svg {
max-width: 100%;
}
}
}
.markdown_preformatted-code (@color: #333) {

View file

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

View file

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

View file

@ -371,7 +371,7 @@
width: 200px;
display: flex;
align-items: center;
.fa {
.fa, .cptools {
font-size: 32px;
min-width: 50px;
}

View file

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

View file

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

View file

@ -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)) {

View file

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

View file

@ -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')) {

View 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;
});

View file

@ -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) {

View file

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

View file

@ -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 () {

View file

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

View file

@ -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));
Common.displayAvatar($span, data.avatar, name, function () {
$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);
}
$span.append($rightCol);
});
}
});
$span.data('uid', data.uid);
$editUsersList.append($span);
});

View file

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

View file

@ -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) {

View file

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

View file

@ -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", {

View file

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

View file

@ -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) {
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);
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;
});
});
}, {
fileType: ['image/']
});
// Export to drive as PNG
framework._.sfCommon.createButton('savetodrive', true, {}).click(function () {