Jump to content

Leaderboard

Popular Content

Showing content with the highest reputation on 05/28/2019 in all areas

  1. It's amazing how much progress they've made since that article. was written For those thinking of diving into Flutter/Dart or even just Dart, don't be scared ?. An advantage we have as PW developers is the OOP side of PHP. Coupled with CSS (styling, box model, etc) and HTML (widget-like structures) plus JavaScript, it makes the dive into Dart (and other [modern] languages) not-so-painful. So you call it a Map we call it an Associative Array (or Dictionary in Python). You call it a List, we call it an Array. So you have collection.map()...that looks familiar. It's dot notation and I've seen map in JavaScript. We can do that, but we also know $this->something....etc. The flutter widget inspector looks really cool, btw. I am also happy that my code of choice, VSC, has Dart plugins and is mentioned in the official Flutter/Dart pages. Me and my ramblings...?
    3 points
  2. A while ago I bookmarked this: https://css-tricks.com/flutter-googles-take-on-cross-platform/
    3 points
  3. That's where Dart comes in :-). Have a look at the docs and examples. With Dart alone, you can build anything from backend servers, console programs and anything in between. Erm, no you don't. Look at the real world examples/showcase. We are talking Alibaba, Reflectly, Hamilton Musical, and the likes. For iOS we have Cupertino Material design. I am not saying these alone are enough to go by but so far, and I have done extensive research, I have yet to come across anyone mentioning that they have to maintain two code bases. In fact, they all say quite the opposite - they have done away with two code bases and their UI renders exactly as they intended in their targeted platforms. How so? The only thing I don't like so far is the styling and structure baked right inside the widgets. I think flutter had the advantage of learning from other solutions and picking the best bits and improving on the not-so-good bits. I am not a zealot (yet :-)), but the more I dive deeper into Dart and Flutter, the more I get convinced that Google got this one right :-).
    2 points
  4. Yes, I am using the default profile. The navbar appears on the homepage. I fixed the problem by going into site/templates/header.inc and commenting out the line"$children->prepend($homepage);" within the following code snippet: // Create the top navigation list by listing the children of the homepage. // If the section we are in is the current (identified by $page->rootParent) // then note it with <a class='on'> so we can style it differently in our CSS // and add a text that is visually hidden, but available for screen readers. // In this case we also want the homepage to be part of our top navigation, // so we prepend it to the pages we cycle through: $homepage = $pages->get("/"); $children = $homepage->children; // $children->prepend($homepage);
    2 points
  5. Hello, I hope you are all doing as well as possible. A friend has sent me the following link: https://undesign.learn.uno. And there seems to be interesting things also directly at https://learn.uno. Explore topics, Learning tools... Have a nice week! NB: I was not sure whether it was preferable to put this topic in Pub or in Dev Talk...
    2 points
  6. @kongondo So excited to see you actively working on this (I had only been watching the private access forum, whoops!). I'm developing a shop with the current full release of PadLoper and will need to launch it without waiting for your new release. We run an annual event and backup/purge the previous years' data so I know I'll at least be able to work with PadLoper 2 eventually! When it does come out, will I be able to run the PadLoper 2 module alongside the current module or will that cause conflicts?
    1 point
  7. @Macrura - Thanks for the info. I wasn't thinking outwith explicit calls to WireMailMailgun, so that makes sense. I'll probably still add the setSender() and setRegion() functions though, might be useful to have. Cheers, Chris
    1 point
  8. @jens.martsch - thinking through it a little more, I think the addition of h:sender should only happen if the "from" domain is different to $this->domain. I'll pop that in place soon. I'd wondered whether using this would effect the DKIM auth etc but a few quick tests suggest that it doesn't ?. @Macrura - I've been thinking about the Dynamic Domain setting, which I'd implemented based on your version but didn't give it much thought. Does it actually work without specifying the API key for the different domain? I wonder whether this could be removed and the following be the way to send from a different domain? <?php $mg = $mail->new(); $sent = $mg->to($to) ->setDomainName("mg.differentdomain.com") ->setApiKey($differentApiKey) ->setRegion("eu") // If the region is different //->setSender("mg.differentdomain.com", $differentApiKey, "eu") // Alternative, region optional ->subject($subject) ->bodyHTML($message) ->send(); Cheers, Chris
    1 point
  9. Not sure if anybody is watching what's going on in the requests repo or here in the forum... nevertheless, if you find this idea good, please support it on github: https://github.com/processwire/processwire-requests/issues/305
    1 point
  10. When I try it, I get something like: Notice: Undefined index: _width in \wire\core\Pageimage.php on line 1936 Notice: Undefined index: _height in \wire\core\Pageimage.php on line 1937 These are the new additions from Ryan that I'm currently have not checked how it works, but definetly, if width and height isn't known, the engines cannot create a new variation. I get this for image objects derived from CAI3 and with the original image too! Possibly a bug in the new pageimage additions, or a different use case that currently is not covered.
    1 point
  11. Hi @jens.martsch - I've merged your request. I'd always thought that was the correct behaviour because if you send from a domain that isn't what you have in Mailgun (e.g. @test.com when @mg.test.com is your verified domain) then the "on behalf of" is the correct result. However, if one line fixes that, that's great! Cheers, Chris
    1 point
  12. A year or so later, I have seen the future. Actually, I just stumbled upon it. Just when I was diving into Angular + TypeScript + NativeScript for mobile apps, I recently came across this thing, Flutter. I have been totally blown away! The last time I was this excited was when I discovered ProcessWire :-). Long story short, before I ended up here, I was looking at Kivy and BeeWare. I managed to pick up Python along the way. Kivy looks promising. I am interested in both mobile and desktop apps and it ticks those boxes. Then along comes Flutter and wow! Cross platform, write once deploy everywhere (iOS, Android, Embedded, Windows, Mac). It's still early days but I am totally convinced. I was a bit hesitant because it is a Google project (you know, their history of killing off projects...) but since it is open source and there are some big players already involved, I am sold. Flutter compiles to machine code! It comes with lots of widgets out of the box, both for iOS and Android. You can also ask it to compile to JavaScript (like TypeScript can and does). To program in Flutter you use Dart, a language developed by Google. I came across Dart a while back. Back then, it was considered a dead language. It has made a resurgence, thanks to Flutter. If you know your OOP and JavaScript, it is very easy to pick up, in an hour or so. If looking at Flutter, have a look at Hummingbird as well. What do you folks think? Anyone used Flutter before?
    1 point
  13. News Update - 26 May 2019 Discounts GUI Most work since the last update has gone to the discounts GUI. I also took the opportunity to trial the Tabbed interface suggested by @szabesz. I think I like the results. There are some crazy JS/CSS issues affecting the layout though. They seem to be coming from the ProcessWire navigation. Sometimes the padding is affected. This realigns correctly when you hover your mouse over the ProcessWire navigation. The dev inspector shows some dynamic activity going on, meaning JS. I'll post this in a separate post in the forums. Please note that this is still WIP. There are 4 types of discounts, each of which can be further refined by other factors including usage limits per order, globally, per customer, minimum requirements (purchase or amount), customer eligibility, etc. Discounts can be applied to specific products or categories or to the entire order. Percentage discounts Fixed amount/value Free Shipping Buy X Get Y Currently, discounts have to be created manually by the shop staff and customers have to enter a discount code at checkout. In future, we'll consider adding automatic discounts which will kick in if certain conditions are met. Here's a short video demoing the creation of discounts. Thanks.
    1 point
  14. Hello there, I've started using ProcessWire at work a while ago and I have been really enjoying building modular, clean and fast sites based on the CMS (at work, I usually post as @schwarzdesign). While building my first couple of websites with ProcessWire, I have written some useful helper functions for repetitive tasks. In this post I want to showcase and explain a particular function that generates a responsive image tag based on an image field, in the hope that some of you will find it useful :) I'll give a short explanation of responsive images and then walk through the different steps involved in generating the necessary markup & image variations. I want to keep this beginner-friendly, so most of you can probably skip over some parts. What are responsive images I want to keep this part short, there's a really good in-depth article about responsive images on MDN if you are interested in the details. The short version is that a responsive image tag is simply an <img>-tag that includes a couple of alternative image sources with different resolutions for the browser to choose from. This way, smaller screens can download the small image variant and save data, whereas high-resolution retina displays can download the extra-large variants for a crisp display experience. This information is contained in two special attributes: srcset - This attribute contains a list of source URLs for this image. For each source, the width of the image in pixels is specified. sizes - This attribute tells the browser how wide a space is available for the image, based on media queries (usually the width of the viewport). This is what a complete responsive image tag may look like: <img srcset="/site/assets/files/1015/happy_sheep_07.300x0.jpg 300w, /site/assets/files/1015/happy_sheep_07.600x0.jpg 600w, /site/assets/files/1015/happy_sheep_07.900x0.jpg 900w, /site/assets/files/1015/happy_sheep_07.1200x0.jpg 1200w, /site/assets/files/1015/happy_sheep_07.1800x0.jpg 1800w, /site/assets/files/1015/happy_sheep_07.2400x0.jpg 2400w" sizes="(min-width: 1140px) 350px, (min-width: 992px) 480px, (min-width: 576px) 540px, 100vw" src="/site/assets/files/1015/happy_sheep_07.1200x0.jpg" alt="One sheep"> This tells the browser that there are six different sources for this image available, ranging from 300px to 2400px wide variants (those are all the same image, just in different resolutions). It also tells the browser how wide the space for the image will be: 350px for viewports >= 1140px 480px for viewports >= 992px 540px for viewports >= 576px 100vw (full viewport width) for smaller viewports The sizes queries are checked in order of appearance and the browser uses the first one that matches. So now, the browser can calculate how large the image needs to be and then select the best fit from the srcset list to download. For browsers that don't support responsive images, a medium-sized variant is included as the normal src-Attribute. This is quite a lot of markup which I don't want to write by hand every time I want to place an image in a ProcessWire template. The helper function will need to generate both the markup and the variations of the original image. Building a reusable responsive image function Let's start with a function that takes two parameters: a Pageimage object and a standard width. Every time you access an image field through the API in a template (e.g. $page->my_image_field), you get a Pageimage object. Let's start with a skeleton for our function: function buildResponsiveImage( Pageimage $img, int $standard_width ): string { $default_img = $img->maxWidth($standard_width); return '<img src="' . $default_img->url() . '" alt="' . $img->description() . '">'; } // usage example echo buildResponsiveImage($page->my_image_field, 1200); This is already enough for a normal img tag (and it will serve as a fallback for older browsers). Now let's start adding to this, trying to keep the function as flexible and reusable as possible. Generating alternate resolutions We want to add a parameter that will allow the caller to specify in what sizes the alternatives should be generated. We could just accept an array parameter that contains the desired sizes as integers. But that is not very extendible, as we'll need to specify those sizes in each function call and change them all if the normal size of the image in the layout changes. Instead, we can use an array of factors; that will allow us to set a reasonable default, and still enable us to manually overwrite it. In the following, the function gets an optional parameter $variant_factor. // get the original image in full size $original_img = $img->getOriginal() ?? $img; // the default image for the src attribute, it wont be upscaled $default_image = $original_img->width($standard_width, ['upscaling' => false]); // the maximum size for our generated images $full_image_width = $original_img->width(); // fill the variant factors with defaults if not set if (empty($variant_factors)) { $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2]; } // build the srcset attribute string, and generate the corresponding widths $srcset = []; foreach ($variant_factors as $factor) { // round up, srcset doesn't allow fractions $width = ceil($standard_width * $factor); // we won't upscale images if ($width <= $full_image_width) { $srcset[] = $original_img->width($width)->url() . " {$width}w"; } } $srcset = implode(', ', $srcset); // example usage echo buildResponsiveImage($page->my_image_field, 1200, [0.4, 0.5, 0.6, 0.8, 1, 1.25, 1.5, 2]); Note that for resizing purposes, we want to get the original image through the API first, as we will generate some larger alternatives of the images for retina displays. We also don't want to generate upscaled versions of the image if the original image isn't wide enough, so I added a constraint for that. The great thing about the foreach-loop is that it generates the markup and the images on the server at the same time. When we call $original_img->width($width), ProcessWire automatically generates a variant of the image in that size if it doesn't exist already. So we need to do little work in terms of image manipulation. Generating the sizes attribute markup For this, we could build elaborate abstractions of the normal media queries, but for now, I've kept it very simple. The sizes attribute is defined through another array parameter that contains the media queries as strings in order of appearance. $sizes_attribute = implode(', ', $sizes_queries); The media queries are always separated by commas followed by a space character, so that part can be handled by the function. We'll still need to manually write the media queries when calling the function though, so that is something that can be improved upon. Finetuning & improvements This is what the function looks like now: function buildResponsiveImage( Pageimage $img, int $standard_width, array $sizes_queries, ?array $variant_factors = [] ): string { // get the original image in full size $original_img = $img->getOriginal() ?? $img; // the default image for the src attribute, it wont be upscaled $default_image = $original_img->width($standard_width, ['upscaling' => false]); // the maximum size for our generated images $full_image_width = $original_img->width(); // fill the variant factors with defaults if not set if (empty($variant_factors)) { $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2]; } // build the srcset attribute string, and generate the corresponding widths $srcset = []; foreach ($variant_factors as $factor) { // round up, srcset doesn't allow fractions $width = ceil($standard_width * $factor); // we won't upscale images if ($width <= $full_image_width) { $srcset[] = $original_img->width($width)->url() . " {$width}w"; } } $srcset = implode(', ', $srcset); return '<img src="' . $default_img->url() . '" alt="' . $img->description() . '" sizes="' . $sizes_attribute . '" srcset="' . $srcset . '">'; } It contains all the part we need, but there are some optimizations to make. First, we can make the $sizes_queries parameters optional. The sizes attribute default to 100vw (so the browser will always download an image large enough to fill the entire viewport width). This isn't optimal as it wastes bandwidth if the image doesn't fill the viewport, but it's good enough as a fallback. We can also make the width optional. When I have used this function in a project, the image I passed in was oftentimes already resized to the correct size. So we can make $standard_width an optional parameter that defaults to the width of the passed image. if (empty($standard_width)) { $standard_width = $img->width(); } Finally, we want to be able to pass in arbitrary attributes that will be added to the element. For now, we can just add a parameter $attributes that will be an associative array of attribute => value pairs. Then we need to collapse those into html markup. $attr_string = implode( ' ', array_map( function($attr, $value) { return $attr . '="' . $value . '"'; }, array_keys($attributes), $attributes ) ); This will also allow for some cleanup in the way the other attributes are generated, as we can simply add those to the $attributes array along the way. Here's the final version of this function with typehints and PHPDoc. Feel free to use this is your own projects. /** * Builds a responsive image element including different resolutions * of the passed image and optionally a sizes attribute build from * the passed queries. * * @param \Processwire\Pageimage $img The base image. * @param int|null $standard_width The standard width for this image. Use 0 or NULL to use the inherent size of the passed image. * @param array|null $attributes Optional array of html attributes. * @param array|null $sizes_queries The full queries and sizes for the sizes attribute. * @param array|null $variant_factors The multiplication factors for the alternate resolutions. * @return string */ function buildResponsiveImage( \Processwire\Pageimage $img, ?int $standard_width = 0, ?array $attributes = [], ?array $sizes_queries = [], ?array $variant_factors = [] ): string { // if $attributes is null, default to an empty array $attributes = $attributes ?? []; // if the standard width is empty, use the inherent width of the image if (empty($standard_width)) { $standard_width = $img->width(); } // get the original image in full size $original_img = $img->getOriginal() ?? $img; // the default image for the src attribute, it wont be // upscaled if the desired width is larger than the original $default_image = $original_img->width($standard_width, ['upscaling' => false]); // we won't create images larger than the original $full_image_width = $original_img->width(); // fill the variant factors with defaults if (empty($variant_factors)) { $variant_factors = [0.25, 0.5, 0.75, 1, 1.5, 2]; } // build the srcset attribute string, and generate the corresponding widths $srcset = []; foreach ($variant_factors as $factor) { // round up, srcset doesn't allow fractions $width = ceil($standard_width * $factor); // we won't upscale images if ($width <= $full_image_width) { $srcset[] = $original_img->width($width)->url() . " {$width}w"; } } $attributes['srcset'] = implode(', ', $srcset); // build the sizes attribute string if ($sizes_queries) { $attributes['sizes'] = implode(', ', $sizes_queries); } // add src fallback and alt attribute $attributes['src'] = $default_image->url(); if ($img->description()) { $attriutes['alt'] = $img->description(); } // implode the attributes array to html markup $attr_string = implode(' ', array_map(function($attr, $value) { return $attr . '="' . $value . '"'; }, array_keys($attributes), $attributes)); return "<img ${attr_string}>"; } Example usage with all arguments: echo buildResponsiveImage( $page->testimage, 1200, ['class' => 'img-fluid', 'id' => 'photo'], [ '(min-width: 1140px) 350px', '(min-width: 992px) 480px', '(min-width: 576px) 540px', '100vw' ], [0.4, 0.5, 0.6, 0.8, 1, 1.25, 1.5, 2] ); Result: <img class="img-fluid" id="photo" srcset="/site/assets/files/1/sean-pierce-1053024-unsplash.480x0.jpg 480w, /site/assets/files/1/sean-pierce-1053024-unsplash.600x0.jpg 600w, /site/assets/files/1/sean-pierce-1053024-unsplash.720x0.jpg 720w, /site/assets/files/1/sean-pierce-1053024-unsplash.960x0.jpg 960w, /site/assets/files/1/sean-pierce-1053024-unsplash.1200x0.jpg 1200w, /site/assets/files/1/sean-pierce-1053024-unsplash.1500x0.jpg 1500w, /site/assets/files/1/sean-pierce-1053024-unsplash.1800x0.jpg 1800w, /site/assets/files/1/sean-pierce-1053024-unsplash.2400x0.jpg 2400w" sizes="(min-width: 1140px) 350px, (min-width: 992px) 480px, (min-width: 576px) 540px, 100vw" src="/site/assets/files/1/sean-pierce-1053024-unsplash.1200x0.jpg" alt="by Sean Pierce"> Now this is actually too much functionality for one function; also, some of the code will be exactly the same for other, similar helper functions. If some of you are interested, I'll write a second part on how to split this into multiple smaller helper functions with some ideas on how to build upon it. But this has gotten long enough, so yeah, I hope this will be helpful or interesting to some of you :) Also, if you recognized any problems with this approach, or can point out some possible improvements, let me know. Thanks for reading!
    1 point
  15. Use a hidden inputfield: $field = $modules->get("InputfieldHidden");
    1 point
×
×
  • Create New...