236 lines
9.5 KiB
PHP
236 lines
9.5 KiB
PHP
<?php
|
|
if (!isset($windowHeight)) $windowHeight = 350;
|
|
if (!isset($fieldName)) $fieldName = 'content';
|
|
|
|
?>
|
|
<style>
|
|
/* Summernote's dialogs (Insert Image / Link / Video / Help) open while the record is
|
|
being edited inside a jQuery UI modal dialog. Two separate things break there:
|
|
|
|
1. STACKING. jQuery UI 1.12's _moveToTop() (jquery-ui.js:12163) reads every visible
|
|
.ui-front sibling and sets its own dialog to max+1. A fixed high z-index on
|
|
.note-modal therefore does NOT win -- jQuery UI simply climbs above it. The
|
|
reliable fix is to keep the Summernote modal out of that comparison and give it
|
|
a z-index above the overlay, while the overlay itself keeps its own value.
|
|
2. HIT TESTING. .ui-widget-overlay is painted over the whole viewport. Even when the
|
|
Summernote dialog is drawn on top, the overlay still captures the clicks unless
|
|
pointer events are disabled on it while a Summernote dialog is open. */
|
|
.note-modal { z-index: 100050 !important; }
|
|
.note-modal-backdrop { z-index: 100040 !important; }
|
|
.note-popover.popover{ z-index: 100060 !important; }
|
|
|
|
/* The file input and URL field live inside .note-modal-content -- make sure nothing
|
|
inherited from the dialog CSS leaves them inert. */
|
|
.note-modal, .note-modal-content, .note-modal * { pointer-events: auto !important; }
|
|
|
|
/* While a Summernote dialog is open the jQuery UI overlay must stop intercepting
|
|
clicks, otherwise "Choose Files" and "Image URL" stay dead even though they are
|
|
visible on top of it. */
|
|
body.note-dialog-open .ui-widget-overlay,
|
|
body:has(.note-modal.open) .ui-widget-overlay { pointer-events: none !important; }
|
|
</style>
|
|
<script>
|
|
// Must run at parse time, not in $(document).ready. form.js.php registers its ready
|
|
// handler first and creates #data-dialog there; a ready-time patch here is too late
|
|
// and that dialog keeps the original focus trap.
|
|
if ($.ui && $.ui.dialog && !window._noteDialogAllowInteraction) {
|
|
window._noteDialogAllowInteraction = true;
|
|
$.widget("ui.dialog", $.ui.dialog, {
|
|
_allowInteraction: function (event) {
|
|
return !!$(event.target).closest(".note-modal, .note-popover, .note-editor").length ||
|
|
this._super(event);
|
|
}
|
|
});
|
|
}
|
|
|
|
$(document).ready(function() {
|
|
|
|
<?php
|
|
// NOTE: include/ajax.Setup.php calls exit() if session_start() returns false
|
|
// (ajax.Setup.php:5-7). By the time this file runs, config.php:217 has already
|
|
// started the session, so that second session_start() fails and exit() aborts
|
|
// the whole page render -- silently discarding this <script> block and the
|
|
// gallery markup below it. Emit the same $.ajaxSetup here instead, guarded.
|
|
if (!isset($_SESSION)) {
|
|
if (session_status() != PHP_SESSION_ACTIVE) {
|
|
session_name('hotlunch');
|
|
@session_start();
|
|
}
|
|
}
|
|
if (is_array($_SESSION) && !array_key_exists('csrf_token', $_SESSION)) {
|
|
$_SESSION['csrf_token'] = str_replace('+','.',base64_encode(openssl_random_pseudo_bytes(32)));
|
|
}
|
|
$csrfToken = (is_array($_SESSION) && array_key_exists('csrf_token', $_SESSION)) ? $_SESSION['csrf_token'] : '';
|
|
?>
|
|
$.ajaxSetup({
|
|
data: window.csrf,
|
|
cache: false,
|
|
headers: {
|
|
'X-CSRF-TOKEN': '<?php echo($csrfToken); ?>'
|
|
}
|
|
});
|
|
|
|
var $noteTarget = $('#<?php echo($fieldName) ?>');
|
|
|
|
// Flag the body while a Summernote dialog is open so the CSS above can drop the
|
|
// jQuery UI overlay's pointer capture. summernote-lite fires these two events on
|
|
// the .note-modal element (verified in summernote-lite.min.js).
|
|
$(document).on("note.modal.show", ".note-modal", function () {
|
|
$("body").addClass("note-dialog-open");
|
|
});
|
|
$(document).on("note.modal.hide", ".note-modal", function () {
|
|
$("body").removeClass("note-dialog-open");
|
|
});
|
|
|
|
if ($.ui && $.ui.dialog) {
|
|
$("#image-gallery-dialog").dialog({
|
|
autoOpen: false,
|
|
minWidth: 950,
|
|
minHeight: 400,
|
|
modal: true,
|
|
position: { my: 'center', at: 'center' }
|
|
});
|
|
}
|
|
|
|
$("#close-gallery").on("click", function () {
|
|
$("#image-gallery-dialog").dialog("close");
|
|
});
|
|
|
|
var Gallery = function (context) {
|
|
var ui = $.summernote.ui;
|
|
|
|
// create button. Font Awesome is not loaded on the table-edit dialog pages, so
|
|
// use Summernote's own icon font and keep a text label as the visible fallback.
|
|
var button = ui.button({
|
|
contents: '<i class="note-icon-picture"></i> Gallery',
|
|
tooltip: '<?php echo(addslashes(getLanguageText("TEXT-IMAGE-GALLERY"))) ?>',
|
|
click: function () {
|
|
loadGallery();
|
|
$("#image-gallery-dialog").dialog("open");
|
|
}
|
|
});
|
|
|
|
return button.render(); // return button as jquery object
|
|
}
|
|
|
|
$noteTarget.summernote({
|
|
height: <?php echo($windowHeight) ?>,
|
|
// THE FIX for the greyed-out, unclickable "Insert Image" popup.
|
|
// summernote-lite always appends its backdrop to document.body
|
|
// this.$backdrop.appendTo(document.body)
|
|
// but appends the dialog itself to (dialogsInBody ? $body : options.container),
|
|
// which defaults to the editor. Here the editor lives inside a jQuery UI modal
|
|
// dialog, and that dialog has its own z-index (~101) forming a stacking context.
|
|
// The dialog is therefore TRAPPED in that context no matter how high its
|
|
// z-index is, while the backdrop sits at the document root above it -- so the
|
|
// backdrop paints over the popup and eats every click. Putting the dialog in
|
|
// <body> makes it a sibling of the backdrop again, where z-index actually works.
|
|
dialogsInBody: true,
|
|
toolbar: [
|
|
['style', ['style']],
|
|
['font', ['bold', 'underline', 'clear']],
|
|
['fontname', ['fontname']],
|
|
['fontSize', ['fontsize']],
|
|
['color', ['color']],
|
|
['para', ['ul', 'ol', 'paragraph']],
|
|
['table', ['table']],
|
|
['mybutton', ['Gallery']],
|
|
['insert', ['link', 'picture', 'video']],
|
|
['view', ['fullscreen', 'codeview', 'help']],
|
|
],
|
|
buttons: {
|
|
Gallery
|
|
},
|
|
callbacks: {
|
|
onImageUpload: function(files, editor, $editable) {
|
|
uploadImageFile(files[0],editor,$editable);
|
|
}
|
|
},
|
|
imageAttributes: {
|
|
// The plugin ignores the top-level dialogsInBody and reads its own copy
|
|
// (summernote-image-attributes.js:60); without it the "Change Image Attributes"
|
|
// popup is trapped under the backdrop exactly like the Insert Image one was.
|
|
dialogsInBody: true,
|
|
icon: '<i class="note-icon-pencil">',
|
|
figureClass: 'figureClass',
|
|
figcaptionClass: 'captionClass',
|
|
captionText: 'Caption Goes Here.',
|
|
manageAspectRatio: true // true = Lock the Image Width/Height, Default to true
|
|
},
|
|
lang: 'en-US',
|
|
popover: {
|
|
image: [
|
|
['image', ['resizeFull', 'resizeHalf', 'resizeQuarter', 'resizeNone']],
|
|
['float', ['floatLeft', 'floatRight', 'floatNone']],
|
|
['custom', ['imageAttributes']],
|
|
['remove', ['removeMedia']],
|
|
],
|
|
}
|
|
});
|
|
|
|
$(document).on('click', '.gallery-image', function() {
|
|
var image = $(this);
|
|
var imageUrl = image.attr('filename');
|
|
|
|
// Create an <img> element with the image URL
|
|
var imgElement = $("<img>").attr("src", imageUrl);
|
|
|
|
// Insert the <img> element into the editor
|
|
$noteTarget.summernote("pasteHTML", imgElement[0].outerHTML);
|
|
|
|
$("#image-gallery-dialog").dialog("close");
|
|
});
|
|
|
|
|
|
function uploadImageFile(file,editor,welEditable) {
|
|
data = new FormData();
|
|
data.append("file", file);
|
|
$.ajax({
|
|
url: "ajax.imageUploader.php",
|
|
data: data,
|
|
cache: false,
|
|
contentType: false,
|
|
processData: false,
|
|
type: 'POST',
|
|
success: function(response){
|
|
var imageUrl = response.trim(); // Trim any leading/trailing whitespace
|
|
|
|
// Create an <img> element with the image URL
|
|
var imgElement = $("<img>").attr("src", imageUrl);
|
|
|
|
// Insert the <img> element into the editor
|
|
$noteTarget.summernote("pasteHTML", imgElement[0].outerHTML);
|
|
},
|
|
error: function(jqXHR, textStatus, errorThrown) {
|
|
console.log(textStatus+" "+errorThrown);
|
|
alert(textStatus+" "+errorThrown);
|
|
}
|
|
|
|
});
|
|
}
|
|
|
|
function loadGallery() {
|
|
var data = "table_name=images"+
|
|
"&sequence_flag=N"+
|
|
"&action=load-image-gallery"+
|
|
"&table_id=";
|
|
$.getJSON( "ajax.DataTable.Fetch.php",data,
|
|
function(results) {
|
|
$("#image-gallery-div").html(results.content);
|
|
}
|
|
);
|
|
}
|
|
|
|
});
|
|
</script>
|
|
|
|
<div id='image-gallery-dialog' title="<?php displayLanguageText('TEXT-IMAGE-GALLERY'); ?>">
|
|
<br>
|
|
<div id='image-gallery-div' style='height: 600px; overflow-y: auto'></div>
|
|
<br>
|
|
<center>
|
|
<button type='button' id='close-gallery' class='btn btn--outline btn--xsmall'><?php displayLanguageText('TEXT-CLOSE'); ?></button>
|
|
</center>
|
|
</div>
|
|
|