206 lines
6.2 KiB
JavaScript
206 lines
6.2 KiB
JavaScript
/* eslint-disable no-useless-escape, no-underscore-dangle, func-names, no-return-assign, consistent-return, class-methods-use-this */
|
|
|
|
import $ from 'jquery';
|
|
import 'cropper';
|
|
import { isString } from 'lodash';
|
|
import { s__ } from '~/locale';
|
|
import { createAlert } from '~/alert';
|
|
import { loadCSSFile } from '../lib/utils/css_utils';
|
|
|
|
(() => {
|
|
// Matches everything but the file name
|
|
const FILENAMEREGEX = /^.*[\\\/]/;
|
|
|
|
class GitLabCrop {
|
|
constructor(
|
|
input,
|
|
{
|
|
filename,
|
|
previewImage,
|
|
modalCrop,
|
|
pickImageEl,
|
|
uploadImageBtn,
|
|
modalCropImg,
|
|
exportWidth = 200,
|
|
exportHeight = 200,
|
|
cropBoxWidth = 200,
|
|
cropBoxHeight = 200,
|
|
} = {},
|
|
) {
|
|
this.onUploadImageBtnClick = this.onUploadImageBtnClick.bind(this);
|
|
this.onModalHide = this.onModalHide.bind(this);
|
|
this.onModalShow = this.onModalShow.bind(this);
|
|
this.onPickImageClick = this.onPickImageClick.bind(this);
|
|
this.fileInput = $(input);
|
|
this.modalCropImg = isString(this.modalCropImg) ? $(this.modalCropImg) : this.modalCropImg;
|
|
this.fileInput
|
|
.attr('name', `${this.fileInput.attr('name')}-trigger`)
|
|
.attr('id', `${this.fileInput.attr('id')}-trigger`);
|
|
this.exportWidth = exportWidth;
|
|
this.exportHeight = exportHeight;
|
|
this.cropBoxWidth = cropBoxWidth;
|
|
this.cropBoxHeight = cropBoxHeight;
|
|
this.form = this.fileInput.parents('form');
|
|
this.filename = filename;
|
|
this.previewImage = previewImage;
|
|
this.modalCrop = modalCrop;
|
|
this.pickImageEl = pickImageEl;
|
|
this.uploadImageBtn = uploadImageBtn;
|
|
this.modalCropImg = modalCropImg;
|
|
this.filename = this.getElement(filename);
|
|
this.previewImage = this.getElement(previewImage);
|
|
this.pickImageEl = this.getElement(pickImageEl);
|
|
this.modalCrop = isString(modalCrop) ? $(modalCrop) : modalCrop;
|
|
this.uploadImageBtn = isString(uploadImageBtn) ? $(uploadImageBtn) : uploadImageBtn;
|
|
this.modalCropImg = isString(modalCropImg) ? $(modalCropImg) : modalCropImg;
|
|
this.cropActionsBtn = this.modalCrop.find('[data-method]');
|
|
this.bindEvents();
|
|
}
|
|
|
|
getElement(selector) {
|
|
return $(selector, this.form);
|
|
}
|
|
|
|
bindEvents() {
|
|
const _this = this;
|
|
this.fileInput.on('change', function (e) {
|
|
_this.onFileInputChange(e, this);
|
|
this.value = null;
|
|
});
|
|
this.pickImageEl.on('click', this.onPickImageClick);
|
|
this.modalCrop.on('shown.bs.modal', this.onModalShow);
|
|
this.modalCrop.on('hidden.bs.modal', this.onModalHide);
|
|
this.uploadImageBtn.on('click', this.onUploadImageBtnClick);
|
|
this.cropActionsBtn.on('click', function () {
|
|
const btn = this;
|
|
return _this.onActionBtnClick(btn);
|
|
});
|
|
return (this.croppedImageBlob = null);
|
|
}
|
|
|
|
onPickImageClick() {
|
|
return this.fileInput.trigger('click');
|
|
}
|
|
|
|
onModalShow() {
|
|
const _this = this;
|
|
return this.modalCropImg.cropper({
|
|
viewMode: 1,
|
|
center: false,
|
|
aspectRatio: 1,
|
|
modal: true,
|
|
scalable: false,
|
|
rotatable: true,
|
|
checkOrientation: true,
|
|
zoomable: true,
|
|
dragMode: 'move',
|
|
guides: false,
|
|
zoomOnTouch: false,
|
|
zoomOnWheel: false,
|
|
cropBoxMovable: false,
|
|
cropBoxResizable: false,
|
|
toggleDragModeOnDblclick: false,
|
|
built() {
|
|
const $image = $(this);
|
|
const container = $image.cropper('getContainerData');
|
|
const { cropBoxWidth, cropBoxHeight } = _this;
|
|
|
|
return $image.cropper('setCropBoxData', {
|
|
width: cropBoxWidth,
|
|
height: cropBoxHeight,
|
|
left: (container.width - cropBoxWidth) / 2,
|
|
top: (container.height - cropBoxHeight) / 2,
|
|
});
|
|
},
|
|
});
|
|
}
|
|
|
|
onModalHide() {
|
|
this.modalCropImg.attr('src', '').cropper('destroy');
|
|
const modalElement = document.querySelector('.modal-profile-crop');
|
|
if (modalElement) modalElement.remove();
|
|
}
|
|
|
|
onUploadImageBtnClick(e) {
|
|
e.preventDefault();
|
|
this.setBlob();
|
|
this.setPreview();
|
|
this.modalCrop.modal('hide');
|
|
return this.fileInput.val('');
|
|
}
|
|
|
|
onActionBtnClick(btn) {
|
|
const data = $(btn).data();
|
|
if (this.modalCropImg.data('cropper') && data.method) {
|
|
return this.modalCropImg.cropper(data.method, data.option);
|
|
}
|
|
}
|
|
|
|
onFileInputChange(e, input) {
|
|
return this.readFile(input);
|
|
}
|
|
|
|
readFile(input) {
|
|
const reader = new FileReader();
|
|
reader.onload = () => {
|
|
this.modalCropImg.attr('src', reader.result);
|
|
import(/* webpackChunkName: 'bootstrapModal' */ 'bootstrap/js/dist/modal')
|
|
.then(() => {
|
|
this.modalCrop.modal('show');
|
|
})
|
|
.catch(() => {
|
|
createAlert({
|
|
message: s__(
|
|
'UserProfile|Failed to set avatar. Please reload the page to try again.',
|
|
),
|
|
});
|
|
});
|
|
};
|
|
return reader.readAsDataURL(input.files[0]);
|
|
}
|
|
|
|
dataURLtoBlob(dataURL) {
|
|
let i = 0;
|
|
let len = 0;
|
|
const binary = atob(dataURL.split(',')[1]);
|
|
const array = [];
|
|
|
|
for (i = 0, len = binary.length; i < len; i += 1) {
|
|
array.push(binary.charCodeAt(i));
|
|
}
|
|
return new Blob([new Uint8Array(array)], {
|
|
type: 'image/png',
|
|
});
|
|
}
|
|
|
|
setPreview() {
|
|
const filename = this.fileInput.val().replace(FILENAMEREGEX, '');
|
|
this.previewImage.attr('src', this.dataURL);
|
|
this.previewImage.attr('srcset', this.dataURL);
|
|
return this.filename.text(filename);
|
|
}
|
|
|
|
setBlob() {
|
|
this.dataURL = this.modalCropImg
|
|
.cropper('getCroppedCanvas', {
|
|
width: 200,
|
|
height: 200,
|
|
})
|
|
.toDataURL('image/png');
|
|
return (this.croppedImageBlob = this.dataURLtoBlob(this.dataURL));
|
|
}
|
|
|
|
getBlob() {
|
|
return this.croppedImageBlob;
|
|
}
|
|
}
|
|
|
|
const cropModal = document.querySelector('.modal-profile-crop');
|
|
if (cropModal) loadCSSFile(cropModal.dataset.cropperCssPath);
|
|
|
|
$.fn.glCrop = function (opts) {
|
|
return this.each(function () {
|
|
return $(this).data('glcrop', new GitLabCrop(this, opts));
|
|
});
|
|
};
|
|
})(window.gl || (window.gl = {}));
|