-
Posts
6,670 -
Joined
-
Last visited
-
Days Won
366
Everything posted by bernhard
-
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Good point, guess I was just too lazy π Definitely better, thx! -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
There you can input 1,2,3 for "every 1st monday". Thx for the question, I added this: With that ui really complex rules are possible and imho quite easy to understand: -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Very well done! Looks great. What does it show if "every 1 day" is selected? I also thought of hiding those settings based on the frequency dropdown, but I realised that they can be used in a combined way as I showed above. Not sure what to do about this. Sometimes it might be preferable to have more options, sometimes it might be better to have a slicker ui... -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Thx @szabesz I've corrected this! Now it is in sync with the resulting rrule text π @monollonom the interface is nice, but also limited as far as I can see? Would the rule shown in the screenshot above be at all possible in your UI? Or what did you want to say with your post? -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
I removed the header in simple mode to be even more compact: In advanced mode the header will be shown: -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Thx. I changed the default pagination size to 5 instead of 10 which makes the grid almost half the vertical size: If anybody needs to see more events the pagination size can be changed via dropdown. I think completely hiding it is not a good idea, because the live preview is important to double check the result of the rrule that is setup above. For example it's easy to forget to change from "every day" to "every week" and with the live preview one can instantly see that, because days will be mo, tu, we, th, fr... instead of mo, mo, mo, mo... -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Cool, thx π Thx a lot. Always appreciated! Actually it's the other way round. I think I can just remove the warning π -
Hey @gebeer thx for choosing RockPdf and thx for the great write up π I agree with @gmclelland that the pdfs look very good! π I'm wondering why you have append = true here? Some background for anybody interested: This flag is intended for multi-language use, where you might want to create multiple versions of one pdf (english, german, etc.). Using this flag you can foreach over all languages and then create the PDF in that language and append it to the file field in question π Maybe that's why you are using it? Then this background info might be worth to mention π This is a real gem! For anybody not aware of this see https://www.baumrock.com/en/processwire/modules/rockfrontend/docs/dom/
-
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
This is a demo of how to use the new trash feature π And this is a demo of how to create a quite complex custom recurring schedule: I think this should already be quite usable! -
Done! Here is the link for everybody to submit a review π https://www.softaculous.com/review/ProcessWire If you are short on time: https://www.softaculous.com/rate/ProcessWire Both without registration!
-
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Exactly. That's one of the advantages of this concept π The UI is the tricky part... Yeah a draft is already there π But there is more to it to cover all options. That's the next part to tackle π€ -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
It will be a standalone module, but for the recurring events part you will need the "RockGrid" module. Other than that there will be no dependencies, no RockMigrations, no RockFrontend. -
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
Thx @erikvanberkum! Don't see the need to replace cal.com as it is free and works very well and has lots of options that I'd have to rebuild. RockCalendar will not handle timezones on its own. It will always store UTC dates in the database. If you need to support timezones than you can do so, but you have to implement that on your own. That should not be a big deal, as the part on how you present all dates to public users will be up to you anyhow. So in my case I manage events for a cave. They have a schedule with several dates for guided tours. For example on Saturdays at 14:00 from May to end of October. When testing this use case I realized that after passing the daylight saving change date all following events where @ 15:00 instead of 14:00 (or 13:00 instead of 14:00 I can't remember). To prevent this I let fullcalendar think that all entered dates are actually UTC dates. UTC does not have daylight saving so whenever anyone enters 14:00 it get's displayed as 14:00; That's it and that's how fullcalendar handles timezones itself, as far as I understood: https://fullcalendar.io/docs/timeZone When presenting those dates to users I will ignore that fact that dates are technically UTC dates and just present them as they are. That means that when anybody is browsing through the calendar he/she will see all tours starting @ 14:00 and he/she will expect that to be a local time, which is the case even though the date is technically stored as UTC. If I did that differently the user would see 13:00 as start date for events until October and 14:00 for events after 1st of October (or something like that, don't know when the actual change happens as my smartphone will do the switch for me π ). This works for all websites presenting dates to local customers in one single timezone. 2 things to mention here: If anybody from another timezone was going to edit an event in the backend, he/she would still see 14:00 as time, which might be totally off his/her local time but will be correct for the local timezone of the location the event takes place. If the website presented events to users from different timezones the conversions would have to be done by the developer of the frontend. I think this should be quite easy though. Maybe we'd need to add a setting to the module in which timezone all dates are stored so that the frontend knows how to convert them to local times. Maybe it would need some modifications to the module. We'll see. If anybody knows that already please let me know. The plan is to handle all that by the single DaterangePicker field. So no need to setup any new templates. No need to setup anything else. No need to construct any complicated selectors. Just add the daterange field to your event template and that's it. And to query events it will be "template=event,daterange.inMonth=2024-08" or similar and you'll get all events including all recurrences. I use a hook to only show the daterange field of recurring events and hide everything else as everything else will be inherited from the main event. That means all occurrences are of the same type and have the same fields etc. just only the main event has all the fields populated. I'm working on that. It's not that hard, the only annoying thing is that I need to support both the calendar UI and the use case when someone edits events via the page tree. Both should be possible imho and unfortunately as it means more work. Yes. I thought of adding another grid that lists already created events that are part of the series, but not sure if that's good or not. Actually I have an idea that might also solve the problem mentioned above... I'll have to try this today or tomorrow! Generally speaking I'll add a switch that lets the user choose from edit this event edit this and all following edit all events But it's not so easy unfortunately as that could mean we need to update 1000s of pages and therefore I'll need a gui with a progressbar again... That's why I think it will be necessary to add a second grid to the daterange field. It adds bloat to the UI but the other option would be to save the job in the background and process it via cronjob, but that means a more complicated setup and no instant feedback to the user. I think a second table is the better and more flexible option. Yeah me too, thx π It's actually really easy. Just a Page::loaded hook protected function inheritFieldValues(HookEvent $event): void { /** @var Page $page */ $page = $event->object; if (!$page->hasField(self::field_date)) return; $date = $page->getFormatted(self::field_date); if (!$date->isRecurring) return; $mainPage = $date->mainPage; if (!$mainPage->id) return; foreach ($mainPage->fields as $f) { if ($f->name == self::field_date) continue; $page->set($f->name, $mainPage->get($f->name)); } } There are some downsides with this again, but that's only an issue for advanced calendars and should be no issue for 99,9% of use cases. Thx for the great use case!! This can quite easily be accomplished with how I developed the module. It would need some modifications but nothing complex I think. My idea would be to have one global description and then have an additional field that is explicitly not inherited. So the main description could show something like this: So every event would show the general info and then merge the individual book info. If the book-info is edited it only affects one event. If the general info is edited it would update all events (as it is inherited). The problem here is scalability. What if a user wants to create 1000 recurring events? Or maybe only 100. How would you do that? One option is to do that in the background. That means a possibly veeeeeery long loading time after save. Or maybe even a timeout. Or maybe the user hitting refresh several times and creating too much events or crashing the server or whatnot. The other option is a background job. Also with downsides as mentioned above. I think the preview table is the most intuitive and flexible solution. But if you have better ideas go ahead π -
@FireWire glad you found the issue. Could you please open a new thread for this and explain the benefits of filesystem cache and how you are using it? Then we can discuss there in an isolated environment which makes it easier to reply, link, refer to... Please also explain your use case as I've never used filesystem cache.
-
One idea to solve this in a quite easy way: Add a hidden field to your template called "quantity_before_edit" Add a saveReady hook that calculates the difference between "quantity_before_edit" and "quantity" Use that delta to calculate the new "quantity" Example: Quantity is 10 User A visits the public website (quantity = 10) User B visits the backend (quantity = 10, quantity_before_edit = 10) User A orders 2 pieces and the page gets saved (quantity = 8 ) User B saves the page without editing the quantity (quantity = 10, quantity_before_edit = 10) saveReady hook kicks in: quantity = 10, quantity_before_edit = 10 ---> diff = 0 get current quantity from uncached page from the database, quantity = 8 add diff and write result to $page->quantity = 8 ideally show a warning to the user that a quantity has been saved that is different from his/her input page is saved, final result is quantity = 8
-
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
First milestone reached!!! ππ Yesterday I spent the whole day with refactoring the JS of the rrule gui and I added some more options to cover hopefully 99.9 of all necessary scenarios. The gui now has a toggle to switch between simple and advanced mode to keep things as clean as possible and not overwhelm the users for simple rrules like "every week for 4 times". At the moment 80 hours have gone into this module (excluding the daterange input, which was already done some time ago). πͺπ€― Here my answers to the open questions: I don't think there is an ideal solution to this problem. I even found a bug in google calendar when comparing and playing around!!! I decided against a fake "never" option, as it does something different than what the UI shows. So in my case if the user does not enter an end date or a max number of events it get's limited to 100. This limit is configurable in the module's settings, though π I've also added the dates of the first and last event beside the resulting rrule to make it clear what is going to happen. Additionally the user will get a table of all events that will be created. Sometimes - but not always! rrules are tricky π - the first occurrence is the main event itself. In that case the table shows a hopefully clear indicator: Yes and no, I'm using a mix to somehow get the best of both worlds. I'm creating real pages for the events, but I'm only populating the date field. All other fields (like shown with the title in the video) will be inherited from the main event at runtime. This makes it possible to have complex event descriptions (like one built with RockPageBuilder) with images etc. and when creating 1000 recurring events it will still only consume the space of one event + 1000 date inputs (but not 1000 copies of images). I hope the video answers that? π -
Single page select value type: which do you prefer?
bernhard replied to Jonathan Lahijani's topic in General Support
As @teppo mentioned in the issue this is possible to do this and I think this is the most robust way of writing code for page reference fields that work consistently and are not going to break if someone changes field formatting: foreach($page->get('my_pageref_field[]') as $p) ... if($page->get('my_pageref_field.first')) ... -
Ok got it working! I think that's quite cool and has a lot of potential. Does that code example make sense @poljpocket ? class HelloWorld { ___greet(salut = "hello", what = "world") { return `${salut} ${what}`; } } const helloWorld = ProcessWire.wire(new HelloWorld()); // shows hello world console.log(helloWorld.greet()); // shows hi there console.log(helloWorld.greet("hi", "there")); // add BEFORE hook ProcessWire.addHookBefore("HelloWorld::greet", (event) => { event.arguments(0, "hallo"); event.arguments(1, "welt"); }); // shows hallo welt console.log(helloWorld.greet()); // shows hallo welt console.log(helloWorld.greet("servas", "oida")); // add AFTER hook ProcessWire.addHookAfter("HelloWorld::greet", (event) => { console.log(event.arguments()); event.return = "hi universe"; }); // shows ['hallo', 'welt'] // shows hi universe console.log(helloWorld.greet()); And another one showing hook priority: class PrioDemo { ___greet() { return "hello world"; } } const prio = ProcessWire.wire(new PrioDemo()); ProcessWire.addHookAfter( "PrioDemo::greet", () => { console.log("second"); }, 20 ); ProcessWire.addHookAfter( "PrioDemo::greet", () => { console.log("first"); }, 10 ); ProcessWire.addHookAfter( "PrioDemo::greet", () => { console.log("third"); }, 30 ); // shows // first // second // third // hello world console.log(prio.greet());
-
Haha you don't have to. I appreciate the input and questions. It shows I have to be more careful with the explanations. The terms "frontend" and "backend" are very confusing in that context as they refer to two things. Backend could either be the pw admin area or the server implementation, in our case php. Frontend could be the websites public frontend or it could be the JS implementation on the frontend (public website) or the backend (pw admin). I try to be more careful with the wording in my explanations once I have something working. At the moment I'm fighting with modifying arguments from within the addHookBefore...
-
Didn't feel like that, just thought you misunderstood the request from what you wrote. It's really not about the backend. It has nothing to do with the backend. That's why I still don't understand your answers and your example using fetch() as that's a totally different story. My "sold out" wording was misleading in that regard, I'll edit that to avoid future confusion, thx. Nothing. It really doesn't matter. It's absolutely not related to the backend at all. It's just about having the convenience and power of applying the same concept that we have in the backend for stuff on the JS side (most likely the pw admin area). You mean customization via dom element attributes? That might work for their use case but is something very different than what I propose. A very powerful concept of hooks are before hooks with event.replace = true. I don't think that is possible with the snipcart way. But I might be wrong. Admittedly I took just a quick look π (edit: need a real world example why before hooks are super useful? see here) As an example where dom-attributes make absolutely no sense or are totally limited: My module RockGrid uses tabulator.info to render tables. Rows are basically PW pages. So the backend only provides the endpoint to get a json with page objects aka table rows. Everything else happens on the frontend and from within JS. I only have a single dom element <div id='RockGrid-123'></div> With hooks my clients could modify any part of the grid just by hooking into the relevant method. A lot can be done with callbacks and tabulator has an internal event bus that can be used for that, but I think hooks are a lot more powerful and feel a lot more familiar when you know pw well. I might come up with better examples. Thx for your input.
-
Emptying / resetting all fields for a recently cloned page?
bernhard replied to theoretic's topic in General Support
Good point. I think you could hook BEFORE Pages::clone and do exactly that instead of instructing the users to so manually. Note that you need the $event->replace = true; flag so that the original clone process does not kick in after your new page has been created. Something like this (untested): <?php $wire->addHookBefore('Pages::clone', function($event) { $page = $event->arguments('page'); if($page->template != 'your-template') return; $p = new Page(); $p->template = $page->template; $p->parent = $page->parent; $p->title = $page->title; $p->save(); $event->replace = true; // should not be necessary but just to be sure wire()->session->redirect($p->editUrl()); }); Of course that would mean that any clone would wipe all data. But you could add a checkbox to that page that disables the hook and therefore would work as a normal clone. -
@poljpocket thx for your question. It sounds like you totally misunderstood the idea of my proposal, so maybe the explanation was not good. I'll try it in other words: Imagine you are building a module that stores monetary values in the database. They are stored as numbers (eg "123.45") in the db, but you likely want to present them to the user in a different way. Now there could be hundreds of different formats the enduser might want to see and that would mean a lot of options for you as the module developer to support. In RockCommerce for example I need the flexibility to modify prices based on the users need (eg customers/website visitors could see different prices based on their region and tax settings. See https://www.hetzner.com/storage/storage-box/ for example where you can choose the tax setting in the header and then you get different prices. My proposal is to bring hooks to the JS world of ProcessWire as well, as we all know how powerful and useful these hooks can be! In the example you as a module dev would only have to implement a hookable "___format()" method instead of the "format()" method without underscores and you'd only have to instantiate the class via ProcessWire.proxy(...): class MyMoneyModule { ___format(num) { return "β¬ " + num; } } let demo = ProcessWire.proxy(new MyMoneyModule()); // this will output β¬ 123.45 console.log(demo.format(123.45)); ProcessWire.addHookAfter("MyMoneyModule::format", (event) => { event.return = "Hooked format: " + event.return; }); // this will output "Hooked format: β¬ 123.45" console.log(demo.format(123.45)); ProcessWire.addHookBefore("MyMoneyModule::format", (event) => { event.return = "****"; event.replace = true; }); // this will output "SOLD OUT" console.log(demo.format(123.45)); I hope this makes things clear π
-
Request for Input: What features should a PW calendar module have?
bernhard replied to bernhard's topic in Modules/Plugins
What do you mean, I don't understand?