Sindbad~EG File Manager
import $ from 'jquery';
import { throttle } from 'underscore';
import { ajax, dialog, hooks } from 'peepso';
import peepsodata, { currentuserid as USER_ID, profile as profileData } from 'peepsodata';
const Hammer = window.Hammer;
const UPLOAD_MAXSIZE = +peepsodata.upload_size;
const PEEPSO_NONCE = peepsodata.peepso_nonce;
const PROFILE_ID = +profileData.id;
const IMG_COVER_DEFAULT = profileData.img_cover_default;
const COVER_NONCE = profileData.cover_nonce;
const COVER_UPLOAD_URL = `${peepsodata.ajaxurl_legacy}profile.upload_cover?cover`;
const COVER_TEXT_ERROR_FILETYPE = profileData.text_error_filetype;
const COVER_TEXT_ERROR_FILESIZE = profileData.text_error_filetype;
let hasCover = +profileData.has_cover;
let hammertime;
$(function () {
let $container = $('.ps-js-focus--profile .ps-js-cover');
if (!$container.length) {
return;
}
let $upload = $('.ps-js-cover-upload').on('click', upload),
$uploadFile = uploadInit(),
$remove = $('.ps-js-cover-remove').on('click', remove),
$reposition = $('.ps-js-cover-reposition').on('click', repositionStart),
$repositionActions = $('.ps-js-cover-reposition-actions').hide(),
$repositionCancel = $('.ps-js-cover-reposition-cancel').on('click', repositionCancel),
$repositionConfirm = $('.ps-js-cover-reposition-confirm').on('click', repositionConfirm),
$rotateLeft = $('.ps-js-cover-rotate-left').on('click', { dir: 'ccw' }, rotate),
$rotateRight = $('.ps-js-cover-rotate-right').on('click', { dir: 'cw' }, rotate),
$coverWrapper = $container.find('.ps-js-cover-wrapper'),
$coverImage = $container.find('.ps-js-cover-image'),
$coverLoading = $container.find('.ps-js-cover-loading');
// Do not show related buttons if cover image is not set.
if (!hasCover) {
$reposition.hide();
$rotateLeft.hide();
$rotateRight.hide();
$remove.hide();
}
/**
* Upload a new cover image.
*
* @param {Event} e
*/
function upload(e) {
e.preventDefault();
// Reset input file value before use to prevent the need to replace the element.
// https://github.com/blueimp/jQuery-File-Upload/wiki/Frequently-Asked-Questions#why-is-the-file-input-field-cloned-and-replaced-after-each-selection
// https://stackoverflow.com/questions/1703228/how-can-i-clear-an-html-file-input-with-javascript
$uploadFile[0].value = null;
// Simulate user click.
$uploadFile.trigger('click');
}
function uploadInit() {
let name = 'profile-cover-upload',
accept = 'image/*',
css = { position: 'absolute', opacity: 0, height: 1, width: 1 },
html = `<input type="file" name="filedata" accept="${accept}" data-name="${name}" />`,
$file = $(html).css(css);
$file.appendTo(document.body);
if ($file.psFileupload) {
$file.psFileupload({
formData: { user_id: PROFILE_ID, _wpnonce: COVER_NONCE },
dataType: 'json',
url: COVER_UPLOAD_URL,
beforeSend: function (xhr) {
xhr.setRequestHeader('X-PeepSo-Nonce', PEEPSO_NONCE);
},
replaceFileInput: false,
dropZone: null,
add(e, data) {
let file = data.files[0];
if (!file.type.match(/image\/(jpe?g|png|webp)$/i)) {
alert(COVER_TEXT_ERROR_FILETYPE);
} else if (file.size > UPLOAD_MAXSIZE) {
alert(COVER_TEXT_ERROR_FILESIZE);
} else {
$coverImage.css('opacity', 0.5);
$coverLoading.show();
data.submit();
}
},
done(e, data) {
let json = data.result;
$coverLoading.hide();
if (json.success) {
let imgCover = json.data.image_url;
$reposition.show();
$rotateLeft.show();
$rotateRight.show();
$remove.show();
hasCover = true;
$coverImage
.attr('style', '')
.attr('src', imgCover + '?' + Math.random())
.one('load', fixHorizontalPadding);
hooks.doAction('profile_cover_updated', PROFILE_ID, imgCover);
} else if (json.errors) {
alert(json.errors);
}
}
});
}
return $file;
}
/**
* Remove cover image.
*/
function remove(e) {
e.preventDefault();
let popup = dialog(profileData.template_cover_remove).show();
popup.$el.on('click', '.ps-js-cancel', () => popup.hide());
popup.$el.on('click', '.ps-js-submit', () => {
popup.hide();
$coverImage.css('opacity', 0.5);
let params = { uid: USER_ID, user_id: PROFILE_ID, _wpnonce: COVER_NONCE };
ajax.post('profile.remove_cover_photo', params).then(json => {
if (json.success) {
$reposition.hide();
$rotateLeft.hide();
$rotateRight.hide();
$remove.hide();
hasCover = false;
$coverImage
.attr('style', '')
.attr('src', IMG_COVER_DEFAULT)
.one('load', fixHorizontalPadding);
hooks.doAction('profile_cover_updated', PROFILE_ID, IMG_COVER_DEFAULT);
}
});
});
}
/**
* Initialize cover repositioning.
*
* @param {Event} e
*/
function repositionStart(e) {
e.preventDefault();
// Save current style for undo-ing.
$coverImage.data('style', $coverImage.attr('style'));
$coverImage.css('z-index', 1);
$container.addClass('ps-focus-cover-edit');
$repositionActions.show();
let minLeft = $coverWrapper.width() - $coverImage.width(),
minTop = $coverWrapper.height() - $coverImage.height();
// #4985 Disable default image dragging on Firefox.
$coverImage.off('mousedown').on('mousedown', function (e) {
e.preventDefault();
});
if ('undefined' === typeof Hammer) {
return;
}
hammertime = new Hammer.Manager($coverImage[0]);
hammertime.add(new Hammer.Pan({ direction: Hammer.DIRECTION_ALL, treshhold: 0 }));
hammertime.on('pan panstart panend', e => {
e.srcEvent.stopPropagation();
e.srcEvent.preventDefault();
let $image = $(e.target);
if (e.type === 'panstart') {
$image.data('position', $image.position());
$image.css('cursor', 'move');
} else if (e.type === 'pan') {
let position = $image.data('position'),
shift = { top: e.deltaY, left: e.deltaX };
// Respect horizontal boundaries.
shift.left = Math.max(shift.left, minLeft - position.left);
shift.left = Math.min(shift.left, 0 - position.left);
// Respect vertical boundaries.
shift.top = Math.max(shift.top, minTop - position.top);
shift.top = Math.min(shift.top, 0 - position.top);
$image.css('transform', `translate3d(${shift.left}px, ${shift.top}px, 0)`);
} else {
// Convert value to percentage.
let position = $image.position(),
left = (100 * position.left) / $coverWrapper.width(),
top = (100 * position.top) / $coverWrapper.height();
// Round the value.
left = Math.ceil(left * 10000) / 10000;
top = Math.ceil(top * 10000) / 10000;
$image.css({ top: `${top}%`, left: `${left}%`, transform: '' });
$image.removeData('position');
$image.data({ reposX: left, reposY: top });
$image.css('cursor', '');
}
});
}
/**
* Cancel cover repositioning.
*
* @param {Event} e
*/
function repositionCancel(e) {
e.preventDefault();
hammertime.destroy();
hammertime = null;
$container.removeClass('ps-focus-cover-edit');
$repositionActions.hide();
$coverImage.css('z-index', '');
// Put back previous style.
$coverImage.attr('style', $coverImage.data('style')).removeData('style');
}
/**
* Confirm cover repositioning.
*
* @param {Event} e
*/
function repositionConfirm(e) {
e.preventDefault();
hammertime.destroy();
hammertime = null;
$container.removeClass('ps-focus-cover-edit');
$repositionActions.hide();
$coverImage.css('z-index', '');
let params = {
user_id: PROFILE_ID,
_wpnonce: COVER_NONCE,
// Values are swapped :/
y: $coverImage.data('reposX'),
x: $coverImage.data('reposY')
};
ajax.post('profile.reposition_cover', params); // Optimistic call.
}
/**
* Rotate cover image.
*/
function rotate(e) {
e.preventDefault();
let params = $.extend(
{ direction: 'ccw' === e.data.dir ? 'ccw' : 'cw' },
{ user_id: PROFILE_ID, _wpnonce: COVER_NONCE }
);
ajax.post('profile.rotate_cover', params).then(json => {
if (json.success) {
let imgCover = json.data.image_url;
reloadImage(imgCover);
$coverImage
.attr('style', '')
.attr('src', imgCover + '?' + Math.random())
.one('load', fixHorizontalPadding);
hooks.doAction('profile_cover_updated', PROFILE_ID, imgCover);
}
});
}
/**
* Fix horizontal padding issue caused by dimension difference between
* the cover image and its container.
*/
let fixHorizontalPadding = () => {
// Reset image height.
$coverImage.css({ height: 'auto', width: '100%', minWidth: '100%', maxWidth: '100%' });
// Adjust image height to fill available space vertically it is less than the container width.
let wrapperHeight = $coverWrapper.height(),
wrapperWidth = $coverWrapper.width(),
coverHeight = $coverImage.height(),
coverWidth = $coverImage.width();
if (coverHeight < wrapperHeight) {
$coverImage.css({
height: '100%',
width: 'auto',
minWidth: '100%',
maxWidth: 'none'
});
coverHeight = $coverImage.height();
coverWidth = $coverImage.width();
}
// Make sure image vertical position doesn't go out of viewport due to reposition value.
let top = parseFloat($coverImage[0].style.top) || 0,
minTop = 0;
if (coverHeight >= wrapperHeight) {
minTop = ((coverHeight - wrapperHeight) / wrapperHeight) * -100;
if (top < minTop) {
$coverImage.css('top', `${minTop}%`);
}
}
// Make sure image horizontal position doesn't go out of viewport due to reposition value.
let left = parseFloat($coverImage[0].style.left) || 0,
minLeft = 0;
if (coverWidth >= wrapperWidth) {
minLeft = ((coverWidth - wrapperWidth) / wrapperWidth) * -100;
if (left < minLeft) {
$coverImage.css('left', `${minLeft}%`);
}
}
// Show initially invisible cover image.
$coverImage.css('opacity', '');
};
// Throttle the function.
fixHorizontalPadding = throttle(fixHorizontalPadding, 500);
// Fix horizontal padding issue on page load.
$coverImage.each(function () {
let img = new Image();
img.onload = fixHorizontalPadding;
img.src = this.src;
});
// Efficiently handles cover image dimension change on browser resize.
let _docWidth;
hooks.addAction('browser_resize', 'profile_cover', dimension => {
if (!_docWidth || _docWidth !== dimension.width) {
_docWidth = dimension.width;
fixHorizontalPadding();
}
});
let $coverButtonPopup = $('.ps-js-cover-button-popup');
$coverButtonPopup.on('click', function (e) {
if (e.currentTarget !== e.target) {
return;
}
let $button = $(this);
let coverUrl = $button.data('cover-url');
if (coverUrl) {
peepso.simple_lightbox(coverUrl);
}
});
hooks.addAction('profile_cover_updated', 'page_profile', (id, imageUrl) => {
if (+id === PROFILE_ID) {
if (imageUrl.indexOf(`/users/${id}/`) > -1) {
// Custom cover.
$coverButtonPopup.css('cursor', 'pointer');
$coverButtonPopup.data('cover-url', imageUrl);
} else {
// Default cover.
$coverButtonPopup.css('cursor', '');
$coverButtonPopup.removeData('cover-url');
}
}
});
});
/**
* Reload image.
*
* @param {string} url
*/
function reloadImage(url) {
fetch(url, { cache: 'reload', mode: 'no-cors' }).then(() =>
document.body.querySelectorAll(`img[src='${url}']`).forEach(function (img) {
img.src = url;
})
);
}
Sindbad File Manager Version 1.0, Coded By Sindbad EG ~ The Terrorists