320 lines
11 KiB
JavaScript
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();
|
|
}]);
|