Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by 3fingers

  1. Great video @bernhard, RockFrontend looks really handy and I will try it for sure on my next projects. Nice little funny touches on the video too, also your pace fits perfectly with the way I like to learn, not too slow and straight to the point in a concise but practical way. ??
  2. Check this : https://processwire.com/api/ref/page/children/ // Render navigation for all child pages below this one foreach($page->children() as $child) { echo "<li><a href='$child->url'>$child->title</a></li>"; } So in your case: $children = $pages->find("parent=/categories/, sort=title")->children(); foreach($children as $child) { // ... manipulate $child here }
  3. What about: $pages->findOne('page_reference=value') Not tested but findOne method should return just the first occurence of the page array.
  4. May I ask you why are you trying to resize svg? Svg are scalable by nature, so my personal approach you be to size them via css or html attributes on the svg tag itself.
  5. // Get images of the author if they exist if count($page->images): echo $page->images->each(function($image) { return "<li><a href='$image->size(100,100)->url'>$image->description</a></li>"; // Just an output example }); // Otherwise get images of their book covers else: foreach($page->page_ref_for_their_books as $all_pages): foreach($all_pages->images as $image): echo "<li><a href='$image->size(100,100)->url'>$image->description</a></li>"; endforeach; endforeach; endif;
  6. Looking at your pseudo-code you're outputting a single image (the first one) from the page reference field, so you don't need to loop through it. // Get images of the author if they exist if $page->images !='': foreach $page->images as $source: echo $source->size(100,100)->url; endforeach; // Otherwise get images of their book covers else: $source = $page->page_ref_for_their_books->images->first; echo $source->size(100,100)->url; endif;
  7. You can translate your "C" inside admin translation files, the right one is: wire--modules--languagesupport--languagesupport-module for each language you can define the setting there. More on setlocale here, if you want to set it via api: Docs
  8. You can configure your locale, according to your server settings, inside site/config.php like this: setlocale(LC_ALL, 'it_IT.UTF-8'); // where 'it_IT.UTF-8' is MY locale setting. You can find a list of all locales here on Stack Overflow
  9. <img src="<?= $page->my_image_field->url ?>" alt="<?= $page->my_image_field->description ?>"> // never forget to add "alt" attribute here In your example the "url" property was missing.
  10. This looks really cool but I have to admit that I would have to look at the code to really understand what's going on ? It looks like you are mastering htmx a lot lately, nice job!
  11. Just to be on the safe sife I would try to get those input variables like this: // On the php file whom handles your inputs (REMEMBER, IT HAS TO BE PLACED OUTISDE THE "template" folder) $page_id = $input->get->int->pageid; $status = $input->get->text->status; Moreover, as a test I'd try to use a relative path for your ajax call: $.ajax({ type: "GET", url: "./../ajax/file.php", // or wherever your file is placed/called data: { pageid: ckVal, status: ckStatus }, success: function(){ console.log(this.url); } Let us know ?
  12. Try: $wire->addHookBefore('Pages::saveReady', function($event){ $page = $event->arguments(0); if($page->hasField("my_checkbox")) { if($page->my_checkbox == 0) { $page->setAndSave('another_integer_field',0); $this->message("This should have worked"); //for debugging only } } });
  13. @kongondo Here I've found an interesting article about SSE and php and one thing mentioned, to avoid session locking (which I think its our culprit here) is to use: // make session read-only session_start(); session_write_close(); Above everything else in the code used to send data. I cannot test it at the moment, would you mind to have a check and report it back to us? ? I've found however possible bad implications doing this, as mentioned here in the forum.
  14. I think the best approach would be to use css ::first-line pseudo selector for that.
  15. Actually is not. PageTable (which is in the core but disabled by default) is not the same as Pro Field Table :)
  16. Following @bernhard implementation I've modified my code like this: while(true) { echo "event: ping" . PHP_EOL; echo "data: $result\n\n"; echo str_pad('',8186)."\n"; flush(); while(ob_get_level() > 0) ob_end_flush(); if(connection_aborted()) break; sleep(1); } The difference now is that, on my side, the polling (still present) is acting every 1 second. Moreover the pw admin (and every other page) doesn't load, the browser loading indicator spins forever....
  17. The fact is that SSE takes the connection open IF the server is responding something, otherwise it quits and retry a connection after five seconds. That's why it behaves like polling. The only way I found to keep the connection opened it's by tweaking server side code, wrapping the query in a while(true) function, considering the various drawbacks and flooding it can cause very quickly. I might be wrong but, as far as I understand, the only reliable way to keep a connection open, without any hassle, it's to use websockets (a whole different implementation however).
  18. Yes, I do see event.data being streamed at regular intervals (five seconds roughly + those 300ms delay driven by setTimeout). sse.mp4 Of course, for a change to take place and be visible on the browser, a pw page must be saved in order to trigger a change in the data being requested by SSE.
  19. Here is a little breakdown on what I've done to achieve what I needed. Basically I wanted to have the ability to change page content without browser refresh, using a simple page reference field placed on top of the page tree, allowing the selection of a page (and fields) I want to use to replace the content with. I've adopted the "kinda new" url hooks, in orded to have and end-point to make my request and have the content I wanted as response: <?php namespace ProcessWire; $wire->addHook('/emit', function ($event) { header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); $data = []; // page_selector is a page reference field $contributor = $event->pages->get('/')->page_selector->title; // get the current data for the page I have selected $data['current'] = $event->pages->getRaw("title=$contributor, field=id|title|text|image|finished, entities=1"); // other data I wanted to retrieve foreach($event->pages->findRaw("template=basic-page") as $key=>$value) { $data['contributors'][$key] = $value; } $result = json_encode($data); // This is the payload sent to the client, it has to be formatted correctly. // More on this here: https://developer.mozilla.org/en-US/docs/Web/API/Server-sent_events/Using_server-sent_events#event_stream_format echo "event: ping" . PHP_EOL; // The event name could be whatever, "ping" in this case. echo "data: " . $result . PHP_EOL; echo PHP_EOL; ob_end_flush(); flush(); }); Doing so we now have a url to point our SSE client. Let's see how it looks like: Vue.createApp({ data() { return { // This propertied are filled by resolveData() method below. fragmentShow: false, finished: '', id: '', title: '', text: '', image: '', imageDescription: '', contributors: '', } }, methods: { // imageUrl(), basePath() and idClass are helper functions. imageUrl() { return `http://localhost/sse_vue/site/assets/files/${this.id}/${this.image}`; }, basePath() { return `http://localhost/sse_vue/site/assets/files/`; }, idClass() { return `id-${this.id}`; }, // Retrieve data from the incoming stream getData(event) { return new Promise((resolve, reject) => { if (event.data) { let result = JSON.parse(event.data); // If the incoming page id is different than the current one, hide the container. if (this.id != result.current.id) { this.fragmentShow = false; } // This allows the <Transition> vue component to complete its animation before resolving the result. setTimeout(() => { resolve(result); }, 300) } }).then((result) => { this.resolveData(result); }); }, resolveData(result) { // Once the new values has come show the page again this.fragmentShow = true; // Set incoming values to vue reactive data() object this.finished = result.current.finished, this.id = result.current.id, this.title = result.current.title, this.text = result.current.text, this.image = result.current.image[0].data, this.imageDescription = result.current.image[0].description, this.contributors = result.contributors }, }, mounted: function() { // Init SSE and listen to php page emitter let source = new EventSource('/sse_vue/emit/'); source.addEventListener('ping', (event) => { // Get the incoming data this.getData(event); }); } }).mount('#app') On mounted vue lifecycle hook I start listening to the incoming stream and place useful informations inside the reactive data() object properties. Then I populated the html with those properties: <div id="app" class="container"> <Transition> <div :class="idClass()" class="bg-slate-200" v-show="fragmentShow"> <h1>{{title}}</h1> <p v-html="text"></p> <img :src="imageUrl()" :alt="imageDescription"> <div v-for="(contributor, index) in contributors"> <p :class="contributor.finished == 1 ? 'finished' : ''">{{contributor.title}}</p> <div v-if="contributor.document"> <a :href="basePath() + contributor.id + '/' + contributor.document[0].data">Download document</a> </div> </div> </div> </Transition> </div> Attached the video of the result (please don't look at the styling of it, it sucks). sse.mp4
  20. If anyone is still interested about this topic I've gracefully solved sse implementation both with alpine.js and vue.js (just for fun). Let me know if you want some code examples and I'll post them here.
  21. Reading from the docs I've found this: https://processwire.com/api/ref/wire-file-tools/send/ where you can specify, among other options, the content-type for the file you'd like to serve. Does it fits your needs?
  • Create New...