first commit
This commit is contained in:
166
assets/js/media-admin.js
Normal file
166
assets/js/media-admin.js
Normal file
@@ -0,0 +1,166 @@
|
||||
(function (window, document) {
|
||||
'use strict';
|
||||
|
||||
var page = document.getElementById('media-admin-page');
|
||||
if (!page) {
|
||||
return;
|
||||
}
|
||||
|
||||
var uploadForm = document.getElementById('media-upload-form');
|
||||
var uploadButton = document.getElementById('media-upload-submit');
|
||||
var uploadInput = document.getElementById('media-upload-input');
|
||||
var feedback = document.getElementById('media-upload-feedback');
|
||||
var isPickerMode = page.dataset.pickerMode === '1';
|
||||
|
||||
function setFeedback(message, isError) {
|
||||
if (!feedback) {
|
||||
return;
|
||||
}
|
||||
|
||||
feedback.textContent = message;
|
||||
feedback.style.color = isError ? '#b91c1c' : '';
|
||||
}
|
||||
|
||||
async function copyToClipboard(text) {
|
||||
if (navigator.clipboard && navigator.clipboard.writeText) {
|
||||
await navigator.clipboard.writeText(text);
|
||||
return;
|
||||
}
|
||||
|
||||
var helper = document.createElement('textarea');
|
||||
helper.value = text;
|
||||
helper.setAttribute('readonly', 'readonly');
|
||||
helper.style.position = 'absolute';
|
||||
helper.style.left = '-9999px';
|
||||
document.body.appendChild(helper);
|
||||
helper.select();
|
||||
document.execCommand('copy');
|
||||
document.body.removeChild(helper);
|
||||
}
|
||||
|
||||
function toAbsoluteUrl(url) {
|
||||
try {
|
||||
return new URL(String(url || ''), window.location.origin).href;
|
||||
} catch (error) {
|
||||
return String(url || '');
|
||||
}
|
||||
}
|
||||
|
||||
function buildImageHtml(url, mediaId) {
|
||||
return '<img src="' + String(url)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>') + '" alt="" data-media-id="' + Number(mediaId) + '">';
|
||||
}
|
||||
|
||||
function flashButtonLabel(button, message, isError) {
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!button.dataset.originalLabel) {
|
||||
button.dataset.originalLabel = button.textContent.trim();
|
||||
}
|
||||
|
||||
if (button.dataset.restoreTimerId) {
|
||||
window.clearTimeout(Number(button.dataset.restoreTimerId));
|
||||
}
|
||||
|
||||
button.textContent = message;
|
||||
|
||||
if (isError) {
|
||||
button.classList.add('btn--danger');
|
||||
}
|
||||
|
||||
button.dataset.restoreTimerId = String(window.setTimeout(function () {
|
||||
button.textContent = button.dataset.originalLabel || '';
|
||||
button.classList.remove('btn--danger');
|
||||
delete button.dataset.restoreTimerId;
|
||||
}, 1800));
|
||||
}
|
||||
|
||||
async function handleUpload() {
|
||||
if (!uploadForm || !uploadButton || !uploadInput) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!uploadInput.files || uploadInput.files.length === 0) {
|
||||
setFeedback('Sélectionnez une image avant de téléverser.', true);
|
||||
return;
|
||||
}
|
||||
|
||||
uploadButton.disabled = true;
|
||||
setFeedback('Téléversement en cours…', false);
|
||||
|
||||
try {
|
||||
var response = await fetch(uploadForm.dataset.uploadUrl || uploadForm.action || window.location.href, {
|
||||
method: 'POST',
|
||||
body: new FormData(uploadForm),
|
||||
credentials: 'same-origin',
|
||||
headers: {
|
||||
'X-Requested-With': 'XMLHttpRequest'
|
||||
}
|
||||
});
|
||||
|
||||
var payload = await response.json();
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(payload.error || 'Le téléversement a échoué.');
|
||||
}
|
||||
|
||||
setFeedback('Image téléversée. Rafraîchissement…', false);
|
||||
window.location.reload();
|
||||
} catch (error) {
|
||||
setFeedback(error instanceof Error ? error.message : 'Le téléversement a échoué.', true);
|
||||
} finally {
|
||||
uploadButton.disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (uploadButton) {
|
||||
uploadButton.addEventListener('click', function () {
|
||||
handleUpload();
|
||||
});
|
||||
}
|
||||
|
||||
page.addEventListener('click', async function (event) {
|
||||
var button = event.target.closest('[data-media-action]');
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
|
||||
var action = button.dataset.mediaAction;
|
||||
var url = button.dataset.mediaUrl || '';
|
||||
var mediaId = Number(button.dataset.mediaId || '0');
|
||||
|
||||
if (action === 'insert-editor') {
|
||||
if (isPickerMode && window.parent && window.parent !== window) {
|
||||
window.parent.postMessage({
|
||||
type: 'netslim:media-selected',
|
||||
url: url,
|
||||
mediaId: mediaId,
|
||||
html: buildImageHtml(url, mediaId)
|
||||
}, window.location.origin);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (action === 'copy-url') {
|
||||
await copyToClipboard(toAbsoluteUrl(url));
|
||||
flashButtonLabel(button, 'URL copiée.', false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (action === 'copy-html') {
|
||||
await copyToClipboard(buildImageHtml(url, mediaId));
|
||||
flashButtonLabel(button, 'HTML copié.', false);
|
||||
return;
|
||||
}
|
||||
} catch (error) {
|
||||
flashButtonLabel(button, 'Copie impossible.', true);
|
||||
setFeedback('Impossible de copier dans le presse-papiers.', true);
|
||||
}
|
||||
});
|
||||
})(window, document);
|
||||
147
assets/js/post-editor-media-picker.js
Normal file
147
assets/js/post-editor-media-picker.js
Normal file
@@ -0,0 +1,147 @@
|
||||
(function (window, document, $) {
|
||||
'use strict';
|
||||
|
||||
if (!$ || typeof $.fn.trumbowyg !== 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
var editorElement = document.getElementById('editor');
|
||||
var modal = document.getElementById('media-picker-modal');
|
||||
var closeButton = document.getElementById('media-picker-close');
|
||||
var frame = document.getElementById('media-picker-frame');
|
||||
|
||||
if (!editorElement) {
|
||||
return;
|
||||
}
|
||||
|
||||
var $editor = $(editorElement);
|
||||
var previousActiveElement = null;
|
||||
|
||||
function escapeHtmlAttribute(value) {
|
||||
return String(value)
|
||||
.replace(/&/g, '&')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>');
|
||||
}
|
||||
|
||||
function createMediaHtml(url, mediaId) {
|
||||
return '<img src="' + escapeHtmlAttribute(url) + '" alt="" data-media-id="' + Number(mediaId) + '">';
|
||||
}
|
||||
|
||||
function ensurePickerLoaded() {
|
||||
if (!frame || !frame.dataset.pickerSrc) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!frame.getAttribute('src')) {
|
||||
frame.setAttribute('src', frame.dataset.pickerSrc);
|
||||
}
|
||||
}
|
||||
|
||||
function focusToolbarButton() {
|
||||
var button = document.querySelector('.trumbowyg-mediaPicker-button');
|
||||
if (button) {
|
||||
button.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function openPicker() {
|
||||
if (!modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
previousActiveElement = document.activeElement;
|
||||
$editor.trumbowyg('saveRange');
|
||||
ensurePickerLoaded();
|
||||
modal.hidden = false;
|
||||
modal.classList.add('is-open');
|
||||
modal.setAttribute('aria-hidden', 'false');
|
||||
|
||||
if (closeButton) {
|
||||
closeButton.focus();
|
||||
}
|
||||
}
|
||||
|
||||
function closePicker() {
|
||||
if (!modal) {
|
||||
return;
|
||||
}
|
||||
|
||||
modal.classList.remove('is-open');
|
||||
modal.setAttribute('aria-hidden', 'true');
|
||||
modal.hidden = true;
|
||||
|
||||
if (previousActiveElement instanceof HTMLElement) {
|
||||
previousActiveElement.focus();
|
||||
return;
|
||||
}
|
||||
|
||||
focusToolbarButton();
|
||||
}
|
||||
|
||||
function insertSelectedMedia(url, mediaId) {
|
||||
if (!url || !mediaId) {
|
||||
return;
|
||||
}
|
||||
|
||||
$editor.trumbowyg('restoreRange');
|
||||
$editor.trumbowyg('execCmd', {
|
||||
cmd: 'insertHTML',
|
||||
param: createMediaHtml(url, mediaId)
|
||||
});
|
||||
closePicker();
|
||||
$editor.trumbowyg('saveRange');
|
||||
}
|
||||
|
||||
$editor.trumbowyg({
|
||||
lang: 'fr',
|
||||
removeformatPasted: true,
|
||||
btnsDef: {
|
||||
mediaPicker: {
|
||||
fn: function () {
|
||||
openPicker();
|
||||
return true;
|
||||
},
|
||||
ico: 'upload',
|
||||
title: 'Médiathèque'
|
||||
}
|
||||
},
|
||||
btns: [
|
||||
['viewHTML'],
|
||||
['formatting'],
|
||||
['strong', 'em', 'underline', 'del'],
|
||||
['link', 'mediaPicker'],
|
||||
['justifyLeft', 'justifyCenter', 'justifyRight'],
|
||||
['unorderedList', 'orderedList'],
|
||||
['insertHorizontalRule'],
|
||||
['fullscreen']
|
||||
]
|
||||
});
|
||||
|
||||
if (closeButton) {
|
||||
closeButton.addEventListener('click', closePicker);
|
||||
}
|
||||
|
||||
if (modal) {
|
||||
modal.addEventListener('click', function (event) {
|
||||
if (event.target === modal) {
|
||||
closePicker();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener('keydown', function (event) {
|
||||
if (event.key === 'Escape' && modal && !modal.hidden) {
|
||||
closePicker();
|
||||
}
|
||||
});
|
||||
|
||||
window.addEventListener('message', function (event) {
|
||||
if (event.origin !== window.location.origin || !event.data || event.data.type !== 'netslim:media-selected') {
|
||||
return;
|
||||
}
|
||||
|
||||
insertSelectedMedia(event.data.url, event.data.mediaId);
|
||||
});
|
||||
})(window, document, window.jQuery);
|
||||
Reference in New Issue
Block a user