Leaderboard
Popular Content
Showing content with the highest reputation on 12/23/2022 in all areas
-
Merry Christmas, Happy Hanukkah, and Happy Holidays! The plan is to release a newyear main/master core version. I'm not currently aware of any showstopper issues specific to the current dev branch, but if you are aware of any, please report them in the GitHub issues repo (or reply to an existing issue report), as the dev branch will soon become the master branch. There's not yet a hard deadline, so whether it's end of December or the 1st week of January, we'll have a new release out shortly. The dev branch is very stable right now (likely more stable than the master branch) so it's a good time to get a new version out. I've also been holding off on several larger updates to the dev branch in anticipation of this merge to master and new release, so I've likewise been holding back on any commits that would add more to test. Once we get a new main/master release out there, the dev branch will then get InputfieldTinyMCE merged into it and there will be some JS library updates, along with other larger updates, and those that would need dev branch testing. Thanks for reading and I hope that you have a great holiday weekend and week ahead20 points
-
6 points
-
4 points
-
@szabesz I'm not sure I've got the ability to develop a code editor for TinyMCE. And I'm also not sure about how many people really need that, as isn't the the main benefit of a rich text editor to be able to not have to code the HTML? (though no doubt it's useful to resolve occasionally issues in the markup). But I do think it would be nice to have something more like Ace than something like Notepad, and the current editor source code popup is more like Notepad. Maybe a way to achieve that would be a toggle that would let you temporarily swap the Input type from TinyMCE to an Ace editor Inputfield or something, it does seem technically possible, though there's probably more to it than that, but interesting to consider.2 points
-
2 points
-
It's right here ? Anyway, glad the module is working for you! Let me know if you run into any more issues.1 point
-
Thanks @Robin S! That seems like a smart solution. I didn't know about renderReadyHook before.1 point
-
Whoops, my bad! I always default to the functions api because of the benefits laid our here https://processwire.com/docs/start/api-access/1 point
-
Yes. I realised after my last update that was probably the cause and that there is no delay in setting up. Maybe a small update to the module documentation? Anyway a really helpful module and very easy to install in Formbuilder. Thanks a lot!1 point
-
1 point
-
@Ivan Gretskywhat do you think about extending the InputfieldLeafletMapMarker with some address inputs and implementing a clean JS approach roughly following my example from above along with a clean UI? I'd be willing to contribute to this effort. EDIT: Oh and there is a custom fieldtype I once made that we could borrow some code from https://github.com/gebeer/FieldtypeAddressGeonames1 point
-
@Ivan Gretskygreat news. I contributed to the module many years ago with leaflet providers and marker cluster integration. It definitely needs some attention and love. Upgrading assets etc. I think that leaflet.js in general is still a viable solution for open source maps in general. Mapbox have changed their subscription model few years ago that is why I still prefer Leaflet over Mapbox. As for geocoding addresses this is still an issue with the open source provider that sits behind InputfieldLeafletMapMarker (Nominatim). They have improved a lot over time. But still failing on more exotic addresses where the Google Maps geocoder is doing a better job. There's quite a few open source geocoding services out there, but most of them use data from OSM's Nominatim. So you can't expect better results than you get with Nominatim. If looking for closed source geocoding APIs, one that might be worth looking into is https://positionstack.com/ . They have a free tier and seem to have a huge address pool. And I'd rather trust my data with an Austrian Company then sending it to Google. Just sayin... It could be used a s a fallback in case Nominatim returns garbage or nothing. It is not. At least with v3.0.3 of InputfieldLeafletMapMarker. You can make seperate inputfields that hold address data work together with the InputfieldLeafletMapMarker. I once wrote a module for a specific use case where I have 3 inputfields, address, postcode, city. The module loads some JS that first hides the default InputfieldLeafletMapMarker inputs, adds a button which takes the values from those fields, geocodes them through Nominatim, adjusts the marker on the map in the InputfieldLeafletMapMarker and fills the (now hidden) fields with the lat lng and name. Although I have done this about 4 years ago or so, it is still working. Here's the module code for reference in case anyone wants to go a similar route. Not a very clean and portable integration but it is doing the job and is here mainly to serve as an example how you could tackle this scenario. EDIT: short screencast to show UI AddressToMap.module.php (just loads the necessary JS) <?php use ProcessWire\HookEvent; class AddressToMap extends WireData implements Module { /** * getModuleInfo is a module required by all modules to tell ProcessWire about them * * @return array * */ public static function getModuleInfo() { return array( // The module'ss title, typically a little more descriptive than the class name 'title' => 'AddressToMap', // version number 'version' => 001, // summary is brief description of what this module is 'summary' => 'Geocode an Address and put a Pin on the Leaflet Map', // singular=true: indicates that only one instance of the module is allowed. // This is usually what you want for modules that attach hooks. 'singular' => true, // autoload=true: indicates the module should be started with ProcessWire. // This is necessary for any modules that attach runtime hooks, otherwise those // hooks won't get attached unless some other code calls the module on it's own. // Note that autoload modules are almost always also 'singular' (seen above). 'autoload' => "template=admin", // Optional font-awesome icon name, minus the 'fa-' part 'icon' => 'map', ); } public function init() { $this->wire->addHookAfter('ProcessPageEdit::loadPage', $this, 'loadAssets'); } public function loadAssets(Hookevent $event) { $id = $event->arguments(0); $page = $this->pages->get($id); if($page->template == 'member') { $this->config->scripts->add($this->config->urls->siteModules . $this->className . "/{$this->className}.js"); } } } AddressToMap.js var AddressToMap = { init: function () { // $(window).on('map:init', function (e) { // map = e.originalEvent.detail.map; // console.log(map); // }); var coder = window.L.Control.Geocoder.nominatim(); // console.log(AddressToMap.geocoder); var address = $('p.InputfieldLeafletMapMarkerAddress').css({ 'display': 'none' }); var setAddress = $('<p></p>').addClass('InputfieldLeafletMapMarkerSetAddress'); var button = $($.parseHTML("<button class='btn btn-primary btn-block' id='setAddress'><i class='fa fa-arrow-down fa-fw'></i>" + ProcessWire.config.strings.addresstomap + "<i class='fa fa-arrow-down fa-fw'></i></button>")); setAddress.append(button); setAddress.insertAfter(address); var inputfieldName = $('.Inputfield.InputfieldLeafletMapMarker').attr('id').replace('wrap_', ''); button.on('click', function (event) { event.preventDefault(); var combAddress = $('#Inputfield_address').val() + ', ' + $('#Inputfield_postcode').val() + ', ' + $('#Inputfield_city').val(); coder.geocode(combAddress, function (results) { if(results[0] !== undefined) { var map = window.leafletmap; map.eachLayer(function(layer){ if(layer.options.draggable === true) { var latlng = L.latLng(results[0].center.lat, results[0].center.lng); layer.setLatLng(latlng); $('#_' + inputfieldName + '_lat').val(results[0].center.lat); $('#_' + inputfieldName + '_lng').val(results[0].center.lng); $('input#' + inputfieldName).val(results[0].name); map.fitBounds(results[0].bbox); } }); } else { alert('Could not geocode this address'); } }); }); } } $(document).ready(function () { AddressToMap.init(); });1 point
-
For my approach you don't need full pagination, just one link to the next page, something like 'newspages/page2'. The JS plugin will take care of fetching that next page and then updating the link to read 'newspages/page3' etc. Look at my code sample how I build that initial link URL. I don't see anything messy about pagination links in general. But, like I said, you don't need them for my approach. What you describe is exactly what the infinitescroll plugin does, except for search/sort. You could implement that via a JS filter. But typically infinite scroll implementations do not need search/filtering. From a UX perspective that would be overkill. If you need search/filtering capabilities, infinite scroll might not be the best solution for your use case in the first place. Mind the link that @bernhardposted above. In my example approach search engines have a link to the next batch of posts and can index on from there. Recommended resources: https://processwire.com/docs/front-end/markup-pager-nav/ Yes. vistors without JS (search engine bots etc.) will not see any posts on initial page load client side scroll performance because of non-throttled $(window).scroll event listener. generally the applied scroll detecting technique seems outdated. https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API would be a better approach usability: no bowser history (back/forward) button jQuery dependency (not a real problem more a matter of preference) You still have not stated why you don't want to use plugins. I don't know if taking some seemingly outdated code to build upon is a good approach for a solution in 2023. No offence intended, just my opinion.1 point
-
@gebeer, the findReady method is working for me: $wire->addHookAfter('ProcessPageSearch::findReady', function(HookEvent $event) { $selector = $event->return; if($event->wire()->user->isSuperuser()) return; // If the selector looks like it comes from a particular autocomplete Page Reference field // (I wish this method provided a better way of working out where the selector is coming from) if(strpos($selector, 'parent_id=1329, templates_id=62,') === 0) { $selector .= ", include=all"; $event->return = $selector; } });1 point
-
Config() is your Problem ? (it’s only available when the functions api is activated) <?php echo $config->urls->httpRoot; ?>auction_longpolling.php1 point
-
@MarkEWere you viewing the form while logged in as superuser? Since version 2.0.0, the module comes with a permission to bypass hCaptcha. This permission also hides the widget from the frontend. The superuser skips all permission checks, so they never see the widget. Make sure to test the form in a private browser window where you're not logged in.1 point
-
Interesting read: https://www.nngroup.com/articles/infinite-scrolling-tips/1 point
-
Hey @Robin S thanks for your advice! I think you are right, it's not really possible to protect against a malicious superuser account (e.g. If it got hacked). Since the code is saved as a string anyway, I don't think it would cause harm, even if there would be php or javascript code in the field right? But I feel better to use the hook you mentioned. Here is the code, wich works nicely: public function __construct() { $this->addHookBefore('InputfieldTextarea::processInput', $this, 'sanitizeValue'); } public function sanitizeValue(HookEvent $event) { $input = $event->arguments(0); $input->customStyles = strip_tags($input->customStyles, ''); $event->arguments(0, $input); }1 point
-
We are working to fix exactly these issues. But it is slower than I imagined) Hope to get all this fixed some time soon, as we do need it. The Address field use here is different comparing to FieldtypeMapMarker. It is for storing the object address returned by geocoder, not for storing address data you enter. That's why I think it is better to have another field to store the actual address, and Leaflet Map to only set and store a point on the map. Maybe we could find a way to connect them via js, but now it is impossible. By the way, storing address in a a separate field is better for ML environment anyway.1 point
-
@eelkenet, cool that you were able to find a solution! Here's another way you could add disabled section items into the Page Reference AsmSelect using the PW API. It avoids getting each page individually in a loop so probably a bit more efficient. // Add dummy items to the selectable pages to act as section headings $wire->addHookAfter('InputfieldPage::getSelectablePages', function(HookEvent $event) { /** @var InputfieldPage $inputfield */ $inputfield = $event->object; $field = $inputfield->hasField; $selectable = $event->return; $t = null; $i = 1; if($field && $field->name === 'my_page_reference') { foreach($selectable as $p) { if($p->template->name !== $t) { $section = new NullPage(); $section->id = "section{$i}"; $section->title = mb_strtoupper($p->template->label) . ' ––––––––––––––––––––'; $selectable->insertBefore($section, $p); $t = $p->template->name; $i++; } } $event->return = $selectable; } }); // Set the dummy options to disabled $wire->addHookAfter('InputfieldAsmSelect::renderReadyHook', function(HookEvent $event) { /** @var InputfieldAsmSelect $inputfield */ $inputfield = $event->object; $field = $inputfield->hasField; if($field && $field->name === 'my_page_reference') { foreach($inputfield->options as $value => $label) { if(substr($value, 0, 7) === 'section') { $inputfield->addOptionAttributes($value, ['disabled' => 'disabled']); } } } });1 point
-
You could apply the purify sanitizer when the field value is saved by hooking InputfieldTextarea::processInput(). But looking at it another way, it isn't really possible to guard against a malicious superuser - they could destroy the site in any number of ways. Therefore you have to accept that superuser is a role for trusted users only.1 point
-
What about this: I (Stefanowitsch) will create a cronjob module that fetches new reviews maybe once a week so hat you don't need to do an API request every single time someone visits the page. ??1 point
-
@thetuningspoon magicpages are super cool ? the only drawback is that they come with a small performance penalty as I need to load all available templates once on init and then attach the hooks or magic methods on applicable templates: https://github.com/baumrock/RockMigrations/blob/87541c899901f773bf62068a639f070f48a85453/MagicPages.module.php#L43-L51 The init() and ready() method (and the magic methods) are only called once for every template because I create one runtime page for each template on ProcessWire::init The magic methods on the other hand only trigger for the correct pageclass because I have an early exit in the hook if the pageclass does not match: https://github.com/baumrock/RockMigrations/blob/87541c899901f773bf62068a639f070f48a85453/MagicPages.module.php#L113-L119 You might also like this:1 point
-
Just being able to specify styles right within settings is a monster feature alone. My goodness that is sweet. Thanks for your hard work on this. And the post is excellent. I love your clear and thorough writing.1 point