Jump to content

Module: RuntimeMarkup Fieldtype & Inputfield


kongondo

Recommended Posts

Thanks @adrian

@Robin S's module is simple and sweet. Sadly cannot use in FormBuilder as it has both the Inputfield class and the Fieldtype class within the FieldtypeRuntimeOnly.module file. FormBuilder looks for module files prefixed with 'Inputfield' in its list of approved input types.

I use @bernhard's module 'RockMarkup2' elsewhere in the project and only discovered that it's designed to only work in admin and it's been deprecated. However, just tried it in FormBuilder and it works a treat.

Maybe Robin and Bernhard can get together to come up with an easy to use module that has separate files for Fieldtype & Inputfield. That would be awesome! 

Link to comment
Share on other sites

Hey @psy I'd create a custom runtime module, it's not too hard:

1) Create the fieldtype:

2) Create the inputfield:

RockMarkup is deprecated because I don't plan to use it as base module for other Fieldtypes in the future. I think it makes things more complicated and that's not worth it. Building custom fieldtypes + inputfields is easy once you know how things work. Especially runtime fields are easy because you don't need all the DB related parts.

If you need any help just ask.

  • Like 2
Link to comment
Share on other sites

3 minutes ago, bernhard said:

I'd create a custom runtime module

Thanks @bernhard, after looking at your RockMarkup2 and Adrian's RuntimeOnly modules + your tutorials, am sure I could figure it out. For this project however, I'm under the gun with a rapidly approaching deadline. Will explore creating my own module when the pressure is off.

Link to comment
Share on other sites

@psy, in theory you don't need any sort of special module to put runtime markup into a field. Instead just add a Markup field to the form and then hook before the form is rendered to put whatever markup you want into it.

Having said that, there are some oddities with Markup fields in FormBuilder. I raised some questions that Ryan answered here: 

 

But I still had some other problems (I can't remember exactly what they were now) that I ended up resolving by making a clone of the core InputfieldMarkup module with some minor changes. I've attached the resulting InputfieldCustomMarkup module. If you install this module and enable it for use in FormBuilder then you can use it the same as a Markup field but without the snags.

InputfieldCustomMarkup.zip

  • Like 2
Link to comment
Share on other sites

@Robin S

Thank you! So many options and as said to Bernhard, will explore when I have time. Right now RockMarkup2 is doing the job with FB and elsewhere in the project.  Will replace when the pressure is off

Link to comment
Share on other sites

  • 1 month later...

Great module, but I'm having a couple of minor issues (unrelated, I think).

The first issue seems intermittent and I can't work out why In some cases, I can't get the inclusion of .js and .css to work. I've triple-checked all the naming etc. but the files just don't seem to load. My work-round (easy enough) is just to load the files in the php.

The second issue may be because I am stretching the fieldtype's capability! I am using it within a PageTable field as follows.

The PageTable field ("panelled_carousel") has a template "Panelled_carousel" which has fields "title", "imagePages" (a page reference field linking to a page with template "Image" and an image field "image_single") and "runtime_markup_images" (a runtime markup field with php file "RuntimeMarkup/Images.php").

The php file is (including a bit of debugging):

$imagePages = $page->imagePages;
bd($page, 'page with carousel');
$out = '';
wire()->log->save('debug', 'Page is ' . $page->title);
foreach ($imagePages as $imagePage) {
    bd($imagePage, 'imagePage');
    foreach ($imagePage->image_single as $image) {
        bd($image, 'image');
       if (is_a($image, '\ProcessWire\Pageimage')) $out .= '<img src="' . $image->pia("width=200")->url . '"/>';
    }
}
return  $out;

The RM field is updated when the imagePages field changes by javascript/AJAX :

When editing the Page Table field, this all works well - any changes in the imagePages (add/re-order/delete etc) are immediately reflected in the RM field. However, when saving the Page Table Field and returning to the host page, the RM PHP throws an error unless I catch it with the condition - is_a($image, '\ProcessWire\Pageimage') - in the code above. The reason is that in some cases $image seems to be taking a string, integer or boolean value, even though $imagePage has class Page and the dump shows it is the right page. Trapping this error means that the images in the table are all blank after the save. However refreshing the page puts everything right again. So not a deal-breaker but a bit odd.

To illustrate, here is the top page with the page table (including images):

1403291032_Toppage.thumb.jpg.ba0e32c4ea399931384b1e698af6fcad.jpg

Clicking on "Blue" to edit an item we get:

837229460_EditPageTableitem.thumb.jpg.41ff6cfec4e5f679cb7e63155d4e99f2.jpg

Then, clicking save and returning to the top page, the images do not render:

431478913_Aftersave.thumb.jpg.90ed19714a18bf1d45f8a1fa99e14c93.jpg

The debugging shows that this is not because Images.php has not run, but because $image is of the wrong type (as described above).

Refreshing the page restores the images.

Any ideas?

EDIT: I should add that the problem does not seem to be related to my .js script, or even RuntimeMarkup specifically as exactly the same issue happens in a Page Table with @Robin S's RuntimeOnly module with no js attached to it. So it seems to be something to do with how the runtime markup is interacting with the page table display.

Link to comment
Share on other sites

To make this work inside a page table, I had to hack the InputfieldPageTable.js as follows:

function InputfieldPageTableDialog() {

	var $a = $(this);
	var url = $a.attr('data-url');
	var title = $a.attr('data-title');
	var closeOnSave = true;
	var $container = $(this).parents('.InputfieldPageTableContainer');
	var wrap = $(this).closest('.InputfieldPageTable'); // MDE added
	var dialogPageID = 0;
	var noclose = parseInt($container.attr('data-noclose'));
	var modalSettings = {
		close: function(event, ui) {
			if(dialogPageID > 0) {
				var ajaxURL = $container.attr('data-url') + '&InputfieldPageTableAdd=' + dialogPageID;
				var sort = $container.siblings(".InputfieldPageTableSort").val();
				if(typeof sort != "undefined" && sort.length) ajaxURL += '&InputfieldPageTableSort=' + sort.replace(/\|/g, ',');
				$.get(ajaxURL, function(data) {
					$container.html(data);
					$container.find(".Inputfield").trigger('reloaded', ['InputfieldPageTable']);
					$container.effect('highlight', 500, function() {
						var $table = $container.find('table');
						$table.find('tbody').css('overflow', 'visible');
						InputfieldPageTableSortable($table);

						// restore appearnace of any items marked for deletion
						var deleteIDs = $container.siblings("input.InputfieldPageTableDelete").eq(0).val().split('|');
						if(deleteIDs.length) {
							for(var n = 0; n < deleteIDs.length; n++) {
								var deleteID = deleteIDs[n];
								$table.find("tr[data-id=" + deleteID + "]")
									.addClass('InputfieldPageTableDelete ui-state-error-text ui-state-disabled');
							}
						}
					});
				});
				if ($(wrap).attr('id')) $('#' + wrap.attr('id')).load(document.URL +  ' #' + wrap.attr('id')); // MDE added
			}
		}
	}
                                                                ....

The new lines are the ones annotated "MDE added"

I haven't found any unwanted side-effects (so far ..) but obviously I'm a bit unhappy about amending core code unless it warrants a PR, so I would be grateful for any thoughts on this, or other ideas.

Link to comment
Share on other sites

11 hours ago, MarkE said:

The debugging shows that this is not because Images.php has not run, but because $image is of the wrong type (as described above).

Refreshing the page restores the images.

Any ideas?

Sorry Mark, I got lost in that Green Bedroom. Man, I am dog tired and could do with that rest! ? 

OK, back to reality. I haven't used the Page Table field in ages. How does it save stuff? Via Ajax or normal POST? I am just wondering whether this has to do with renderReady() as I have had similar issues before with Media Manager and Repeaters. Currently,  I don't have time to test but hopefully can get to this soon.

I've just seen your edit: Ajax it is.

Edited by kongondo
Link to comment
Share on other sites

Putting this:

    $(document).on('pw-modal-closed', function(event) {
        var wrap = $(this).find('.InputfieldPageTable');
        if ($(wrap).attr('id')) $('#' + wrap.attr('id')).load(document.URL +  ' #' + wrap.attr('id'));
    });

in the admin js avoids the need to hack the InputfieldPageTable.js. Again, there may be side effects that I haven't noticed. One side-effect I have noticed is that, after closing the modal, the rows in the Page Table can no longer be sorted by dragging - a full window refresh is still required for that.

Link to comment
Share on other sites

Here's my complete work-round for the problem with runtime markup images in a Page Table field. Something that prevents the problem occurring in the first instance would be better though!

1. Add the following condition for images rendered in the runtime markup:

if (is_a($image, '\ProcessWire\Pageimage')) $out .= '<img src="' . $image->url . '"/>';

2. Add the following to admin.js (the 2 functions are lifted from InputfieldPageTable.js):

/*******************************************************************************************************************/
/* Work-round to reload and re-enable sorting of Page Table field, which includes runtime markup, after modal edit */
/*******************************************************************************************************************/
    $(document).on('pw-modal-closed', function(event) {
        var wrap = $(this).find('.InputfieldPageTable');
        if ($(wrap).attr('id')) $('#' + wrap.attr('id')).load(document.URL +  ' #' + wrap.attr('id') + '> *'); // To just load the inner html of wrap - avoiding duplicating it
    });

    $('.InputfieldPageTable').mouseenter(function () {
        if (!$('tbody').hasClass("ui-sortable")) {
            var $table = $('tbody').closest('table');
            InputfieldPageTableSortable($table);
        }
    });

    function InputfieldPageTableUpdate($table) {
        var value = '';
        if(!$table.is('tbody')) $table = $table.find('tbody');
        $table.find('tr').each(function() {
            var pageID = $(this).attr('data-id');
            if(value.length > 0) value += '|';
            value += pageID;
        });
        var $container = $table.parents('.InputfieldPageTableContainer');
        var $input = $container.siblings('.InputfieldPageTableSort');
        $input.val(value);
    }

    function InputfieldPageTableSortable($table) {

        $table.find('tbody').sortable({
            axis: 'y',
            start: function(event, ui) {
                var widths = [];
                var n = 0;
                $table.find('thead').find('th').each(function() {
                    widths[n] = $(this).width();
                    n++;
                });
                n = 0;
                ui.helper.find('td').each(function() {
                    $(this).attr('width', widths[n]);
                    n++;
                });
            },
            stop: function(event, ui) {
                InputfieldPageTableUpdate($(this));
            }
        });

    }

/*******************************************************************************************************************/

 

Link to comment
Share on other sites

12 hours ago, kongondo said:

Still not sure whether this is a RM issue or a PageTable one.

Nor me. It seems like PT calls the RM PHP file more than once. The first time it works properly with a Pageimage, but then later calls submit a string/integer/boolean. The code to bypass the latter has the side effect that the RM field now has nothing in it - hence the need for the reload. All pretty messy! I've tried various debugging routes, but can't work out how the multiple calls are happening.

Link to comment
Share on other sites

Hi Kongondo,

 

first of all many thanks for this useful module!

My question is about the behaviour of RM fields on save. Usually, we fill the RM fields with some static html markup. After saving pages with RM fields, these fields always are anounced as "changed", but why? Is is possible to prevent this?

 

Best regards,

Thomas.

  • Like 1
Link to comment
Share on other sites

Hi @xportde. I have noticed the same thing. I assume this is important to you because you have some hook or other that you only want to operate if fields have changed. What I do is simply catch and exclude any field changes that I'm not interested in. E.g. in a Pages::saved hook:

        $excludeFields = ['runtime_markup_parent', etc.......];
        $changes = array_diff($event->arguments(1), $excludeFields);

 

Link to comment
Share on other sites

6 hours ago, xportde said:

After saving pages with RM fields, these fields always are anounced as "changed", but why? I

Because I tend to be a silly billy often times ?.

It's happening because RM is not letting its parent class know that it is handling the processing of its WireInputData

6 hours ago, xportde said:

Is is possible to prevent this?

Yes, it is. I'll make the changes in the repo eventually, but meanwhile....please open up InputfieldRuntimeMarkup.module for editing. Scroll down to the end of the file. Find the method ___processInput() and un-comment it. The method's body is intentionally blank, so no changes needed there. Save :-). That should do it.

  • Like 1
Link to comment
Share on other sites

  • 2 months later...

Hi,

I tried your module but in the end went for @Robin S 's one. However when trying to uninstall the inputfield first, I had an error saying the class "RuntimeMarkupUtilities" did not exist. I just cut-pasted it from the fieldtype to the inputfield and all went good after that.

I don't know if it changes anything when using the module, but it might be worth to update the code to ease the uninstall process.

Link to comment
Share on other sites

2 minutes ago, monollonom said:

However when trying to uninstall the inputfield first, I had an error saying the class "RuntimeMarkupUtilities" did not exist.

Yes, it's a known issue that I've never gotten round to fixing (although several fixes exist, a number of posts in this thread). I'll get to it at some point. Sorry for the pain.

Link to comment
Share on other sites

  • 1 month later...
On 11/11/2020 at 9:08 AM, Orkun said:

I am using this field also inside the lister.

I can't remember if I ever tested this inside Lister but I doubt it will work. Lister retrieves values from the database. This field has no database table. I'll have a look if a workaround is possible but you might have to wait a long time. PRs welcome though :-).

Link to comment
Share on other sites

  • 6 months later...

Today I also got the class "RuntimeMarkupUtilities" does not exist error. (At a very harmless unexpected spot, when trying to edit a simple body textarea in a template: some local field settings).

I love the RuntimeMarkup Field, never had the problem with it before and did not want to give up easily. The only difference with my other PW installs: this PW install was brand new straight from the PW github beta repo and filled with a couple of modules, including this one. When started setting up my templates, I had activated the RuntimeMarkup Module for latter use already. But had not set up a RuntimeMarkup field yet.

Now the interesting part: As soon as I had my first RuntimeMarkup field set up (just with the default settings) the "RuntimeMarkupUtilities missing" error mentioned above was gone.

Maybe the observation gives you some indication about the possible nature of the bug. Maybe there is nothing wrong with the RuntimeMarkup module code, there might be just a timing problem, or the module is looking for a  class of some target code not running because not in use at that point. Just guessing.

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
×
×
  • Create New...