Jump to content


  • Posts

  • Joined

  • Last visited

  • Days Won


Everything posted by 3fingers

  1. 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
  2. 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
  3. <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.
  4. 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!
  5. 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 πŸ™‚
  6. 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 } } });
  7. @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.
  8. I think the best approach would be to use css ::first-line pseudo selector for that.
  9. Actually is not. PageTable (which is in the core but disabled by default) is not the same as Pro Field Table :)
  10. 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....
  11. 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).
  12. 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.
  13. 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
  14. 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.
  15. 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?
  16. Let's hope then this is the year! πŸ™‚
  17. So I recall, and still waiting 😞 It was on top of his list but... EDIT: https://processwire.com/blog/posts/roadmap-2017/#whats-in-store-for-processwire-in-2017
  18. Some quotes missing here I think. Probably for the previous issue?
  19. I reply to you since nobody else does πŸ™‚ The motivation behind this silence is that in the past there was a similar thread in which someone else raised the same questions, regarding themes and a marketplace eventually. Short answer is no, most of the users here in the forum don't rely on theme market (as far as I remember, personally I design them from scratch). Same goes as having a starting point for processwire, due to the fact I build heterogeneous sites where it's kinda rare I feel the need for something different than a blank profile. Tailwind css rules πŸ‘πŸΌ
  20. Hello Mate, a while back I've made a video on how I usually approach usage of Tailwind with Pw, you can find it here. Nowaday, with Tailwind v.3.x I've changed my approach slightly, since some additional postcss packages are already included. Below my updated package.json file, in order to better understand which scripts I invoke: { "devDependencies": { "cross-env": "^7.0.2", "cssnano": "^4.1.10", "laravel-mix": "^6.0.41", "postcss": "^8.4.5", "postcss-import": "^14.0.2", "postcss-preset-env": "^7.2.3", "tailwindcss": "^3.0.18" }, "dependencies": { "concurrently": "^7.0.0", "postcss-cli": "^9.1.0" }, "scripts": { "start": "npx tailwindcss build -i styles/entry.pcss -o styles/dist/dist.css", "watch": "concurrently \"npx postcss styles/entry.pcss -o styles/dist/dist.css --watch\" \" npx mix watch \"", "build": "concurrently \"cross-env NODE_ENV=production npx postcss styles/entry.pcss -o styles/dist/dist.css\" \"npx mix --production\"" } } Basically I rely on tailwindcss cli to kickoff the first compilation of my entry point, then I invoke postcss --watch and mix watch (for js). At build time I switch node environment to production (which cssnano the final css) and mix --production to finalize my js (minification, module resolving, etc.). For completion here is the postcss.config.js: const cssnano = require('cssnano'); module.exports = () => ({ plugins: [ require('postcss-import'), require('tailwindcss/nesting'), require('tailwindcss'), require('autoprefixer'), require('postcss-preset-env')({ features: { 'nesting-rules': false } }), ...(process.env.NODE_ENV === 'production' ? [cssnano] : []) ] });
  21. Take a look here: https://processwire.com/blog/posts/pw-3.0.141/#example-1-changing-the-templates-directory
  22. Hello all, as title suggests I'm facing an issue where findRaw() doesn't recognise file fields, they are completely ignored. Is it something already issued? Is there a workaround for this? Thanks! EDIT: My fault, they are ignored as long they are empty. They show up correctly once populated.
  23. Hi @bernhard, this is what worked for me: <?php namespace ProcessWire; $wire->addHook('/emit', function ($event) { header('Content-Type: text/event-stream'); header('Cache-Control: no-cache'); $reference = $event->pages->get('/')->page_selector->title; $selector = $event->pages->getRaw("title=$reference, field=id|title|text|image, entities=1"); $result = json_encode($selector); while (true) { echo "event: ping" . PHP_EOL; echo "data: " . $result . PHP_EOL; echo PHP_EOL; ob_end_flush(); flush(); sleep(1); } }); In the frontend then: // Init SSE and listen to php page emitter let source = new EventSource("/sse/emit/"); source.addEventListener("ping", function(event) { getData(event) }); // Retrieve ping data, parse it and pass the result to the resolveData function function getData(event) { return new Promise((resolve, reject) => { if (event.data) { let result = JSON.parse(event.data); resolve(result); } }).then((result) => { resolveData(result) }); } // Resolve data and update alpine data function resolveData(result) { console.log(new Date().getSeconds()); // It logs correctly every 1 sec Object.assign(Alpine.store('sse'), { fragmentShow: true, id: result.id, title: result.title, text: result.text, image: result.image[0].data, imageDescription: result.image[0].description }); }
  24. Hello all! A client asked us to implement a landing page where some content would have to swap in real time when needed. Basically I need to implement a way to select in the backend (via a select dropdown or whatever) which page I want to use as the "replacer", save and then immediately use its html content to swap the old content, in real-time, on the front-end. I've read about htmx and its sse implementation, and also took a look at this simple example on how to dispach an event via php every second. The front-end part looks way easier to implement, but the backend one it's over my knowledge at the time of this writing. I know @netcarver did some test and also @kongondo is playing with those technology a bit lately. This is the first time I came to such a request and I'm looking for some advice from you guys! :)
  • Create New...