diff --git a/www/common/inner/common-mediatag.js b/www/common/inner/common-mediatag.js new file mode 100644 index 000000000..6a6fbdb49 --- /dev/null +++ b/www/common/inner/common-mediatag.js @@ -0,0 +1,238 @@ +define([ + 'jquery', + '/common/common-util.js', + '/common/common-hash.js', + '/common/common-interface.js', + '/common/media-tag.js', + '/customize/messages.js', + + '/bower_components/croppie/croppie.min.js', + 'css!/bower_components/croppie/croppie.css', +], function ($, Util, Hash, UI, MediaTag, Messages) { + var MT = {}; + + // 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 ) + var avatars = {}; + + MT.getCursorAvatar = function (cursor) { + var html = ''; + html += (cursor.avatar && avatars[cursor.avatar]) || ''; + html += cursor.name + ''; + 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 = $('', {'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); } + }; + + // XXX Drop support for external URLs + var parsed = Hash.parsePadUrl(href); + if (parsed.type !== "file" || parsed.hashData.type !== "file") { + var $img = $('').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 = $('').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 = $('
', { + '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.previewMediaTag = function (common, config) { + config = config || {}; + + var metadataMgr = common.getMetadataMgr(); + var priv = metadataMgr.getPrivateData(); + + var src = config.src; + var key = config.key; + if (config.href) { + var parsed = Hash.parsePadUrl(config.href); + var secret = Hash.getSecrets(parsed.type, parsed.hash, config.password); + var host = priv.fileHost || priv.origin || ''; + src = host + Hash.getBlobPathFromHex(secret.channel); + key = secret.keys && secret.keys.cryptKey; + } + if (!src || !key) { + // XXX + return; + } + + var tag = h('media-tag', { + src: src, + 'data-crypto-key': 'cryptpad:' + key + }); + $img.attr('src', src); + $img.attr('data-crypto-key', 'cryptpad:' + cryptKey); + + + }; + + return MT; +});