Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 04/12/2020 in all areas

  1. @MarkE - there might be other ways, but what I do is use AOS's ability to add JS to the admin and use this: .cke_combopanel__hannadropdown { width:400px !important; min-height: 250px !important; }
    2 points
  2. Hey Ryan — just wanted to say thanks. Assuming that I've got this right and this could mean that eventually ProcessWire can natively (or at least with a module that doesn't have to rely on any weird tricks) support something like S3 or Google Cloud Storage, this is a brilliant move! Very much looking forward to that. Thanks again, and keep up the great work ?
    2 points
  3. Updated version here - works with more field types - just make sure you have at least 3.0.148 if you want to use it with autocomplete /* Script to refresh a form content when an element gets changed To work across all admin pages, this script needs to be loaded in admin.php – add the line $config->scripts->add($config->urls->templates . "scripts/form-update.js"); before the final require in templates/admin.php. Typical use is to modify other elements based on a select drop-down change The trigger element can have the following data attributes assigned to it (typically set these with $myInputfield->attr() in a module or hook): * data-action="form-update" : Required to run the script. * data-update-target="#myid1" : Required - the element to change. Note that this should not be the whole form, otherwise .find(target) will not find it. * data-confirm="Some confirmation text": Optional - if you want to show a confirmation before the update, this holds the text to display. If absent, there will be no confirmation dialogue. If the user chooses ‘cancel’, the script will revert the change and terminate. * data-alert="Some alert text": Optional – if you want to warn the user that the update cannot happen for some reason (the script will then revert the change and terminate). * data-cache="#myid2" : Optional - if you want to cache the (changed) value, this element stores it. * data-cache-prefix="Some prefix string" : Optional (requires data-cache) - a prefix to prepend the value stored in the cache This currently works with the following trigger elements: * select options * select page (single and multiple) * page list select (single and multiple) * asm select * page autocomplete (but note that data attributes must be set in the wrapper element - e.g. $myInputfield->wrapAttr() ) Note also that autocomplete only works fully with the latest master 3.0.148 * checkboxes (set attributes in wrapper as above) * checkbox (set attributes in wrapper as above; also, if you need to set or get the value (0 or 1) you may need to use getParent() ) * toggle (but only with 0,1 formatting and 'select' input type; plus see the comments for checkbox above) but not with: * toggle other than as described above * radio buttons NOTE: If you are using this with other js scripts (e.g. in a module) that listen for events in the target, you must use event delegation (e.g. $(document).on("change","#myid", function(){}); NOT $("#myid").onchange(function(){}); ) because #myid is dynamic if it is inside the target) */ $(document).on('change focusin', '[data-action="form-update"]', formUpdate); // need 'change' to catch normal select fields and 'mouseenter' for others function formUpdate(event) { console.log("event type = " + event.type); value = inputVal(this); if (event.type != 'change') { // if the input has not changed, just get the value now so that we can revert if necessary when it is changed console.log("Saving prev value " + value); $(this).data('prevVal', value); return; } console.log("Saving current value " + value); $(this).data('currVal', value); var prev = $(this).data('prevVal'); var current = $(this).data('currVal'); console.log("Prev value " + prev); console.log("New value " + current); // if trigger element has data-confirm attribute, confirm or revert and exit var confirmText = $(this).data('confirm'); if (confirmText) { if (!confirm(confirmText)) { $(this).val(inputVal(this, prev)); return; } } // if trigger element has data-alert attribute, show alert and exit var alertText = $(this).data('alert'); if (alertText) { alert(alertText); $(this).val(inputVal(this, prev)); return; } // cache the value before proceeding (if data-cache set) var cache = $(this).data('cache'); var cachePrefix = ($(this).data('cache-prefix')) ? $(this).data('cache-prefix') : ''; $(cache).val(cachePrefix + current); var $form = $(this).closest('form'); var target = $(this).data('update-target'); console.log("Target is " + target); var method = $form.attr('method'); var action = $form.attr('action'); var data = $form.serialize(); var encodedName; // .serialize() will omit select elements that do not have a 'null' option (e.g. asm select, page list select) // or checkboxes with nothing selected // so find them and add empty parameters to the data string, otherwise the page field will not be updated $($form.find('select, input').each(function(index){ console.log('Select element no. ' + index + ' with name ' + $(this).attr("name") + ' has serialize = ' + $(this).serialize()); encodedName = encodeURI($(this).attr("name")); if (data.search(encodedName) === -1) { data += ('&' + encodeURI($(this).attr("name")) + '='); } })); console.log("Submitted data: " + data); if (!method) method = 'get'; if (!action) action = window.location.href; // If you want to fade the affected inputfields then assign the loading class to their wrappers with method wrapClass(loading) $(target).find('.loading').css({ display: 'block', opacity: 0.2 }).animate({ opacity: 1 }, 5000); // then send your request $.ajax(action, { type: method, // type used, not method, for older versions of jquery data: data, // you can also add an error handler here if required, in case the server returns an error on the request success: function (data) { // Initial ajax just returns an array with message. Need to GET the form data. $.ajax(window.location.href, { type: 'GET', cache: false, success: function (data) { // then just take the target, and replace it with the target div from the returned data $(target).html($(data).find(target).html()); console.log("Returned data: " + data); console.log("Updating html with: " + $(data).find(target).html()); } }); } }); } function inputVal(el, val=null) { var value = $(el).val(); var inputfield = $(el); if ($(el).hasClass('InputfieldCheckbox')) { console.log("checkbox"); inputfield = $(el).find("input[type='checkbox'], input[type='radio']").first(); if (val === 1) { $(inputfield).attr('checked', 'checked'); } else if (val === 0) { $(inputfield).removeAttr('checked'); } value = ($(inputfield).attr('checked') === 'checked') ? 1 : 0; } else if ($(el).hasClass('InputfieldToggle')) { console.log("toggle"); inputfield = $(el).find("option[selected='selected']").first(); if (val === '1') { $(inputfield).attr('selected', 'selected'); } else if (val === '0') { $(inputfield).removeAttr('selected'); } value = ($(inputfield).attr('selected') === 'selected') ? '1' : '0'; } else if ($(el).hasClass('InputfieldPage') && $(el).find(".InputfieldPageAutocompleteData")) { console.log("page autocomplete"); inputfield = $(el).find(".InputfieldPageAutocompleteData").first(); value = $(inputfield).val(); } else { console.log("other selector type"); if (val) { $(el).val(val); } value = $(el).val(); } console.log("returning value = " + value); return value; }
    2 points
  4. Please note that the updated version of this script and any other associated info is now at https://github.com/MetaTunes/Form-update I had a need to interactively update the page choices in a multi-choice page select field. I chose to do this with a general-purpose piece of jQuery. By combining it with a InputfieldPage::getSelectablePages hook, you can get the trigger field to alter the selectable pages interactively. I have also found this to be useful in a number of other situations - e.g. updating a RuntimeMarkup field for changes on a page. There may be more elegant ways of achieving this (I'm open to suggestions), but in case it is useful to others, I'll post it here. Hopefully the comments in the script are self-explanatory and describe how to use it. Note that there are several console.log statements to help with debugging, which you can remove once happy with its operation. Happy to answer any questions (if I can ? ). Also, if anyone can explain how to get it working fully with checbox/toggle ad radio buttons, I would be grateful. /* Script to refresh a form content when an element gets changed To work across all admin pages, this script needs to be loaded in admin.php – add the line $config->scripts->add($config->urls->templates . "scripts/form-update.js"); before the final require in templates/admin.php. Typical use is to modify other elements based on a select drop-down change The trigger element can have the following data attributes assigned to it (typically set these with $myInputfield->attr() in a module or hook): * data-action="form-update" : Required to run the script. * data-update-target="#myid1" : Required - the element to change. Note that this should not be the whole form, otherwise .find(target) will not find it. * data-confirm="Some confirmation text": Optional - if you want to show a confirmation before the update, this holds the text to display. If absent, there will be no confirmation dialogue. If the user chooses ‘cancel’, the script will revert the change and terminate. * data-alert="Some alert text": Optional – if you want to warn the user that the update cannot happen for some reason (the script will then revert the change and terminate). * data-cache="#myid2" : Optional - if you want to cache the (changed) value, this element stores it. * data-cache-prefix="Some prefix string" : Optional (requires data-cache) - a prefix to prepend the value stored in the cache This currently works with the following trigger elements: * select options * select page (single and multiple) * page list select (single and multiple) * asm select * page autocomplete (but note that data attributes must be set in the wrapper element - e.g. $myInputfield->wrapAttr() ) * checkboxes (set attributes in wrapper as above) but not with: * toggle * checkbox * radio buttons (These partly work - the attributes need to be in the wrapper -, but doesn't work completely as wrapper 'value' attribute is not updated by PW (always 0) ) NOTE: If you are using this with other js scripts (e.g. in a module) that listen for events in the target, you must use event delegation (e.g. $(document).on("change","#myid", function(){}); NOT $("#myid").onchange(function(){}); ) because #myid is dynamic if it is inside the target) */ $(document).on('focusin', '[data-action="form-update"]', function(){ // get the value before the element is changed console.log("Saving value " + $(this).val()); $(this).data('val', $(this).val()); }).on('change','[data-action="form-update"]', function(event){ var prev = $(this).data('val'); var current = $(this).val(); console.log("Prev value " + prev); console.log("New value " + current); // if trigger element has data-confirm attribute, confirm or revert and exit var confirmText = $(this).data('confirm'); if (confirmText) { if (!confirm(confirmText)) { $(this).val(prev); return; } } // if trigger element has data-alert attribute, show alert and exit var alertText = $(this).data('alert'); if (alertText) { alert(alertText); $(this).val(prev); return; } // cache the value before proceeding (if data-cache set) var cache = $(this).data('cache'); var cachePrefix = ($(this).data('cache-prefix')) ? $(this).data('cache-prefix') : ''; $(cache).val(cachePrefix + current); var $form = $(this).closest('form'); var target = $(this).data('update-target'); console.log("Target is " + target); var method = $form.attr('method'); var action = $form.attr('action'); var data = $form.serialize(); var encodedName; // .serialize() will omit select elements that do not have a 'null' option (e.g. asm select, page list select) // or checkboxes with nothing selected // so find them and add empty parameters to the data string, otherwise the page field will not be updated $($form.find('select, input').each(function(index){ console.log('Select element no. ' + index + ' with name ' + $(this).attr("name") + ' has serialize = ' + $(this).serialize()); encodedName = encodeURI($(this).attr("name")) if (data.search(encodedName) === -1) { data += ('&' + encodeURI($(this).attr("name")) + '='); } })); console.log("Submitted data: " + data); if (!method) method = 'get'; if (!action) action = window.location.href; // If you want to fade the affected inputfields then assign the loading class to their wrappers with method wrapClass(loading) $(target).find('.loading').css({ display: 'block', opacity: 0.2 }).animate({ opacity: 1 }, 5000); // then send your request $.ajax(action, { type: method, // type used, not method, for older versions of jquery data: data, // you can also add an error handler here if required, in case the server returns an error on the request success: function (data) { // Initial ajax just returns an array with message. Need to GET the form data. $.ajax(window.location.href, { type: 'GET', cache: false, success: function (data) { // then just take the target, and replace it with the target div from the returned data console.log("Returned data: " + data); console.log("Updating html with: " + $(data).find(target).html()); $(target).html($(data).find(target).html()); } }); } }); });
    1 point
  5. Your code as well as eelkenet’s should work if you set output formatting to false at the top instead of at the bottom. AFAIK, without output formatting, File fields always return a WireArray, or rather, a Pagefiles array, which inherits from WireArray. In general the reason you disable output formatting is that you can work with the “raw” data before saving. Changing the formatted data and then only disabling output formatting before the save() should be pointless and/or introduce errors. For example, if you have a field with Markdown formatting and you modify its contents without disabling output formatting, you’re modifying and saving the rendered HTML, destroying your original Markdown markup.
    1 point
  6. Sorry for not looking in here. I replaced the code as recommended by @Robin S without further testing and hope it works well now. I didn't use the module by myself for a long time. Stay healthy!
    1 point
  7. Tbh, I find this whole “virtual field” business somewhat unfortunate… The announcement of custom image fields filled me with joy, and I thought the idea of using templates seemed pretty ingenious (although I don’t like how it introduces magic strings into template names, and generally restricts their naming, and doesn’t allow multiple image fields to share a template. Feels icky to me. Why not have a template selector in the field settings?). However, I was disappointed to find that values are just serialized and dumped into the image-field table. Seems like this data is treated as some kind of second-class citizen. If the custom fields were stored in their own database columns, as suggested by using templates and fields, it would have been a trivial INSERT to migrate from the ImageExtra module. Now I needed to use the PW API to move values from one field to the next, which involves all kinds of voodoo behind the scenes. Wouldn’t it be much less work to just store a page reference with each image and have the custom image fields stored in their respective field-tables? Surely that way it would be easier to make everything play nicely with selectors and everything? Of course, I have to admit I don’t have a lot of MySQL experience. Maybe there are easy and performant and reliable ways to query serialized fields like this and I just need to read up a little ?
    1 point
  8. Hello, I've updated my polish language pacakge for ProcessWire 3.x to be fully compatibile with the latest master version - 3.0.148 In this update: - added all missing translations for a new features, - removed translation strings marked as abandoned - few small corrections for typos download at: http://modules.processwire.com/modules/polski/ or: https://github.com/sevenstudio/polish-wire/archive/1.0.7.zip
    1 point
  9. @jonassalen, open the ProcessSetupPageName.module file in your code editor and try replacing this section at the top of the createFromFormat() method... if ($languageID == null && $this->languageSupport == true) $languageID = $this->wire('languages')->getDefault()->id; $langID = $this->wire('languages')->get($languageID)->isDefault()? null : $languageID; if ($this->languageSupport) { $userLang = $this->wire('user')->language; $this->wire('user')->language = $this->wire('languages')->get($languageID); } ...with... $langID = null; if ($this->languageSupport) { if ($languageID == null) $languageID = $this->wire('languages')->getDefault()->id; $langID = $this->wire('languages')->get($languageID)->isDefault()? null : $languageID; $userLang = $this->wire('user')->language; $this->wire('user')->language = $this->wire('languages')->get($languageID); }
    1 point
  10. Just looked at this issue recently. This seems to do the job: $this->addHookAfter('FieldtypeRepeater::wakeupValue', function($event) { $field = $event->arguments('field'); // Only for a particular repeater field // Could also use page argument for other tests if($field->name !== 'my_repeater') return; $pa = $event->return; $pa->sort("-created"); // or whatever sort you want $event->return = $pa; });
    1 point
×
×
  • Create New...