Jump to content

Stefanowitsch

Members
  • Posts

    400
  • Joined

  • Last visited

  • Days Won

    7

Everything posted by Stefanowitsch

  1. I know this behaviour and it bothers me on every project. I always get a 500 time out error when loading loads of images the first time. This happens mostly in my local dev environment, though. The live server seems to be powerful enough to handle it faster without the timeout.
  2. As one of the earliest RockPageBuilder users (I think you can say so) I have to admit that this is my go-to module since day one. If you liked the RepeaterMatrix module for building pages you will absolutely love this one. In my opinion it is far superior and the frontend editing possibilities seem to be the "missing link" that developers & designers were always looking for. I made around 7 websites with this tool (small and medium in scale) and I definitely will showcase some of them as this module is finally released ?
  3. Tutorial Time! So finally I was able to make fetching the Instagram data work. And here's my tutorial how to achieve this. These are my requirements: - Load images from an instagram account and append them into a carousel slider on a website - To reduce loading times and file sizes I want to apply a "scrollspy" behaviour that only fetches data when the carousel is about to enter the viewport - I only load a certain amount of data and once the user is about to reach the end of the carousel, new data is fetched and appended automatically Using the UIKit framework comes in handy here. I am in fact using the UIKit slider component in combination with the UIKit scrollspy component here. Let's start: 1. This piece of code has to be implemented at the very top of your template PHP file (in my case it's the home.php) What this code does is basically: "If the this page is requested through an ajax all then get the media from the instagram account, print it out and then stop processing the rest of the template code." <?php $instagram = $modules->get('InstagramBasicDisplayApi'); if($config->ajax) { echo $instagram->getImages('USERNAME',6); // change USERNAME to the name that is authorized in the InstagramBasicDisplayApi module settings die(); } ?> 2. This is the HTML markup for our slider carousel (using the UIKit slider). Put it into the same template that has the code above. <section class="instagram-feed" uk-scrollspy="cls:uk-animation-slide-bottom"> <div class="uk-container"> <div class="uk-text-center"> <h2>MY INSTAGRAM FEED</h2> </div> <div class="insta-spinner uk-text-center uk-flex uk-flex-column uk-flex-middle"> <div uk-spinner="ratio: 2"></div> <p><b>Loading data...</b></p> </div> <div uk-slider> <div class="uk-position-relative"> <div class="uk-slider-container uk-margin"> <ul class="uk-slider-items uk-child-width-1-2 uk-child-width-1-5@m uk-grid" uk-scrollspy="target: > li > .last-item"> </ul> </div> <div class="uk-visible@s"> <a href="#" class="slider-arrow uk-position-center-left-out uk-position-medium" uk-slider-item="previous"><img src="/site/templates/images/icons/icon-arrow-left.svg" width="30" height="30" alt="Pfeil Links" loading="lazy"></a> <a href="#" class="slider-arrow uk-position-center-right-out uk-position-medium" uk-slider-item="next"><img src="/site/templates/images/icons/icon-arrow-right.svg" width="30" height="30" alt="Pfeil Rechts" loading="lazy"></a> </div> </div> <ul class="uk-slider-nav uk-dotnav uk-flex-center uk-margin"></ul> </div> </div> </section> Note: - I am using a loading spinner right away, this will be removed later on when data is fetched. - We are implementing the scrollspy component for the whole markup block. So when this block enters the viewport an event is fired that allows us to then start fetching data. - We are also implementing the scrollspy component that looks for the <li> with the "last-item" class. This will be our indicator for appending new data later on. - There are currently no <li> elements! That is of of course what we desire. We will load images from instagram and create those <li> elements on the fly. 3. This is the script that will fetch data and append the new carousel items. Put this code below the HTML markup or in a separate JS file: <script> document.addEventListener("DOMContentLoaded", () => { let feed = document.querySelector('.instagram-feed'); let sliderList = document.querySelector('.uk-slider-items'); let spinner = document.querySelector('.insta-spinner'); // listen for the scrollspy 'inview' event and execute this function if the carousel element comes into the viewport feed.addEventListener('inview', () => fetchData()); // create new carousel items and append them to the carousel let appendSlides = function(data) { data = JSON.parse(data); data.forEach((item) => { let image = document.createElement('li'); image.innerHTML = `<a href="${item.link}" target="_blank" rel="noopener" class="uk-display-block uk-height-1-1 uk-position-relative"><img src="${item.src}" alt="${item.alt}"/></a>`; sliderList.appendChild(image); }); // add new 'last-item' class to the second last carousel item so that new data is fetched when this element comes into the viewport const lastItem = sliderList.querySelector('li:nth-last-child(2) > a'); lastItem.classList.add('last-item'); // listen for the scrollspy 'inview' event and execute this function if the last carousel item comes into the viewport if (lastItem) { lastItem.addEventListener('inview', () => fetchData()); } }; // Make an ajax request using the fetch API async function fetchData() { try { const response = await fetch(window.location.href, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest' } }); let data = await response.text(); // Once data is received pass this data to our function to generate the carousel items appendSlides(data); // and don't forget to remove the loading spinner! spinner.remove(); } catch (error) { console.error(error); } } }); </script> That's it! If everything works correctly it should look like this:
  4. Added before line 439 this does not log anything (but also no error!): $this->log(json_encode($data)); This logs "false": bd(json_encode($data));
  5. This outputs an Array containing all the data I would expect. No errors at all.
  6. No it does not change anything. This logs "false" (when executed in the header of the template in the if $config->ajax statment. bd($instagram->getMedia('myusername'))
  7. Yes I have a working instance of the InstagramBasicDisplayApi on my Page. The media is fetched from my account and displayed in a carousel: This is the code, as I mentioned it works fine: <ul class="uk-slider-items uk-child-width-1-2 uk-child-width-1-5@m uk-grid"> <?php // Get the 12 most recent items and render them based on type foreach($instagram->getMedia('thumann.media',12) as $item) { switch($item->type) { case 'VIDEO': $media_src = $item->poster; $media_icon = '<i class="fas fa-film"></i>'; break; case 'CAROUSEL_ALBUM': // Just get the first item $media_src = $item->children->first->src; $media_icon = '<i class="far fa-images"></i>'; break; default: $media_src = $item->src; $media_icon = '<i class="far fa-images"></i>'; break; } ?> <li> <a href="<?=$item->link?>" target="_blank" rel="noopener"> <img class="lazyload img-fluid" src="<?=$media_src?>" alt="<?=$item->alt?>"/> <?=$media_icon?> </a> </li> <? } ?> </ul> Right now only 12 items are fetched. I want to go the next step and load the content of my Instagram channel in batches and append them when scrolling through the carousel. So I went to the documentation on the PW modules pages under "Pagination": https://processwire.com/modules/instagram-basic-display-api/ Lazy loading of items can be achieved using getMedia(). The following example shows how to return batches of items using AJAX requests: $instagram = $modules->get('InstagramBasicDisplayApi'); // The pagination cursor is reset if the request is not AJAX, e.g. when the page is loaded. if($config->ajax) { header('Content-Type: application/json'); echo $instagram->getMedia(); // ['json' => true] is inferred by $config->ajax die(); } But when I include a Tracy Debugger bardump on the $instagram->getMedia() function here it returns nothing.
  8. @nbcommunication thanks for your input! It seems the problem lies somewhere else. I am trying to get the most basic output but all I am receiving is an empty data object. On my home.php template I have this code at the very top: <?php $instagram = $modules->get('InstagramBasicDisplayApi'); // The pagination cursor is reset if the request is not AJAX, e.g. when the page is loaded. if($config->ajax) { header('Content-Type: application/json'); echo $instagram->getMedia(); // ['json' => true] is inferred by $config->ajax bd($instagram->getMedia()); die(); } ?> Then inside my template I have this code below which should do nothing else than send an AJAX request to the page itself to execute the code shown above. Also to make tracy debugger log the WireArray that is returned by the $instagram->getMedia() function. <script> (async () => { console.log('try to fetch data'); try { const response = await fetch(window.location.href, { method: 'GET', headers: { 'X-Requested-With': 'XMLHttpRequest' }, responseType: 'json' }); if (response.status === 200) { const data = await response.text(); console.log(data); } else { console.log(response.status); console.log(response.statusText); } } catch (error) { console.error(error); } })(); </script> Wenn viewing the homepage this script is executed but the console.log(data) prints out an empty string. The bd($instagram->getMedia()) instruction in the header also logs nothing.
  9. @nbcommunication For my new project I want to make use of the lazy loading function. So I followed the steps in the documentation. My main question is: where do I have to put this code? $instagram = $modules->get('InstagramBasicDisplayApi'); // The pagination cursor is reset if the request is not AJAX, e.g. when the page is loaded. if($config->ajax) { header('Content-Type: application/json'); echo $instagram->getMedia(); // ['json' => true] is inferred by $config->ajax die(); } echo '<div id=instagram class="uk-grid-small uk-child-width-1-2 uk-child-width-1-3@s uk-child-width-1-4@l" data-uk-grid data-uk-lightbox data-uk-scrollspy="target: > div; cls: uk-animation-slide-bottom-small; delay: 128;"></div>'; It it necessary to enter the user name in the getMedia() function? $instagram->getMedia('my.account'); When viewing the page I receive the following error in the console. I guess that has to do with the placement of the code above. (Index):403 SyntaxError: Unexpected token '<', "<!DOCTYPE "... is not valid JSON When placing the code at the top of my template (before the <!DOCTYPE is declared) I receive the following error: SyntaxError: Unexpected end of JSON input
  10. @bernhard does this mean that RockFrontend soon will support the compiling of SCSS files? Please say no. After years of using SCSS I switched to LESS just because of this feature ?
  11. It's great to see new recommendations popping up after 4 years ? I was able to solve this via the multi select field from the page tree ever since.
  12. I can reproduce this behaviour. It seems if you copy a text from a website and paste it into the frontend editor all the formatting (this means all HTML tags and elements) are also copied. This works fine on regular body fields that allow HTML tags. For example you can just copy & paste entire HTML tables without creating them in the editor from scratch. But when you then copy this text into a field that is set to not allow html tags it results in this kind of mess in the frontend: In the Backend it looks like this: This is because of the Textformatter settings for this headline field. HTML Tags are just rendered as plain text.
  13. I guess that is the perfect conclusion to this ?
  14. I've implemented an ajax-driven auto complete search on a website and I am wondering if you should use the CSRF check on this one or if this would be a bit "over the top"? More information: https://processwire.com/api/ref/session/c-s-r-f/
  15. I like to re-use most of the fields. For example in most projects i have one body field, one headline field and one (single) image field. With fieldsets I can reuse these fields as often an as much on a single template as I want. As long as the field settings not differ that much there is no use to create a "body2" or "body3" field. BUT if you need to alter the field settings in one case it is possible to override these changes on a fieldset-basis. For example I have this fieldset here with two generic input fields: A single image field and a body copy field. These are generic fields that I use all over the place. If I want to make slight changes to those fields in the context of the fieldset I can edit the fieldset and then click on the name of one of the fields inside it. This will open a dialogue where you can override very basic field settings. It is in most cases not possible to customize a field very much this way. For example you can't change the width and height cropping properties on an image field.
  16. After upgrading the PW Version to the latest master version 3.0.227 I get the message that there are two versions of the TinyMCE installed: This is because before the TinyMCE was officially a part of the PW core I installed it manually. My question is: Is it "safe" to just delete the module folder of the manually installed version that lives in the /site/modules folder? I want to make use of the core version from now on.
  17. Yeah I had the pleasure to be one of the earliest customers who uses this module and already made a few websites with it. Once it's released I will give some insight here in the board how I created this and that with it. It's a really powerful tool!
  18. Hello! I know exactly what you are meaning. Well you have at least three possibilites: 1. Use the Fieldset Page in ProcessWire. With this you can combine fields into one Fieldset. I don't use this Fielset anmyore but if I remember correct you have to install it from the "Core Modules Tab" (under: /processwire/module/). You create a new field (name it for example fieldset_introduction) and then you add fields to it that you want to make use of (cool thing: you can reuse this fields in all other fieldset page fields and don't have to create a "body copy field" for each and everyone of them separetely!) And here is what it looks like on a page template. The fields shown above are aligned in a fieldset named "Introduction". You can add several Fieldsets this way and just put them in any order on your page template. 2. Use the Repeater Matrix Pro Field. This ones commercial but it makes handling and editing Sections on your pages much easier and more flexible! Cool thing is that you can define your content blocks in the field settngs and add the needed fields right there. Then on your page template you can select the type of content block (or name it section): After that it's super easy and comfortable to edit these sections and also change their order! 3. Use a third party page builder module like the RockPageBuilder from @bernhard. This module even beats the popular Repeater Matrix module in my opinion as it accelerates the creation and editing (and managing!) of content massively! Even better, it kind of combines the Repeater Matrix block-buidling functions with frontend editing which is a massive leap forward in terms of workflow optimization and customer happiness (cause it is also very easy to use for non-technically experienced users!).
  19. Truly an inspiring project! The technical solutions here are fascinating. I haven't touched a project with a custom backend for users (yet!) and I always wondered how to approach it.
  20. I now changed Line 322 in InputfieldImageMarker.module from $addInfoPages = $modules->get('InputfieldAsmSelect'); foreach($opts as $opt) $addInfoPages->addOption($opt->id, $opt->title); to: $addInfoPages = $modules->get('InputfieldAsmSelect'); foreach($opts as $opt) $addInfoPages->addOption($opt->id, $opt->headline); Now the headline is shown as title in the select field: But the bummer is: It turns out that this field does not work properly inside a repeater matrix. The table with the marker coordinates never shows up after saving ?
  21. Ah sorry, my bad! This is not what I meant. I want to make the headline field of the repeater item pages shown in my screenshot to be listed in the AsmSelect Inputfield of the Image Marker Field. Right now this AsmSelect Field is only showing the page ID's of the repeater item pages: I don't know if this is even possible via hook.
  22. That's an interesting approach. The repeater items are located here in this case (rep_stories), how would I hook into the title rendering function in this case?
  23. I am in the need of using this module in a current project ? Turns out it works just as fine as I could ever wish! Except one thing: I want to make use of Repater Field Items as selectable pages only. So I added this line of code in the field settings. The page ID in this case is my repeater field that contains the child elements (=pages) that I want to be able to select. This works but unfortunately I see only the page IDs in the AsmSelect Inputfield as labels: I know that there is a setting for the AsmSelect to tell which field to use for the label: BUT since the AsmSelect in the ImageMarker module is generated via API code it is not possible to adjust this setting. @kongondo can you help me out on this one? it is somehow possible to tell the AsmSelect which field to use as a label?
  24. Ah that is a classic mistake I also made in the past. Page paths always have to end with a backslash in ProcessWire (but that is adjustable in the template settings!). When you call up an URL you can leave the backslash - this will work - but in that case theres a redirect going on that leads to the data-loss when submitting form data.
  25. I am stumbling over and over again over this issue and I really think this should be fixed, or at least the 'remove' option of the fixUnclosedTags() Function should be adjustable in the $sanitizer->truncate() method. @ryan
×
×
  • Create New...