Files
cloudron-box/dashboard/public/views/branding.js
2024-10-04 14:30:44 +02:00

320 lines
11 KiB
JavaScript

'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();
}]);