'use strict'; /* global angular:false */ /* global $:false */ angular.module('Application').controller('BrandingController', ['$scope', '$location', 'Client', function ($scope, $location, Client) { Client.onReady(function () { if (!Client.getUserInfo().isAtLeastAdmin) $location.path('/'); }); $scope.user = Client.getUserInfo(); $scope.config = Client.getConfig(); $scope.openSubscriptionSetup = function () { Client.openSubscriptionSetup($scope.$parent.subscription); }; $scope.avatarChange = { avatar: null, // { file, data, url } availableAvatars: [{ file: null, data: null, url: '/img/avatars/logo.png', }, { file: null, data: null, url: '/img/avatars/logo-green.png' }, { file: null, data: null, url: '/img/avatars/logo-orange.png' }, { file: null, data: null, url: '/img/avatars/logo-darkblue.png' }, { file: null, data: null, url: '/img/avatars/logo-red.png' }, { file: null, data: null, url: '/img/avatars/logo-yellow.png' }, { file: null, data: null, url: '/img/avatars/logo-black.png' }], avatarUrl: function () { if ($scope.avatarChange.avatar) { return $scope.avatarChange.avatar.data || $scope.avatarChange.avatar.url; } else { return Client.avatar; } }, getBlobFromImg: function (img, callback) { var size = 512; var canvas = document.createElement('canvas'); canvas.width = size; canvas.height = size; var imageDimensionRatio = img.width / img.height; var canvasDimensionRatio = canvas.width / canvas.height; var renderableHeight, renderableWidth, xStart, yStart; if (imageDimensionRatio > canvasDimensionRatio) { renderableHeight = canvas.height; renderableWidth = img.width * (renderableHeight / img.height); xStart = (canvas.width - renderableWidth) / 2; yStart = 0; } else if (imageDimensionRatio < canvasDimensionRatio) { renderableWidth = canvas.width; renderableHeight = img.height * (renderableWidth / img.width); xStart = 0; yStart = (canvas.height - renderableHeight) / 2; } else { renderableHeight = canvas.height; renderableWidth = canvas.width; xStart = 0; yStart = 0; } var ctx = canvas.getContext('2d'); ctx.clearRect(0, 0, canvas.width, canvas.height); ctx.drawImage(img, xStart, yStart, renderableWidth, renderableHeight); canvas.toBlob(callback); }, setPreviewAvatar: function (avatar) { $scope.avatarChange.avatar = avatar; }, showChangeAvatar: function () { $scope.avatarChange.avatar = $scope.about.avatar; $('#avatarChangeModal').modal('show'); }, showCustomAvatarSelector: function () { $('#avatarFileInput').click(); }, setAvatar: function () { if (angular.equals($scope.about.avatar, $scope.avatarChange.avatar)) return $('#avatarChangeModal').modal('hide'); // nothing changed $scope.about.avatar = $scope.avatarChange.avatar; // get the blob now, we cannot get it if dialog is hidden var img = document.getElementById('previewAvatar'); $scope.avatarChange.getBlobFromImg(img, function (blob) { $scope.about.avatarBlob = blob; $('#avatarChangeModal').modal('hide'); }); }, }; $('#avatarFileInput').get(0).onchange = function (event) { var fr = new FileReader(); fr.onload = function () { $scope.$apply(function () { var tmp = { file: event.target.files[0], data: fr.result, url: null }; $scope.avatarChange.availableAvatars.push(tmp); $scope.avatarChange.setPreviewAvatar(tmp); }); }; fr.readAsDataURL(event.target.files[0]); }; $scope.background = { enabled: false, file: null, src: null, cleared: false, newImageFile: null, cacheBusting: Date.now(), url() { if ($scope.background.cleared) return '/img/background-image-placeholder.svg'; else if ($scope.background.src) return $scope.background.src; else return `${Client.apiOrigin}/api/v1/cloudron/background?${$scope.background.cacheBusting}`; }, selectNew() { document.getElementById('backgroundFileInput').click(); }, submit(callback) { if ($scope.background.cleared) { Client.changeCloudronBackground(null, callback); } else if ($scope.background.newImageFile) { Client.changeCloudronBackground($scope.background.newImageFile, callback); } else { callback(); } }, clear() { $scope.background.cleared = true; } }; document.getElementById('backgroundFileInput').onchange = function (event) { const fr = new FileReader(); fr.onload = function () { const image = new Image(); image.onload = function () { // convert and scale to webp max 4k const maxWidth = 4096; const canvas = document.createElement('canvas'); if (image.naturalWidth > maxWidth) { canvas.width = maxWidth; canvas.height = (image.naturalHeight / image.naturalWidth) * maxWidth; } else { canvas.width = image.naturalWidth; canvas.height = image.naturalHeight; } canvas.getContext('2d').drawImage(image, 0, 0, canvas.width, canvas.height); canvas.toBlob((blob) => { $scope.$apply(function () { const myImage = new File([blob], 'background.webp', { type: blob.type }); $scope.background.cleared = false; $scope.background.newImageFile = myImage; $scope.background.src = URL.createObjectURL(myImage); }); }, 'image/webp'); $scope.background.file = event.target.files[0]; }; image.src = fr.result; }; fr.readAsDataURL(event.target.files[0]); }; $scope.about = { busy: false, error: {}, cloudronName: '', avatar: null, avatarBlob: null, avatarUrl() { if ($scope.about.avatar) { return $scope.about.avatar.data || $scope.about.avatar.url; } else { return Client.avatar; } }, refresh() { $scope.about.cloudronName = $scope.config.cloudronName; $scope.about.avatar = null; Client.hasCloudronBackground(function (error, result) { if (error) return console.error('Failed to get background state.', error); $scope.background.enabled = result; $scope.background.file = null; $scope.background.src = null; $scope.background.newImageFile = null; $scope.background.cacheBusting = Date.now(); }); }, submit() { $scope.about.error.name = null; $scope.about.busy = true; var NOOP = function (next) { return next(); }; var changeCloudronName = $scope.about.cloudronName !== $scope.config.cloudronName ? Client.changeCloudronName.bind(null, $scope.about.cloudronName) : NOOP; changeCloudronName(function (error) { if (error) { $scope.about.busy = false; if (error.statusCode === 400) { $scope.about.error.cloudronName = error.message || 'Invalid name'; $('#inputCloudronName').focus(); } else { console.error('Unable to change name.', error); return; } } var changeAvatar = $scope.about.avatar ? Client.changeCloudronAvatar.bind(null, $scope.about.avatarBlob) : NOOP; changeAvatar(function (error) { if (error) { $scope.about.busy = false; console.error('Unable to change avatar.', error); return; } $scope.background.submit(function (error) { if (error) { $scope.about.busy = false; console.error('Unable to change background.', error); return; } Client.refreshConfig(function () { if ($scope.about.avatar) Client.resetAvatar(); $scope.aboutForm.$setPristine(); $scope.about.avatar = null; $scope.about.refresh(); $scope.about.busy = false; }); }); }); }); } }; $scope.footer = { content: '', busy: false, refresh: function () { Client.getFooter(function (error, result) { if (error) return console.error('Failed to get footer.', error); $scope.footer.content = result; }); }, submit: function () { $scope.footer.busy = true; Client.setFooter($scope.footer.content.trim(), function (error) { if (error) return console.error('Failed to set footer.', error); Client.refreshConfig(function () { $scope.footer.busy = false; $scope.footerForm.$setPristine(); }); }); } }; Client.onReady(function () { $scope.about.refresh(); $scope.footer.refresh(); }); $('.modal-backdrop').remove(); }]);