Jump to content

Speed up modal page editing by adding a "Save + Close" button, plus easily add custom CSS and JS to the PW admin


Robin S
 Share

Recommended Posts

I was browsing the requests repo and saw a request from @adrian that reminded me of a PW feature I had forgotten existed: from Page List you can open a page for editing in a modal window by long-clicking on the Edit button.

image.png.2ff0c169cea19a6918a1840f2e79406d.png

This is quite handy for when you want to make a quick edit to a page. But as the request notes, it would speed things up if there was a "Save + Close" button in the modal.

Until the request is actioned in the core I thought I'd try implementing it in some custom code, and it's also an opportunity to show an easy way you can add custom JS and CSS to the ProcessWire admin.

 

The first step is to create the following files at /site/templates/admin-assets/admin-custom.js and /site/templates/admin-assets/admin-custom.css. The CSS is optional.

admin-custom.js

$(document).ready(function() {

	const $body = $('body');
	const is_modal = $body.hasClass('modal') || $body.hasClass('pw-iframe');

	if($body.hasClass('ProcessPageEdit') && is_modal) {
		const params = new URLSearchParams(window.location.search);
		const $save_button = $('#submit_save');
		if(params.has('quick_edit') && $save_button.length) {
			$save_button.parent().append('<button type="submit" name="submit_save" value="Save" class="ui-button uk-hidden" id="save-and-close">Save + Close</button>');
		}
	}

	if($body.hasClass('ProcessPageList') && !is_modal) {
		$(document).on('ajaxComplete', function() {
			$('.PageListActionEdit a:not([data-autoclose])').each(function() {
				$(this).attr('data-autoclose', '#save-and-close').attr('href', $(this).attr('href') + '&quick_edit=1');
			});
		});
	}

});

admin-custom.css

/* Avoid Tracy debugbar appearing on top of modal */
.ui-widget-overlay.ui-front { z-index:40000; }
.ui-dialog { z-index:40001; }
/* Place modal buttons on the left rather than the right */
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float:none; }

 

The second step is to add the following hook to /site/ready.php

One good thing about using a hook to AdminTheme::getExtraMarkup to add custom CSS is that the file gets loaded after any CSS files that are loaded by modules or the PW core, so you can override any CSS rules without needing to add extra specificity.

// Add custom JS and CSS to admin
$wire->addHookAfter('AdminTheme::getExtraMarkup', function(HookEvent $event) {
	$parts = $event->return;
	$config = $event->wire()->config;

	// JS file should exist at /site/templates/admin-assets/admin-custom.js
	$js_url = $config->urls->templates . 'admin-assets/admin-custom.js';
	$modified = filemtime(rtrim($config->paths->root, '/') . $js_url);
	$parts['head'] .= "<script type='text/javascript' src='$js_url?m=$modified'></script>";

	// CSS file should exist at /site/templates/admin-assets/admin-custom.css
	$css_url = $config->urls->templates . 'admin-assets/admin-custom.css';
	$modified = filemtime(rtrim($config->paths->root, '/') . $css_url);
	$parts['head'] .= "<link rel='stylesheet' href='$css_url?m=$modified'>";

	$event->return = $parts;
});

 

The end result:

image.png.e908ad80ebc6dde46e525731cd584619.png

 

 

  • Like 12
Link to comment
Share on other sites

10 hours ago, Robin S said:

One good thing about using a hook to AdminTheme::getExtraMarkup to add custom CSS is that the file gets loaded after any CSS files that are loaded by modules or the PW core, so you can override any CSS rules without needing to add extra specificity.

This is pretty neat, thanks for sharing!

Until now I was adding these admin css tweaks through $config->styles in admin.php and thus I had a plethora of “!important” in my CSS...

  • Like 2
Link to comment
Share on other sites

Hey Robin! Thanks for this. I haven't had time to test this, but looking the code I see uk-hidden class on button. Would button even show? (and I know it's there for a reason)

  • Like 1
Link to comment
Share on other sites

3 hours ago, matjazp said:

looking the code I see uk-hidden class on button. Would button even show?

Yes, it does show, but only in the modal and not in Page Edit itself, which is the intention. The way that modal buttons work is that the modal script looks for buttons that are actually within the page that is being displayed in the modal iframe and then it constructs new buttons for the bottom of the modal. The newly constructed buttons don't carry over things like the uk-hidden class so they are not hidden.

But because the button I'm adding is actually within the Page Edit interface (right next to the normal Save button) I never want that button to be shown in normal page editing because "close" wouldn't make sense there. The check for is_modal should also prevent the Save + Close button being displayed when it isn't wanted so the uk-hidden is really just optional but it's a sort of "belt and suspenders" approach just to be on the safe side. 🙂

Link to comment
Share on other sites

Now that you explain it, I remember this behavior of modal.js. But, unfortunately, it doesn't work here, only the Save button is cloned. Looking at the modal.js line 417, $icontents.find(buttonSelector) only returns one button, not two as expected. It seems like the Save+Close button is added too late, after the modal has already cloned the Save button. While debugging, I added the button unconditionally and also removed the uk-hidden class, and then edited the page in a new tab with modal=1, and both buttons were there, as expected. But not in modal. I guess if I add the button directly to the ProcessPageEdit.module (or via hook), it would work. But it's working for you, so there must be something with my installation. It's a bit late here, so I'll continue testing tomorrow. 

Link to comment
Share on other sites

On 2/22/2024 at 10:48 AM, matjazp said:

It seems like the Save+Close button is added too late, after the modal has already cloned the Save button.

It's working reliably on a few sites I've tested on but what you're saying makes sense. So you could add the button with PHP in a hook and not in the JS as demonstrated below.

I also had a thought that Page Edit might be opened in a modal in some other circumstances (I think ListerPro has an option for this) where the "Save + Close" button wouldn't work or wouldn't be wanted. So I've updated the code in the first post and in the code below so that a "quick_edit" URL parameter is added for identification purposes.

admin-custom.js

$(document).ready(function() {

	const $body = $('body');
	const is_modal = $body.hasClass('modal') || $body.hasClass('pw-iframe');

	if($body.hasClass('ProcessPageList') && !is_modal) {
		$(document).on('ajaxComplete', function() {
			$('.PageListActionEdit a:not([data-autoclose])').each(function() {
				$(this).attr('data-autoclose', '#save-and-close').attr('href', $(this).attr('href') + '&quick_edit=1');
			});
		});
	}

});

Additional hook for /site/ready.php

$wire->addHookAfter('ProcessPageEdit::buildForm', function(HookEvent $event) {
	/* @var InputfieldWrapper $form */
	$form = $event->return;
	// Return if Page Edit is not in a modal window
	if(!$event->wire()->config->modal) return;
	// Return if quick_edit GET parameter is not present
	if(!$this->wire()->input->get('quick_edit')) return;

	$save_button = $form->getChildByName('submit_save');
	if(!$save_button) return;
	/** @var InputfieldSubmit $f */
	$f = $event->wire()->modules->get('InputfieldSubmit');
	$f->id = 'save-and-close';
	$f->name = 'submit_save';
	$f->value = 'Save';
	$f->text = 'Save + Close';
	$f->addClass('uk-hidden', 'wrapClass');
	$form->insertAfter($f, $save_button);
});

 

  • Like 1
Link to comment
Share on other sites

Thx Robin! While the Save + Close button is there (as expected), the js part makes the edit links all open home page, eg. they all have the link /processwire/page/edit/?id=1&quick_edit=1 I fixed that with:

const $links = $('.PageListActionEdit a:not([data-autoclose])');
$links.each(function() {
    $link = $(this);
    $link.attr('data-autoclose', '#save-and-close').attr('href', $link.attr('href') + '&quick_edit=1');
});

Just to mention that using uk-hidden class (as a "belt and suspender" approach) would only work in AdminThemeUIkit, leaving out newer (and older) admin themes.

  • Like 3
Link to comment
Share on other sites

5 hours ago, matjazp said:

While the Save + Close button is there (as expected), the js part makes the edit links all open home page,

Oh, good spotting, thanks! I updated my earlier posts.

  • Like 1
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...